From 2691a99850a46400746e17ff34964ef7ee8ab9e5 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Sat, 13 Feb 2010 08:31:11 +0000 Subject: See ChangeLog --- muse/ChangeLog | 10 + muse/muse/arranger/pcanvas.cpp | 2 - muse/muse/audio.cpp | 6 +- muse/muse/driver/audiodev.h | 2 - muse/muse/driver/dummyaudio.cpp | 4 +- muse/muse/driver/jack.cpp | 289 ++++++++++---------- muse/muse/driver/jackaudio.h | 5 +- muse/muse/driver/jackmidi.cpp | 570 ++++++++++++++++++++++++++++++++++++++-- muse/muse/driver/jackmidi.h | 48 +++- muse/muse/dssihost.cpp | 1 + muse/muse/midi.cpp | 83 ++++-- muse/muse/midictrl.h | 1 + muse/muse/mididev.cpp | 2 + muse/muse/midiseq.cpp | 14 +- 14 files changed, 817 insertions(+), 220 deletions(-) diff --git a/muse/ChangeLog b/muse/ChangeLog index e4d60b27..a44ae038 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,13 @@ +13.02.2010 + * Fixed: Jack midi output should now be frame-accurate, support variable length events (like sysex), + and most controllers should work. (T356) + - TODO: No record yet. Just playback. + - TODO: I have code in place for multiple device listing (like ALSA) with auto-connect, + instead of single 'jackmidi' device, but it doesn't seem to want to actually connect. + Simply enable the #define JACK_MIDI_SHOW_MULTIPLE_DEVICES in driver/jackmidi.h + and it will magically switch. Shows port names as their alias #1 (with a rem'able line to + revert to non-alias names - to be made configurable later). I swear it was working, + then intermittent, then not at all. Hmm... 06.02.2010 * Fixed: MusE hanging on close, with Jack driver. (T356) - Unregister Jack midi ports on destruction of JackAudioDevice. diff --git a/muse/muse/arranger/pcanvas.cpp b/muse/muse/arranger/pcanvas.cpp index 4cb3db1a..080bf9bf 100644 --- a/muse/muse/arranger/pcanvas.cpp +++ b/muse/muse/arranger/pcanvas.cpp @@ -1446,7 +1446,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) p.setPen(darkGray); EventList* events = mp->events(); iEvent ito(events->lower_bound(to)); - // Added by Tim. P3.3.6 //printf("PartCanvas::drawItem pTick:%d from:%d to:%d part len:%d\n", pTick, from, to, part->lenTick()); for (iEvent i = events->begin(); i != ito; ++i) { @@ -1455,7 +1454,6 @@ void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect) if (t > (to + pTick)) { - // Added by Tim. P3.3.6 printf("PartCanvas::drawItem t:%d > to:%d + pTick:%d i->first:%d\n", t, to, pTick, i->first); break; diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index 1fb53bc8..d8c12331 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -462,7 +462,7 @@ void Audio::process(unsigned frames) } - // P3.3.25 + // p3.3.25 if(extSyncFlag.value()) { nextTickPos = curTickPos + midiExtSyncTicks; @@ -1204,7 +1204,7 @@ void Audio::stopRolling() mp->sendMMCStop(); //mp->sendSysex(mmcPos, sizeof(mmcPos)); - // P3.3.31 + // p3.3.31 // Added check of option send continue not start. // Hmm, is this required? Seems to make other devices unhappy. /* @@ -1223,7 +1223,7 @@ void Audio::stopRolling() // "set song position pointer" mp->sendStop(); - // P3.3.31 + // p3.3.31 // Added check of option send continue not start. // Hmm, is this required? Seems to make other devices unhappy. /* diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h index 437b1eee..e0ddb3b9 100644 --- a/muse/muse/driver/audiodev.h +++ b/muse/muse/driver/audiodev.h @@ -57,8 +57,6 @@ class AudioDevice { virtual void setFreewheel(bool f) = 0; virtual void graphChanged() {} virtual int setMaster(bool f) = 0; - - virtual bool putEvent(int port, const MidiPlayEvent&) = 0; }; #endif diff --git a/muse/muse/driver/dummyaudio.cpp b/muse/muse/driver/dummyaudio.cpp index bd95647d..e22c44da 100644 --- a/muse/muse/driver/dummyaudio.cpp +++ b/muse/muse/driver/dummyaudio.cpp @@ -167,8 +167,6 @@ class DummyAudioDevice : public AudioDevice { } virtual void setFreewheel(bool) {} void setRealTime() { realtimeFlag = true; } - - virtual bool putEvent(int /*port*/, const MidiPlayEvent&) { return true;}; }; DummyAudioDevice* dummyAudio = 0; @@ -242,7 +240,7 @@ static void* dummyLoop(void* ptr) { //unsigned int tickRate = 25; - // P3.3.30 + // p3.3.30 //sampleRate = 25600; sampleRate = config.dummyAudioSampleRate; //segmentSize = dummyFrames; diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp index 4cd471b0..ee15c4b3 100644 --- a/muse/muse/driver/jack.cpp +++ b/muse/muse/driver/jack.cpp @@ -43,18 +43,35 @@ extern void undoSetuid(); #include #endif -extern int jackmidi_pi[2]; -extern int jackmidi_po[2]; +//extern int jackmidi_pi[2]; +//extern int jackmidi_po[2]; jack_port_t *midi_port_in[JACK_MIDI_CHANNELS]; jack_port_t *midi_port_out[JACK_MIDI_CHANNELS]; -muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS]; -muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS]; +//muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS]; +//muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS]; -// p3.3.32 //jack_port_t *jackMidiInPort = 0; //jack_port_t *jackMidiOutPort = 0; +/* +struct JackPort +{ + int adr; + //char* name; + QString name; + int flags; + //JackPort(int a, const char* s, int f) { + JackPort(int a, const QString& s, int f) + { + adr = a; + //name = strdup(s); + name = QString(s); + flags = f; + } +}; +static std::list portList; +*/ JackAudioDevice* jackAudio; @@ -140,6 +157,7 @@ print_triplet(unsigned char *data) fprintf(stderr, "%x,%x,%x", a, b, c); } +/* void handle_jack_midi_in_events(jack_nframes_t frames) { char buf = 0; @@ -191,18 +209,18 @@ void handle_jack_midi_out_events(jack_nframes_t frames) //for(i = 0; i < JACK_MIDI_CHANNELS; i++){ for(i = 0; i < JACK_MIDI_CHANNELS; ++i){ - /* jack-midi-clear any old events */ + // jack-midi-clear any old events while(jack_midi_out_data[i].buffer[jack_midi_out_data[i].take*4+3] == 2){ port_buf = jack_port_get_buffer(midi_port_out[i], frames); jack_midi_clear_buffer(port_buf); jack_midi_out_data[i].buffer[jack_midi_out_data[i].take*4+3] = 0; - /* point the take to the next slot */ + // point the take to the next slot jack_midi_out_data[i].take++; if(jack_midi_out_data[i].take >= JACK_MIDI_BUFFER_SIZE){ jack_midi_out_data[i].take = 0; } } - /* check if any incoming midi-events from muse */ + // check if any incoming midi-events from muse if(jack_midi_out_data[i].give != jack_midi_out_data[i].take){ if(jack_midi_out_data[i].give > jack_midi_out_data[i].take){ @@ -213,25 +231,23 @@ void handle_jack_midi_out_events(jack_nframes_t frames) } port_buf = jack_port_get_buffer(midi_port_out[i], frames); jack_midi_clear_buffer(port_buf); - /* FIX: midi events has different sizes, compare note-on to - program-change. We should first walk over the events - counting the size. */ - /* - data = jack_midi_event_reserve(port_buf, 0, n*3); - x = jack_midi_out_data[i].take; - for(j = 0; j < n; j++){ - data[j*3+0] = jack_midi_out_data[i].buffer[x*4+0]; - data[j*3+1] = jack_midi_out_data[i].buffer[x*4+1]; - data[j*3+2] = jack_midi_out_data[i].buffer[x*4+2]; + // FIX: midi events has different sizes, compare note-on to + // program-change. We should first walk over the events + // counting the size. + //data = jack_midi_event_reserve(port_buf, 0, n*3); + //x = jack_midi_out_data[i].take; + //for(j = 0; j < n; j++){ + // data[j*3+0] = jack_midi_out_data[i].buffer[x*4+0]; + // data[j*3+1] = jack_midi_out_data[i].buffer[x*4+1]; + // data[j*3+2] = jack_midi_out_data[i].buffer[x*4+2]; // after having copied the buffer over to the jack-buffer, // mark the muses midi-out buffer as 'need-cleaning' - jack_midi_out_data[i].buffer[x*4+3] = 2; - x++; - if(x >= JACK_MIDI_BUFFER_SIZE){ - x = 0; - } - } - */ + // jack_midi_out_data[i].buffer[x*4+3] = 2; + // x++; + // if(x >= JACK_MIDI_BUFFER_SIZE){ + // x = 0; + // } + //} x = jack_midi_out_data[i].take; for(j = 0; j < n; ++j) @@ -258,14 +274,15 @@ void handle_jack_midi_out_events(jack_nframes_t frames) } } } +*/ //static int processAudio(jack_nframes_t frames, void*) int JackAudioDevice::processAudio(jack_nframes_t frames, void*) { jackAudio->_frameCounter += frames; - handle_jack_midi_in_events(frames); - handle_jack_midi_out_events(frames); +/// handle_jack_midi_in_events(frames); +/// handle_jack_midi_out_events(frames); // if (JACK_DEBUG) // printf("processAudio - >>>>\n"); @@ -346,7 +363,7 @@ static void timebase_callback(jack_transport_state_t /* state */, // p3.3.29 //printf("Jack timebase_callback pos->frame:%u audio->tickPos:%d song->cpos:%d\n", pos->frame, audio->tickPos(), song->cpos()); - // P3.3.27 + // p3.3.27 //Pos p(pos->frame, false); Pos p(extSyncFlag.value() ? audio->tickPos() : pos->frame, extSyncFlag.value() ? true : false); // Can't use song pos - it is only updated every (slow) GUI heartbeat ! @@ -558,56 +575,40 @@ bool initJackAudio() } undoSetuid(); - // setup midi input/output - memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); - memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); - if(client){ - for(i = 0; i < JACK_MIDI_CHANNELS; i++){ - char buf[80]; - snprintf(buf, 80, "muse-jack-midi-in-%d", i+1); - midi_port_in[i] = jack_port_register(client, buf, - JACK_DEFAULT_MIDI_TYPE, - JackPortIsInput, 0); - if(midi_port_in[i] == NULL){ - fprintf(stderr, "failed to register jack-midi-in\n"); - exit(-1); - } - snprintf(buf, 80, "muse-jack-midi-out-%d", i+1); - midi_port_out[i] = jack_port_register(client, buf, - JACK_DEFAULT_MIDI_TYPE, - JackPortIsOutput, 0); - if(midi_port_out == NULL){ - fprintf(stderr, "failed to register jack-midi-out\n"); - exit(-1); + // setup midi input/output + //memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); + //memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); + if(client){ + for(i = 0; i < JACK_MIDI_CHANNELS; i++) + { + char buf[80]; + snprintf(buf, 80, "muse-jack-midi-in-%d", i+1); + midi_port_in[i] = jack_port_register(client, buf, + JACK_DEFAULT_MIDI_TYPE, + JackPortIsInput, 0); + if(midi_port_in[i] == NULL){ + fprintf(stderr, "failed to register jack-midi-in\n"); + exit(-1); + } + snprintf(buf, 80, "muse-jack-midi-out-%d", i+1); + midi_port_out[i] = jack_port_register(client, buf, + JACK_DEFAULT_MIDI_TYPE, + JackPortIsOutput, 0); + if(midi_port_out == NULL) + { + fprintf(stderr, "failed to register jack-midi-out\n"); + exit(-1); + } + } } - } - }else{ - fprintf(stderr, "WARNING NO muse-jack midi connection\n"); - } - - /* - char buf[80]; - snprintf(buf, 80, "muse-jack-midi-in-%d", i+1); - midi_port_in[i] = jack_port_register(client, buf, - JACK_DEFAULT_MIDI_TYPE, - JackPortIsInput, 0); - if(midi_port_in[i] == NULL){ - fprintf(stderr, "failed to register jack-midi-in\n"); - exit(-1); - } - snprintf(buf, 80, "muse-jack-midi-out-%d", i+1); - midi_port_out[i] = jack_port_register(client, buf, - JACK_DEFAULT_MIDI_TYPE, - JackPortIsOutput, 0); - if(midi_port_out == NULL){ - fprintf(stderr, "failed to register jack-midi-out\n"); - exit(-1); + else + { + fprintf(stderr, "WARNING NO muse-jack midi connection\n"); } - */ - - + if (client) { audioDevice = jackAudio; + jackAudio->scanMidiPorts(); return false; } return true; @@ -1451,6 +1452,10 @@ void* JackAudioDevice::findPort(const char* name) return p; } +//--------------------------------------------------------- +// setMaster +//--------------------------------------------------------- + int JackAudioDevice::setMaster(bool f) { if (JACK_DEBUG) @@ -1489,90 +1494,60 @@ int JackAudioDevice::setMaster(bool f) return r; } - //--------------------------------------------------------- -// putEvent -// return true if successful +// scanMidiPorts //--------------------------------------------------------- -//void JackAudioDevice::putEvent(Port port, const MidiEvent& e) -bool JackAudioDevice::putEvent(int port, const MidiPlayEvent& e) - { - if(port >= JACK_MIDI_CHANNELS) - return false; - - //if (midiOutputTrace) { - // printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().data()); - // e.dump(); - // } - - //void* pb = jack_port_get_buffer(port.jackPort(), segmentSize); - void* pb = jack_port_get_buffer(midi_port_out[port], segmentSize); - - int ft = e.time() - _frameCounter; - - if (ft < 0) - ft = 0; - if (ft >= (int)segmentSize) { - printf("JackAudio::putEvent: time out of range %d(seg=%d)\n", ft, segmentSize); - if (ft > (int)segmentSize) - ft = segmentSize - 1; - } - switch(e.type()) { - case ME_NOTEON: - case ME_NOTEOFF: - case ME_POLYAFTER: - case ME_CONTROLLER: - case ME_PITCHBEND: - { - unsigned char* p = jack_midi_event_reserve(pb, ft, 3); - if (p == 0) { - fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); - return false; - } - p[0] = e.type() | e.channel(); - p[1] = e.dataA(); - p[2] = e.dataB(); - } - break; - - case ME_PROGRAM: - case ME_AFTERTOUCH: - { - unsigned char* p = jack_midi_event_reserve(pb, ft, 2); - if (p == 0) { - fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); - return false; - } - p[0] = e.type() | e.channel(); - p[1] = e.dataA(); - } - break; - case ME_SYSEX: - { - 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, "JackMidi: buffer overflow, event lost\n"); - return false; - } - 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: - printf("JackMidi: event type %x not supported\n", e.type()); - return false; - break; - } - - return true; - } - +void JackAudioDevice::scanMidiPorts() +{ + #ifdef JACK_MIDI_SHOW_MULTIPLE_DEVICES + + const char* type = JACK_DEFAULT_MIDI_TYPE; + const char** ports = jack_get_ports(_client, 0, type, 0); + for (const char** p = ports; p && *p; ++p) + { + jack_port_t* port = jack_port_by_name(_client, *p); + if(!port) + continue; + int nsz = jack_port_name_size(); + char buffer[nsz]; + strncpy(buffer, *p, nsz); + // Ignore the MusE Jack port. + if(strncmp(buffer, "MusE", 4) == 0) + continue; + + // If there are aliases for this port, use the first one - much better for identifying. + //char a1[nsz]; + char a2[nsz]; + char* aliases[2]; + //aliases[0] = a1; + aliases[0] = buffer; + aliases[1] = a2; + // To disable aliases, just rem this line. + jack_port_get_aliases(port, aliases); + //int na = jack_port_get_aliases(port, aliases); + //char* namep = (na >= 1) ? aliases[0] : buffer; + char* namep = aliases[0]; + + int flags = 0; + int pf = jack_port_flags(port); + // If Jack port can send data to us... + if(pf & JackPortIsOutput) + // Mark as input capable. + flags |= 2; + // If Jack port can receive data from us... + if(pf & JackPortIsInput) + // Mark as output capable. + flags |= 1; + + //JackPort jp(0, QString(buffer), flags); + //portList.append(jp); + + MidiJackDevice* dev = new MidiJackDevice(0, QString(namep)); + dev->setrwFlags(flags); + midiDevices.add(dev); + } + #endif + +} diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h index 76753eec..e8a74ac1 100644 --- a/muse/muse/driver/jackaudio.h +++ b/muse/muse/driver/jackaudio.h @@ -38,6 +38,8 @@ class JackAudioDevice : public AudioDevice { virtual ~JackAudioDevice(); virtual void nullify_client() { _client = 0; } + void scanMidiPorts(); + //virtual void start(); virtual void start(int); virtual void stop (); @@ -79,9 +81,6 @@ class JackAudioDevice : public AudioDevice { void graphChanged(); virtual int setMaster(bool f); - // Port is not midi port, it is the port(s) created for MusE. - virtual bool putEvent(int port, const MidiPlayEvent&); - //static bool jackStarted; }; diff --git a/muse/muse/driver/jackmidi.cpp b/muse/muse/driver/jackmidi.cpp index 52a696f0..cc400fd9 100644 --- a/muse/muse/driver/jackmidi.cpp +++ b/muse/muse/driver/jackmidi.cpp @@ -5,6 +5,7 @@ // (C) Copyright 1999-2010 Werner Schweer (ws@seh.de) //========================================================= +#include #include #include @@ -20,12 +21,18 @@ #include "../audio.h" #include "mpevent.h" //#include "sync.h" +#include "audiodev.h" + +// Turn on debug messages. +//#define JACK_MIDI_DEBUG int jackmidi_pi[2]; int jackmidi_po[2]; -extern muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS]; -extern muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS]; +//extern muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS]; +//extern muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS]; +extern jack_port_t *midi_port_in[JACK_MIDI_CHANNELS]; +extern jack_port_t *midi_port_out[JACK_MIDI_CHANNELS]; MidiJackDevice* gmdev = NULL; @@ -43,6 +50,7 @@ MidiJackDevice::MidiJackDevice(const int& a, const QString& n) init(); } +/* //--------------------------------------------------------- // select[RW]fd //--------------------------------------------------------- @@ -56,6 +64,7 @@ int MidiJackDevice::selectWfd() { return jackmidi_po[0]; } +*/ //--------------------------------------------------------- // open @@ -63,10 +72,40 @@ int MidiJackDevice::selectWfd() QString MidiJackDevice::open() { - _readEnable = true; + #ifdef JACK_MIDI_SHOW_MULTIPLE_DEVICES + _openFlags &= _rwFlags; // restrict to available bits + + //jack_port_t* jp = jack_port_by_name(_client, name().latin1()); + jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1()); + + if(!jp) + { + printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().latin1()); + return QString("Jack midi port not found"); + } + + int pf = jack_port_flags(jp); + + // If Jack port can receive data from us and we actually want to... + if((pf & JackPortIsInput) && (_openFlags & 1)) + { + // src, dest + //TODO: Having trouble here, may need to coordinate or move to graphChanged. + audioDevice->connect(midi_port_out[0], jp); + _writeEnable = true; + } + + // If Jack port can send data to us and we actually want it... + if((pf & JackPortIsOutput) && (_openFlags & 2)) + { + audioDevice->connect(jp, midi_port_in[0]); + _readEnable = true; + } + #else _writeEnable = true; - - + _readEnable = true; + #endif + return QString("OK"); } @@ -76,8 +115,39 @@ QString MidiJackDevice::open() void MidiJackDevice::close() { - _readEnable = false; + #ifdef JACK_MIDI_SHOW_MULTIPLE_DEVICES + + //jack_port_t* jp = jack_port_by_name(_client, name().latin1()); + jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1()); + + if(!jp) + { + printf("MidiJackDevice::close: Jack midi port %s not found!\n", name().latin1()); + return; + } + + //int pf = jack_port_flags(jp); + + // If Jack port can receive data from us and we actually want to... + //if((pf & JackPortIsInput) && (_openFlags & 1)) + if(jack_port_connected_to(midi_port_out[0], name().latin1())) + { + // src, dest + audioDevice->disconnect(midi_port_out[0], jp); + _writeEnable = false; + } + + // If Jack port can send data to us and we actually want it... + //if((pf & JackPortIsOutput) && (_openFlags & 2)) + if(jack_port_connected_to(midi_port_in[0], name().latin1())) + { + audioDevice->disconnect(jp, midi_port_in[0]); + _readEnable = false; + } + #else _writeEnable = false; + _readEnable = false; + #endif } //--------------------------------------------------------- @@ -88,8 +158,9 @@ void MidiJackDevice::close() * we return false (indicating OK). Otherwise * it seems muse will retry forever */ -bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event) +bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& /*event*/) { + /* int give, channel = event.channel(); int x; @@ -146,6 +217,7 @@ bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event) } jack_midi_out_data[channel].give = give; return false; + */ /* // @@ -153,6 +225,7 @@ bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event) // or select other MusE ports. MusE ALSA midi only creates one port as well. // const int museport = 0; + if(event.type() == ME_CONTROLLER) { int a = event.dataA(); @@ -249,13 +322,11 @@ bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event) { audioDriver->putEvent(museport, event); } - - // Just return OK for now. - return false; */ - + return false; } +/* //--------------------------------------------------------- // putEvent // return false if event is delivered @@ -266,6 +337,455 @@ bool MidiJackDevice::putEvent(int* event) int *y; y = event; return false; } +*/ + +//--------------------------------------------------------- +// queueEvent +// return true if event cannot be delivered +//--------------------------------------------------------- + +bool MidiJackDevice::putEvent(const MidiPlayEvent& ev) +{ + if(!_writeEnable) + //return true; + 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; +} + +//--------------------------------------------------------- +// queueEvent +// return true if successful +//--------------------------------------------------------- + +//void JackAudioDevice::putEvent(Port port, const MidiEvent& e) +bool MidiJackDevice::queueEvent(int port, const MidiPlayEvent& e) +//bool MidiJackDevice::queueEvent(const MidiPlayEvent& e) +{ + // Perhaps we can find use for this value later, together with the Jack midi MusE port(s). + // No big deal if not. Not used for now. + //int port = e.port(); + + if(port >= JACK_MIDI_CHANNELS) + return false; + + //if (midiOutputTrace) { + // printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().data()); + // e.dump(); + // } + + //if(debugMsg) + // printf("MidiJackDevice::queueEvent\n"); + + + //void* pb = jack_port_get_buffer(port.jackPort(), segmentSize); + void* pb = jack_port_get_buffer(midi_port_out[port], segmentSize); + + //jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1()); + //if(!jp) + // printf("MidiJackDevice::queueEvent: Jack midi port %s not found!\n", name().latin1()); + //void* pb = jack_port_get_buffer(jp ? jp : midi_port_out[port], segmentSize); + + //unsigned frameCounter = ->frameTime(); + int frameOffset = audio->getFrameOffset(); + unsigned pos = audio->pos().frame(); + //int ft = e.time() - _frameCounter; + //int ft = e.time() - frameOffset - frameCounter; + int ft = e.time() - frameOffset - pos; + + if (ft < 0) + ft = 0; + if (ft >= (int)segmentSize) { + 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) { + fprintf(stderr, "MidiJackDevice::queueEvent #1: buffer overflow, event lost\n"); + 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) { + fprintf(stderr, "MidiJackDevice::queueEvent #2: buffer overflow, event lost\n"); + 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 #3: buffer overflow, event lost\n"); + return false; + } + 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: + printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type()); + return false; + break; + } + + return true; +} + +//--------------------------------------------------------- +// processEvent +//--------------------------------------------------------- + +void MidiJackDevice::processEvent(int museport, const MidiPlayEvent& event) +{ + //int frameOffset = audio->getFrameOffset(); + //unsigned pos = audio->pos().frame(); + + int chn = event.channel(); + unsigned t = event.time(); + + // 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(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()); + #endif + + if(event.type() == ME_CONTROLLER) + { + int a = event.dataA(); + int b = event.dataB(); + // Perhaps we can find use for this value later, together with the Jack midi MusE port(s). + // No big deal if not. Not used for now. + int port = event.port(); + + if(a == CTRL_PITCH) + { + int v = b + 8192; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)); + } + else if (a == CTRL_PROGRAM) + { + // don't output program changes for GM drum channel + //if (!(song->mtype() == MT_GM && chn == 9)) { + int hb = (b >> 16) & 0xff; + int lb = (b >> 8) & 0xff; + int pr = b & 0x7f; + if (hb != 0xff) + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)); + if (lb != 0xff) + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)); + // } + } + /* + else if (a == CTRL_MASTER_VOLUME) + { + unsigned char sysex[] = { + 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00 + }; + sysex[1] = deviceId(); + sysex[4] = b & 0x7f; + sysex[5] = (b >> 7) & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, ME_SYSEX, sysex, 6)); + } + */ + else if (a < CTRL_14_OFFSET) + { // 7 Bit Controller + queueEvent(museport, event); + //queueEvent(museport, MidiPlayEvent(t, port, chn, event)); + } + else if (a < CTRL_RPN_OFFSET) + { // 14 bit high resolution controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + int dataH = (b >> 7) & 0x7f; + int dataL = b & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL)); + } + else if (a < CTRL_NRPN_OFFSET) + { // RPN 7-Bit Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)); + } + else if (a < CTRL_RPN14_OFFSET) + { // NRPN 7-Bit Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)); + } + else if (a < CTRL_NRPN14_OFFSET) + { // RPN14 Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + int dataH = (b >> 7) & 0x7f; + int dataL = b & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)); + queueEvent(museport, MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)); + } + else if (a < CTRL_NONE_OFFSET) + { // NRPN14 Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + int dataH = (b >> 7) & 0x7f; + int dataL = b & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)); + queueEvent(museport, MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)); + } + else + { + printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a); + } + } + else + { + queueEvent(museport, event); + //queueEvent(museport, MidiPlayEvent(t, port, chn, event)); + } +} + +//--------------------------------------------------------- +// processMidi called from audio process only. +//--------------------------------------------------------- + +void MidiJackDevice::processMidi() +{ + // + // NOTICE: Only one MusE port (port 0) is supported for now ! MusE has no mechanism to create + // or select other MusE ports. MusE ALSA midi only creates one port as well. + // + const int museport = 0; + void* port_buf = jack_port_get_buffer(midi_port_out[museport], segmentSize); + jack_midi_clear_buffer(port_buf); + + //int frameOffset = audio->getFrameOffset(); + //unsigned pos = audio->pos().frame(); + //MPEventList* el = playEvents(); + + while(!eventFifo.isEmpty()) + { + MidiPlayEvent e(eventFifo.get()); + int evTime = e.time(); + // Is event marked to be played immediately? + 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()); + } + + #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(museport, e); + } + + MPEventList* el = playEvents(); + if(el->empty()) + return; + + //if(debugMsg) + // printf("MidiJackDevice::processMidi\n"); + + //int port = midiPort(); + //MidiPort* mp = port != -1 ? &midiPorts[port] : 0; + iMPEvent i = nextPlayEvent(); + //int tickpos = audio->tickPos(); + //bool extsync = extSyncFlag.value(); + + + for(; i != el->end(); ++i) + { + processEvent(museport, *i); + + /* + const MidiPlayEvent& event = *i; + int chn = event.channel(); + unsigned t = event.time(); + + // No sub-tick playback resolution yet, with external sync. + // Just do this for now until we figure out more precise external timings. Tested OK so far ! + if(extSyncFlag.value()) + t = frameOffset + pos; + + #ifdef JACK_MIDI_DEBUG + printf("MidiJackDevice::processMidi time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB()); + #endif + + if(event.type() == ME_CONTROLLER) + { + int a = event.dataA(); + int b = event.dataB(); + // Perhaps we can find use for this value later, together with the Jack midi MusE port(s). + // No big deal if not. Not used for now. + int port = event.port(); + + if(a == CTRL_PITCH) + { + int v = b + 8192; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)); + } + else if (a == CTRL_PROGRAM) + { + // don't output program changes for GM drum channel + //if (!(song->mtype() == MT_GM && chn == 9)) { + int hb = (b >> 16) & 0xff; + int lb = (b >> 8) & 0xff; + int pr = b & 0x7f; + if (hb != 0xff) + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)); + if (lb != 0xff) + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)); + // } + } + //else if (a == CTRL_MASTER_VOLUME) + //{ + // unsigned char sysex[] = { + // 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00 + // }; + // sysex[1] = deviceId(); + // sysex[4] = b & 0x7f; + // sysex[5] = (b >> 7) & 0x7f; + // queueEvent(museport, MidiPlayEvent(t, port, ME_SYSEX, sysex, 6)); + //} + else if (a < CTRL_14_OFFSET) + { // 7 Bit Controller + queueEvent(museport, event); + //queueEvent(museport, MidiPlayEvent(t, port, chn, event)); + } + else if (a < CTRL_RPN_OFFSET) + { // 14 bit high resolution controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + int dataH = (b >> 7) & 0x7f; + int dataL = b & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL)); + } + else if (a < CTRL_NRPN_OFFSET) + { // RPN 7-Bit Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)); + } + else if (a < CTRL_RPN14_OFFSET) + { // NRPN 7-Bit Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)); + } + else if (a < CTRL_NRPN14_OFFSET) + { // RPN14 Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + int dataH = (b >> 7) & 0x7f; + int dataL = b & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)); + queueEvent(museport, MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)); + } + else if (a < CTRL_NONE_OFFSET) + { // NRPN14 Controller + int ctrlH = (a >> 8) & 0x7f; + int ctrlL = a & 0x7f; + int dataH = (b >> 7) & 0x7f; + int dataL = b & 0x7f; + queueEvent(museport, MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)); + queueEvent(museport, MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)); + queueEvent(museport, MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)); + queueEvent(museport, MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)); + } + else + { + printf("MidiJackDevice::processMidi: unknown controller type 0x%x\n", a); + } + } + else + { + queueEvent(museport, event); + //queueEvent(museport, MidiPlayEvent(t, port, chn, event)); + } + */ + + } + //md->setNextPlayEvent(i); + setNextPlayEvent(i); + +} //--------------------------------------------------------- // initMidiJack @@ -276,8 +796,9 @@ bool initMidiJack() { int adr = 0; - memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); - memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); +// Removed p3.3.36 +/// memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); +/// memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer)); MidiJackDevice* dev = new MidiJackDevice(adr, QString("jack-midi")); dev->setrwFlags(3); /* set read and write flags */ @@ -290,23 +811,33 @@ bool initMidiJack() /// fprintf(stderr, "cant create midi-jack output pipe\n"); /// } + #ifndef JACK_MIDI_SHOW_MULTIPLE_DEVICES midiDevices.add(dev); + #endif + gmdev = dev; /* proclaim the global jack-midi instance */ + //jackScanMidiPorts(); + return false; } +/* struct JackPort { int adr; - char* name; + //char* name; + QString name; int flags; - JackPort(int a, const char* s, int f) { + //JackPort(int a, const char* s, int f) { + JackPort(int a, const QString& s, int f) { adr = a; - name = strdup(s); + //name = strdup(s); + name = QString(s); flags = f; } }; + static std::list portList; //--------------------------------------------------------- @@ -343,7 +874,9 @@ void jackScanMidiPorts() } } } +*/ +/* //--------------------------------------------------------- // processInput //--------------------------------------------------------- @@ -359,13 +892,13 @@ static void handle_jack_midi_in(int channel) event.setPort(gmdev->midiPort()); event.setB(0); - if(t == 0x90){ /* note on */ + if(t == 0x90){ // note on fprintf(stderr, "jackProcessMidiInput note-on\n"); event.setChannel(channel); event.setType(ME_NOTEON); event.setA(n); event.setB(v); - }else if (t == 0x80){ /* note off */ + }else if (t == 0x80){ // note off fprintf(stderr, "jackProcessMidiInput note-off\n"); event.setChannel(channel); event.setType(ME_NOTEOFF); @@ -398,3 +931,4 @@ void MidiJackDevice::processInput() } } +*/ \ No newline at end of file diff --git a/muse/muse/driver/jackmidi.h b/muse/muse/driver/jackmidi.h index cf651714..2758ae89 100644 --- a/muse/muse/driver/jackmidi.h +++ b/muse/muse/driver/jackmidi.h @@ -11,19 +11,29 @@ #include #include "mididev.h" +class MidiFifo; + +// Turn on to show multiple devices, work in progress, +// not working fully yet, can't seem to connect... +/// #define JACK_MIDI_SHOW_MULTIPLE_DEVICES /* jack-midi channels */ -#define JACK_MIDI_CHANNELS 32 +// Sorry, only one MusE Jack midi port for now. +//#define JACK_MIDI_CHANNELS 32 +#define JACK_MIDI_CHANNELS 1 + /* jack-midi buffer size */ -#define JACK_MIDI_BUFFER_SIZE 32 +//#define JACK_MIDI_BUFFER_SIZE 32 +/* typedef struct { int give; int take; - /* 32 parallel midi events, where each event contains three - * midi-bytes and one busy-byte */ + // 32 parallel midi events, where each event contains three + // midi-bytes and one busy-byte char buffer[4 * JACK_MIDI_BUFFER_SIZE]; } muse_jack_midi_buffer; +*/ //--------------------------------------------------------- // MidiJackDevice @@ -34,25 +44,39 @@ class MidiJackDevice : public MidiDevice { int adr; private: + // fifo for midi events sent from gui + // direct to midi port: + MidiFifo eventFifo; + virtual QString open(); virtual void close(); - bool putEvent(int*); + //bool putEvent(int*); + + void processEvent(int /*port*/, const MidiPlayEvent&); + // Port is not midi port, it is the port(s) created for MusE. + bool queueEvent(int /*port*/, const MidiPlayEvent&); + //bool queueEvent(const MidiPlayEvent&); + virtual bool putMidiEvent(const MidiPlayEvent&); + //bool sendEvent(const MidiPlayEvent&); public: MidiJackDevice() {} MidiJackDevice(const int&, const QString& name); + void processMidi(); virtual ~MidiJackDevice() {} - virtual int selectRfd(); - virtual int selectWfd(); - virtual void processInput(); + //virtual int selectRfd(); + //virtual int selectWfd(); + //virtual void processInput(); + + virtual bool putEvent(const MidiPlayEvent&); }; extern bool initMidiJack(); -extern int jackSelectRfd(); -extern int jackSelectWfd(); -extern void jackProcessMidiInput(); -extern void jackScanMidiPorts(); +//extern int jackSelectRfd(); +//extern int jackSelectWfd(); +//extern void jackProcessMidiInput(); +//extern void jackScanMidiPorts(); #endif diff --git a/muse/muse/dssihost.cpp b/muse/muse/dssihost.cpp index f66ea4c3..b9825a83 100644 --- a/muse/muse/dssihost.cpp +++ b/muse/muse/dssihost.cpp @@ -28,6 +28,7 @@ #include #include #include +#include //#include //#include #include diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index ffb40ba2..dc14a3bf 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -23,6 +23,7 @@ #include "audio.h" #include "mididev.h" #include "driver/alsamidi.h" +#include "driver/jackmidi.h" #include "wave.h" #include "synth.h" #include "sync.h" @@ -825,7 +826,7 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts) if (port == defaultPort) { //printf("Adding event normally: frame=%d port=%d channel=%d pitch=%d velo=%d\n",frame, port, channel, pitch, velo); - // P3.3.25 + // p3.3.25 // If syncing to external midi sync, we cannot use the tempo map. // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. if(extSyncFlag.value()) @@ -841,7 +842,7 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts) MidiDevice* mdAlt = midiPorts[port].device(); if (mdAlt) { - // P3.3.25 + // p3.3.25 if(extSyncFlag.value()) mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo)); else @@ -878,7 +879,7 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts) MidiDevice* mdAlt = midiPorts[port].device(); if(mdAlt) { - // P3.3.25 + // p3.3.25 // If syncing to external midi sync, we cannot use the tempo map. // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. if(extSyncFlag.value()) @@ -894,7 +895,7 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts) break; } } - // P3.3.25 + // p3.3.25 if(extSyncFlag.value()) playEvents->add(MidiPlayEvent(tick, port, channel, ev)); else @@ -905,7 +906,7 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts) default: - // P3.3.25 + // p3.3.25 if(extSyncFlag.value()) playEvents->add(MidiPlayEvent(tick, port, channel, ev)); else @@ -957,7 +958,7 @@ void Audio::processMidi() iMPEvent nextPlayEvent = metronome->nextPlayEvent(); playEvents->erase(playEvents->begin(), nextPlayEvent); - // P3.3.25 + // p3.3.25 bool extsync = extSyncFlag.value(); for (iMidiTrack t = song->midis()->begin(); t != song->midis()->end(); ++t) @@ -1111,8 +1112,9 @@ void Audio::processMidi() // p3.3.35 // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice. - if(!extsync) - event.setTime(event.time() + segmentSize*(segmentCount-1)); + // p3.3.36 + //if(!extsync) + // event.setTime(event.time() + segmentSize*(segmentCount-1)); // dont't echo controller changes back to software // synthesizer: @@ -1233,7 +1235,7 @@ void Audio::processMidi() break; MidiPlayEvent ev(*k); - // P3.3.25 + // p3.3.25 //int frame = tempomap.tick2frame(k->time()) + frameOffset; if(extsync) { @@ -1245,7 +1247,7 @@ void Audio::processMidi() ev.setTime(frame); } - // P3.3.25 + // p3.3.25 //ev.setTime(frame); playEvents->add(ev); @@ -1279,17 +1281,17 @@ void Audio::processMidi() else if (state == PRECOUNT) { isMeasure = (clickno % clicksMeasure) == 0; } - // P3.3.25 + // p3.3.25 //int frame = tempomap.tick2frame(midiClick) + frameOffset; int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset; - // P3.3.25 + // p3.3.25 //MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON, beatClickNote, beatClickVelo); if (md) { - // P3.3.25 + // p3.3.25 //MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON, beatClickNote, beatClickVelo); @@ -1301,7 +1303,7 @@ void Audio::processMidi() playEvents->add(ev); } if (audioClickFlag) { - // P3.3.25 + // p3.3.25 //MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0); MidiPlayEvent ev1(evtime, 0, 0, ME_NOTEON, 0, 0); @@ -1310,7 +1312,7 @@ void Audio::processMidi() } if (md) { ev.setB(0); - // P3.3.25 + // p3.3.25 // Removed. Why was this here? //frame = tempomap.tick2frame(midiClick+20) + frameOffset; // @@ -1355,6 +1357,57 @@ void Audio::processMidi() stuckNotes->clear(); } } + + + // p3.3.36 + //int tickpos = audio->tickPos(); + //bool extsync = extSyncFlag.value(); + // + // Special for Jack midi devices: Play all Jack midi events up to curFrame. + // + for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) + { + MidiDevice* md = *id; + // Is it a Jack midi device? + MidiJackDevice* mjd = dynamic_cast(md); + if(!mjd) + continue; + + mjd->processMidi(); + + /* + int port = md->midiPort(); + MidiPort* mp = port != -1 ? &midiPorts[port] : 0; + MPEventList* el = md->playEvents(); + if (el->empty()) + continue; + iMPEvent i = md->nextPlayEvent(); + for(; i != el->end(); ++i) + { + // If syncing to external midi sync, we cannot use the tempo map. + // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. + //if(i->time() > curFrame) + if(i->time() > (extsync ? tickpos : curFrame)) + { + //printf(" curT %d frame %d\n", i->time(), curFrame); + break; // skip this event + } + + if(mp) + { + if(mp->sendEvent(*i)) + break; + } + else + { + if(md->putEvent(*i)) + break; + } + } + md->setNextPlayEvent(i); + */ + } + midiBusy=false; } diff --git a/muse/muse/midictrl.h b/muse/muse/midictrl.h index eb4c06bd..45e4255b 100644 --- a/muse/muse/midictrl.h +++ b/muse/muse/midictrl.h @@ -69,6 +69,7 @@ const int CTRL_RPN_OFFSET = 0x20000; const int CTRL_NRPN_OFFSET = 0x30000; const int CTRL_RPN14_OFFSET = 0x50000; const int CTRL_NRPN14_OFFSET = 0x60000; +const int CTRL_NONE_OFFSET = 0x70000; class Xml; class Part; diff --git a/muse/muse/mididev.cpp b/muse/muse/mididev.cpp index 7d02cc74..4d9f425c 100644 --- a/muse/muse/mididev.cpp +++ b/muse/muse/mididev.cpp @@ -166,6 +166,8 @@ void MidiDevice::recordEvent(MidiRecordEvent& event) //event.setTime(audio->timestamp()); event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : audio->timestamp()); + //printf("MidiDevice::recordEvent event time:%d\n", event.time()); + // Added by Tim. p3.3.8 // By T356. Set the loop number which the event came in at. diff --git a/muse/muse/midiseq.cpp b/muse/muse/midiseq.cpp index e10427e5..c597573a 100644 --- a/muse/muse/midiseq.cpp +++ b/muse/muse/midiseq.cpp @@ -22,7 +22,7 @@ #include "midictrl.h" #include "audio.h" #include "driver/alsamidi.h" -//#include "driver/jackmidi.h" +#include "driver/jackmidi.h" #include "sync.h" #include "synth.h" #include "song.h" @@ -676,7 +676,7 @@ void MidiSeq::processTimerTick() // printf("Midi Time Code Sync generation not impl.\n"); // } - // P3.3.25 + // p3.3.25 int tickpos = audio->tickPos(); bool extsync = extSyncFlag.value(); // @@ -684,16 +684,20 @@ void MidiSeq::processTimerTick() // for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) { MidiDevice* md = *id; - int port = md->midiPort(); - MidiPort* mp = port != -1 ? &midiPorts[port] : 0; + // Is it a Jack midi device? p3.3.36 + MidiJackDevice* mjd = dynamic_cast(md); + if(mjd) + continue; if (md->isSynti()) // syntis are handled by audio thread continue; + int port = md->midiPort(); + MidiPort* mp = port != -1 ? &midiPorts[port] : 0; MPEventList* el = md->playEvents(); if (el->empty()) continue; iMPEvent i = md->nextPlayEvent(); for (; i != el->end(); ++i) { - // P3.3.25 + // p3.3.25 // If syncing to external midi sync, we cannot use the tempo map. // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. //if (i->time() > curFrame) { -- cgit v1.2.3