void sendNoteOnOff(int status, const mxArray *prhs[]) { int n,N; const double *note, *vel; int channel = (int) mxGetScalar(prhs[1]); if (channel < 1 || channel > 16) mexErrMsgTxt("Channel (2nd arg.) must be 1..16"); --channel; if (!mxIsDouble(prhs[2]) || !mxIsDouble(prhs[3])) { mexErrMsgTxt("3rd and 4th arguments (note number and velocity) must be 'double' arrays"); } N = mxGetNumberOfElements(prhs[2]); if (N != mxGetNumberOfElements(prhs[3])) { mexErrMsgTxt("3rd and 4th arguments (note number and velocity) must have same number of elements"); } note = mxGetPr(prhs[2]); vel = mxGetPr(prhs[3]); status = (status & 0xF0) | channel; for (n=0;n<N;n++) { PmMessage msg; PmError err; msg = Pm_Message(status, (int) note[n], (int) vel[n]); /* latency=0 => send asap */ err = Pm_WriteShort(outStream, 0, msg); if (err!=pmNoError) reportPmError(err); } }
void init() { PmError err1; PtError err2; if (isInit) return; mexPrintf("Initialising PortMidi\n"); MUTEX_LOCK; note = malloc(INPUT_BUFFER_SIZE*sizeof(int32_t)); channel = malloc(INPUT_BUFFER_SIZE*sizeof(int32_t)); velocity = malloc(INPUT_BUFFER_SIZE*sizeof(int32_t)); timestamp = malloc(INPUT_BUFFER_SIZE*sizeof(int32_t)); if (!(channel && note && velocity && timestamp)) { FREE(channel); FREE(note); FREE(velocity); FREE(timestamp); MUTEX_UNLOCK; mexErrMsgTxt("Could not allocate memory"); } else { MUTEX_UNLOCK; } err1 = Pm_Initialize(); reportPmError(err1); err2 = Pt_Start(1, receive_poll, NULL); reportPtError(err2); /* getting here means that PortMidi and PortTime are both fine */ mexAtExit(exitFunction); isInit = 1; }
void init() { PmError err; if (isInit) return; printf("Initialising PortMidi\n"); err = Pm_Initialize(); reportPmError(err); if (Pt_Start(1,NULL,NULL) == 0) { mexAtExit(exitFunction); isInit = 1; } else { Pm_Terminate(); mexErrMsgTxt("Could start PortMidi, but not PortTime."); } }
void exitFunction() { if (isInit) { mexPrintf("Terminating PortMidi\n"); reportPtError(Pt_Stop()); if (inStream != NULL) { reportPmError(Pm_Close(inStream)); inStream = NULL; } Pm_Terminate(); FREE(channel); FREE(note); FREE(velocity); FREE(timestamp); isInit = 0; deviceOpen = -1; numReceived = 0; } }
void playRaw(const mxArray *A) { int N = mxGetNumberOfElements(A); unsigned char * data = mxGetData(A); int n; PmMessage msg; PmError err; if (N % 3 != 0) mexErrMsgTxt("Raw arguments must be a multiple of 3 elements long."); N/=3; for (n=0;n<N;n++) { msg = Pm_Message(data[0], data[1], data[2]); err = Pm_WriteShort(outStream, 0, msg); if (err!=pmNoError) reportPmError(err); data+=3; } }
void sendProgChange(const mxArray *prhs[]) { int channel = (int) mxGetScalar(prhs[1]); int prog = (int) mxGetScalar(prhs[2]); int status; PmMessage msg; PmError err; if (channel < 1 || channel > 16) mexErrMsgTxt("Channel (2nd arg.) must be 1..16"); --channel; if (!mxIsDouble(prhs[2])) { mexErrMsgTxt("3rd argument (program number) must be a 'double'"); } status = 0xC0 | channel; msg = Pm_Message(status, prog-1, 0); /* latency=0 => send asap */ err = Pm_WriteShort(outStream, 0, msg); if (err!=pmNoError) reportPmError(err); }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int code = 'L'; PmError err1; PtError err2; init(); /* this returns immediately if already done */ if (nrhs > 0) { char arg[2]; if (!mxIsChar(prhs[0]) || mxGetNumberOfElements(prhs[0]) > 1) { mexErrMsgTxt("Bad call\n"); } mxGetString(prhs[0], arg, 2); code = arg[0]; } switch(code) { case 'V': if (inStream == NULL) { mexErrMsgTxt("No MIDI input device is opened"); } else { if (nrhs < 2) mexErrMsgTxt("Usage for 'verbose': midiIn('V', value)"); verbose = mxGetScalar(prhs[1]); } break; case 'G': /* Return the buffered events as array */ if (inStream == NULL) { mexErrMsgTxt("No MIDI input device is opened"); } else { plhs[0] = getEvent(); } break; case 'F': /* Flush all buffered events */ if (inStream == NULL) { mexErrMsgTxt("No MIDI input device is opened"); } else { /* reset the counter to the beginning of the buffer */ numReceived = 0; } break; case 'C': /* Close input stream */ if (inStream == NULL) { mexWarnMsgTxt("No MIDI input device is opened - ignoring 'close' command"); } else { err1 = Pm_Close(inStream); inStream = NULL; if (err1 != pmNoError) reportPmError(err1); } break; case 'O': /* Open input stream */ { int device = 0; if (nrhs<2 || !mxIsNumeric(prhs[1])) mexErrMsgTxt("Bad call\n"); device = (int) mxGetScalar(prhs[1]); if (device < 1 || device > Pm_CountDevices()) mexErrMsgTxt("Device index out of range"); --device; if (inStream != NULL) { if (deviceOpen == device) { mexWarnMsgTxt("MIDI input device is already open - ignoring request"); return; } mexWarnMsgTxt("Another MIDI input device is open - closing that one"); err1 = Pm_Close(inStream); inStream = NULL; if (err1 != pmNoError) reportPmError(err1); } err1 = Pm_OpenInput(&inStream, device, NULL, INPUT_BUFFER_SIZE, NULL, NULL); if (err1 != pmNoError) { inStream = NULL; reportPmError(err1); } /* remember which device we just opened */ deviceOpen = device; } break; case 'L': /* List devices */ plhs[0] = getDevices(); break; default: mexErrMsgTxt("Bad call\n"); } }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int code = 'L'; PmError err; init(); /* returns immediately if already done */ if (nrhs > 0) { char arg[2]; if (mxIsUint8(prhs[0])) { if (outStream == NULL) { mexErrMsgTxt("No MIDI output device is opened"); } else { playRaw(prhs[0]); } return; } if (!mxIsChar(prhs[0]) || mxGetNumberOfElements(prhs[0]) > 1) { mexErrMsgTxt("Bad call\n"); } mxGetString(prhs[0], arg, 2); code = arg[0]; } switch(code) { case 'P': if (outStream == NULL) { mexErrMsgTxt("No MIDI output device is opened"); } else { if (nrhs < 3) mexErrMsgTxt("Usage for 'program change': midiOut('P', channel, program)"); sendProgChange(prhs); } break; case '+': /* Note on */ if (outStream == NULL) { mexErrMsgTxt("No MIDI output device is opened"); } else { if (nrhs < 4) mexErrMsgTxt("Usage for 'note on': midiOut('+', channel, notes, velocities)"); sendNoteOnOff(0x90, prhs); } break; case '-': /* Note off */ if (outStream == NULL) { mexErrMsgTxt("No MIDI output device is opened"); } else { if (nrhs < 4) mexErrMsgTxt("Usage for 'note on': midiOut('+', channel, notes, velocities)"); sendNoteOnOff(0x80, prhs); } break; case '.': /* All notes off */ if (outStream == NULL) { mexErrMsgTxt("No MIDI output device is opened"); } else { int channel; if (nrhs < 2) mexErrMsgTxt("Usage for 'all notes off': midiOut('.', channel)"); channel = (int) mxGetScalar(prhs[1]); if (channel < 1 || channel > 16) mexErrMsgTxt("Channel (2nd arg.) must be 1..16"); --channel; err = Pm_WriteShort(outStream, 0, Pm_Message(0xB0 | channel, 123, 0)); if (err!=pmNoError) reportPmError(err); } break; case 'C': /* Close output stream */ if (outStream == NULL) { mexWarnMsgTxt("No MIDI output device is opened - ignoring 'close' command"); } else { err = Pm_Close(outStream); outStream = NULL; } break; case 'O': /* Open output stream */ { int device = 0; if (nrhs<2 || !mxIsNumeric(prhs[1])) mexErrMsgTxt("Bad call\n"); device = (int) mxGetScalar(prhs[1]); if (device < 1 || device > Pm_CountDevices()) mexErrMsgTxt("Device index out of range"); --device; if (outStream != NULL) { if (openID == device) { mexWarnMsgTxt("MIDI output device is already open - ignoring request"); return; } mexWarnMsgTxt("Another MIDI output device is open - closing that one"); err = Pm_Close(outStream); outStream = NULL; if (err != pmNoError) reportPmError(err); } /* last parameter = latency = 0 means that timestamps are ignored */ err = Pm_OpenOutput(&outStream, device, NULL, OUTPUT_BUFFER_SIZE, NULL, NULL, 0); if (err != pmNoError) { outStream = NULL; reportPmError(err); } openID = device; } break; case 'L': /* List devices */ plhs[0] = getDevices(); break; default: mexErrMsgTxt("Bad call\n"); } }