bool MidiPort::sendEvent(const MidiPlayEvent& ev, bool forceSend) { if (ev.type() == ME_CONTROLLER) { //TODO: This is where PC are added // printf("current sustain %d %d %d\n", hwCtrlState(ev.channel(),CTRL_SUSTAIN), CTRL_SUSTAIN, ev.dataA()); // Added by T356. int da = ev.dataA(); int db = ev.dataB(); db = limitValToInstrCtlRange(da, db); // Removed by T356. // // optimize controller settings // if (!setHwCtrlState(ev.channel(), da, db)) { if (debugMsg) printf("setHwCtrlState failed\n"); if (!forceSend) return false; } } else if (ev.type() == ME_PITCHBEND) { int da = limitValToInstrCtlRange(CTRL_PITCH, ev.dataA()); if (!setHwCtrlState(ev.channel(), CTRL_PITCH, da)) { if(!forceSend) return false; } } else if (ev.type() == ME_PROGRAM) { if (!setHwCtrlState(ev.channel(), CTRL_PROGRAM, ev.dataA())) { if(!forceSend) return false; } } if (!_device) { if (debugMsg) printf("no device for this midi port\n"); return true; } //printf("MidiPort::sendEvent\n"); return _device->putEvent(ev); }
bool MidiDevice::putEvent(const MidiPlayEvent& ev) { if(!_writeEnable) //return true; return false; unsigned t = ev.time(); int port = ev.port(); if (ev.type() == ME_CONTROLLER) { int a = ev.dataA(); int b = ev.dataB(); int chn = ev.channel(); if (a == CTRL_PITCH) { return putMidiEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, b, 0)); } if ((a | 0xff) == CTRL_POLYAFTER) { return putMidiEvent(MidiPlayEvent(t, port, chn, ME_POLYAFTER, a & 0x7f, b & 0x7f)); } if (a == CTRL_AFTERTOUCH) { return putMidiEvent(MidiPlayEvent(t, port, chn, ME_AFTERTOUCH, b, 0)); } if (a == CTRL_PROGRAM) { int hb = (b >> 16) & 0xff; int lb = (b >> 8) & 0xff; int pr = b & 0x7f; if (hb != 0xff) putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)); if (lb != 0xff) putMidiEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)); return putMidiEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0)); }
bool VstSynthIF::putEvent(const MidiPlayEvent& ev) { if (midiOutputTrace) ev.dump(); AEffect* plugin = _fst->plugin; static struct VstEvents events; static struct VstMidiEvent event; events.numEvents = 1; events.reserved = 0; events.events[0] = (VstEvent*)(&event); event.type = kVstMidiType; event.byteSize = 24; event.deltaFrames = 0; event.flags = 0; event.detune = 0; event.noteLength = 0; event.noteOffset = 0; event.reserved1 = 0; event.reserved2 = 0; event.noteOffVelocity = 0; switch (ev.type()) { case ME_PITCHBEND: { int a = ev.dataA() + 8192; int b = a >> 7; event.midiData[0] = (ev.type() | ev.channel()) & 0xff; event.midiData[1] = a & 0x7f; event.midiData[2] = b & 0x7f; event.midiData[3] = 0; } break; case ME_CONTROLLER: case ME_NOTEON: default: event.midiData[0] = (ev.type() | ev.channel()) & 0xff; event.midiData[1] = ev.dataA() & 0xff; event.midiData[2] = ev.dataB() & 0xff; event.midiData[3] = 0; break; } int rv = plugin->dispatcher(plugin, effProcessEvents, 0, 0, &events, 0.0f); return false; }
bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e) { if (midiOutputTrace) { printf("MidiOut: midiAlsa: "); e.dump(); } int chn = e.channel(); int a = e.dataA(); int b = e.dataB(); snd_seq_event_t event; memset(&event, 0, sizeof (event)); event.queue = SND_SEQ_QUEUE_DIRECT; event.source = losPort; event.dest = adr; switch (e.type()) { case ME_NOTEON: snd_seq_ev_set_noteon(&event, chn, a, b); break; case ME_NOTEOFF: snd_seq_ev_set_noteoff(&event, chn, a, 0); break; case ME_PROGRAM: snd_seq_ev_set_pgmchange(&event, chn, a); break; case ME_CONTROLLER: #if 1 snd_seq_ev_set_controller(&event, chn, a, b); #else { int a = e.dataA(); int b = e.dataB(); int chn = e.channel(); if (a < CTRL_14_OFFSET) { // 7 Bit Controller snd_seq_ev_set_controller(&event, chn, a, b); } else if (a < CTRL_RPN_OFFSET) { // 14 bit high resolution controller int ctrlH = (a >> 8) & 0x7f; int ctrlL = a & 0x7f; a = (ctrlH << 7) + ctrlL; snd_seq_ev_set_controller(&event, chn, a, b); event.type = SND_SEQ_EVENT_CONTROL14; } else if (a < CTRL_NRPN_OFFSET) { // RPN 7-Bit Controller int ctrlH = (a >> 8) & 0x7f; int ctrlL = a & 0x7f; a = (ctrlH << 7) + ctrlL; b <<= 7; snd_seq_ev_set_controller(&event, chn, a, b); event.type = SND_SEQ_EVENT_REGPARAM; }
bool MidiJackDevice::putEvent(const MidiPlayEvent& ev) { if (!_writeEnable || !_out_client_jackport) return false; #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::putEvent time:%d type:%d ch:%d A:%d B:%d\n", ev.time(), ev.type(), ev.channel(), ev.dataA(), ev.dataB()); #endif bool rv = eventFifo.put(ev); if (rv) printf("MidiJackDevice::putEvent: port overflow\n"); return rv; }
bool Mess::processEvent(const MidiPlayEvent& ev) { switch(ev.type()) { case ME_NOTEON: return playNote(ev.channel(), ev.dataA(), ev.dataB()); case ME_NOTEOFF: return playNote(ev.channel(), ev.dataA(), 0); case ME_SYSEX: return sysex(ev.len(), ev.data()); case ME_CONTROLLER: return setController(ev.channel(), ev.dataA(), ev.dataB()); case ME_PITCHBEND: // Tim. return setController(ev.channel(), CTRL_PITCH, ev.dataA()); } return false; }
bool MidiJackDevice::processEvent(const MidiPlayEvent& event) { int chn = event.channel(); unsigned t = event.time(); int a = event.dataA(); int b = event.dataB(); // Perhaps we can find use for this value later, together with the Jack midi LOS port(s). // No big deal if not. Not used for now. int port = event.port(); // TODO: No sub-tick playback resolution yet, with external sync. // 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 (t == 0 /*|| extSyncFlag.value()*/) t = audio->getFrameOffset() + audio->pos().frame(); #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()); #endif //Send to monitor thread for processing monitorOutputEvent(event); if (event.type() == ME_PROGRAM) { // don't output program changes for GM drum channel int hb = (a >> 16) & 0xff; int lb = (a >> 8) & 0xff; int pr = a & 0x7f; //TODO: NOTE this is where program changes are sent we can later debug this to diagnose the dropped events if (hb != 0xff) { if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb))) return false; } if (lb != 0xff) { if(!queueEvent(MidiPlayEvent(t + 1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb))) return false; } //sleep(1); if(!queueEvent(MidiPlayEvent(t + 2, port, chn, ME_PROGRAM, pr, 0))) return false; }
void Organ::processMessages() { //Process messages from the gui // // get and process all pending events from the // synthesizer GUI // while (gui->fifoSize()) { MidiPlayEvent ev = gui->readEvent(); if (ev.type() == ME_CONTROLLER) { // process local? setController(ev.dataA(), ev.dataB()); sendEvent(ev); } else printf("Organ::process(): unknown event\n"); } }
bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) { if (!_out_client_jackport) // p3.3.55 return false; void* pb = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55 int frameOffset = audio->getFrameOffset(); unsigned pos = audio->pos().frame(); int ft = e.time() - frameOffset - pos; if (ft < 0) ft = 0; if (ft >= (int) segmentSize) { if(debugMsg) printf("MidiJackDevice::queueEvent: Event time:%d out of range. offset:%d ft:%d (seg=%d)\n", e.time(), frameOffset, ft, segmentSize); if (ft > (int) segmentSize) ft = segmentSize - 1; } #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB()); #endif switch (e.type()) { case ME_NOTEON: case ME_NOTEOFF: case ME_POLYAFTER: case ME_CONTROLLER: case ME_PITCHBEND: { #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent note on/off polyafter controller or pitch\n"); #endif unsigned char* p = jack_midi_event_reserve(pb, ft, 3); if (p == 0) { #ifdef JACK_MIDI_DEBUG fprintf(stderr, "MidiJackDevice::queueEvent NOTE CONTROL PAT or PB: buffer overflow, stopping until next cycle\n"); #endif return false; } p[0] = e.type() | e.channel(); p[1] = e.dataA(); p[2] = e.dataB(); } break; case ME_PROGRAM: case ME_AFTERTOUCH: { #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent program or aftertouch\n"); #endif unsigned char* p = jack_midi_event_reserve(pb, ft, 2); if (p == 0) { #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(); p[1] = e.dataA(); } break; case ME_SYSEX: { #ifdef JACK_MIDI_DEBUG printf("MidiJackDevice::queueEvent sysex\n"); #endif const unsigned char* data = e.data(); int len = e.len(); unsigned char* p = jack_midi_event_reserve(pb, ft, len + 2); if (p == 0) { fprintf(stderr, "MidiJackDevice::queueEvent ME_SYSEX: buffer overflow, sysex too big, event lost\n"); return true; } p[0] = 0xf0; p[len + 1] = 0xf7; memcpy(p + 1, data, len); } break; case ME_SONGPOS: case ME_CLOCK: case ME_START: case ME_CONTINUE: case ME_STOP: if(debugMsg) printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type()); return true; break; } return true; }
bool LOS::importMidi(const QString name, bool merge)/*{{{*/ { bool popenFlag; FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag); if (fp == 0) return true; MidiFile mf(fp); bool rv = mf.read(); popenFlag ? pclose(fp) : fclose(fp); if (rv) { QString s(tr("reading midifile\n ")); s += name; s += tr("\nfailed: "); s += mf.error(); QMessageBox::critical(this, QString("LOS"), s); return rv; } // // evaluate song Type (GM, XG, GS, unknown) // MType t = song->midiType(); if (!merge) { t = mf.mtype(); song->setMType(t); } MidiInstrument* instr = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { MidiInstrument* mi = *i; if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_GM))) || ((mi->iname() == "GS") && (t == MT_GS)) || ((mi->iname() == "XG") && (t == MT_XG))) { instr = mi; break; } } if (instr == 0) { // the standard instrument files (GM, GS, XG) must be present printf("no instrument, type %d\n", t); return true; //abort(); } MidiFileTrackList* etl = mf.trackList(); int division = mf.division(); // // create MidiTrack and copy events to ->events() // - combine note on/off events // - calculate tick value for internal resolution // for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { MPEventList* el = &((*t)->events); if (el->empty()) continue; // // if we split the track, SYSEX and META events go into // the first target track bool first = true; // somewhat silly and slooow: for (int port = 0; port < kMaxMidiPorts; ++port) { for (int channel = 0; channel < kMaxMidiChannels; ++channel) { // // check if there are any events for port/channel in track: // iMPEvent i; for (i = el->begin(); i != el->end(); ++i) { MidiPlayEvent ev = *i; if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel && ev.port() == port) break; } if (i == el->end()) continue; MidiTrack* track = new MidiTrack(); if ((*t)->isDrumTrack) { track->setType(Track::DRUM); } track->setOutChannel(channel); track->setOutPort(port); MidiPort* mport = &midiPorts[track->outPort()]; // this overwrites any instrument set for this port: mport->setInstrument(instr); EventList* mel = track->events(); //buildMidiEventList(mel, el, track, division, first); // Don't do loops. buildMidiEventList(mel, el, track, division, first, false); first = false; // Hmm. buildMidiEventList already takes care of this. // But it seems to work. How? Must test. if (channel == 9 && song->midiType() != MT_UNKNOWN) { track->setType(Track::DRUM); // // remap drum pitch with drumInmap // EventList* tevents = track->events(); for (iEvent i = tevents->begin(); i != tevents->end(); ++i) { Event ev = i->second; if (ev.isNote()) { int pitch = drumInmap[ev.pitch()]; ev.setPitch(pitch); } else if (ev.type() == Controller) { int ctl = ev.dataA(); MidiController *mc = mport->drumController(ctl); if (mc) ev.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]); } } } processTrack(track); song->insertTrack(track, -1); } } if (first) { // // track does only contain non-channel messages // (SYSEX or META) // MidiTrack* track = new MidiTrack(); track->setOutChannel(0); track->setOutPort(0); EventList* mel = track->events(); //buildMidiEventList(mel, el, track, division, true); // Do SysexMeta. Don't do loops. buildMidiEventList(mel, el, track, division, true, false); processTrack(track); song->insertTrack(track, -1); } } if (!merge) { TrackList* tl = song->tracks(); if (!tl->empty()) { Track* track = tl->front(); track->setSelected(true); } song->initLen(); int z, n; ///sigmap.timesig(0, z, n); sigmap.timesig(0, z, n); int tempo = tempomap.tempo(0); transport->setTimesig(z, n); transport->setTempo(tempo); bool masterF = !tempomap.empty(); song->setMasterFlag(masterF); transport->setMasterFlag(masterF); song->updatePos(); composer->reset(); ///composer->setMode(int(song->midiType())); // p4.0.7 Tim } else { song->initLen(); } return false; }/*}}}*/
bool LOS::importMidi(const QString name, bool merge)/*{{{*/ { bool popenFlag; FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag); if (fp == 0) return true; MidiFile mf(fp); bool rv = mf.read(); popenFlag ? pclose(fp) : fclose(fp); if (rv) { QString s(tr("reading midifile\n ")); s += name; s += tr("\nfailed: "); s += mf.error(); QMessageBox::critical(this, QString("LOS"), s); return rv; } // // evaluate song Type (GM, XG, GS, unknown) // MType t = song->midiType(); if (!merge) { t = mf.mtype(); song->setMType(t); } MidiInstrument* instr = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { MidiInstrument* mi = *i; if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_GM))) || ((mi->iname() == "GS") && (t == MT_GS)) || ((mi->iname() == "XG") && (t == MT_XG))) { instr = mi; break; } } if (instr == 0) { // the standard instrument files (GM, GS, XG) must be present printf("no instrument, type %d\n", t); return true; //abort(); } MidiFileTrackList* etl = mf.trackList(); int division = mf.division(); // // create MidiTrack and copy events to ->events() // - combine note on/off events // - calculate tick value for internal resolution // int mPort = getFreeMidiPort(); for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { MPEventList* el = &((*t)->events); if (el->empty()) continue; // // if we split the track, SYSEX and META events go into // the first target track bool first = true; // somewhat silly and slooow: QList<QPair<int, int> > eventChannelList; if(mPort >= 0 && mPort < kMaxMidiPorts) { for (int channel = 0; channel < kMaxMidiChannels; ++channel) { // // check if there are any events for port/channel in track: // iMPEvent i; for (i = el->begin(); i != el->end(); ++i) { MidiPlayEvent ev = *i; if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel) break; } if (i == el->end()) continue; MidiTrack* track = new MidiTrack(); track->setDefaultName(); track->setMasterFlag(true); track->setOutChannel(channel); track->setOutPort(mPort); MidiPort* mport = &midiPorts[track->outPort()]; // this overwrites any instrument set for this port: mport->setInstrument(instr); EventList* mel = track->events(); buildMidiEventList(mel, el, track, division, first, false, false); first = false; processTrack(track); song->insertTrack(track, -1); //Create the Audio input side of the track Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false); if(input) { input->setMasterFlag(false); input->setChainMaster(track->id()); track->addManagedTrack(input->id()); } } } if (first) { // // track does only contain non-channel messages // (SYSEX or META) // MidiTrack* track = new MidiTrack(); track->setDefaultName(); track->setMasterFlag(true); track->setOutChannel(0); track->setOutPort(mPort); EventList* mel = track->events(); //buildMidiEventList(mel, el, track, division, true); // Do SysexMeta. Don't do loops. buildMidiEventList(mel, el, track, division, true, false, false); processTrack(track); song->insertTrack(track, -1); //Create the Audio input side of the track Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false); if(input) { input->setMasterFlag(false); input->setChainMaster(track->id()); track->addManagedTrack(input->id()); } } mPort++; //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash //Or maintain a list of configured or inuse ports while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts) mPort++;//Just incase we have a configured port after an empty one } if (!merge) { TrackList* tl = song->tracks(); if (!tl->empty()) { Track* track = tl->front(); track->setSelected(true); } song->initLen(); int z, n; sigmap.timesig(0, z, n); int tempo = tempomap.tempo(0); transport->setTimesig(z, n); transport->setTempo(tempo); bool masterF = !tempomap.empty(); song->setMasterFlag(masterF); transport->setMasterFlag(masterF); song->updatePos(); composer->reset(); } else { song->initLen(); } return false; }/*}}}*/
void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track, int div, bool addSysexMeta, bool doLoops) { int hbank = 0xff; int lbank = 0xff; int rpnh = -1; int rpnl = -1; int datah = 0; int datal = 0; int dataType = 0; // 0 : disabled, 0x20000 : rpn, 0x30000 : nrpn EventList mel; for (iMPEvent i = el->begin(); i != el->end(); ++i) { MidiPlayEvent ev = *i; if (!addSysexMeta && (ev.type() == ME_SYSEX || ev.type() == ME_META)) continue; if (!(ev.type() == ME_SYSEX || ev.type() == ME_META || ((ev.channel() == track->outChannel()) && (ev.port() == track->outPort())))) continue; unsigned tick = ev.time(); // Added by Tim. p3.3.8 // Added by T356. if (doLoops) { if (tick >= song->lPos().tick() && tick < song->rPos().tick()) { int loopn = ev.loopNum(); int loopc = audio->loopCount(); int cmode = song->cycleMode(); // CYCLE_NORMAL, CYCLE_MIX, CYCLE_REPLACE // If we want REPLACE and the event was recorded in a previous loop, // just ignore it. This will effectively ignore ALL previous loop events inside // the left and right markers, regardless of where recording was started or stopped. // We want to keep any loop 0 note-offs from notes which crossed over the left marker. // To avoid more searching here, just keep ALL note-offs from loop 0, and let code below // sort out and keep which ones had note-ons. if (!(ev.isNoteOff() && loopn == 0)) { if (cmode == Song::CYCLE_REPLACE && loopn < loopc) { // Added by Tim. p3.3.8 //printf("buildMidiEventList: CYCLE_REPLACE t:%d type:%d A:%d B:%d ln:%d lc:%d\n", tick, ev.type(), ev.dataA(), ev.dataB(), loopn, loopc); continue; } // If we want NORMAL, same as REPLACE except keep all events from the previous loop // from rec stop position to right marker (and beyond). if (cmode == Song::CYCLE_NORMAL) { // Not sure of accuracy here. Adjust? Adjusted when used elsewhere? unsigned endRec = audio->getEndRecordPos().tick(); if ((tick < endRec && loopn < loopc) || (tick >= endRec && loopn < (loopc - 1))) { // Added by Tim. p3.3.8 //printf("buildMidiEventList: CYCLE_NORMAL t:%d type:%d A:%d B:%d ln:%d lc:%d\n", tick, ev.type(), ev.dataA(), ev.dataB(), loopn, loopc); continue; } } } } } Event e; switch (ev.type()) { case ME_NOTEON: e.setType(Note); if (track->type() == Track::DRUM) { int instr = drumInmap[ev.dataA()]; e.setPitch(instr); } else { e.setPitch(ev.dataA()); } e.setVelo(ev.dataB()); e.setLenTick(0); break; case ME_NOTEOFF: e.setType(Note); if (track->type() == Track::DRUM) { int instr = drumInmap[ev.dataA()]; e.setPitch(instr); } else e.setPitch(ev.dataA()); e.setVelo(0); e.setVeloOff(ev.dataB()); e.setLenTick(0); break; case ME_POLYAFTER: e.setType(PAfter); e.setA(ev.dataA()); e.setB(ev.dataB()); break; case ME_CONTROLLER: { int val = ev.dataB(); switch (ev.dataA()) { case CTRL_HBANK: hbank = val; break; case CTRL_LBANK: lbank = val; break; case CTRL_HDATA: datah = val; // check if a CTRL_LDATA follows // e.g. wie have a 14 bit controller: { iMPEvent ii = i; ++ii; bool found = false; for (; ii != el->end(); ++ii) { MidiPlayEvent ev = *ii; if (ev.type() == ME_CONTROLLER) { if (ev.dataA() == CTRL_LDATA) { // handle later found = true; } break; } } if (!found) { if (rpnh == -1 || rpnl == -1) { printf("parameter number not defined, data 0x%x\n", datah); } else { int ctrl = dataType | (rpnh << 8) | rpnl; e.setType(Controller); e.setA(ctrl); e.setB(datah); } } } break; case CTRL_LDATA: datal = val; if (rpnh == -1 || rpnl == -1) { printf("parameter number not defined, data 0x%x 0x%x, tick %d, channel %d\n", datah, datal, tick, track->outChannel()); break; } // assume that the sequence is always // CTRL_HDATA - CTRL_LDATA // eg. that LDATA is always send last e.setType(Controller); // 14 Bit RPN/NRPN e.setA((dataType + 0x30000) | (rpnh << 8) | rpnl); e.setB((datah << 7) | datal); break; case CTRL_HNRPN: rpnh = val; dataType = 0x30000; break; case CTRL_LNRPN: rpnl = val; dataType = 0x30000; break; case CTRL_HRPN: rpnh = val; dataType = 0x20000; break; case CTRL_LRPN: rpnl = val; dataType = 0x20000; break; default: e.setType(Controller); int ctl = ev.dataA(); e.setA(ctl); if (track->type() == Track::DRUM) { // Is it a drum controller event, according to the track port's instrument? MidiController *mc = midiPorts[track->outPort()].drumController(ctl); if (mc) // Store an index into the drum map. e.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]); } e.setB(val); break; } } break; case ME_PROGRAM: e.setType(Controller); e.setA(CTRL_PROGRAM); e.setB((hbank << 16) | (lbank << 8) | ev.dataA()); break; case ME_AFTERTOUCH: e.setType(CAfter); e.setA(ev.dataA()); break; case ME_PITCHBEND: e.setType(Controller); e.setA(CTRL_PITCH); e.setB(ev.dataA()); break; case ME_SYSEX: e.setType(Sysex); e.setData(ev.data(), ev.len()); break; case ME_META: { const unsigned char* data = ev.data(); switch (ev.dataA()) { case 0x01: // Text if (track->comment().isEmpty()) track->setComment(QString((const char*) data)); else track->setComment(track->comment() + "\n" + QString((const char*) data)); break; case 0x03: // Sequence-/TrackName track->setName(QString((char*) data)); break; case 0x6: // Marker { unsigned ltick = CALC_TICK(tick); //(tick * config.division + div/2) / div; song->addMarker(QString((const char*) (data)), ltick, false); } break; case 0x5: // Lyrics case 0x8: // text case 0x9: case 0xa: break; case 0x0f: // Track Comment track->setComment(QString((char*) data)); break; case 0x51: // Tempo { unsigned tempo = data[2] + (data[1] << 8) + (data[0] << 16); unsigned ltick = CALC_TICK(tick); // (unsigned(tick) * unsigned(config.division) + unsigned(div/2)) / unsigned(div); // After ca 10 mins 32 bits will not be enough... This expression has to be changed/factorized or so in some "sane" way... tempomap.addTempo(ltick, tempo); } break; case 0x58: // Time Signature { int timesig_z = data[0]; int n = data[1]; int timesig_n = 1; for (int i = 0; i < n; i++) timesig_n *= 2; int ltick = CALC_TICK(tick); //(tick * config.division + div/2) / div; ///sigmap.add(ltick, timesig_z, timesig_n); AL::sigmap.add(ltick, AL::TimeSignature(timesig_z, timesig_n)); } break; case 0x59: // Key Signature // track->scale.set(data[0]); // track->scale.setMajorMinor(data[1]); break; default: printf("unknown Meta 0x%x %d\n", ev.dataA(), ev.dataA()); } } break; } // switch(ev.type() if (!e.empty()) { e.setTick(tick); // Added by Tim. p3.3.8 //printf("buildMidiEventList: mel adding t:%d type:%d A:%d B:%d C:%d\n", tick, e.type(), e.dataA(), e.dataB(), e.dataC()); mel.add(e); } } // i != el->end() //--------------------------------------------------- // resolve NoteOff events //--------------------------------------------------- // for (iEvent i = mel.begin(); i != mel.end(); ++i) { // Event event = i->second; // if (event.isNote()) // event.setLenTick(0); // } // Added by Tim. p3.3.8 // The loop is a safe way to delete while iterating. bool loop; do { loop = false; for (iEvent i = mel.begin(); i != mel.end(); ++i) { Event ev = i->second; if (ev.isNote()) { if (ev.isNoteOff()) { iEvent k; bool found = false; for (k = i; k != mel.end(); ++k) { Event event = k->second; if (event.tick() > ev.tick()) break; if (event.isNoteOff(ev)) { ev.setLenTick(1); ev.setVelo(event.velo()); ev.setVeloOff(0); // Added by Tim. p3.3.8 //printf("buildMidiEventList: found note off: event t:%d len:%d type:%d A:%d B:%d C:%d ev t:%d len:%d type:%d A:%d B:%d C:%d\n", event.tick(), event.lenTick(), event.type(), event.dataA(), event.dataB(), event.dataC(), ev.tick(), ev.lenTick(), ev.type(), ev.dataA(), ev.dataB(), ev.dataC()); found = true; break; } } if (!found) { printf("NOTE OFF without Note ON tick %d type %d %d %d\n", ev.tick(), ev.type(), ev.pitch(), ev.velo()); } else { mel.erase(k); // Changed by Tim. p3.3.8 //continue; loop = true; break; } } // Added by Tim. p3.3.8 // If the event length is not zero, it means the event and its // note on/off have already been taken care of. So ignore it. if (ev.lenTick() != 0) { continue; } iEvent k; for (k = mel.lower_bound(ev.tick()); k != mel.end(); ++k) { Event event = k->second; if (ev.isNoteOff(event)) { int t = k->first - i->first; if (t <= 0) { if (debugMsg) { printf("Note len is (%d-%d)=%d, set to 1\n", k->first, i->first, k->first - i->first); ev.dump(); event.dump(); } t = 1; } ev.setLenTick(t); ev.setVeloOff(event.veloOff()); // Added by Tim. p3.3.8 //printf("buildMidiEventList: set len and velOff: event t:%d len:%d type:%d A:%d B:%d C:%d ev t:%d len:%d type:%d A:%d B:%d C:%d\n", event.tick(), event.lenTick(), event.type(), event.dataA(), event.dataB(), event.dataC(), ev.tick(), ev.lenTick(), ev.type(), ev.dataA(), ev.dataB(), ev.dataC()); break; } } if (k == mel.end()) { printf("-no note-off! %d pitch %d velo %d\n", ev.tick(), ev.pitch(), ev.velo()); // // switch off at end of measure // int endTick = song->roundUpBar(ev.tick() + 1); ev.setLenTick(endTick - ev.tick()); } else { mel.erase(k); // Added by Tim. p3.3.8 loop = true; break; } } } } while (loop); // DEBUG: any note offs left? // Removed by Tim. p3.3.8 //for (iEvent i = mel.begin(); i != mel.end(); ++i) { // Event ev = i->second; // if (ev.isNoteOff()) { // printf("+extra note-off! %d pitch %d velo %d\n", // i->first, ev.pitch(), ev.velo()); // ev.dump(); // } // } for (iEvent i = mel.begin(); i != mel.end(); ++i) { Event ev = i->second; if (ev.isNoteOff()) { printf("+extra note-off! %d pitch %d velo %d\n", i->first, ev.pitch(), ev.velo()); // ev.dump(); continue; } int tick = CALC_TICK(ev.tick()); //(ev.tick() * config.division + div/2) / div; if (ev.isNote()) { int lenTick = CALC_TICK(ev.lenTick()); //(ev.lenTick() * config.division + div/2) / div; ev.setLenTick(lenTick); } ev.setTick(tick); del->add(ev); } }
void FluidSynthGui::processEvent(const MidiPlayEvent& ev) { //Sysexes sent from the client if (ev.type() == ME_SYSEX) { byte* data = ev.data(); switch (*data) { case FS_LASTDIR_CHANGE: lastdir = QString((const char*)data+1); break; case FS_ERROR: { char* msg = (char*) (data+1); printf("OOMidi: fluidsynth error: %s\n", msg); break; } case FS_SEND_SOUNDFONTDATA: { int chunk_len; int filename_len; int count = (int)*(data+1); //Number of elements byte* cp = data+2; //Point to beginning of first chunk sfListView->clear(); //Clear the listview stack.clear(); //Clear the stack since we're starting over again while (count) { FluidGuiSoundFont font; filename_len = strlen((const char*)cp) + 1; font.name = (const char*)cp; font.id = *(cp + filename_len); chunk_len = filename_len + FS_SFDATALEN; stack.push_front(font); cp += chunk_len; //Move to next chunk count--; } updateSoundfontListView(); updateChannelListView(); break; } case FS_SEND_CHANNELINFO: { byte* chptr = (data+1); for (int i=0; i< FS_MAX_NR_OF_CHANNELS; i++) { byte id = *chptr; byte channel = *(chptr+1); channels[channel] = id; chptr+=2; } updateChannelListView(); break; } case FS_SEND_DRUMCHANNELINFO: { byte* drumchptr = (data+1); for (int i=0; i<FS_MAX_NR_OF_CHANNELS; i++) { drumchannels[i] = *drumchptr; drumchptr++; } updateChannelListView(); break; } default: if (FS_DEBUG) printf("FluidSynthGui::processEvent() : Unknown Sysex received: %d\n", ev.type()); break; } } //Controllers sent from the client: else if(ev.type() == ME_CONTROLLER) { int id = ev.dataA(); int val = ev.dataB(); switch (id) { case FS_GAIN: { bool sb = Gain->signalsBlocked(); Gain->blockSignals(true); // Update Gain-slider without causing it to respond to it's own signal (and send another msg to the synth) Gain->setValue(val); Gain->blockSignals(sb); break; } case FS_REVERB_ON: { bool sb = Reverb->signalsBlocked(); Reverb->blockSignals(true); Reverb->setChecked(val); Reverb->blockSignals(sb); break; } case FS_REVERB_LEVEL: { bool sb = ReverbLevel->signalsBlocked(); ReverbLevel->blockSignals(true); ReverbLevel->setValue(val); ReverbLevel->blockSignals(sb); break; } case FS_REVERB_DAMPING: { bool sb = ReverbDamping->signalsBlocked(); ReverbDamping->blockSignals(true); ReverbDamping->setValue(val); ReverbDamping->blockSignals(sb); break; } case FS_REVERB_ROOMSIZE: { bool sb = ReverbRoomSize->signalsBlocked(); ReverbRoomSize->blockSignals(true); ReverbRoomSize->setValue(val); ReverbRoomSize->blockSignals(sb); break; } case FS_REVERB_WIDTH: { bool sb = ReverbWidth->signalsBlocked(); ReverbWidth->blockSignals(true); ReverbWidth->setValue(val); ReverbWidth->blockSignals(sb); break; } case FS_CHORUS_ON: { Chorus->blockSignals(true); Chorus->setChecked(val); Chorus->blockSignals(false); break; } case FS_CHORUS_SPEED: { ChorusSpeed->blockSignals(true); ChorusSpeed->setValue(val); ChorusSpeed->blockSignals(false); break; } case FS_CHORUS_NUM: { ChorusNumber->blockSignals(true); ChorusNumber->setValue(val); ChorusNumber->blockSignals(false); break; } case FS_CHORUS_TYPE: { ChorusType->blockSignals(true); ChorusType->setCurrentIndex(val); ChorusType->blockSignals(false); break; } case FS_CHORUS_DEPTH: { ChorusDepth->blockSignals(true); ChorusDepth->setValue(val); ChorusDepth->blockSignals(false); break; } case FS_CHORUS_LEVEL: { ChorusLevel->blockSignals(true); ChorusLevel->setValue(val); ChorusLevel->blockSignals(false); break; } default: if (FS_DEBUG) printf("FluidSynthGui::processEvent() : Unknown controller sent to gui: %x\n",id); break; } } else if (FS_DEBUG) printf("FluidSynthGui::processEvent - unknown event of type %dreceived from synth.\n", ev.type()); }