void midibus::continue_from( long a_tick ) { /* tell the device that we are going to start at a certain position */ long pp16th = (c_ppqn / 4); long leftover = ( a_tick % pp16th ); long beats = ( a_tick / pp16th ); long starting_tick = a_tick - leftover; /* was there anything left?, then wait for next beat (16th note) to start clocking */ if ( leftover > 0) { starting_tick += pp16th; } //printf ( "continue_from leftover[%ld] starting_tick[%ld]\n", leftover, starting_tick ); m_lasttick = starting_tick - 1; if ( m_clock_type != e_clock_off ) { PmEvent event; event.timestamp = 0; event.message = Pm_Message( EVENT_MIDI_CONTINUE, 0,0 ); Pm_Write( m_pms, &event, 1 ); event.message = Pm_Message( EVENT_MIDI_SONG_POS, (beats & 0x3F80 >> 7), (beats & 0x7F) ); Pm_Write( m_pms, &event, 1 ); }
static void writemidi4(PortMidiStream* stream, int a, int b, int c, int d) { PmEvent buffer; buffer.timestamp = 0; buffer.message = ((a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16) | ((d & 0xff) << 24)); Pm_Write(stream, &buffer, 1); }
PmError Pm_WriteShort( PortMidiStream *stream, long when, long msg) { PmEvent event; event.timestamp = when; event.message = msg; return Pm_Write(stream, &event, 1); }
void MIDIController::poll_loop() { int update_freq = 5; // 5 Hz (200ms) std::vector<float> x; while(keep_polling){ microsleep(1000/update_freq); if(source.data(x) == false) continue; unsigned int d = 8; if(x.size() < d) d = x.size(); unsigned int m = 0; for(unsigned int i=0;i<d;i++){ if(mute[i]) continue; // don't send this controller's value int v = (int)(127*x[i]); if(v > 127) v = 127; else if(v < 0) v = 0; if(i < 4){ // controller values [0x10-0x13]: 0-127 unsigned int cc = (0x10 + i); event[m].message = Pm_Message((0xB0+channel), cc, ((unsigned int)v)); event[m].timestamp = 0; m++; } else{ // controller values [0x50-0x53]: 0-127 unsigned int cc = (0x50+(i-4)); event[m].message = Pm_Message((0xB0+channel), cc, ((unsigned int)v)); event[m].timestamp = 0; m++; } } if(m > 0){ pthread_mutex_lock(&portmidi_lock); if(Pm_Write(midi, event, m) == pmNoError){ sending_data = true; } else{ sending_data = false; } pthread_mutex_unlock(&portmidi_lock); } else{ sending_data = false; } } }
PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when, unsigned char *msg) { /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */ /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */ #define BUFLEN (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)) PmEvent buffer[BUFLEN]; /* the next byte in the buffer is represented by an index, bufx, and a shift in bits */ int shift = 0; int bufx = 0; buffer[0].message = 0; buffer[0].timestamp = when; while (1) { /* insert next byte into buffer */ buffer[bufx].message |= ((*msg) << shift); shift += 8; if (shift == 32) { shift = 0; bufx++; if (bufx == BUFLEN) { PmError err = Pm_Write(stream, buffer, BUFLEN); if (err) return err; /* prepare to fill another buffer */ bufx = 0; } buffer[bufx].message = 0; buffer[bufx].timestamp = when; } /* keep inserting bytes until you find MIDI_EOX */ if (*msg++ == MIDI_EOX) break; } /* we're finished sending full buffers, but there may * be a partial one left. */ if (shift != 0) bufx++; /* add partial message to buffer len */ if (bufx) { /* bufx is number of PmEvents to send from buffer */ return Pm_Write(stream, buffer, bufx); } return pmNoError; }
static ERL_NIF_TERM do_write(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { static PortMidiStream ** stream; ErlNifResourceType* streamType = (ErlNifResourceType*)enif_priv_data(env); if(!enif_get_resource(env, argv[0], streamType, (PortMidiStream **) &stream)) { return enif_make_badarg(env); } ERL_NIF_TERM erlMessages = argv[1]; const ERL_NIF_TERM * erlEvent; const ERL_NIF_TERM * erlMessage; ERL_NIF_TERM erlTuple; unsigned int numOfMessages; int tupleSize; enif_get_list_length(env, erlMessages, &numOfMessages); PmEvent events[numOfMessages]; long int status, note, velocity, timestamp; for(unsigned int i = 0; i < numOfMessages; i++) { enif_get_list_cell(env, erlMessages, &erlTuple, &erlMessages); enif_get_tuple(env, erlTuple, &tupleSize, &erlEvent); enif_get_tuple(env, erlEvent[0], &tupleSize, &erlMessage); enif_get_long(env, erlMessage[0], &status); enif_get_long(env, erlMessage[1], ¬e); enif_get_long(env, erlMessage[2], &velocity); enif_get_long(env, erlEvent[1], ×tamp); PmEvent event; event.message = Pm_Message(status, note, velocity); event.timestamp = timestamp; events[i] = event; } PmError writeError; writeError = Pm_Write(*stream, events, numOfMessages); if (writeError == pmNoError) { return enif_make_atom(env, "ok"); } const char * writeErrorMsg; writeErrorMsg = Pm_GetErrorText(writeError); return enif_make_tuple2( env, enif_make_atom(env, "error"), enif_make_string(env, writeErrorMsg, ERL_NIF_LATIN1) ); }
void sys_putmidimess(int portno, int a, int b, int c) { PmEvent buffer; /* fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev); */ if (portno >= 0 && portno < mac_nmidioutdev) { buffer.message = Pm_Message(a, b, c); buffer.timestamp = 0; /* fprintf(stderr, "put msg\n"); */ Pm_Write(mac_midioutdevlist[portno], &buffer, 1); } }
int keyboard_send(MidiObj* m,uint8_t a,uint8_t b , uint8_t c) { if(!m->midi_stream_out) return 0; static PmEvent events[KEYBOARD_MAX_EVENTS]; events[0].timestamp = 0; events[0].message = Pm_Message( a,b,c ); int i = Pm_Write(m->midi_stream_out, events, 1); return i; }
static int WriteMidiData_(CSOUND *csound, void *userData, const unsigned char *mbuf, int nbytes) { int n, st; PmEvent mev; PortMidiStream *midistream; /* * Writes to user-defined MIDI output. */ midistream = (PortMidiStream*) userData; if (UNLIKELY(nbytes < 1)) return 0; n = 0; do { //int time = csound->GetCurrentTimeSamples(csound)/csound->GetSr(csound); //printf("jitter: %d \n", // Pt_Time(NULL) - (int)(1000*time/csound->GetSr(csound))); st = (int)*(mbuf++); if (UNLIKELY(st < 0x80)) { portMidiErrMsg(csound, Str("invalid MIDI out data")); break; } if (UNLIKELY(st >= 0xF0 && st < 0xF8)) { portMidiErrMsg(csound, Str("MIDI out: system message 0x%02X is not supported"), (unsigned int) st); break; } nbytes -= (datbyts[(st - 0x80) >> 4] + 1); if (UNLIKELY(nbytes < 0)) { portMidiErrMsg(csound, Str("MIDI out: truncated message")); break; } mev.message = (PmMessage) 0; mev.timestamp = (PmTimestamp) 0; mev.message |= (PmMessage) Pm_Message(st, 0, 0); if (datbyts[(st - 0x80) >> 4] > 0) mev.message |= (PmMessage) Pm_Message(0, (int)*(mbuf++), 0); if (datbyts[(st - 0x80) >> 4] > 1) mev.message |= (PmMessage) Pm_Message(0, 0, (int)*(mbuf++)); if (UNLIKELY(Pm_Write(midistream, &mev, 1L) != pmNoError)) portMidiErrMsg(csound, Str("MIDI out: error writing message")); else { n += (datbyts[(st - 0x80) >> 4] + 1); } } while (nbytes > 0); /* return the number of bytes written */ return n; }
/* callback function for PortTime -- computes histogram */ void pt_callback(PtTimestamp timestamp, void *userData) { PtTimestamp difference = timestamp - previous_callback_time - period; previous_callback_time = timestamp; /* allow 5 seconds for the system to settle down */ if (timestamp < 5000) return; iteration++; /* send a note on/off if user requested it */ if (test_out && (iteration % output_period == 0)) { PmEvent buffer[1]; buffer[0].timestamp = Pt_Time(NULL); if (note_on) { /* note off */ buffer[0].message = Pm_Message(0x90, 60, 0); note_on = 0; } else { /* note on */ buffer[0].message = Pm_Message(0x90, 60, 100); note_on = 1; } Pm_Write(out, buffer, 1); iteration = 0; } /* read all waiting events (if user requested) */ if (test_in) { PmError status; PmEvent buffer[1]; do { status = Pm_Poll(in); if (status == TRUE) { Pm_Read(in,buffer,1); } } while (status == TRUE); } if (difference < 0) return; /* ignore when system is "catching up" */ /* update the histogram */ if (difference < HIST_LEN) { histogram[difference]++; } else { out_of_range++; } if (max_latency < difference) max_latency = difference; }
void midibus::play (event * a_e24, unsigned char a_channel) { automutex locker(m_mutex); PmEvent event; event.timestamp = 0; /* fill buffer and set midi channel */ unsigned char buffer[3]; /* temp for midi data */ buffer[0] = a_e24->get_status(); buffer[0] += (a_channel & 0x0F); a_e24->get_data(&buffer[1], &buffer[2]); event.message = Pm_Message(buffer[0], buffer[1], buffer[2]); /*PmError err = */ Pm_Write(m_pms, &event, 1); }
void pm_pressout(Server *self, int value, int chan, long timestamp) { int i, curtime; PmEvent buffer[1]; PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data; curtime = Pt_Time(); buffer[0].timestamp = curtime + timestamp; if (chan == 0) buffer[0].message = Pm_Message(0xD0, value, 0); else buffer[0].message = Pm_Message(0xD0 | (chan - 1), value, 0); for (i=0; i<self->midiout_count; i++) { Pm_Write(be_data->midiout[i], buffer, 1); } }
void pm_bendout(Server *self, int value, int chan, long timestamp) { int i, lsb, msb, curtime; PmEvent buffer[1]; PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data; curtime = Pt_Time(); buffer[0].timestamp = curtime + timestamp; lsb = value & 0x007F; msb = (value & (0x007F << 7)) >> 7; if (chan == 0) buffer[0].message = Pm_Message(0xE0, lsb, msb); else buffer[0].message = Pm_Message(0xE0 | (chan - 1), lsb, msb); for (i=0; i<self->midiout_count; i++) { Pm_Write(be_data->midiout[i], buffer, 1); } }
/* 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); }
/* The winmm stream mode is used for latency>0, and sends timestamped messages. The timestamps are relative (delta) times, whereas PortMidi times are absolute. Since peculiar things happen when messages are not always sent in advance, this function allows us to exercise the system and test it. */ void main_test_stream() { PmStream * midi; char line[80]; PmEvent buffer[16]; /* determine which output device to use */ int i = get_number("Type output number: "); latency = 500; /* ignore LATENCY for this test and fix the latency at 500ms */ /* It is recommended to start timer before PortMidi */ TIME_START; /* open output device */ Pm_OpenOutput(&midi, i, DRIVER_INFO, OUTPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO, latency); printf("Midi Output opened with %ld ms latency.\n", (long) latency); /* output note on/off w/latency offset; hold until user prompts */ printf("ready to send output... (type RETURN):"); fgets(line, STRING_MAX, stdin); /* if we were writing midi for immediate output, we could always use timestamps of zero, but since we may be writing with latency, we will explicitly set the timestamp to "now" by getting the time. The source of timestamps should always correspond to the TIME_PROC and TIME_INFO parameters used in Pm_OpenOutput(). */ buffer[0].timestamp = TIME_PROC(TIME_INFO); buffer[0].message = Pm_Message(0xC0, 0, 0); buffer[1].timestamp = buffer[0].timestamp; buffer[1].message = Pm_Message(0x90, 60, 100); buffer[2].timestamp = buffer[0].timestamp + 1000; buffer[2].message = Pm_Message(0x90, 62, 100); buffer[3].timestamp = buffer[0].timestamp + 2000; buffer[3].message = Pm_Message(0x90, 64, 100); buffer[4].timestamp = buffer[0].timestamp + 3000; buffer[4].message = Pm_Message(0x90, 66, 100); buffer[5].timestamp = buffer[0].timestamp + 4000; buffer[5].message = Pm_Message(0x90, 60, 0); buffer[6].timestamp = buffer[0].timestamp + 4000; buffer[6].message = Pm_Message(0x90, 62, 0); buffer[7].timestamp = buffer[0].timestamp + 4000; buffer[7].message = Pm_Message(0x90, 64, 0); buffer[8].timestamp = buffer[0].timestamp + 4000; buffer[8].message = Pm_Message(0x90, 66, 0); Pm_Write(midi, buffer, 9); #ifdef SEND8 /* Now, we're ready for the real test. Play 4 notes at now, now+500, now+1000, and now+1500 Then wait until now+2000. Play 4 more notes as before. We should hear 8 evenly spaced notes. */ now = TIME_PROC(TIME_INFO); for (i = 0; i < 4; i++) { buffer[i * 2].timestamp = now + (i * 500); buffer[i * 2].message = Pm_Message(0x90, 60, 100); buffer[i * 2 + 1].timestamp = now + 250 + (i * 500); buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0); } Pm_Write(midi, buffer, 8); while (Pt_Time() < now + 2500) /* busy wait */; /* now we are 500 ms behind schedule, but since the latency is 500, the delay should not be audible */ now += 2000; for (i = 0; i < 4; i++) { buffer[i * 2].timestamp = now + (i * 500); buffer[i * 2].message = Pm_Message(0x90, 60, 100); buffer[i * 2 + 1].timestamp = now + 250 + (i * 500); buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0); } Pm_Write(midi, buffer, 8); #endif /* close device (this not explicitly needed in most implementations) */ printf("ready to close and terminate... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_Close(midi); Pm_Terminate(); printf("done closing and terminating...\n"); }
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(); }
void main_test_output() { PmStream * midi; char line[80]; int32_t off_time; int chord[] = { 60, 67, 76, 83, 90 }; #define chord_size 5 PmEvent buffer[chord_size]; PmTimestamp timestamp; /* determine which output device to use */ int i = get_number("Type output number: "); /* It is recommended to start timer before PortMidi */ TIME_START; /* open output device -- since PortMidi avoids opening a timer when latency is zero, we will pass in a NULL timer pointer for that case. If PortMidi tries to access the time_proc, we will crash, so this test will tell us something. */ Pm_OpenOutput(&midi, i, DRIVER_INFO, OUTPUT_BUFFER_SIZE, (latency == 0 ? NULL : TIME_PROC), (latency == 0 ? NULL : TIME_INFO), latency); printf("Midi Output opened with %ld ms latency.\n", (long) latency); /* output note on/off w/latency offset; hold until user prompts */ printf("ready to send program 1 change... (type RETURN):"); fgets(line, STRING_MAX, stdin); /* if we were writing midi for immediate output, we could always use timestamps of zero, but since we may be writing with latency, we will explicitly set the timestamp to "now" by getting the time. The source of timestamps should always correspond to the TIME_PROC and TIME_INFO parameters used in Pm_OpenOutput(). */ buffer[0].timestamp = TIME_PROC(TIME_INFO); /* Send a program change to increase the chances we will hear notes */ /* Program 0 is usually a piano, but you can change it here: */ #define PROGRAM 0 buffer[0].message = Pm_Message(0xC0, PROGRAM, 0); Pm_Write(midi, buffer, 1); printf("ready to note-on... (type RETURN):"); fgets(line, STRING_MAX, stdin); buffer[0].timestamp = TIME_PROC(TIME_INFO); buffer[0].message = Pm_Message(0x90, 60, 100); Pm_Write(midi, buffer, 1); printf("ready to note-off... (type RETURN):"); fgets(line, STRING_MAX, stdin); buffer[0].timestamp = TIME_PROC(TIME_INFO); buffer[0].message = Pm_Message(0x90, 60, 0); Pm_Write(midi, buffer, 1); /* output short note on/off w/latency offset; hold until user prompts */ printf("ready to note-on (short form)... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_WriteShort(midi, TIME_PROC(TIME_INFO), Pm_Message(0x90, 60, 100)); printf("ready to note-off (short form)... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_WriteShort(midi, TIME_PROC(TIME_INFO), Pm_Message(0x90, 60, 0)); /* output several note on/offs to test timing. Should be 1s between notes */ printf("chord will arpeggiate if latency > 0\n"); printf("ready to chord-on/chord-off... (type RETURN):"); fgets(line, STRING_MAX, stdin); timestamp = TIME_PROC(TIME_INFO); for (i = 0; i < chord_size; i++) { buffer[i].timestamp = timestamp + 1000 * i; buffer[i].message = Pm_Message(0x90, chord[i], 100); } Pm_Write(midi, buffer, chord_size); off_time = timestamp + 1000 + chord_size * 1000; while (TIME_PROC(TIME_INFO) < off_time) /* busy wait */; for (i = 0; i < chord_size; i++) { buffer[i].timestamp = timestamp + 1000 * i; buffer[i].message = Pm_Message(0x90, chord[i], 0); } Pm_Write(midi, buffer, chord_size); /* close device (this not explicitly needed in most implementations) */ printf("ready to close and terminate... (type RETURN):"); fgets(line, STRING_MAX, stdin); Pm_Close(midi); Pm_Terminate(); printf("done closing and terminating...\n"); }
int main() { char line[STRING_MAX]; int i; int len; int choice; PtTimestamp stop; printf("Latency histogram.\n"); period = 0; while (period < 1) { period = get_number("Choose timer period (in ms, >= 1): "); } printf("Benchmark with:\n\t%s\n\t%s\n\t%s\n\t%s\n", "1. No MIDI traffic", "2. MIDI input", "3. MIDI output", "4. MIDI input and output"); choice = get_number("? "); switch (choice) { case 1: test_in = 0; test_out = 0; break; case 2: test_in = 1; test_out = 0; break; case 3: test_in = 0; test_out = 1; break; case 4: test_in = 1; test_out = 1; break; default: assert(0); } if (test_in || test_out) { /* list device information */ for (i = 0; i < Pm_CountDevices(); i++) { const PmDeviceInfo *info = Pm_GetDeviceInfo(i); if ((test_in && info->input) || (test_out && info->output)) { printf("%d: %s, %s", i, info->interf, info->name); if (info->input) printf(" (input)"); if (info->output) printf(" (output)"); printf("\n"); } } /* open stream(s) */ if (test_in) { int i = get_number("MIDI input device number: "); Pm_OpenInput(&in, i, NULL, INPUT_BUFFER_SIZE, (long (*)(void *)) Pt_Time, NULL); /* turn on filtering; otherwise, input might overflow in the 5-second period before timer callback starts reading midi */ Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK); } if (test_out) { int i = get_number("MIDI output device number: "); PmEvent buffer[1]; Pm_OpenOutput(&out, i, NULL, OUTPUT_BUFFER_SIZE, (long (*)(void *)) Pt_Time, NULL, 0); /* no latency scheduling */ /* send a program change to force a status byte -- this fixes a problem with a buggy linux MidiSport driver, and shouldn't hurt anything else */ buffer[0].timestamp = 0; buffer[0].message = Pm_Message(0xC0, 0, 0); /* program change */ Pm_Write(out, buffer, 1); output_period = get_number( "MIDI out should be sent every __ callback iterations: "); assert(output_period >= 1); } } printf("%s%s", "Latency measurements will start in 5 seconds. ", "Type return to stop: "); Pt_Start(period, &pt_callback, 0); fgets(line, STRING_MAX, stdin); stop = Pt_Time(); Pt_Stop(); /* courteously turn off the last note, if necessary */ if (note_on) { PmEvent buffer[1]; buffer[0].timestamp = Pt_Time(NULL); buffer[0].message = Pm_Message(0x90, 60, 0); Pm_Write(out, buffer, 1); } /* print the histogram */ printf("Duration of test: %g seconds\n\n", max(0, stop - 5000) * 0.001); printf("Latency(ms) Number of occurrences\n"); /* avoid printing beyond last non-zero histogram entry */ len = min(HIST_LEN, max_latency + 1); for (i = 0; i < len; i++) { printf("%2d %10ld\n", i, histogram[i]); } printf("Number of points greater than %dms: %ld\n", HIST_LEN - 1, out_of_range); printf("Maximum latency: %ld milliseconds\n", max_latency); printf("\nNote that due to rounding, actual latency can be 1ms higher\n"); printf("than the numbers reported here.\n"); printf("Type return to exit..."); fgets(line, STRING_MAX, stdin); if(choice == 2) Pm_Close(in); else if(choice == 3) Pm_Close(out); else if(choice == 4) { Pm_Close(in); Pm_Close(out); } return 0; }
void midiWrite(struct Note *note) { outBuffer[0].timestamp = Pt_Time(NULL); outBuffer[0].message = Pm_Message(note->status, note->note, note->vol); Pm_Write(out, outBuffer, 1); }
void midiNoteOn(int note, int vol) { outBuffer[0].timestamp = Pt_Time(NULL); outBuffer[0].message = Pm_Message(0x90, note, vol); /* program change */ Pm_Write(out, outBuffer, 1); }