summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog4
-rw-r--r--muse/muse/driver/jackmidi.cpp205
-rw-r--r--muse/muse/driver/jackmidi.h13
-rw-r--r--muse/muse/midi.cpp80
-rw-r--r--muse/muse/midi.h34
-rw-r--r--muse/muse/mididev.cpp66
-rw-r--r--muse/muse/mididev.h28
-rw-r--r--muse/muse/mpevent.h2
8 files changed, 368 insertions, 64 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index a44ae038..d77a3d83 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,7 @@
+14.02.2010
+ * Added: Jack midi input should be working now. Controllers, too. (T356)
+ - Tested with large 1024 frame buffer. Events are recorded with good sub-tick (frame) resolution,
+ as viewed in pianoroll with 64T snap grid.
13.02.2010
* Fixed: Jack midi output should now be frame-accurate, support variable length events (like sysex),
and most controllers should work. (T356)
diff --git a/muse/muse/driver/jackmidi.cpp b/muse/muse/driver/jackmidi.cpp
index cc400fd9..c603d1be 100644
--- a/muse/muse/driver/jackmidi.cpp
+++ b/muse/muse/driver/jackmidi.cpp
@@ -9,9 +9,10 @@
#include <stdio.h>
#include <jack/jack.h>
-#include <jack/midiport.h>
+//#include <jack/midiport.h>
#include "jackmidi.h"
+#include "song.h"
#include "globals.h"
#include "midi.h"
#include "mididev.h"
@@ -22,12 +23,14 @@
#include "mpevent.h"
//#include "sync.h"
#include "audiodev.h"
+#include "../mplugins/midiitransform.h"
+#include "../mplugins/mitplugin.h"
// Turn on debug messages.
//#define JACK_MIDI_DEBUG
-int jackmidi_pi[2];
-int jackmidi_po[2];
+///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];
@@ -340,6 +343,202 @@ bool MidiJackDevice::putEvent(int* event)
*/
//---------------------------------------------------------
+// recordEvent
+//---------------------------------------------------------
+
+void MidiJackDevice::recordEvent(MidiRecordEvent& event)
+ {
+ // By T356. Set the loop number which the event came in at.
+ //if(audio->isRecording())
+ if(audio->isPlaying())
+ event.setLoopNum(audio->loopCount());
+
+ if (midiInputTrace) {
+ printf("Jack MidiInput: ");
+ event.dump();
+ }
+
+ if(_port != -1)
+ {
+ int idin = midiPorts[_port].syncInfo().idIn();
+
+// p3.3.26 1/23/10 Section was disabled, enabled by Tim.
+//#if 0
+ int typ = event.type();
+
+ //---------------------------------------------------
+ // filter some SYSEX events
+ //---------------------------------------------------
+
+ if (typ == ME_SYSEX) {
+ const unsigned char* p = event.data();
+ int n = event.len();
+ if (n >= 4) {
+ if ((p[0] == 0x7f)
+ //&& ((p[1] == 0x7f) || (p[1] == rxDeviceId))) {
+ && ((p[1] == 0x7f) || (idin == 0x7f) || (p[1] == idin))) {
+ if (p[2] == 0x06) {
+ //mmcInput(p, n);
+ midiSeq->mmcInput(_port, p, n);
+ return;
+ }
+ if (p[2] == 0x01) {
+ //mtcInputFull(p, n);
+ midiSeq->mtcInputFull(_port, p, n);
+ return;
+ }
+ }
+ else if (p[0] == 0x7e) {
+ //nonRealtimeSystemSysex(p, n);
+ midiSeq->nonRealtimeSystemSysex(_port, p, n);
+ return;
+ }
+ }
+ }
+ else
+ // p3.3.26 1/23/10 Moved here from alsaProcessMidiInput(). Anticipating Jack midi support, so don't make it ALSA specific. Tim.
+ // Trigger general activity indicator detector. Sysex has no channel, don't trigger.
+ midiPorts[_port].syncInfo().trigActDetect(event.channel());
+
+//#endif
+
+ }
+
+ //
+ // process midi event input filtering and
+ // transformation
+ //
+
+ processMidiInputTransformPlugins(event);
+
+ if (filterEvent(event, midiRecordType, false))
+ return;
+
+ if (!applyMidiInputTransformation(event)) {
+ if (midiInputTrace)
+ printf(" midi input transformation: event filtered\n");
+ return;
+ }
+
+ //
+ // transfer noteOn events to gui for step recording and keyboard
+ // remote control
+ //
+ if (event.type() == ME_NOTEON) {
+ int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
+ song->putEvent(pv);
+ }
+
+ if(_recordFifo.put(MidiPlayEvent(event)))
+ printf("MidiJackDevice::recordEvent: fifo overflow\n");
+ }
+
+//---------------------------------------------------------
+// midiReceived
+//---------------------------------------------------------
+
+void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
+ {
+ MidiRecordEvent event;
+ event.setB(0);
+
+ //
+ // move all events 2*segmentSize into the future to get
+ // jitterfree playback
+ //
+ // cycle n-1 n n+1
+ // -+----------+----------+----------+-
+ // ^ ^ ^
+ // catch process play
+ //
+// const SeqTime* st = audio->seqTime();
+
+ //unsigned curFrame = st->startFrame() + segmentSize;
+// unsigned curFrame = st->lastFrameTime;
+ //int frameOffset = audio->getFrameOffset();
+ unsigned pos = audio->pos().frame();
+ event.setTime(pos + ev->time);
+
+ event.setChannel(*(ev->buffer) & 0xf);
+ int type = *(ev->buffer) & 0xf0;
+ int a = *(ev->buffer + 1) & 0x7f;
+ int b = *(ev->buffer + 2) & 0x7f;
+ event.setType(type);
+ switch(type) {
+ case ME_NOTEON:
+ case ME_NOTEOFF:
+ case ME_CONTROLLER:
+ event.setA(*(ev->buffer + 1));
+ event.setB(*(ev->buffer + 2));
+ break;
+ case ME_PROGRAM:
+ case ME_AFTERTOUCH:
+ event.setA(*(ev->buffer + 1));
+ break;
+
+ case ME_PITCHBEND:
+ event.setA(((b << 7) + a) - 8192);
+ break;
+
+ case ME_SYSEX:
+ {
+ int type = *(ev->buffer) & 0xff;
+ switch(type) {
+ case ME_SYSEX:
+ event.setTime(0); // mark as used
+ event.setType(ME_SYSEX);
+ event.setData((unsigned char*)(ev->buffer + 1),
+ ev->size - 2);
+ break;
+ case ME_CLOCK:
+ case ME_SENSE:
+ break;
+ default:
+ printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type);
+ return;
+ }
+ }
+ return;
+ }
+
+ if (midiInputTrace) {
+ printf("MidiInput<%s>: ", name().latin1());
+ event.dump();
+ }
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::eventReceived time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
+ #endif
+
+ // Let recordEvent handle it from here, with timestamps, filtering, gui triggering etc.
+ recordEvent(event);
+ }
+
+//---------------------------------------------------------
+// collectMidiEvents
+//---------------------------------------------------------
+
+//void MidiJackDevice::collectMidiEvents(MidiInPort* track, Port port)
+void MidiJackDevice::collectMidiEvents(int port)
+ {
+ //void* port_buf = jack_port_get_buffer(port.jackPort(), segmentSize);
+ void* port_buf = jack_port_get_buffer(midi_port_in[port], segmentSize);
+ jack_midi_event_t event;
+ jack_nframes_t eventCount = jack_midi_get_event_count(port_buf);
+ for (jack_nframes_t i = 0; i < eventCount; ++i) {
+ jack_midi_event_get(&event, port_buf, i);
+
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::collectMidiEvents number:%d time:%d\n", i, event.time);
+ #endif
+
+ //track->eventReceived(&event);
+ eventReceived(&event);
+ }
+ }
+
+
+//---------------------------------------------------------
// queueEvent
// return true if event cannot be delivered
//---------------------------------------------------------
diff --git a/muse/muse/driver/jackmidi.h b/muse/muse/driver/jackmidi.h
index 2758ae89..1c65a423 100644
--- a/muse/muse/driver/jackmidi.h
+++ b/muse/muse/driver/jackmidi.h
@@ -8,10 +8,16 @@
#ifndef __JACKMIDI_H__
#define __JACKMIDI_H__
-#include <config.h>
+//#include <config.h>
+
+#include <jack/midiport.h>
#include "mididev.h"
+
+class QString;
class MidiFifo;
+class MidiRecordEvent;
+class MidiPlayEvent;
// Turn on to show multiple devices, work in progress,
// not working fully yet, can't seem to connect...
@@ -59,6 +65,8 @@ class MidiJackDevice : public MidiDevice {
virtual bool putMidiEvent(const MidiPlayEvent&);
//bool sendEvent(const MidiPlayEvent&);
+
+ void eventReceived(jack_midi_event_t*);
public:
MidiJackDevice() {}
@@ -69,7 +77,10 @@ class MidiJackDevice : public MidiDevice {
//virtual int selectWfd();
//virtual void processInput();
+ virtual void recordEvent(MidiRecordEvent&);
+
virtual bool putEvent(const MidiPlayEvent&);
+ virtual void collectMidiEvents(int port);
};
extern bool initMidiJack();
diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp
index dc14a3bf..61504a97 100644
--- a/muse/muse/midi.cpp
+++ b/muse/muse/midi.cpp
@@ -945,13 +945,25 @@ void Audio::processMidi()
playEvents->erase(playEvents->begin(), nextPlayEvent);
// klumsy hack for synti devices:
- if (!md->isSynti())
- continue;
- SynthI* s = (SynthI*)md;
- while (s->eventsPending()) {
- MidiRecordEvent ev = s->receiveEvent();
- md->recordEvent(ev);
- }
+ if(md->isSynti())
+ {
+ SynthI* s = (SynthI*)md;
+ while (s->eventsPending())
+ {
+ MidiRecordEvent ev = s->receiveEvent();
+ md->recordEvent(ev);
+ }
+ }
+
+ // Is it a Jack midi device?
+ MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
+ if(mjd)
+ // TODO: Just use MusE port 0 for now. Support for multiple MusE ports maybe will come later.
+ mjd->collectMidiEvents(0);
+
+ // Take snapshots of the current sizes of the recording fifos,
+ // because they may change while here in process, asynchronously.
+ md->beforeProcess();
}
MPEventList* playEvents = metronome->playEvents();
@@ -1008,17 +1020,25 @@ void Audio::processMidi()
if (devport == -1 || !(portMask & (1 << devport)))
continue;
- MREventList* el = dev->recordEvents();
- for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
+ //MREventList* el = dev->recordEvents();
+ MidiFifo& rf = dev->recordEvents();
+ // Get the frozen snapshot of the size.
+ int count = dev->tmpRecordCount();
+
+ //for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
+ for(int i = 0; i < count; ++i)
{
- int channel = ie->channel();
+ MidiPlayEvent event(rf.peek(i));
+
+ //int channel = ie->channel();
+ int channel = event.channel();
int defaultPort = devport;
if (!(channelMask & (1 << channel)))
{
continue;
}
- MidiPlayEvent event(*ie);
+ //MidiPlayEvent event(*ie);
int drumRecPitch=0; //prevent compiler warning: variable used without initialization
MidiController *mc = 0;
int ctl = 0;
@@ -1121,23 +1141,18 @@ void Audio::processMidi()
if (!dev->isSynti())
{
- // Added by Tim. p3.3.8
- if(track->recEcho())
- {
-
- //Check if we're outputting to another port than default:
- if (devport == defaultPort) {
- event.setPort(port);
- if(md)
- playEvents->add(event);
- }
- else {
- // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
- MidiDevice* mdAlt = midiPorts[devport].device();
- if(mdAlt)
- mdAlt->playEvents()->add(event);
- }
- }
+ //Check if we're outputting to another port than default:
+ if (devport == defaultPort) {
+ event.setPort(port);
+ if(md && track->recEcho())
+ playEvents->add(event);
+ }
+ else {
+ // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
+ MidiDevice* mdAlt = midiPorts[devport].device();
+ if(mdAlt && track->recEcho())
+ mdAlt->playEvents()->add(event);
+ }
// Shall we activate meters even while rec echo is off? Sure, why not...
if(event.isNote() && event.dataB() > track->activity())
track->setActivity(event.dataB());
@@ -1220,11 +1235,12 @@ void Audio::processMidi()
//
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
MidiDevice* md = *id;
- md->recordEvents()->clear();
-
- // By T356. Done processing this rec buffer, now flip to the other one.
- md->flipRecBuffer();
+ ///md->recordEvents()->clear();
+ // By T356. Done processing this rec buffer, now flip to the other one.
+ ///md->flipRecBuffer();
+ // We are done with the 'frozen' recording fifos, remove the events.
+ md->afterProcess();
MPEventList* stuckNotes = md->stuckNotes();
MPEventList* playEvents = md->playEvents();
diff --git a/muse/muse/midi.h b/muse/muse/midi.h
index ee4c6291..ee13fb36 100644
--- a/muse/muse/midi.h
+++ b/muse/muse/midi.h
@@ -15,20 +15,26 @@
#include <qstring.h>
enum {
- ME_NOTEOFF = 0x80,
- ME_NOTEON = 0x90,
- ME_POLYAFTER = 0xa0,
- ME_CONTROLLER = 0xb0,
- ME_PROGRAM = 0xc0,
- ME_AFTERTOUCH = 0xd0,
- ME_PITCHBEND = 0xe0,
- ME_SYSEX = 0xf0,
- ME_META = 0xff,
- ME_SONGPOS = 0xf2,
- ME_CLOCK = 0xf8,
- ME_START = 0xfa,
- ME_CONTINUE = 0xfb,
- ME_STOP = 0xfc,
+ ME_NOTEOFF = 0x80,
+ ME_NOTEON = 0x90,
+ ME_POLYAFTER = 0xa0,
+ ME_CONTROLLER = 0xb0,
+ ME_PROGRAM = 0xc0,
+ ME_AFTERTOUCH = 0xd0,
+ ME_PITCHBEND = 0xe0,
+ ME_SYSEX = 0xf0,
+ ME_META = 0xff,
+ ME_MTC_QUARTER = 0xf1,
+ ME_SONGPOS = 0xf2,
+ ME_SONGSEL = 0xf3,
+ ME_TUNE_REQ = 0xf6,
+ ME_SYSEX_END = 0xf7,
+ ME_CLOCK = 0xf8,
+ ME_TICK = 0xf9,
+ ME_START = 0xfa,
+ ME_CONTINUE = 0xfb,
+ ME_STOP = 0xfc,
+ ME_SENSE = 0xfe
};
#define ME_TIMESIG 0x58
diff --git a/muse/muse/mididev.cpp b/muse/muse/mididev.cpp
index 4d9f425c..01eb429e 100644
--- a/muse/muse/mididev.cpp
+++ b/muse/muse/mididev.cpp
@@ -82,14 +82,16 @@ void MidiDevice::init()
MidiDevice::MidiDevice()
{
- _recBufFlipped = false;
+ ///_recBufFlipped = false;
+ _tmpRecordCount = 0;
init();
}
MidiDevice::MidiDevice(const QString& n)
: _name(n)
{
- _recBufFlipped = false;
+ ///_recBufFlipped = false;
+ _tmpRecordCount = 0;
init();
}
@@ -98,7 +100,8 @@ MidiDevice::MidiDevice(const QString& n)
// return true if event filtered
//---------------------------------------------------------
-static bool filterEvent(const MEvent& event, int type, bool thru)
+//static bool filterEvent(const MEvent& event, int type, bool thru)
+bool filterEvent(const MEvent& event, int type, bool thru)
{
switch(event.type()) {
case ME_NOTEON:
@@ -143,6 +146,52 @@ static bool filterEvent(const MEvent& event, int type, bool thru)
}
//---------------------------------------------------------
+// afterProcess
+// clear all recorded events after a process cycle
+//---------------------------------------------------------
+
+void MidiDevice::afterProcess()
+ {
+ while (_tmpRecordCount--)
+ _recordFifo.remove();
+ }
+
+//---------------------------------------------------------
+// beforeProcess
+// "freeze" fifo for this process cycle
+//---------------------------------------------------------
+
+void MidiDevice::beforeProcess()
+ {
+ //if (!jackPort(0).isZero())
+ // audioDriver->collectMidiEvents(this, jackPort(0));
+ _tmpRecordCount = _recordFifo.getSize();
+ }
+
+/*
+//---------------------------------------------------------
+// getEvents
+//---------------------------------------------------------
+
+void MidiDevice::getEvents(unsigned , unsigned , int ch, MPEventList* dst) //from //to
+{
+ for (int i = 0; i < _tmpRecordCount; ++i) {
+ const MidiPlayEvent& ev = _recordFifo.peek(i);
+ if (ch == -1 || (ev.channel() == ch))
+ dst->insert(ev);
+ }
+
+ //while(!recordFifo.isEmpty())
+ //{
+ // MidiPlayEvent e(recordFifo.get());
+ // if (ch == -1 || (e.channel() == ch))
+ // dst->insert(e);
+ //}
+}
+*/
+
+/*
+//---------------------------------------------------------
// recordEvent
//---------------------------------------------------------
@@ -154,6 +203,7 @@ MREventList* MidiDevice::recordEvents()
else
return &_recordEvents2;
}
+*/
//---------------------------------------------------------
// recordEvent
@@ -251,10 +301,12 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)
song->putEvent(pv);
}
- if(_recBufFlipped)
- _recordEvents2.add(event); // add event to secondary list of recorded events
- else
- _recordEvents.add(event); // add event to primary list of recorded events
+ ///if(_recBufFlipped)
+ /// _recordEvents2.add(event); // add event to secondary list of recorded events
+ ///else
+ /// _recordEvents.add(event); // add event to primary list of recorded events
+ if(_recordFifo.put(MidiPlayEvent(event)))
+ printf("MidiDevice::recordEvent: fifo overflow\n");
}
//---------------------------------------------------------
diff --git a/muse/muse/mididev.h b/muse/muse/mididev.h
index 8117b4da..a0744923 100644
--- a/muse/muse/mididev.h
+++ b/muse/muse/mididev.h
@@ -23,9 +23,13 @@ class MidiDevice {
MPEventList _stuckNotes;
MPEventList _playEvents;
iMPEvent _nextPlayEvent;
- MREventList _recordEvents;
- MREventList _recordEvents2;
- bool _recBufFlipped;
+ ///MREventList _recordEvents;
+ ///MREventList _recordEvents2;
+
+ // Used for multiple reads of fifo during process.
+ int _tmpRecordCount;
+
+ ///bool _recBufFlipped;
// Holds sync settings and detection monitors.
//MidiSyncInfo _syncInfo;
@@ -36,6 +40,8 @@ class MidiDevice {
int _openFlags; // configured open flags
bool _readEnable; // set when opened/closed.
bool _writeEnable; //
+ // Recording fifo.
+ MidiFifo _recordFifo;
void init();
virtual bool putMidiEvent(const MidiPlayEvent&) = 0;
@@ -67,15 +73,22 @@ class MidiDevice {
virtual void processInput() {}
virtual void discardInput() {}
- void recordEvent(MidiRecordEvent&);
+ virtual void recordEvent(MidiRecordEvent&);
virtual bool putEvent(const MidiPlayEvent&);
MPEventList* stuckNotes() { return &_stuckNotes; }
MPEventList* playEvents() { return &_playEvents; }
- MREventList* recordEvents();
- void flipRecBuffer() { _recBufFlipped = _recBufFlipped ? false : true; }
- bool recBufFlipped() { return _recBufFlipped; }
+
+ ///MREventList* recordEvents();
+ ///void flipRecBuffer() { _recBufFlipped = _recBufFlipped ? false : true; }
+ ///bool recBufFlipped() { return _recBufFlipped; }
+ void beforeProcess();
+ void afterProcess();
+ int tmpRecordCount() { return _tmpRecordCount; }
+ MidiFifo& recordEvents() { return _recordFifo; }
+ //virtual void getEvents(unsigned /*from*/, unsigned /*to*/, int /*channel*/, MPEventList* /*dst*/);
+
iMPEvent nextPlayEvent() { return _nextPlayEvent; }
void setNextPlayEvent(iMPEvent i) { _nextPlayEvent = i; }
bool sendNullRPNParams(int, bool);
@@ -97,6 +110,7 @@ class MidiDeviceList : public std::list<MidiDevice*> {
extern MidiDeviceList midiDevices;
extern void initMidiDevices();
+extern bool filterEvent(const MEvent& event, int type, bool thru);
#endif
diff --git a/muse/muse/mpevent.h b/muse/muse/mpevent.h
index 8ec11ddf..6df7b0c0 100644
--- a/muse/muse/mpevent.h
+++ b/muse/muse/mpevent.h
@@ -138,6 +138,7 @@ struct MPEventList : public MPEL {
typedef MPEventList::iterator iMPEvent;
typedef MPEventList::const_iterator ciMPEvent;
+/*
//---------------------------------------------------------
// MREventList
// memory allocation in midi thread domain
@@ -155,6 +156,7 @@ struct MREventList : public MREL {
typedef MREventList::iterator iMREvent;
typedef MREventList::const_iterator ciMREvent;
+*/
//---------------------------------------------------------
// MidiFifo