diff options
Diffstat (limited to 'muse2/muse/driver/jackmidi.cpp')
-rw-r--r-- | muse2/muse/driver/jackmidi.cpp | 242 |
1 files changed, 172 insertions, 70 deletions
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp index d401c7e1..c950e096 100644 --- a/muse2/muse/driver/jackmidi.cpp +++ b/muse2/muse/driver/jackmidi.cpp @@ -1150,7 +1150,8 @@ void MidiJackDevice::collectMidiEvents() bool MidiJackDevice::putEvent(const MidiPlayEvent& ev) { - if(!_writeEnable) + //if(!_writeEnable) + if(!_writeEnable || !_out_client_jackport) // p4.0.15 //return true; return false; @@ -1225,7 +1226,9 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) unsigned char* p = jack_midi_event_reserve(pb, ft, 3); if (p == 0) { - fprintf(stderr, "MidiJackDevice::queueEvent #1: buffer overflow, event lost\n"); + #ifdef JACK_MIDI_DEBUG + fprintf(stderr, "MidiJackDevice::queueEvent NOTE CTL PAT or PB: buffer overflow, stopping until next cycle\n"); + #endif return false; } p[0] = e.type() | e.channel(); @@ -1243,7 +1246,9 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) unsigned char* p = jack_midi_event_reserve(pb, ft, 2); if (p == 0) { - fprintf(stderr, "MidiJackDevice::queueEvent #2: buffer overflow, event lost\n"); + #ifdef JACK_MIDI_DEBUG + fprintf(stderr, "MidiJackDevice::queueEvent PROG or AT: buffer overflow, stopping until next cycle\n"); + #endif return false; } p[0] = e.type() | e.channel(); @@ -1260,8 +1265,16 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) int len = e.len(); unsigned char* p = jack_midi_event_reserve(pb, ft, len+2); if (p == 0) { - fprintf(stderr, "MidiJackDevice::queueEvent #3: buffer overflow, event lost\n"); - return false; + fprintf(stderr, "MidiJackDevice::queueEvent ME_SYSEX: buffer overflow, sysex too big, event lost\n"); + + //return false; + // Changed to true. Absorb the sysex if it is too big, to avoid attempting + // to resend repeatedly. If the sysex is too big, it would just stay in the + // list and never be processed, because Jack could never reserve enough space. + // Other types of events should be OK since they are small and can be resent + // next cycle. p4.0.15 Tim. + // FIXME: We really need to chunk sysex events properly. It's tough. Investigating... + return true; } p[0] = 0xf0; p[len+1] = 0xf7; @@ -1273,8 +1286,10 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) case ME_START: case ME_CONTINUE: case ME_STOP: - printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type()); - return false; + if(debugMsg) + printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type()); + //return false; + return true; // Absorb the event. Don't want it hanging around in the list. FIXME: Support these? p4.0.15 Tim. break; } @@ -1283,9 +1298,10 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) //--------------------------------------------------------- // processEvent +// return true if successful //--------------------------------------------------------- -void MidiJackDevice::processEvent(const MidiPlayEvent& event) +bool MidiJackDevice::processEvent(const MidiPlayEvent& event) { //int frameOffset = audio->getFrameOffset(); //unsigned pos = audio->pos().frame(); @@ -1302,12 +1318,15 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) // Just do this 'standard midi 64T timing thing' for now until we figure out more precise external timings. // Does require relatively short audio buffers, in order to catch the resolution, but buffer <= 256 should be OK... // Tested OK so far with 128. - if(extSyncFlag.value()) + ///if(extSyncFlag.value()) + // p4.0.15 Or, is the event marked to be played immediately? + // Nothing to do but stamp the event to be queued for frame 0+. + if(t == 0 || extSyncFlag.value()) t = audio->getFrameOffset() + audio->pos().frame(); //t = frameOffset + pos; #ifdef JACK_MIDI_DEBUG - printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB()); + //printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", t, event.type(), chn, a, b); #endif if(event.type() == ME_PROGRAM) @@ -1318,15 +1337,18 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) int lb = (a >> 8) & 0xff; int pr = a & 0x7f; - // p3.3.44 //printf("MidiJackDevice::processEvent ME_PROGRAM time:%d type:%d ch:%d A:%d B:%d hb:%d lb:%d pr:%d\n", // event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr); if (hb != 0xff) - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb))) + return false; // p4.0.15 Inform that processing the event in general failed. Ditto all below... if (lb != 0xff) - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)); - queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)); + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb))) + return false; + if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0))) + return false; + // } } else @@ -1336,7 +1358,8 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) // p3.3.44 //printf("MidiJackDevice::processEvent ME_PITCHBEND v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB()); - queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f))) + return false; } else if(event.type() == ME_CONTROLLER) @@ -1365,7 +1388,8 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) // p3.3.44 //printf("MidiJackDevice::processEvent CTRL_PITCH v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB()); - queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f))) + return false; } else if (a == CTRL_PROGRAM) { @@ -1380,28 +1404,36 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) // event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr); if (hb != 0xff) - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)); + { + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb))) + return false; + } if (lb != 0xff) - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)); - queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)); + { + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb))) + return false; + } + if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0))) + return false; + // } } - /* - else if (a == CTRL_MASTER_VOLUME) + else if (a == CTRL_MASTER_VOLUME) // Enabled p4.0.15 Tim. { unsigned char sysex[] = { 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00 }; - sysex[1] = deviceId(); + //sysex[1] = deviceId(); TODO FIXME p4.0.15 Grab the ID from midi port sync info. sysex[4] = b & 0x7f; sysex[5] = (b >> 7) & 0x7f; - queueEvent(MidiPlayEvent(t, port, ME_SYSEX, sysex, 6)); + if(!queueEvent(MidiPlayEvent(t, port, ME_SYSEX, sysex, 6))) + return false; } - */ else if (a < CTRL_14_OFFSET) { // 7 Bit Controller - queueEvent(event); //queueEvent(museport, MidiPlayEvent(t, port, chn, event)); + if(!queueEvent(event)) + return false; } else if (a < CTRL_RPN_OFFSET) { // 14 bit high resolution controller @@ -1409,46 +1441,62 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) int ctrlL = a & 0x7f; int dataH = (b >> 7) & 0x7f; int dataL = b & 0x7f; - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH)); - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH))) + return false; + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL))) + return false; } else if (a < CTRL_NRPN_OFFSET) { // RPN 7-Bit Controller int ctrlH = (a >> 8) & 0x7f; int ctrlL = a & 0x7f; - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)); - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)); - queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH))) + return false; + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL))) + return false; + if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b))) + return false; t += 3; // Select null parameters so that subsequent data controller events do not upset the last *RPN controller. //sendNullRPNParams(chn, false); if(nvh != 0xff) { - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f))) + return false; t += 1; } if(nvl != 0xff) - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f)); + { + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f))) + return false; + } } //else if (a < CTRL_RPN14_OFFSET) else if (a < CTRL_INTERNAL_OFFSET) { // NRPN 7-Bit Controller int ctrlH = (a >> 8) & 0x7f; int ctrlL = a & 0x7f; - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)); - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)); - queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH))) + return false; + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL))) + return false; + if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b))) + return false; t += 3; //sendNullRPNParams(chn, true); if(nvh != 0xff) { - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f))) + return false; t += 1; } if(nvl != 0xff) - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f)); + { + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f))) + return false; + } } else if (a < CTRL_NRPN14_OFFSET) { // RPN14 Controller @@ -1456,20 +1504,28 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) int ctrlL = a & 0x7f; int dataH = (b >> 7) & 0x7f; int dataL = b & 0x7f; - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)); - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)); - queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)); - queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH))) + return false; + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL))) + return false; + if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH))) + return false; + if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL))) + return false; t += 4; //sendNullRPNParams(chn, false); if(nvh != 0xff) { - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f))) + return false; t += 1; } if(nvl != 0xff) - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f)); + { + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f))) + return false; + } } else if (a < CTRL_NONE_OFFSET) { // NRPN14 Controller @@ -1477,31 +1533,44 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) int ctrlL = a & 0x7f; int dataH = (b >> 7) & 0x7f; int dataL = b & 0x7f; - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)); - queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)); - queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)); - queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH))) + return false; + if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL))) + return false; + if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH))) + return false; + if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL))) + return false; t += 4; //sendNullRPNParams(chn, true); if(nvh != 0xff) { - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)); + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f))) + return false; t += 1; } if(nvl != 0xff) - queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f)); + { + if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f))) + return false; + } } else { - printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a); + if(debugMsg) + printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a); + //return false; // Just ignore it. } } else { - queueEvent(event); //queueEvent(MidiPlayEvent(t, port, chn, event)); + if(!queueEvent(event)) + return false; } + + return true; } //--------------------------------------------------------- @@ -1511,40 +1580,58 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event) void MidiJackDevice::processMidi() { //if(!_client_jackport) - if(!_out_client_jackport) // p3.3.55 - return; + //if(!_out_client_jackport) // p3.3.55 + // return; + //void* port_buf = jack_port_get_buffer(_client_jackport, segmentSize); - void* port_buf = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55 - jack_midi_clear_buffer(port_buf); + //void* port_buf = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55 + void* port_buf = 0; + if(_out_client_jackport && _writeEnable) // p4.0.15 + { + port_buf = jack_port_get_buffer(_out_client_jackport, segmentSize); + jack_midi_clear_buffer(port_buf); + } while(!eventFifo.isEmpty()) { - MidiPlayEvent e(eventFifo.get()); - int evTime = e.time(); - // Is event marked to be played immediately? - if(evTime == 0) - { + ///MidiPlayEvent e(eventFifo.get()); + MidiPlayEvent e(eventFifo.peek()); // p4.0.15 + + ///int evTime = e.time(); + // Is event marked to be played immediately? p4.0.15 Moved into processEvent(). + ///if(evTime == 0) + ///{ // Nothing to do but stamp the event to be queued for frame 0+. //e.setTime(frameOffset + pos); - e.setTime(audio->getFrameOffset() + audio->pos().frame()); - } + /// e.setTime(audio->getFrameOffset() + audio->pos().frame()); + ///} - #ifdef JACK_MIDI_DEBUG - printf("MidiJackDevice::processMidi eventFifo time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB()); - #endif + //#ifdef JACK_MIDI_DEBUG + //printf("MidiJackDevice::processMidi eventFifo time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB()); + //#endif //el->insert(eventFifo.get()); //el->insert(e); - processEvent(e); + ///processEvent(e); + // p4.0.15 Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. + if(port_buf && !processEvent(e)) + return; // Give up. The Jack buffer is full. Nothing left to do. + eventFifo.remove(); // Successfully processed event. Remove it from FIFO. } MPEventList* el = playEvents(); if(el->empty()) + { + //printf("MidiJackDevice::processMidi play events empty\n"); return; + } - iMPEvent i = nextPlayEvent(); + //printf("MidiJackDevice::processMidi play events:\n"); + ///iMPEvent i = nextPlayEvent(); + iMPEvent i = el->begin(); // p4.0.15 for(; i != el->end(); ++i) { + //printf("MidiJackDevice::processMidi playEvent time:%d type:%d ch:%d A:%d B:%d\n", i->time(), i->type(), i->channel(), i->dataA(), i->dataB()); // p3.3.39 Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values. // Same code as in MidiPort::sendEvent() if(_port != -1) @@ -1562,7 +1649,6 @@ void MidiJackDevice::processMidi() else if(i->type() == ME_PITCHBEND) { - // p3.3.44 //printf("MidiJackDevice::processMidi playEvents ME_PITCHBEND time:%d type:%d ch:%d A:%d B:%d\n", (*i).time(), (*i).type(), (*i).channel(), (*i).dataA(), (*i).dataB()); int da = mp->limitValToInstrCtlRange(CTRL_PITCH, i->dataA()); @@ -1581,10 +1667,26 @@ void MidiJackDevice::processMidi() } } - processEvent(*i); + ///processEvent(*i); + // p4.0.15 Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. + if(port_buf && !processEvent(*i)) + { + //setNextPlayEvent(i); + //return; + break; + } } - setNextPlayEvent(i); + ///setNextPlayEvent(i); + // p4.0.15 We are done with these events. Let us erase them here instead of Audio::processMidi. + // That way we can simply set the next play event to the beginning. + // This also allows other events to be inserted without the problems caused by the next play event + // being at the 'end' iterator and not being *easily* set to some new place beginning of the newer insertions. + // The way that MPEventList sorts made it difficult to predict where the iterator of the first newly inserted items was. + // The erasure in Audio::processMidi was missing some events because of that. + el->erase(el->begin(), i); + // setNextPlayEvent(el->begin()); // Removed p4.0.15 Tim. + } //--------------------------------------------------------- |