PortMidi  2.2.x
portmidi.c
1 #ifdef _MSC_VER
2  #pragma warning(disable: 4244) // stop warnings about downsize typecasts
3  #pragma warning(disable: 4018) // stop warnings about signed/unsigned
4 #endif
5 
6 #include "stdlib.h"
7 #include "string.h"
8 #include "portmidi.h"
9 #include "porttime.h"
10 #include "pmutil.h"
11 #include "pminternal.h"
12 #include <assert.h>
13 
14 #define MIDI_CLOCK 0xf8
15 #define MIDI_ACTIVE 0xfe
16 #define MIDI_STATUS_MASK 0x80
17 #define MIDI_SYSEX 0xf0
18 #define MIDI_EOX 0xf7
19 #define MIDI_START 0xFA
20 #define MIDI_STOP 0xFC
21 #define MIDI_CONTINUE 0xFB
22 #define MIDI_F9 0xF9
23 #define MIDI_FD 0xFD
24 #define MIDI_RESET 0xFF
25 #define MIDI_NOTE_ON 0x90
26 #define MIDI_NOTE_OFF 0x80
27 #define MIDI_CHANNEL_AT 0xD0
28 #define MIDI_POLY_AT 0xA0
29 #define MIDI_PROGRAM 0xC0
30 #define MIDI_CONTROL 0xB0
31 #define MIDI_PITCHBEND 0xE0
32 #define MIDI_MTC 0xF1
33 #define MIDI_SONGPOS 0xF2
34 #define MIDI_SONGSEL 0xF3
35 #define MIDI_TUNE 0xF6
36 
37 #define is_empty(midi) ((midi)->tail == (midi)->head)
38 
39 /* this is not static so that pm_init can set it directly if
40  * (see pmmac.c:pm_init())
41  */
42 int pm_initialized = FALSE;
43 
44 int pm_hosterror;
45 char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
46 
47 #ifdef PM_CHECK_ERRORS
48 
49 #include <stdio.h>
50 
51 #define STRING_MAX 80
52 
53 static void prompt_and_exit(void)
54 {
55  char line[STRING_MAX];
56  printf("type ENTER...");
57  fgets(line, STRING_MAX, stdin);
58  /* this will clean up open ports: */
59  exit(-1);
60 }
61 
62 
63 static PmError pm_errmsg(PmError err)
64 {
65  if (err == pmHostError) {
66  /* it seems pointless to allocate memory and copy the string,
67  * so I will do the work of Pm_GetHostErrorText directly
68  */
69  printf("PortMidi found host error...\n %s\n", pm_hosterror_text);
70  pm_hosterror = FALSE;
71  pm_hosterror_text[0] = 0; /* clear the message */
72  prompt_and_exit();
73  } else if (err < 0) {
74  printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
75  prompt_and_exit();
76  }
77  return err;
78 }
79 #else
80 #define pm_errmsg(err) err
81 #endif
82 
83 /*
84 ====================================================================
85 system implementation of portmidi interface
86 ====================================================================
87 */
88 
89 int pm_descriptor_max = 0;
90 int pm_descriptor_index = 0;
91 descriptor_type descriptors = NULL;
92 
93 /* pm_add_device -- describe interface/device pair to library
94  *
95  * This is called at intialization time, once for each
96  * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1)
97  * The strings are retained but NOT COPIED, so do not destroy them!
98  *
99  * returns pmInvalidDeviceId if device memory is exceeded
100  * otherwise returns pmNoError
101  */
102 PmError pm_add_device(char *interf, char *name, int input,
103  void *descriptor, pm_fns_type dictionary) {
104  if (pm_descriptor_index >= pm_descriptor_max) {
105  // expand descriptors
106  descriptor_type new_descriptors = (descriptor_type)
107  pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
108  if (!new_descriptors) return pmInsufficientMemory;
109  if (descriptors) {
110  memcpy(new_descriptors, descriptors,
111  sizeof(descriptor_node) * pm_descriptor_max);
112  free(descriptors);
113  }
114  pm_descriptor_max += 32;
115  descriptors = new_descriptors;
116  }
117  descriptors[pm_descriptor_index].pub.interf = interf;
118  descriptors[pm_descriptor_index].pub.name = name;
119  descriptors[pm_descriptor_index].pub.input = input;
120  descriptors[pm_descriptor_index].pub.output = !input;
121 
122  /* default state: nothing to close (for automatic device closing) */
123  descriptors[pm_descriptor_index].pub.opened = FALSE;
124 
125  /* ID number passed to win32 multimedia API open */
126  descriptors[pm_descriptor_index].descriptor = descriptor;
127 
128  /* points to PmInternal, allows automatic device closing */
129  descriptors[pm_descriptor_index].internalDescriptor = NULL;
130 
131  descriptors[pm_descriptor_index].dictionary = dictionary;
132 
133  pm_descriptor_index++;
134 
135  return pmNoError;
136 }
137 
138 
139 /* utility to look up device, given a pattern,
140  note: pattern is modified
141  */
142 int pm_find_default_device(char *pattern, int is_input)
143 {
144  int id = pmNoDevice;
145  int i;
146  /* first parse pattern into name, interf parts */
147  char *interf_pref = ""; /* initially assume it is not there */
148  char *name_pref = strstr(pattern, ", ");
149 
150  if (name_pref) { /* found separator, adjust the pointer */
151  interf_pref = pattern;
152  name_pref[0] = 0;
153  name_pref += 2;
154  } else {
155  name_pref = pattern; /* whole string is the name pattern */
156  }
157  for (i = 0; i < pm_descriptor_index; i++) {
158  const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
159  if (info->input == is_input &&
160  strstr(info->name, name_pref) &&
161  strstr(info->interf, interf_pref)) {
162  id = i;
163  break;
164  }
165  }
166  return id;
167 }
168 
169 
170 /*
171 ====================================================================
172 portmidi implementation
173 ====================================================================
174 */
175 
176 PMEXPORT int Pm_CountDevices( void ) {
177  Pm_Initialize();
178  /* no error checking -- Pm_Initialize() does not fail */
179  return pm_descriptor_index;
180 }
181 
182 
183 PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
184  Pm_Initialize(); /* no error check needed */
185  if (id >= 0 && id < pm_descriptor_index) {
186  return &descriptors[id].pub;
187  }
188  return NULL;
189 }
190 
191 /* pm_success_fn -- "noop" function pointer */
192 PmError pm_success_fn(PmInternal *midi) {
193  return pmNoError;
194 }
195 
196 /* none_write -- returns an error if called */
197 PmError none_write_short(PmInternal *midi, PmEvent *buffer) {
198  return pmBadPtr;
199 }
200 
201 /* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */
202 PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp) {
203  return pmBadPtr;
204 }
205 
206 PmError none_write_byte(PmInternal *midi, unsigned char byte,
207  PmTimestamp timestamp) {
208  return pmBadPtr;
209 }
210 
211 /* pm_fail_fn -- generic function, returns error if called */
212 PmError pm_fail_fn(PmInternal *midi) {
213  return pmBadPtr;
214 }
215 
216 static PmError none_open(PmInternal *midi, void *driverInfo) {
217  return pmBadPtr;
218 }
219 static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) {
220  *msg = 0; // empty string
221 }
222 static unsigned int none_has_host_error(PmInternal * midi) {
223  return FALSE;
224 }
225 PmTimestamp none_synchronize(PmInternal *midi) {
226  return 0;
227 }
228 
229 #define none_abort pm_fail_fn
230 #define none_close pm_fail_fn
231 
232 pm_fns_node pm_none_dictionary = {
233  none_write_short,
234  none_sysex,
235  none_sysex,
236  none_write_byte,
237  none_write_short,
238  none_write_flush,
239  none_synchronize,
240  none_open,
241  none_abort,
242  none_close,
243  none_poll,
244  none_has_host_error,
245  none_get_host_error
246 };
247 
248 
249 PMEXPORT const char *Pm_GetErrorText( PmError errnum ) {
250  const char *msg;
251 
252  switch(errnum)
253  {
254  case pmNoError:
255  msg = "";
256  break;
257  case pmHostError:
258  msg = "PortMidi: `Host error'";
259  break;
260  case pmInvalidDeviceId:
261  msg = "PortMidi: `Invalid device ID'";
262  break;
263  case pmInsufficientMemory:
264  msg = "PortMidi: `Insufficient memory'";
265  break;
266  case pmBufferTooSmall:
267  msg = "PortMidi: `Buffer too small'";
268  break;
269  case pmBadPtr:
270  msg = "PortMidi: `Bad pointer'";
271  break;
272  case pmInternalError:
273  msg = "PortMidi: `Internal PortMidi Error'";
274  break;
275  case pmBufferOverflow:
276  msg = "PortMidi: `Buffer overflow'";
277  break;
278  case pmBadData:
279  msg = "PortMidi: `Invalid MIDI message Data'";
280  break;
281  case pmBufferMaxSize:
282  msg = "PortMidi: `Buffer cannot be made larger'";
283  break;
284  default:
285  msg = "PortMidi: `Illegal error number'";
286  break;
287  }
288  return msg;
289 }
290 
291 
292 /* This can be called whenever you get a pmHostError return value.
293  * The error will always be in the global pm_hosterror_text.
294  */
295 PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len) {
296  assert(msg);
297  assert(len > 0);
298  if (pm_hosterror) {
299  strncpy(msg, (char *) pm_hosterror_text, len);
300  pm_hosterror = FALSE;
301  pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it
302  might help with debugging */
303  msg[len - 1] = 0; /* make sure string is terminated */
304  } else {
305  msg[0] = 0; /* no string to return */
306  }
307 }
308 
309 
310 PMEXPORT int Pm_HasHostError(PortMidiStream * stream) {
311  if (pm_hosterror) return TRUE;
312  if (stream) {
313  PmInternal * midi = (PmInternal *) stream;
314  pm_hosterror = (*midi->dictionary->has_host_error)(midi);
315  if (pm_hosterror) {
316  midi->dictionary->host_error(midi, pm_hosterror_text,
317  PM_HOST_ERROR_MSG_LEN);
318  /* now error message is global */
319  return TRUE;
320  }
321  }
322  return FALSE;
323 }
324 
325 
326 PMEXPORT PmError Pm_Initialize( void ) {
327  if (!pm_initialized) {
328  pm_hosterror = FALSE;
329  pm_hosterror_text[0] = 0; /* the null string */
330  pm_init();
331  pm_initialized = TRUE;
332  }
333  return pmNoError;
334 }
335 
336 
337 PMEXPORT PmError Pm_Terminate( void ) {
338  if (pm_initialized) {
339  pm_term();
340  // if there are no devices, descriptors might still be NULL
341  if (descriptors != NULL) {
342  free(descriptors);
343  descriptors = NULL;
344  }
345  pm_descriptor_index = 0;
346  pm_descriptor_max = 0;
347  pm_initialized = FALSE;
348  }
349  return pmNoError;
350 }
351 
352 
353 /* Pm_Read -- read up to length messages from source into buffer */
354 /*
355  * returns number of messages actually read, or error code
356  */
357 PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length) {
358  PmInternal *midi = (PmInternal *) stream;
359  int n = 0;
360  PmError err = pmNoError;
361  pm_hosterror = FALSE;
362  /* arg checking */
363  if(midi == NULL)
364  err = pmBadPtr;
365  else if(!descriptors[midi->device_id].pub.opened)
366  err = pmBadPtr;
367  else if(!descriptors[midi->device_id].pub.input)
368  err = pmBadPtr;
369  /* First poll for data in the buffer...
370  * This either simply checks for data, or attempts first to fill the buffer
371  * with data from the MIDI hardware; this depends on the implementation.
372  * We could call Pm_Poll here, but that would redo a lot of redundant
373  * parameter checking, so I copied some code from Pm_Poll to here: */
374  else err = (*(midi->dictionary->poll))(midi);
375 
376  if (err != pmNoError) {
377  if (err == pmHostError) {
378  midi->dictionary->host_error(midi, pm_hosterror_text,
379  PM_HOST_ERROR_MSG_LEN);
380  pm_hosterror = TRUE;
381  }
382  return pm_errmsg(err);
383  }
384 
385  while (n < length) {
386  PmError err = Pm_Dequeue(midi->queue, buffer++);
387  if (err == pmBufferOverflow) {
388  /* ignore the data we have retreived so far */
389  return pm_errmsg(pmBufferOverflow);
390  } else if (err == 0) { /* empty queue */
391  break;
392  }
393  n++;
394  }
395  return n;
396 }
397 
398 PMEXPORT PmError Pm_Poll( PortMidiStream *stream )
399 {
400  PmInternal *midi = (PmInternal *) stream;
401  PmError err;
402 
403  pm_hosterror = FALSE;
404  /* arg checking */
405  if(midi == NULL)
406  err = pmBadPtr;
407  else if (!descriptors[midi->device_id].pub.opened)
408  err = pmBadPtr;
409  else if (!descriptors[midi->device_id].pub.input)
410  err = pmBadPtr;
411  else
412  err = (*(midi->dictionary->poll))(midi);
413 
414  if (err != pmNoError) {
415  if (err == pmHostError) {
416  midi->dictionary->host_error(midi, pm_hosterror_text,
417  PM_HOST_ERROR_MSG_LEN);
418  pm_hosterror = TRUE;
419  }
420  return pm_errmsg(err);
421  }
422 
423  return !Pm_QueueEmpty(midi->queue);
424 }
425 
426 
427 /* this is called from Pm_Write and Pm_WriteSysEx to issue a
428  * call to the system-dependent end_sysex function and handle
429  * the error return
430  */
431 static PmError pm_end_sysex(PmInternal *midi)
432 {
433  PmError err = (*midi->dictionary->end_sysex)(midi, 0);
434  midi->sysex_in_progress = FALSE;
435  if (err == pmHostError) {
436  midi->dictionary->host_error(midi, pm_hosterror_text,
437  PM_HOST_ERROR_MSG_LEN);
438  pm_hosterror = TRUE;
439  }
440  return err;
441 }
442 
443 
444 /* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and
445  Pm_WriteSysEx all operate a state machine that "outputs" calls to
446  write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
447 
448 PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length)
449 {
450  PmInternal *midi = (PmInternal *) stream;
451  PmError err = pmNoError;
452  int i;
453  int bits;
454 
455  pm_hosterror = FALSE;
456  /* arg checking */
457  if(midi == NULL)
458  err = pmBadPtr;
459  else if(!descriptors[midi->device_id].pub.opened)
460  err = pmBadPtr;
461  else if(!descriptors[midi->device_id].pub.output)
462  err = pmBadPtr;
463  else
464  err = pmNoError;
465 
466  if (err != pmNoError) goto pm_write_error;
467 
468  if (midi->latency == 0) {
469  midi->now = 0;
470  } else {
471  midi->now = (*(midi->time_proc))(midi->time_info);
472  if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) {
473  /* time to resync */
474  midi->now = (*midi->dictionary->synchronize)(midi);
475  midi->first_message = FALSE;
476  }
477  }
478  /* error recovery: when a sysex is detected, we call
479  * dictionary->begin_sysex() followed by calls to
480  * dictionary->write_byte() and dictionary->write_realtime()
481  * until an end-of-sysex is detected, when we call
482  * dictionary->end_sysex(). After an error occurs,
483  * Pm_Write() continues to call functions. For example,
484  * it will continue to call write_byte() even after
485  * an error sending a sysex message, and end_sysex() will be
486  * called when an EOX or non-real-time status is found.
487  * When errors are detected, Pm_Write() returns immediately,
488  * so it is possible that this will drop data and leave
489  * sysex messages in a partially transmitted state.
490  */
491  for (i = 0; i < length; i++) {
492  uint32_t msg = buffer[i].message;
493  bits = 0;
494  /* is this a sysex message? */
495  if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
496  if (midi->sysex_in_progress) {
497  /* error: previous sysex was not terminated by EOX */
498  midi->sysex_in_progress = FALSE;
499  err = pmBadData;
500  goto pm_write_error;
501  }
502  midi->sysex_in_progress = TRUE;
503  if ((err = (*midi->dictionary->begin_sysex)(midi,
504  buffer[i].timestamp)) != pmNoError)
505  goto pm_write_error;
506  if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
507  buffer[i].timestamp)) != pmNoError)
508  goto pm_write_error;
509  bits = 8;
510  /* fall through to continue sysex processing */
511  } else if ((msg & MIDI_STATUS_MASK) &&
512  (Pm_MessageStatus(msg) != MIDI_EOX)) {
513  /* a non-sysex message */
514  if (midi->sysex_in_progress) {
515  /* this should be a realtime message */
516  if (is_real_time(msg)) {
517  if ((err = (*midi->dictionary->write_realtime)(midi,
518  &(buffer[i]))) != pmNoError)
519  goto pm_write_error;
520  } else {
521  midi->sysex_in_progress = FALSE;
522  err = pmBadData;
523  /* ignore any error from this, because we already have one */
524  /* pass 0 as timestamp -- it's ignored */
525  (*midi->dictionary->end_sysex)(midi, 0);
526  goto pm_write_error;
527  }
528  } else { /* regular short midi message */
529  if ((err = (*midi->dictionary->write_short)(midi,
530  &(buffer[i]))) != pmNoError)
531  goto pm_write_error;
532  continue;
533  }
534  }
535  if (midi->sysex_in_progress) { /* send sysex bytes until EOX */
536  /* see if we can accelerate data transfer */
537  if (bits == 0 && midi->fill_base && /* 4 bytes to copy */
538  (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
539  (msg & 0x80808080) == 0) { /* all data */
540  /* copy 4 bytes from msg to fill_base + fill_offset */
541  unsigned char *ptr = midi->fill_base +
542  *(midi->fill_offset_ptr);
543  ptr[0] = msg; ptr[1] = msg >> 8;
544  ptr[2] = msg >> 16; ptr[3] = msg >> 24;
545  (*midi->fill_offset_ptr) += 4;
546  continue;
547  }
548  /* no acceleration, so do byte-by-byte copying */
549  while (bits < 32) {
550  unsigned char midi_byte = (unsigned char) (msg >> bits);
551  if ((err = (*midi->dictionary->write_byte)(midi, midi_byte,
552  buffer[i].timestamp)) != pmNoError)
553  goto pm_write_error;
554  if (midi_byte == MIDI_EOX) {
555  err = pm_end_sysex(midi);
556  if (err != pmNoError) goto error_exit;
557  break; /* from while loop */
558  }
559  bits += 8;
560  }
561  } else {
562  /* not in sysex mode, but message did not start with status */
563  err = pmBadData;
564  goto pm_write_error;
565  }
566  }
567  /* after all messages are processed, send the data */
568  if (!midi->sysex_in_progress)
569  err = (*midi->dictionary->write_flush)(midi, 0);
570 pm_write_error:
571  if (err == pmHostError) {
572  midi->dictionary->host_error(midi, pm_hosterror_text,
573  PM_HOST_ERROR_MSG_LEN);
574  pm_hosterror = TRUE;
575  }
576 error_exit:
577  return pm_errmsg(err);
578 }
579 
580 
581 PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when, PmMessage msg)
582 {
583  PmEvent event;
584 
585  event.timestamp = when;
586  event.message = msg;
587  return Pm_Write(stream, &event, 1);
588 }
589 
590 
591 PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
592  unsigned char *msg)
593 {
594  /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */
595  /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */
596  #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)))
597  PmEvent buffer[BUFLEN];
598  int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */
599  PmInternal *midi = (PmInternal *) stream;
600  /* the next byte in the buffer is represented by an index, bufx, and
601  a shift in bits */
602  int shift = 0;
603  int bufx = 0;
604  buffer[0].message = 0;
605  buffer[0].timestamp = when;
606 
607  while (1) {
608  /* insert next byte into buffer */
609  buffer[bufx].message |= ((*msg) << shift);
610  shift += 8;
611  if (*msg++ == MIDI_EOX) break;
612  if (shift == 32) {
613  shift = 0;
614  bufx++;
615  if (bufx == buffer_size) {
616  PmError err = Pm_Write(stream, buffer, buffer_size);
617  /* note: Pm_Write has already called errmsg() */
618  if (err) return err;
619  /* prepare to fill another buffer */
620  bufx = 0;
621  buffer_size = BUFLEN;
622  /* optimization: maybe we can just copy bytes */
623  if (midi->fill_base) {
624  PmError err;
625  while (*(midi->fill_offset_ptr) < midi->fill_length) {
626  midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
627  if (*msg++ == MIDI_EOX) {
628  err = pm_end_sysex(midi);
629  if (err != pmNoError) return pm_errmsg(err);
630  goto end_of_sysex;
631  }
632  }
633  /* I thought that I could do a pm_Write here and
634  * change this if to a loop, avoiding calls in Pm_Write
635  * to the slower write_byte, but since
636  * sysex_in_progress is true, this will not flush
637  * the buffer, and we'll infinite loop: */
638  /* err = Pm_Write(stream, buffer, 0);
639  if (err) return err; */
640  /* instead, the way this works is that Pm_Write calls
641  * write_byte on 4 bytes. The first, since the buffer
642  * is full, will flush the buffer and allocate a new
643  * one. This primes the buffer so
644  * that we can return to the loop above and fill it
645  * efficiently without a lot of function calls.
646  */
647  buffer_size = 1; /* get another message started */
648  }
649  }
650  buffer[bufx].message = 0;
651  buffer[bufx].timestamp = when;
652  }
653  /* keep inserting bytes until you find MIDI_EOX */
654  }
655 end_of_sysex:
656  /* we're finished sending full buffers, but there may
657  * be a partial one left.
658  */
659  if (shift != 0) bufx++; /* add partial message to buffer len */
660  if (bufx) { /* bufx is number of PmEvents to send from buffer */
661  PmError err = Pm_Write(stream, buffer, bufx);
662  if (err) return err;
663  }
664  return pmNoError;
665 }
666 
667 
668 
669 PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
670  PmDeviceID inputDevice,
671  void *inputDriverInfo,
672  int32_t bufferSize,
673  PmTimeProcPtr time_proc,
674  void *time_info)
675 {
676  PmInternal *midi;
677  PmError err = pmNoError;
678  pm_hosterror = FALSE;
679  *stream = NULL;
680 
681  /* arg checking */
682  if (inputDevice < 0 || inputDevice >= pm_descriptor_index)
683  err = pmInvalidDeviceId;
684  else if (!descriptors[inputDevice].pub.input)
685  err = pmInvalidDeviceId;
686  else if(descriptors[inputDevice].pub.opened)
687  err = pmInvalidDeviceId;
688 
689  if (err != pmNoError)
690  goto error_return;
691 
692  /* create portMidi internal data */
693  midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
694  *stream = midi;
695  if (!midi) {
696  err = pmInsufficientMemory;
697  goto error_return;
698  }
699  midi->device_id = inputDevice;
700  midi->write_flag = FALSE;
701  midi->time_proc = time_proc;
702  midi->time_info = time_info;
703  /* windows adds timestamps in the driver and these are more accurate than
704  using a time_proc, so do not automatically provide a time proc. Non-win
705  implementations may want to provide a default time_proc in their
706  system-specific midi_out_open() method.
707  */
708  if (bufferSize <= 0) bufferSize = 256; /* default buffer size */
709  midi->queue = Pm_QueueCreate(bufferSize, (int32_t) sizeof(PmEvent));
710  if (!midi->queue) {
711  /* free portMidi data */
712  *stream = NULL;
713  pm_free(midi);
714  err = pmInsufficientMemory;
715  goto error_return;
716  }
717  midi->buffer_len = bufferSize; /* portMidi input storage */
718  midi->latency = 0; /* not used */
719  midi->sysex_in_progress = FALSE;
720  midi->sysex_message = 0;
721  midi->sysex_message_count = 0;
722  midi->filters = PM_FILT_ACTIVE;
723  midi->channel_mask = 0xFFFF;
724  midi->sync_time = 0;
725  midi->first_message = TRUE;
726  midi->dictionary = descriptors[inputDevice].dictionary;
727  midi->fill_base = NULL;
728  midi->fill_offset_ptr = NULL;
729  midi->fill_length = 0;
730  descriptors[inputDevice].internalDescriptor = midi;
731  /* open system dependent input device */
732  err = (*midi->dictionary->open)(midi, inputDriverInfo);
733  if (err) {
734  *stream = NULL;
735  descriptors[inputDevice].internalDescriptor = NULL;
736  /* free portMidi data */
737  Pm_QueueDestroy(midi->queue);
738  pm_free(midi);
739  } else {
740  /* portMidi input open successful */
741  descriptors[inputDevice].pub.opened = TRUE;
742  }
743 error_return:
744  /* note: if there is a pmHostError, it is the responsibility
745  * of the system-dependent code (*midi->dictionary->open)()
746  * to set pm_hosterror and pm_hosterror_text
747  */
748  return pm_errmsg(err);
749 }
750 
751 
752 PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
753  PmDeviceID outputDevice,
754  void *outputDriverInfo,
755  int32_t bufferSize,
756  PmTimeProcPtr time_proc,
757  void *time_info,
758  int32_t latency )
759 {
760  PmInternal *midi;
761  PmError err = pmNoError;
762  pm_hosterror = FALSE;
763  *stream = NULL;
764 
765  /* arg checking */
766  if (outputDevice < 0 || outputDevice >= pm_descriptor_index)
767  err = pmInvalidDeviceId;
768  else if (!descriptors[outputDevice].pub.output)
769  err = pmInvalidDeviceId;
770  else if (descriptors[outputDevice].pub.opened)
771  err = pmInvalidDeviceId;
772  if (err != pmNoError)
773  goto error_return;
774 
775  /* create portMidi internal data */
776  midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
777  *stream = midi;
778  if (!midi) {
779  err = pmInsufficientMemory;
780  goto error_return;
781  }
782  midi->device_id = outputDevice;
783  midi->write_flag = TRUE;
784  midi->time_proc = time_proc;
785  /* if latency > 0, we need a time reference. If none is provided,
786  use PortTime library */
787  if (time_proc == NULL && latency != 0) {
788  if (!Pt_Started())
789  Pt_Start(1, 0, 0);
790  /* time_get does not take a parameter, so coerce */
791  midi->time_proc = (PmTimeProcPtr) Pt_Time;
792  }
793  midi->time_info = time_info;
794  midi->buffer_len = bufferSize;
795  midi->queue = NULL; /* unused by output */
796  /* if latency zero, output immediate (timestamps ignored) */
797  /* if latency < 0, use 0 but don't return an error */
798  if (latency < 0) latency = 0;
799  midi->latency = latency;
800  midi->sysex_in_progress = FALSE;
801  midi->sysex_message = 0; /* unused by output */
802  midi->sysex_message_count = 0; /* unused by output */
803  midi->filters = 0; /* not used for output */
804  midi->channel_mask = 0xFFFF;
805  midi->sync_time = 0;
806  midi->first_message = TRUE;
807  midi->dictionary = descriptors[outputDevice].dictionary;
808  midi->fill_base = NULL;
809  midi->fill_offset_ptr = NULL;
810  midi->fill_length = 0;
811  descriptors[outputDevice].internalDescriptor = midi;
812  /* open system dependent output device */
813  err = (*midi->dictionary->open)(midi, outputDriverInfo);
814  if (err) {
815  *stream = NULL;
816  descriptors[outputDevice].internalDescriptor = NULL;
817  /* free portMidi data */
818  pm_free(midi);
819  } else {
820  /* portMidi input open successful */
821  descriptors[outputDevice].pub.opened = TRUE;
822  }
823 error_return:
824  /* note: system-dependent code must set pm_hosterror and
825  * pm_hosterror_text if a pmHostError occurs
826  */
827  return pm_errmsg(err);
828 }
829 
830 
831 PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
832 {
833  PmInternal *midi = (PmInternal *) stream;
834  PmError err = pmNoError;
835 
836  if (midi == NULL)
837  err = pmBadPtr;
838  else
839  midi->channel_mask = mask;
840 
841  return pm_errmsg(err);
842 }
843 
844 
845 PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters) {
846  PmInternal *midi = (PmInternal *) stream;
847  PmError err = pmNoError;
848 
849  /* arg checking */
850  if (midi == NULL)
851  err = pmBadPtr;
852  else if (!descriptors[midi->device_id].pub.opened)
853  err = pmBadPtr;
854  else
855  midi->filters = filters;
856  return pm_errmsg(err);
857 }
858 
859 
860 PMEXPORT PmError Pm_Close( PortMidiStream *stream ) {
861  PmInternal *midi = (PmInternal *) stream;
862  PmError err = pmNoError;
863 
864  pm_hosterror = FALSE;
865  /* arg checking */
866  if (midi == NULL) /* midi must point to something */
867  err = pmBadPtr;
868  /* if it is an open device, the device_id will be valid */
869  else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_index)
870  err = pmBadPtr;
871  /* and the device should be in the opened state */
872  else if (!descriptors[midi->device_id].pub.opened)
873  err = pmBadPtr;
874 
875  if (err != pmNoError)
876  goto error_return;
877 
878  /* close the device */
879  err = (*midi->dictionary->close)(midi);
880  /* even if an error occurred, continue with cleanup */
881  descriptors[midi->device_id].internalDescriptor = NULL;
882  descriptors[midi->device_id].pub.opened = FALSE;
883  if (midi->queue) Pm_QueueDestroy(midi->queue);
884  pm_free(midi);
885 error_return:
886  /* system dependent code must set pm_hosterror and
887  * pm_hosterror_text if a pmHostError occurs.
888  */
889  return pm_errmsg(err);
890 }
891 
892 PmError Pm_Synchronize( PortMidiStream* stream ) {
893  PmInternal *midi = (PmInternal *) stream;
894  PmError err = pmNoError;
895  if (midi == NULL)
896  err = pmBadPtr;
897  else if (!descriptors[midi->device_id].pub.output)
898  err = pmBadPtr;
899  else if (!descriptors[midi->device_id].pub.opened)
900  err = pmBadPtr;
901  else
902  midi->first_message = TRUE;
903  return err;
904 }
905 
906 PMEXPORT PmError Pm_Abort( PortMidiStream* stream ) {
907  PmInternal *midi = (PmInternal *) stream;
908  PmError err;
909  /* arg checking */
910  if (midi == NULL)
911  err = pmBadPtr;
912  else if (!descriptors[midi->device_id].pub.output)
913  err = pmBadPtr;
914  else if (!descriptors[midi->device_id].pub.opened)
915  err = pmBadPtr;
916  else
917  err = (*midi->dictionary->abort)(midi);
918 
919  if (err == pmHostError) {
920  midi->dictionary->host_error(midi, pm_hosterror_text,
921  PM_HOST_ERROR_MSG_LEN);
922  pm_hosterror = TRUE;
923  }
924  return pm_errmsg(err);
925 }
926 
927 
928 
929 /* pm_channel_filtered returns non-zero if the channel mask is blocking the current channel */
930 #define pm_channel_filtered(status, mask) \
931  ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
932 
933 
934 /* The following two functions will checks to see if a MIDI message matches
935  the filtering criteria. Since the sysex routines only want to filter realtime messages,
936  we need to have separate routines.
937  */
938 
939 
940 /* pm_realtime_filtered returns non-zero if the filter will kill the current message.
941  Note that only realtime messages are checked here.
942  */
943 #define pm_realtime_filtered(status, filters) \
944  ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
945 
946 /*
947  return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE))
948  || ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK))
949  || ((status == MIDI_START) && (filters & PM_FILT_PLAY))
950  || ((status == MIDI_STOP) && (filters & PM_FILT_PLAY))
951  || ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY))
952  || ((status == MIDI_F9) && (filters & PM_FILT_F9))
953  || ((status == MIDI_FD) && (filters & PM_FILT_FD))
954  || ((status == MIDI_RESET) && (filters & PM_FILT_RESET))
955  || ((status == MIDI_MTC) && (filters & PM_FILT_MTC))
956  || ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION))
957  || ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT))
958  || ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE));
959 }*/
960 
961 
962 /* pm_status_filtered returns non-zero if a filter will kill the current message, based on status.
963  Note that sysex and real time are not checked. It is up to the subsystem (winmm, core midi, alsa)
964  to filter sysex, as it is handled more easily and efficiently at that level.
965  Realtime message are filtered in pm_realtime_filtered.
966  */
967 #define pm_status_filtered(status, filters) ((1 << (16 + ((status) >> 4))) & (filters))
968 
969 
970 /*
971  return ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE))
972  || ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE))
973  || ((status == MIDI_CHANNEL_AT) && (filters & PM_FILT_CHANNEL_AFTERTOUCH))
974  || ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH))
975  || ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM))
976  || ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL))
977  || ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND));
978 
979 }
980 */
981 
982 static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
983 {
984  PmEvent event;
985 
986  /* there may be nothing in the buffer */
987  if (midi->sysex_message_count == 0) return; /* nothing to flush */
988 
989  event.message = midi->sysex_message;
990  event.timestamp = timestamp;
991  /* copied from pm_read_short, avoids filtering */
992  if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
993  midi->sysex_in_progress = FALSE;
994  }
995  midi->sysex_message_count = 0;
996  midi->sysex_message = 0;
997 }
998 
999 
1000 /* pm_read_short and pm_read_bytes
1001  are the interface between system-dependent MIDI input handlers
1002  and the system-independent PortMIDI code.
1003  The input handler MUST obey these rules:
1004  1) all short input messages must be sent to pm_read_short, which
1005  enqueues them to a FIFO for the application.
1006  2) each buffer of sysex bytes should be reported by calling pm_read_bytes
1007  (which sets midi->sysex_in_progress). After the eox byte,
1008  pm_read_bytes will clear sysex_in_progress
1009  */
1010 
1011 /* pm_read_short is the place where all input messages arrive from
1012  system-dependent code such as pmwinmm.c. Here, the messages
1013  are entered into the PortMidi input buffer.
1014  */
1015 void pm_read_short(PmInternal *midi, PmEvent *event)
1016 {
1017  int status;
1018  /* arg checking */
1019  assert(midi != NULL);
1020  /* midi filtering is applied here */
1021  status = Pm_MessageStatus(event->message);
1022  if (!pm_status_filtered(status, midi->filters)
1023  && (!is_real_time(status) ||
1024  !pm_realtime_filtered(status, midi->filters))
1025  && !pm_channel_filtered(status, midi->channel_mask)) {
1026  /* if sysex is in progress and we get a status byte, it had
1027  better be a realtime message or the starting SYSEX byte;
1028  otherwise, we exit the sysex_in_progress state
1029  */
1030  if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
1031  /* two choices: real-time or not. If it's real-time, then
1032  * this should be delivered as a sysex byte because it is
1033  * embedded in a sysex message
1034  */
1035  if (is_real_time(status)) {
1036  midi->sysex_message |=
1037  (status << (8 * midi->sysex_message_count++));
1038  if (midi->sysex_message_count == 4) {
1039  pm_flush_sysex(midi, event->timestamp);
1040  }
1041  } else { /* otherwise, it's not real-time. This interrupts
1042  * a sysex message in progress */
1043  midi->sysex_in_progress = FALSE;
1044  }
1045  } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
1046  midi->sysex_in_progress = FALSE;
1047  }
1048  }
1049 }
1050 
1051 /* pm_read_bytes -- read one (partial) sysex msg from MIDI data */
1052 /*
1053  * returns how many bytes processed
1054  */
1055 unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data,
1056  int len, PmTimestamp timestamp)
1057 {
1058  int i = 0; /* index into data, must not be unsigned (!) */
1059  PmEvent event;
1060  event.timestamp = timestamp;
1061  assert(midi);
1062  /* note that since buffers may not have multiples of 4 bytes,
1063  * pm_read_bytes may be called in the middle of an outgoing
1064  * 4-byte PortMidi message. sysex_in_progress indicates that
1065  * a sysex has been sent but no eox.
1066  */
1067  if (len == 0) return 0; /* sanity check */
1068  if (!midi->sysex_in_progress) {
1069  while (i < len) { /* process all data */
1070  unsigned char byte = data[i++];
1071  if (byte == MIDI_SYSEX &&
1072  !pm_realtime_filtered(byte, midi->filters)) {
1073  midi->sysex_in_progress = TRUE;
1074  i--; /* back up so code below will get SYSEX byte */
1075  break; /* continue looping below to process msg */
1076  } else if (byte == MIDI_EOX) {
1077  midi->sysex_in_progress = FALSE;
1078  return i; /* done with one message */
1079  } else if (byte & MIDI_STATUS_MASK) {
1080  /* We're getting MIDI but no sysex in progress.
1081  * Either the SYSEX status byte was dropped or
1082  * the message was filtered. Drop the data, but
1083  * send any embedded realtime bytes.
1084  */
1085  /* assume that this is a real-time message:
1086  * it is an error to pass non-real-time messages
1087  * to pm_read_bytes
1088  */
1089  event.message = byte;
1090  pm_read_short(midi, &event);
1091  }
1092  } /* all bytes in the buffer are processed */
1093  }
1094  /* Now, i<len implies sysex_in_progress. If sysex_in_progress
1095  * becomes false in the loop, there must have been an overflow
1096  * and we can just drop all remaining bytes
1097  */
1098  while (i < len && midi->sysex_in_progress) {
1099  if (midi->sysex_message_count == 0 && i <= len - 4 &&
1100  ((event.message = (((PmMessage) data[i]) |
1101  (((PmMessage) data[i+1]) << 8) |
1102  (((PmMessage) data[i+2]) << 16) |
1103  (((PmMessage) data[i+3]) << 24))) &
1104  0x80808080) == 0) { /* all data, no status */
1105  if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
1106  midi->sysex_in_progress = FALSE;
1107  }
1108  i += 4;
1109  } else {
1110  while (i < len) {
1111  /* send one byte at a time */
1112  unsigned char byte = data[i++];
1113  if (is_real_time(byte) &&
1114  pm_realtime_filtered(byte, midi->filters)) {
1115  continue; /* real-time data is filtered, so omit */
1116  }
1117  midi->sysex_message |=
1118  (byte << (8 * midi->sysex_message_count++));
1119  if (byte == MIDI_EOX) {
1120  midi->sysex_in_progress = FALSE;
1121  pm_flush_sysex(midi, event.timestamp);
1122  return i;
1123  } else if (midi->sysex_message_count == 4) {
1124  pm_flush_sysex(midi, event.timestamp);
1125  /* after handling at least one non-data byte
1126  * and reaching a 4-byte message boundary,
1127  * resume trying to send 4 at a time in outer loop
1128  */
1129  break;
1130  }
1131  }
1132  }
1133  }
1134  return i;
1135 }
1136 
1137 
PMEXPORT const PmDeviceInfo * Pm_GetDeviceInfo(PmDeviceID id)
Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure referring to the device specified by...
Definition: portmidi.c:183
PMEXPORT PmError Pm_OpenInput(PortMidiStream **stream, PmDeviceID inputDevice, void *inputDriverInfo, int32_t bufferSize, PmTimeProcPtr time_proc, void *time_info)
Pm_OpenInput() and Pm_OpenOutput() open devices.
Definition: portmidi.c:669
#define PM_FILT_ACTIVE
filter active sensing messages (0xFE):
Definition: portmidi.h:389
PMEXPORT PmError Pm_Close(PortMidiStream *stream)
Pm_Close() closes a midi stream, flushing any pending buffers.
Definition: portmidi.c:860
PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
Pm_SetChannelMask() filters incoming messages based on channel.
Definition: portmidi.c:831
PMEXPORT PmError Pm_Abort(PortMidiStream *stream)
Pm_Abort() terminates outgoing messages immediately The caller should immediately close the output po...
Definition: portmidi.c:906
int32_t PmMessage
see PmEvent
Definition: portmidi.h:511
PmError Pm_Synchronize(PortMidiStream *stream)
Pm_Synchronize() instructs PortMidi to (re)synchronize to the time_proc passed when the stream was op...
Definition: portmidi.c:892
PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length)
Pm_Read() retrieves midi data into a buffer, and returns the number of events read.
Definition: portmidi.c:357
PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when, PmMessage msg)
Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
Definition: portmidi.c:581
PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when, unsigned char *msg)
Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
Definition: portmidi.c:591
PMEXPORT PmError Pm_Poll(PortMidiStream *stream)
Pm_Poll() tests whether input is available, returning TRUE, FALSE, or an error value.
Definition: portmidi.c:398
PMEXPORT PmError Pm_Write(PortMidiStream *stream, PmEvent *buffer, int32_t length)
Pm_Write() writes midi data from a buffer.
Definition: portmidi.c:448
const char * name
device name, e.g.
Definition: portmidi.h:209
const char * interf
underlying MIDI API, e.g.
Definition: portmidi.h:208
int input
true iff input is available
Definition: portmidi.h:210
All midi data comes in the form of PmEvent structures.
Definition: portmidi.h:577

Generated for PortMidi by doxygen 1.9.1