summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog3
-rw-r--r--muse/muse/driver/audiodev.h5
-rw-r--r--muse/muse/driver/dummyaudio.cpp9
-rw-r--r--muse/muse/driver/jack.cpp156
-rw-r--r--muse/muse/driver/jackaudio.h10
-rw-r--r--muse/muse/driver/jackmidi.cpp126
6 files changed, 296 insertions, 13 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index 2a796b0d..5cf866d1 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,6 @@
+01.02.2010
+ * Fixed: Jack midi output: Stuck or missing notes. (T356)
+ - Must only be one jack_midi_event_reserve() per event in handle_jack_midi_out_events().
31.01.2010
* Changed: Midi sync window: Clock is now seperated from other real time commands (play/stop etc). (T356)
31.01.2010
diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h
index d3dfda10..437b1eee 100644
--- a/muse/muse/driver/audiodev.h
+++ b/muse/muse/driver/audiodev.h
@@ -12,6 +12,8 @@
#include <qstring.h>
#include <list>
+class MidiPlayEvent;
+
//---------------------------------------------------------
// AudioDevice
//---------------------------------------------------------
@@ -27,6 +29,7 @@ class AudioDevice {
virtual void stop () = 0;
virtual int framePos() const = 0;
+ virtual unsigned frameTime() const = 0;
virtual float* getBuffer(void* port, unsigned long nframes) = 0;
@@ -54,6 +57,8 @@ 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 5007485c..89fbc064 100644
--- a/muse/muse/driver/dummyaudio.cpp
+++ b/muse/muse/driver/dummyaudio.cpp
@@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
#include <errno.h>
#include <stdarg.h>
#include <pthread.h>
@@ -20,6 +21,9 @@
#include "driver/alsatimer.h"
#include "pos.h"
#include "gconfig.h"
+#include "utils.h"
+
+class MidiPlayEvent;
#define DEBUG_DUMMY 0
//---------------------------------------------------------
@@ -113,6 +117,9 @@ class DummyAudioDevice : public AudioDevice {
printf("DummyAudioDevice::getCurFrame %d\n", _framePos);
return _framePos; }
+ virtual unsigned frameTime() const {
+ return lrint(curTime() * sampleRate);
+ }
virtual bool isRealtime() { return realtimeFlag; }
//virtual int realtimePriority() const { return 40; }
virtual int realtimePriority() const { return _realTimePriority; }
@@ -160,6 +167,8 @@ class DummyAudioDevice : public AudioDevice {
}
virtual void setFreewheel(bool) {}
void setRealTime() { realtimeFlag = true; }
+
+ virtual bool putEvent(int port, const MidiPlayEvent&) { };
};
DummyAudioDevice* dummyAudio = 0;
diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp
index 4674f460..41092cea 100644
--- a/muse/muse/driver/jack.cpp
+++ b/muse/muse/driver/jack.cpp
@@ -12,6 +12,7 @@
//#include <time.h>
#include <unistd.h>
#include <jack/midiport.h>
+#include <string.h>
#include "audio.h"
#include "globals.h"
@@ -23,6 +24,9 @@
#include "sync.h"
#include "utils.h"
+#include "midi.h"
+#include "mpevent.h"
+
#include "jackmidi.h"
@@ -48,6 +52,10 @@ 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];
+// p3.3.32
+//jack_port_t *jackMidiInPort = 0;
+//jack_port_t *jackMidiOutPort = 0;
+
JackAudioDevice* jackAudio;
//---------------------------------------------------------
@@ -181,7 +189,8 @@ void handle_jack_midi_out_events(jack_nframes_t frames)
void *port_buf;
int i,j,n,x;
- for(i = 0; i < JACK_MIDI_CHANNELS; i++){
+ //for(i = 0; i < JACK_MIDI_CHANNELS; i++){
+ for(i = 0; i < JACK_MIDI_CHANNELS; ++i){
/* 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);
@@ -207,26 +216,54 @@ void handle_jack_midi_out_events(jack_nframes_t frames)
/* 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' */
+ // 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;
+ }
+ }
+ */
+
+ x = jack_midi_out_data[i].take;
+ for(j = 0; j < n; ++j)
+ {
+ data = jack_midi_event_reserve(port_buf, 0, 3);
+ if(data == 0)
+ {
+ fprintf(stderr, "handle_jack_midi_out_events: buffer overflow, event lost\n");
+ // Can do no more processing. Just return.
+ return;
+ }
+ data[0] = jack_midi_out_data[i].buffer[x*4+0];
+ data[1] = jack_midi_out_data[i].buffer[x*4+1];
+ data[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;
}
}
+
}
}
}
-static int processAudio(jack_nframes_t frames, void*)
+//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);
// if (JACK_DEBUG)
@@ -397,6 +434,7 @@ static void noJackError(const char* /* s */)
JackAudioDevice::JackAudioDevice(jack_client_t* cl, char * name)
: AudioDevice()
{
+ _frameCounter = 0;
//JackAudioDevice::jackStarted=false;
strcpy(jackRegisteredName, name);
_client = cl;
@@ -527,6 +565,28 @@ bool initJackAudio()
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);
+ }
+ */
+
+
if (client) {
audioDevice = jackAudio;
return false;
@@ -1406,3 +1466,91 @@ int JackAudioDevice::setMaster(bool f)
}
return r;
}
+
+
+//---------------------------------------------------------
+// putEvent
+// return true if successful
+//---------------------------------------------------------
+
+//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;
+ }
+
+
diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h
index 7a73eaf5..76753eec 100644
--- a/muse/muse/driver/jackaudio.h
+++ b/muse/muse/driver/jackaudio.h
@@ -11,6 +11,8 @@
#include <jack/jack.h>
#include "audiodev.h"
+class MidiPlayEvent;
+
//---------------------------------------------------------
// JackAudioDevice
//---------------------------------------------------------
@@ -26,6 +28,10 @@ class JackAudioDevice : public AudioDevice {
char jackRegisteredName[8];
int dummyState;
int dummyPos;
+ // Free-running frame counter incremented always in process.
+ jack_nframes_t _frameCounter;
+
+ static int processAudio(jack_nframes_t frames, void*);
public:
JackAudioDevice(jack_client_t* cl, char * jack_id_string);
@@ -38,6 +44,7 @@ class JackAudioDevice : public AudioDevice {
virtual bool dummySync(int state); // Artificial sync when not using Jack transport.
virtual int framePos() const;
+ virtual unsigned frameTime() const { return _frameCounter; }
virtual float* getBuffer(void* port, unsigned long nframes) {
return (float*)jack_port_get_buffer((jack_port_t*)port, nframes);
@@ -72,6 +79,9 @@ 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 fd9c87ce..b4e88683 100644
--- a/muse/muse/driver/jackmidi.cpp
+++ b/muse/muse/driver/jackmidi.cpp
@@ -95,17 +95,17 @@ bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event)
if(channel >= JACK_MIDI_CHANNELS) return false;
- /* buffer up events, because jack eats them in chunks, if
- * the buffer is full, there isn't so much to do, than
- * drop the event
- */
+ // buffer up events, because jack eats them in chunks, if
+ // the buffer is full, there isn't so much to do, than
+ // drop the event
+
give = jack_midi_out_data[channel].give;
if(jack_midi_out_data[channel].buffer[give*4+3]){
fprintf(stderr, "WARNING: muse-to-jack midi-buffer is full, channel=%u\n", channel);
return false;
}
- /* copy event(note-on etc..), pitch and volume */
- /* see http://www.midi.org/techspecs/midimessages.php */
+ // copy event(note-on etc..), pitch and volume
+ // see http://www.midi.org/techspecs/midimessages.php
switch(event.type()){
case ME_NOTEOFF:
jack_midi_out_data[channel].buffer[give*4+0] = 0x80;
@@ -129,7 +129,7 @@ bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event)
break;
case ME_PITCHBEND:
jack_midi_out_data[channel].buffer[give*4+0] = 0xE0;
- /* convert muse pitch-bend to midi standard */
+ // convert muse pitch-bend to midi standard
x = 0x2000 + event.dataA();
jack_midi_out_data[channel].buffer[give*4+1] = x & 0x7f;
jack_midi_out_data[channel].buffer[give*4+2] = (x >> 8) & 0x7f;
@@ -138,14 +138,122 @@ bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& event)
fprintf(stderr, "jack-midi-out %u WARNING: unknown event %x\n", channel, event.type());
return false;
}
- jack_midi_out_data[channel].buffer[give*4+3] = 1; /* mark state of this slot */
- /* finally increase give position */
+ jack_midi_out_data[channel].buffer[give*4+3] = 1; // mark state of this slot
+ // finally increase give position
give++;
if(give >= JACK_MIDI_BUFFER_SIZE){
give = 0;
}
jack_midi_out_data[channel].give = give;
return false;
+
+ /*
+ //
+ // 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;
+ if(event.type() == ME_CONTROLLER)
+ {
+ int a = event.dataA();
+ int b = event.dataB();
+ int chn = event.channel();
+ unsigned t = event.time();
+
+ if(a == CTRL_PITCH)
+ {
+ int v = b + 8192;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, 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)
+ audioDriver->putEvent(museport, MidiPlayEvent(t, chn, ME_CONTROLLER, CTRL_HBANK, hb));
+ if (lb != 0xff)
+ audioDriver->putEvent(museport, MidiPlayEvent(t+1, chn, ME_CONTROLLER, CTRL_LBANK, lb));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+2, 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;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, ME_SYSEX, sysex, 6));
+ }
+ else if (a < CTRL_14_OFFSET)
+ { // 7 Bit Controller
+ audioDriver->putEvent(museport, 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;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, chn, ME_CONTROLLER, ctrlH, dataH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+1, chn, ME_CONTROLLER, ctrlL, dataL));
+ }
+ else if (a < CTRL_NRPN_OFFSET)
+ { // RPN 7-Bit Controller
+ int ctrlH = (a >> 8) & 0x7f;
+ int ctrlL = a & 0x7f;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+1, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+2, 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;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+1, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+2, 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;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+1, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+2, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+3, 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;
+ audioDriver->putEvent(museport, MidiPlayEvent(t, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+1, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+2, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
+ audioDriver->putEvent(museport, MidiPlayEvent(t+3, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+ }
+ else
+ {
+ printf("MidiJackDevice::putMidiEvent: unknown controller type 0x%x\n", a);
+ }
+ }
+ else
+ {
+ audioDriver->putEvent(museport, event);
+ }
+
+ // Just return OK for now.
+ return false;
+ */
+
}
//---------------------------------------------------------