void main_test_both() { int i = 0; int in, out; PmStream * midi, * midiOut; PmEvent buffer[1]; PmError status, length; int num = 10; in = get_number("Type input number: "); out = get_number("Type output number: "); /* In is recommended to start timer before PortMidi */ TIME_START; Pm_OpenOutput(&midiOut, out, DRIVER_INFO, OUTPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO, latency); printf("Midi Output opened with %ld ms latency.\n", (long) latency); /* open input device */ Pm_OpenInput(&midi, in, DRIVER_INFO, INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO); printf("Midi Input opened. Reading %d Midi messages...\n",num); Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK); /* empty the buffer after setting filter, just in case anything got through */ while (Pm_Poll(midi)) { Pm_Read(midi, buffer, 1); } i = 0; while (i < num) { status = Pm_Poll(midi); if (status == TRUE) { length = Pm_Read(midi,buffer,1); if (length > 0) { Pm_Write(midiOut, buffer, 1); printf("Got message %d: time %ld, %2lx %2lx %2lx\n", i, (long) buffer[0].timestamp, (long) Pm_MessageStatus(buffer[0].message), (long) Pm_MessageData1(buffer[0].message), (long) Pm_MessageData2(buffer[0].message)); i++; } else { assert(0); } } } /* close midi devices */ Pm_Close(midi); Pm_Close(midiOut); Pm_Terminate(); }
int osd_midi_device_pm::read(UINT8 *pOut) { int msgsRead = Pm_Read(pmStream, rx_evBuf, RX_EVENT_BUF_SIZE); int bytesOut = 0; if (msgsRead <= 0) { return 0; } for (int msg = 0; msg < msgsRead; msg++) { UINT8 status = Pm_MessageStatus(rx_evBuf[msg].message); if (rx_sysex) { if (status & 0x80) // sys real-time imposing on us? { if ((status == 0xf2) || (status == 0xf3)) { *pOut++ = status; *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); *pOut++ = Pm_MessageData2(rx_evBuf[msg].message); bytesOut += 3; } else { *pOut++ = status; bytesOut++; if (status == MIDI_EOX) { rx_sysex = false; } } } else // shift out the sysex bytes { for (int i = 0; i < 4; i++) { UINT8 byte = rx_evBuf[msg].message & 0xff; *pOut++ = byte; bytesOut++; if (byte == MIDI_EOX) { rx_sysex = false; break; } rx_evBuf[msg].message >>= 8; } } } else { switch ((status>>4) & 0xf) { case 0xc: // 2-byte messages case 0xd: *pOut++ = status; *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); bytesOut += 2; break; case 0xf: // system common switch (status & 0xf) { case 0: // System Exclusive { *pOut++ = status; // this should be OK: the shortest legal sysex is F0 tt dd F7, I believe *pOut++ = (rx_evBuf[msg].message>>8) & 0xff; *pOut++ = (rx_evBuf[msg].message>>16) & 0xff; UINT8 last = *pOut++ = (rx_evBuf[msg].message>>24) & 0xff; bytesOut += 4; rx_sysex = (last != MIDI_EOX); break; } case 7: // End of System Exclusive *pOut++ = status; bytesOut += 1; rx_sysex = false; break; case 2: // song pos case 3: // song select *pOut++ = status; *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); *pOut++ = Pm_MessageData2(rx_evBuf[msg].message); bytesOut += 3; break; default: // all other defined Fx messages are 1 byte break; } break; default: *pOut++ = status; *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); *pOut++ = Pm_MessageData2(rx_evBuf[msg].message); bytesOut += 3; break; } } }
int main(int argc, const char * argv[]) { int i, numDevices, selectedDeviceIndex = 3; long channel; const PmDeviceInfo *info; PortMidiStream *stream; PmEvent event; Pm_Initialize(); numDevices = Pm_CountDevices(); if (numDevices == 0) { return 0; } for (i = 0; i < numDevices; i++) { info = Pm_GetDeviceInfo(i); if (info->input) { } } info = Pm_GetDeviceInfo(selectedDeviceIndex); channel = 1; channel--; Pm_OpenInput(&stream, selectedDeviceIndex, NULL, 8192, NULL, NULL); printf("Setup complete! Waiting for MIDI data...\n"); system("setterm -blank force");//kills all display. to bring back call: setterm -blank poke while (1) { long status, data1, data2; int length, person, audioFile; length = Pm_Read(stream, &event, sizeof(long)); if (length > 0) { status = Pm_MessageStatus(event.message); data1 = Pm_MessageData1(event.message); data2 = Pm_MessageData2(event.message); if (status == (0x80 + channel)) { printf("Note off: %ld, %ld\n", data1, data2); } else if (status == (0x90 + channel)) { printf("Note on: %ld, %ld\n", data1, data2); } else if (status == (0xB0 + channel)) { printf("CC: %ld, %ld\n", data1, data2); } } if (data1 == 25) { if (data2 == 127) { system("clear"); system("playMovie"); } } if(data1 == 26) { if(data2 == 127) { system("setterm -blank force"); } if(data2 == 0) { system("setterm -blank poke"); } } } Pm_Close(stream); Pm_Terminate(); return 0; }
static int ReadMidiData_(CSOUND *csound, void *userData, unsigned char *mbuf, int nbytes) { int n, retval, st, d1, d2; PmEvent mev; pmall_data *data; /* * Reads from MIDI input device linked list. */ n = 0; data = (pmall_data *)userData; while (data) { retval = Pm_Poll(data->midistream); if (retval != FALSE) { if (UNLIKELY(retval < 0)) return portMidiErrMsg(csound, Str("error polling input device")); while ((retval = Pm_Read(data->midistream, &mev, 1L)) > 0) { st = (int)Pm_MessageStatus(mev.message); d1 = (int)Pm_MessageData1(mev.message); d2 = (int)Pm_MessageData2(mev.message); /* unknown message or sysex data: ignore */ if (UNLIKELY(st < 0x80)) continue; /* ignore most system messages */ if (UNLIKELY(st >= 0xF0 && !(st == 0xF8 || st == 0xFA || st == 0xFB || st == 0xFC || st == 0xFF))) continue; nbytes -= (datbyts[(st - 0x80) >> 4] + 1); if (UNLIKELY(nbytes < 0)) { portMidiErrMsg(csound, Str("buffer overflow in MIDI input")); break; } /* channel messages */ n += (datbyts[(st - 0x80) >> 4] + 1); switch (datbyts[(st - 0x80) >> 4]) { case 0: *mbuf++ = (unsigned char) st; break; case 1: *mbuf++ = (unsigned char) st; *mbuf++ = (unsigned char) d1; break; case 2: *mbuf++ = (unsigned char) st; *mbuf++ = (unsigned char) d1; *mbuf++ = (unsigned char) d2; break; } } if (UNLIKELY(retval < 0)) { portMidiErrMsg(csound, Str("read error %d"), retval); if (n < 1) n = -1; } } data = data->next; } /* return the number of bytes read */ return n; }
PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length) { PmInternal *midi = (PmInternal *) stream; PmError err; int i; int bits; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if(Pm_HasHostError(midi)) err = pmHostError; else if(!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.output) err = pmBadPtr; else err = pmNoError; if (err != pmNoError) goto pm_write_error; if (midi->latency == 0) { midi->now = 0; } else { midi->now = (*(midi->time_proc))(midi->time_info); if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) { /* time to resync */ midi->now = (*midi->dictionary->synchronize)(midi); midi->first_message = FALSE; } } for (i = 0; i < length; i++) { unsigned long msg = buffer[i].message; bits = 0; /* is this a sysex message? */ if (Pm_MessageStatus(msg) == MIDI_SYSEX) { if (midi->sysex_in_progress) { /* error: previous sysex was not terminated by EOX */ midi->sysex_in_progress = FALSE; err = pmBadData; goto pm_write_error; } midi->sysex_in_progress = TRUE; if ((err = (*midi->dictionary->begin_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX, buffer[i].timestamp)) != pmNoError) goto pm_write_error; bits = 8; /* fall through to continue sysex processing */ } else if ((msg & MIDI_STATUS_MASK) && (Pm_MessageStatus(msg) != MIDI_EOX)) { /* a non-sysex message */ if (midi->sysex_in_progress) { /* this should be a non-realtime message */ if (is_real_time(msg)) { if ((err = (*midi->dictionary->write_realtime)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; } else { midi->sysex_in_progress = FALSE; err = pmBadData; /* ignore any error from this, because we already have one */ /* pass 0 as timestamp -- it's ignored */ (*midi->dictionary->end_sysex)(midi, 0); goto pm_write_error; } } else { /* regular short midi message */ if ((err = (*midi->dictionary->write_short)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; continue; } } if (midi->sysex_in_progress) { /* send sysex bytes until EOX */ while (bits < 32) { unsigned char midi_byte = (unsigned char) (msg >> bits); if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if (midi_byte == MIDI_EOX) { midi->sysex_in_progress = FALSE; if ((err = (*midi->dictionary->end_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; break; /* from while loop */ } bits += 8; } } else { /* not in sysex mode, but message did not start with status */ err = pmBadData; goto pm_write_error; } }
PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length) { PmInternal *midi = (PmInternal *) stream; PmError err = pmNoError; int i; int bits; pm_hosterror = FALSE; /* arg checking */ if(midi == NULL) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.opened) err = pmBadPtr; else if(!descriptors[midi->device_id].pub.output) err = pmBadPtr; else err = pmNoError; if (err != pmNoError) goto pm_write_error; if (midi->latency == 0) { midi->now = 0; } else { midi->now = (*(midi->time_proc))(midi->time_info); if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) { /* time to resync */ midi->now = (*midi->dictionary->synchronize)(midi); midi->first_message = FALSE; } } /* error recovery: when a sysex is detected, we call * dictionary->begin_sysex() followed by calls to * dictionary->write_byte() and dictionary->write_realtime() * until an end-of-sysex is detected, when we call * dictionary->end_sysex(). After an error occurs, * Pm_Write() continues to call functions. For example, * it will continue to call write_byte() even after * an error sending a sysex message, and end_sysex() will be * called when an EOX or non-real-time status is found. * When errors are detected, Pm_Write() returns immediately, * so it is possible that this will drop data and leave * sysex messages in a partially transmitted state. */ for (i = 0; i < length; i++) { uint32_t msg = buffer[i].message; bits = 0; /* is this a sysex message? */ if (Pm_MessageStatus(msg) == MIDI_SYSEX) { if (midi->sysex_in_progress) { /* error: previous sysex was not terminated by EOX */ midi->sysex_in_progress = FALSE; err = pmBadData; goto pm_write_error; } midi->sysex_in_progress = TRUE; if ((err = (*midi->dictionary->begin_sysex)(midi, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX, buffer[i].timestamp)) != pmNoError) goto pm_write_error; bits = 8; /* fall through to continue sysex processing */ } else if ((msg & MIDI_STATUS_MASK) && (Pm_MessageStatus(msg) != MIDI_EOX)) { /* a non-sysex message */ if (midi->sysex_in_progress) { /* this should be a realtime message */ if (is_real_time(msg)) { if ((err = (*midi->dictionary->write_realtime)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; } else { midi->sysex_in_progress = FALSE; err = pmBadData; /* ignore any error from this, because we already have one */ /* pass 0 as timestamp -- it's ignored */ (*midi->dictionary->end_sysex)(midi, 0); goto pm_write_error; } } else { /* regular short midi message */ if ((err = (*midi->dictionary->write_short)(midi, &(buffer[i]))) != pmNoError) goto pm_write_error; continue; } } if (midi->sysex_in_progress) { /* send sysex bytes until EOX */ /* see if we can accelerate data transfer */ if (bits == 0 && midi->fill_base && /* 4 bytes to copy */ (*midi->fill_offset_ptr) + 4 <= midi->fill_length && (msg & 0x80808080) == 0) { /* all data */ /* copy 4 bytes from msg to fill_base + fill_offset */ unsigned char *ptr = midi->fill_base + *(midi->fill_offset_ptr); ptr[0] = msg; ptr[1] = msg >> 8; ptr[2] = msg >> 16; ptr[3] = msg >> 24; (*midi->fill_offset_ptr) += 4; continue; } /* no acceleration, so do byte-by-byte copying */ while (bits < 32) { unsigned char midi_byte = (unsigned char) (msg >> bits); if ((err = (*midi->dictionary->write_byte)(midi, midi_byte, buffer[i].timestamp)) != pmNoError) goto pm_write_error; if (midi_byte == MIDI_EOX) { err = pm_end_sysex(midi); if (err != pmNoError) goto error_exit; break; /* from while loop */ } bits += 8; } } else {
/* timer interrupt for processing midi data */ void process_midi(PtTimestamp timestamp, void *userData) { PmError result; PmEvent buffer; /* just one message at a time */ long msg; /* do nothing until initialization completes */ if (!active) return; /* check for messages */ do { result = Pm_Dequeue(main_to_midi, &msg); if (result) { if (msg >= -127 && msg <= 127) transpose = msg; else if (msg == QUIT_MSG) { /* acknowledge receipt of quit message */ Pm_Enqueue(midi_to_main, &msg); active = FALSE; return; } else if (msg == MONITOR_MSG) { /* main has requested a pitch. monitor is a flag that * records the request: */ monitor = TRUE; } else if (msg == THRU_MSG) { /* toggle Thru on or off */ midi_thru = !midi_thru; } } } while (result); /* see if there is any midi input to process */ do { result = Pm_Poll(midi_in); if (result) { long status, data1, data2; if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) continue; if (midi_thru) Pm_Write(midi_out, &buffer, 1); /* unless there was overflow, we should have a message now */ status = Pm_MessageStatus(buffer.message); data1 = Pm_MessageData1(buffer.message); data2 = Pm_MessageData2(buffer.message); if ((status & 0xF0) == 0x90 || (status & 0xF0) == 0x80) { /* this is a note-on or note-off, so transpose and send */ data1 += transpose; /* keep within midi pitch range, keep proper pitch class */ while (data1 > 127) data1 -= 12; while (data1 < 0) data1 += 12; /* send the message */ buffer.message = Pm_Message(status, data1, data2); Pm_Write(midi_out, &buffer, 1); /* if monitor is set, send the pitch to the main thread */ if (monitor) { Pm_Enqueue(midi_to_main, &data1); monitor = FALSE; /* only send one pitch per request */ } } } } while (result); }