summaryrefslogtreecommitdiff
path: root/muse2/muse/driver
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2012-03-15 18:21:23 +0000
committerFlorian Jung <flo@windfisch.org>2012-03-15 18:21:23 +0000
commit27b7bf6815cda7abb67026c37b3e44daee1803cb (patch)
tree0b9d1c0bc84ac7ff8032e707f2b5fb4e0aaabb5c /muse2/muse/driver
parent2d6f113a10eb485694e20a78500f650776d701e3 (diff)
merged with trunk
Diffstat (limited to 'muse2/muse/driver')
-rw-r--r--muse2/muse/driver/alsamidi.cpp373
-rw-r--r--muse2/muse/driver/alsamidi.h14
-rw-r--r--muse2/muse/driver/alsatimer.cpp2
-rw-r--r--muse2/muse/driver/jack.cpp720
-rw-r--r--muse2/muse/driver/jackaudio.h12
-rw-r--r--muse2/muse/driver/jackmidi.cpp444
-rw-r--r--muse2/muse/driver/jackmidi.h4
-rw-r--r--muse2/muse/driver/rtctimer.cpp4
-rw-r--r--muse2/muse/driver/rtctimer.h22
9 files changed, 729 insertions, 866 deletions
diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp
index 740de1fb..08f5345f 100644
--- a/muse2/muse/driver/alsamidi.cpp
+++ b/muse2/muse/driver/alsamidi.cpp
@@ -38,6 +38,7 @@
#include "xml.h"
#include "part.h"
#include "gconfig.h"
+#include "track.h"
#include <QApplication>
@@ -58,8 +59,6 @@ MidiAlsaDevice::MidiAlsaDevice(const snd_seq_addr_t& a, const QString& n)
: MidiDevice(n)
{
adr = a;
- stopPending = false;
- seekPending = false;
init();
}
@@ -285,7 +284,7 @@ void MidiAlsaDevice::writeRouting(int level, Xml& xml) const
bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
{
if (MusEGlobal::midiOutputTrace) {
- printf("MidiOut: midiAlsa: ");
+ printf("MidiOut: Alsa: <%s>: ", name().toLatin1().constData());
e.dump();
}
int chn = e.channel();
@@ -309,6 +308,19 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
snd_seq_ev_set_pgmchange(&event, chn, a);
break;
case ME_CONTROLLER:
+ {
+ if(a == CTRL_PROGRAM)
+ {
+ snd_seq_ev_set_pgmchange(&event, chn, b);
+ break;
+ }
+ else if(a == CTRL_PITCH)
+ {
+ snd_seq_ev_set_pitchbend(&event, chn, b);
+ break;
+ }
+ }
+
#if 1
snd_seq_ev_set_controller(&event, chn, a, b);
#else
@@ -453,77 +465,160 @@ bool MidiAlsaDevice::putEvent(snd_seq_event_t* event)
// Called from ALSA midi sequencer thread only.
//---------------------------------------------------------
-#if 0
-void MidiAlsaDevice::processMidi()
-{
- processStuckNotes();
- if (_playEvents.empty())
- return;
- int port = midiPort();
- MidiPort* mp = port != -1 ? &MusEGlobal::midiPorts[port] : 0;
- unsigned curFrame = MusEGlobal::audio->curFrame();
- int tickpos = MusEGlobal::audio->tickPos();
- bool extsync = MusEGlobal::extSyncFlag.value();
- //int frameOffset = getFrameOffset();
- //int nextTick = MusEGlobal::audio->nextTick();
-
- // Play all events up to current frame.
- iMPEvent i = _playEvents.begin();
- for (; i != _playEvents.end(); ++i) {
- if (i->time() > (extsync ? tickpos : curFrame)) // p3.3.25 Check: Should be nextTickPos? p4.0.34
- break;
- if(mp){
- if (mp->sendEvent(*i))
- break;
- }
- else
- if(putMidiEvent(*i))
- break;
- }
- _playEvents.erase(_playEvents.begin(), i);
-}
-
-#else
void MidiAlsaDevice::processMidi()
{
- bool stop = stopPending; // Snapshots
- bool seek = seekPending; //
- seekPending = stopPending = false;
+ //bool stop = stopPending; // Snapshots
+ //bool seek = seekPending; //
+ //seekPending = stopPending = false;
// Transfer the stuck notes FIFO to the play events list.
// FIXME It would be faster to have MidiAlsaDevice automatically add the stuck note so that only
// one FIFO would be needed. But that requires passing an extra 'tick' and 'off velocity' in
// addScheduledEvent, which felt too weird.
- while(!stuckNotesFifo.isEmpty())
- _stuckNotes.add(stuckNotesFifo.get());
+ //while(!stuckNotesFifo.isEmpty())
+ // _stuckNotes.add(stuckNotesFifo.get());
- bool extsync = MusEGlobal::extSyncFlag.value();
//int frameOffset = getFrameOffset();
//int nextTick = MusEGlobal::audio->nextTick();
- // We're in the ALSA midi thread. MusEGlobal::audio->isPlaying() might not be true during seek right now.
- //if(stop || (seek && MusEGlobal::audio->isPlaying()))
- if(stop || seek)
+ //bool is_playing = MusEGlobal::audio->isPlaying();
+ // We're in the ALSA midi thread. audio->isPlaying() might not be true during seek right now. Include START_PLAY state...
+ //bool is_playing = MusEGlobal::audio->isPlaying() || MusEGlobal::audio->isStarting(); // TODO Check this. It includes LOOP1 and LOOP2 besides PLAY.
+ int pos = MusEGlobal::audio->tickPos();
+ int port = midiPort();
+ MidiPort* mp = port == -1 ? 0 : &MusEGlobal::midiPorts[port];
+ bool ext_sync = MusEGlobal::extSyncFlag.value();
+
+ /*
+ if(mp)
{
- //---------------------------------------------------
- // Clear all notes and handle stuck notes
- //---------------------------------------------------
- playEventFifo.clear();
+ MidiSyncInfo& si = mp->syncInfo();
+ if(stop)
+ {
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!ext_sync)
+ {
+ // Shall we check open flags?
+ //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+ //if(!(dev->openFlags() & 1))
+ // return;
+
+ // Send MMC stop...
+ if(si.MMCOut())
+ {
+ unsigned char msg[mmcStopMsgLen];
+ memcpy(msg, mmcStopMsg, mmcStopMsgLen);
+ msg[1] = si.idOut();
+ putMidiEvent(MidiPlayEvent(0, 0, ME_SYSEX, msg, mmcStopMsgLen));
+ }
+
+ // Send midi stop...
+ if(si.MRTOut())
+ {
+ putMidiEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0));
+ // Added check of option send continue not start. p3.3.31
+ // Hmm, is this required? Seems to make other devices unhappy.
+ // (Could try now that this is in MidiDevice. p4.0.22 )
+ //if(!si.sendContNotStart())
+ // mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division);
+ }
+ }
+ }
+
+ if(seek)
+ {
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!ext_sync)
+ {
+ // Send midi stop and song position pointer...
+ if(si.MRTOut())
+ {
+ // Shall we check for device write open flag to see if it's ok to send?...
+ //if(!(rwFlags() & 0x1) || !(openFlags() & 1))
+ //if(!(openFlags() & 1))
+ // continue;
+ putMidiEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0));
+ // Hm, try sending these after stuck notes below...
+ //putMidiEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0));
+ //if(is_playing)
+ // putMidiEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0));
+ }
+ }
+ }
+ }
+ */
+
+ /*
+ if(stop || (seek && is_playing))
+ {
+ // Clear all notes and handle stuck notes...
+ //playEventFifo.clear();
_playEvents.clear();
- //printf("transferring stuck notes\n");
for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)
{
- //printf(" stuck note\n");
MidiPlayEvent ev = *i;
ev.setTime(0);
- _playEvents.add(ev);
+ //_playEvents.add(ev);
+ putMidiEvent(ev); // Play immediately.
}
_stuckNotes.clear();
}
- else
+ */
+
+ /*
+ if(mp)
+ {
+ MidiSyncInfo& si = mp->syncInfo();
+ // Try sending these now after stuck notes above...
+ if(stop || seek)
+ {
+ // Reset sustain.
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+ putMidiEvent(MidiPlayEvent(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0));
+ }
+ if(seek)
+ {
+ // Send new song position.
+ if(!ext_sync && si.MRTOut())
+ {
+ int beat = (pos * 4) / MusEGlobal::config.division;
+ putMidiEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0));
+ }
+ // Send new controller values.
+ MidiCtrlValListList* cll = mp->controller();
+ for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
+ {
+ MidiCtrlValList* vl = ivl->second;
+ iMidiCtrlVal imcv = vl->iValue(pos);
+ if(imcv != vl->end()) {
+ Part* p = imcv->second.part;
+ // Don't send if part or track is muted or off.
+ if(!p || p->mute())
+ continue;
+ Track* track = p->track();
+ if(track && (track->isMute() || track->off()))
+ continue;
+ unsigned t = (unsigned)imcv->first;
+ // Do not add values that are outside of the part.
+ if(t >= p->tick() && t < (p->tick() + p->lenTick()))
+ // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position.
+ mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos);
+ }
+ }
+
+ // Send continue.
+ // REMOVE Tim. This is redundant and too early - Audio::startRolling already properly sends it when sync ready.
+ //if(is_playing && !ext_sync && si.MRTOut())
+ // putMidiEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0));
+ }
+ }
+ */
+
+ //if(!(stop || (seek && is_playing)))
{
// Transfer the play events FIFO to the play events list.
- while(!playEventFifo.isEmpty())
- _playEvents.add(playEventFifo.get());
+ //while(!playEventFifo.isEmpty())
+ // _playEvents.add(playEventFifo.get());
/* TODO Handle these more directly than putting them into play events list.
//if(MusEGlobal::audio->isPlaying())
@@ -545,53 +640,18 @@ void MidiAlsaDevice::processMidi()
processStuckNotes();
}
- /* Instead, done immediately in handleStop and handleSeek using putEvent.
- if(stop)
- {
- // reset sustain...
- MidiPort* mp = &MusEGlobal::midiPorts[_port];
- for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
- {
- if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
- {
- //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch);
- MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
- _playEvents.add(ev);
- }
- }
- }
- if(seek)
- {
- // Send new contoller values...
- for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
- {
- MidiCtrlValList* vl = ivl->second;
- iMidiCtrlVal imcv = vl->iValue(pos);
- if(imcv != vl->end()) {
- Part* p = imcv->second.part;
- unsigned t = (unsigned)imcv->first;
- // Do not add values that are outside of the part.
- if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) )
- _playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
- }
- }
- } */
-
- if (_playEvents.empty())
- return;
+ if(_playEvents.empty())
+ return;
- int port = midiPort();
- MidiPort* mp = port != -1 ? &MusEGlobal::midiPorts[port] : 0;
unsigned curFrame = MusEGlobal::audio->curFrame();
- int tickpos = MusEGlobal::audio->tickPos();
// Play all events up to current frame.
iMPEvent i = _playEvents.begin();
for (; i != _playEvents.end(); ++i) {
- if (i->time() > (extsync ? tickpos : curFrame)) // p3.3.25 Check: Should be nextTickPos? p4.0.34
+ if (i->time() > (ext_sync ? pos : curFrame)) // p3.3.25 Check: Should be nextTickPos? p4.0.34
break;
if(mp){
- if (mp->sendEvent(*i))
+ if (mp->sendEvent(*i, true)) // Force the event to be sent.
break;
}
else
@@ -601,6 +661,7 @@ void MidiAlsaDevice::processMidi()
_playEvents.erase(_playEvents.begin(), i);
}
+/*
//---------------------------------------------------------
// handleStop
//---------------------------------------------------------
@@ -614,21 +675,6 @@ void MidiAlsaDevice::handleStop()
stopPending = true; // Trigger stop handling in processMidi.
//---------------------------------------------------
- // reset sustain
- //---------------------------------------------------
-
- MidiPort* mp = &MusEGlobal::midiPorts[_port];
- for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
- {
- if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
- {
- //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch);
- MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
- putMidiEvent(ev);
- }
- }
-
- //---------------------------------------------------
// send midi stop
//---------------------------------------------------
@@ -646,18 +692,61 @@ void MidiAlsaDevice::handleStop()
if(si.MRTOut())
{
- // Send STOP
mp->sendStop();
-
- // Added check of option send continue not start. p3.3.31
- // Hmm, is this required? Seems to make other devices unhappy.
- // (Could try now that this is in MidiDevice. p4.0.22 )
+ // Added check of option send continue not start. Hmm, is this required? Seems to make other devices unhappy.
+ // (Could try now that this is in MidiDevice.)
//if(!si.sendContNotStart())
// mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division);
}
}
+
+ //---------------------------------------------------
+ // reset sustain
+ //---------------------------------------------------
+
+ MidiPort* mp = &MusEGlobal::midiPorts[_port];
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+ {
+ MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
+ //putMidiEvent(ev);
+ putEvent(ev);
+ // Do sendEvent to get the optimizations - send only on a change of value.
+ //mp->sendEvent(ev);
+ }
+ }
+
+ //---------------------------------------------------
+ // send midi stop
+ //---------------------------------------------------
+
+// // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+// if(!MusEGlobal::extSyncFlag.value())
+// {
+// // Shall we check open flags?
+// //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+// //if(!(dev->openFlags() & 1))
+// // return;
+//
+// MidiSyncInfo& si = mp->syncInfo();
+// if(si.MMCOut())
+// mp->sendMMCStop();
+//
+// if(si.MRTOut())
+// {
+// // Send STOP
+// mp->sendStop();
+// // Added check of option send continue not start. Hmm, is this required? Seems to make other devices unhappy.
+// // (Could try now that this is in MidiDevice.)
+// //if(!si.sendContNotStart())
+// // mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division);
+// }
+// }
}
+*/
+/*
//---------------------------------------------------------
// handleSeek
//---------------------------------------------------------
@@ -675,7 +764,41 @@ void MidiAlsaDevice::handleSeek()
int pos = MusEGlobal::audio->tickPos();
//---------------------------------------------------
- // Send new contoller values
+ // Send STOP
+ //---------------------------------------------------
+
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!MusEGlobal::extSyncFlag.value())
+ {
+ if(mp->syncInfo().MRTOut())
+ {
+ // Shall we check for device write open flag to see if it's ok to send?...
+ //if(!(rwFlags() & 0x1) || !(openFlags() & 1))
+ //if(!(openFlags() & 1))
+ // continue;
+ mp->sendStop();
+ }
+ }
+
+ //---------------------------------------------------
+ // reset sustain
+ //---------------------------------------------------
+
+ MidiPort* mp = &MusEGlobal::midiPorts[_port];
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+ {
+ MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
+ putEvent(ev);
+ //putMidiEvent(ev);
+ // Do sendEvent to get the optimizations - send only on a change of value.
+ //mp->sendEvent(ev);
+ }
+ }
+
+ //---------------------------------------------------
+ // Send new controller values
//---------------------------------------------------
for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
@@ -685,12 +808,18 @@ void MidiAlsaDevice::handleSeek()
if(imcv != vl->end())
{
Part* p = imcv->second.part;
+ // Don't send if part or track is muted or off.
+ if(!p || p->mute())
+ continue;
+ Track* track = p->track();
+ if(track && (track->isMute() || track->off()))
+ continue;
unsigned t = (unsigned)imcv->first;
// Do not add values that are outside of the part.
if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) )
//_playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
- // Hmm, play event list for immediate playback? Try putEvent instead. p4.0.34
- putMidiEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+ // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position.
+ mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos);
}
}
@@ -698,31 +827,23 @@ void MidiAlsaDevice::handleSeek()
// Send STOP and "set song position pointer"
//---------------------------------------------------
- // Don't send if external sync is on. The master, and our sync routing system will take care of that. p3.3.31
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
if(!MusEGlobal::extSyncFlag.value())
{
if(mp->syncInfo().MRTOut())
{
// Shall we check for device write open flag to see if it's ok to send?...
- // This means obey what the user has chosen for read/write in the midi port config dialog,
- // which already takes into account whether the device is writable or not.
//if(!(rwFlags() & 0x1) || !(openFlags() & 1))
//if(!(openFlags() & 1))
// continue;
+ //mp->sendStop(); // Moved above.
int beat = (pos * 4) / MusEGlobal::config.division;
-
- //bool isPlaying = (state == PLAY);
- bool isPlaying = MusEGlobal::audio->isPlaying(); // TODO Check this it includes LOOP1 and LOOP2 besides PLAY. p4.0.22
-
- mp->sendStop();
mp->sendSongpos(beat);
- if(isPlaying)
- mp->sendContinue();
}
}
}
-#endif
+*/
//---------------------------------------------------------
// initMidiAlsa
diff --git a/muse2/muse/driver/alsamidi.h b/muse2/muse/driver/alsamidi.h
index 2054a7d3..7a1ac1c2 100644
--- a/muse2/muse/driver/alsamidi.h
+++ b/muse2/muse/driver/alsamidi.h
@@ -45,10 +45,8 @@ class MidiAlsaDevice : public MidiDevice {
private:
// Special for ALSA midi device: Play event list is processed in the ALSA midi sequencer thread.
// Need this FIFO, to decouple from audio thread which adds events to the list.
- MidiFifo playEventFifo;
- MidiFifo stuckNotesFifo;
- volatile bool stopPending;
- volatile bool seekPending;
+ //MidiFifo playEventFifo;
+ //MidiFifo stuckNotesFifo;
virtual QString open();
virtual void close();
@@ -69,13 +67,13 @@ class MidiAlsaDevice : public MidiDevice {
virtual void writeRouting(int, Xml&) const;
virtual inline int deviceType() const { return ALSA_MIDI; }
// Schedule an event for playback. Returns false if event cannot be delivered.
- virtual bool addScheduledEvent(const MidiPlayEvent& ev) { return !playEventFifo.put(ev); }
+ //virtual bool addScheduledEvent(const MidiPlayEvent& ev) { return !playEventFifo.put(ev); }
// Add a stuck note. Returns false if event cannot be delivered.
- virtual bool addStuckNote(const MidiPlayEvent& ev) { return !stuckNotesFifo.put(ev); }
+ //virtual bool addStuckNote(const MidiPlayEvent& ev) { return !stuckNotesFifo.put(ev); }
// Play all events up to current frame.
virtual void processMidi();
- virtual void handleStop();
- virtual void handleSeek();
+ //virtual void handleStop();
+ //virtual void handleSeek();
};
extern bool initMidiAlsa();
diff --git a/muse2/muse/driver/alsatimer.cpp b/muse2/muse/driver/alsatimer.cpp
index ee72d679..20f7ab88 100644
--- a/muse2/muse/driver/alsatimer.cpp
+++ b/muse2/muse/driver/alsatimer.cpp
@@ -173,7 +173,7 @@ namespace MusECore {
(long int)((1000000000.0 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params)));
}
- return 0;
+ return (long int)((1000000000.0 / snd_timer_info_get_resolution(info)) / snd_timer_params_get_ticks(params));
}
actFreq = (1000000000 / snd_timer_info_get_resolution(info)) / setTick;
if (actFreq != freq) {
diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp
index 421152a7..a52410e9 100644
--- a/muse2/muse/driver/jack.cpp
+++ b/muse2/muse/driver/jack.cpp
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: jack.cpp,v 1.30.2.17 2009/12/20 05:00:35 terminator356 Exp $
// (C) Copyright 2002 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on sourceforge.net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -82,15 +83,6 @@ bool checkAudioDevice()
namespace MusECore {
-//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];
-
JackAudioDevice* jackAudio;
//---------------------------------------------------------
@@ -109,38 +101,9 @@ inline bool checkJackClient(jack_client_t* _client)
// jack_thread_init
//---------------------------------------------------------
-static void jack_thread_init (void* ) // data
+static void jack_thread_init (void* )
{
MusEGlobal::doSetuid();
- /*
- if (jackAudio->isRealtime()) {
- struct sched_param rt_param;
- int rv;
- memset(&rt_param, 0, sizeof(sched_param));
- int type;
- rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
- if (rv != 0)
- perror("get scheduler parameter");
- if (type != SCHED_FIFO) {
- fprintf(stderr, "JACK thread not running SCHED_FIFO, try to set...\n");
-
- memset(&rt_param, 0, sizeof(sched_param));
- rt_param.sched_priority = 1;
- rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param);
- if (rv != 0)
- perror("set realtime scheduler");
- memset(&rt_param, 0, sizeof(sched_param));
- rv = pthread_getschedparam(pthread_self(), &type, &rt_param);
- if (rv != 0)
- perror("get scheduler parameter");
- if (type != SCHED_FIFO)
- fprintf(stderr, "JACK still not running FIFO !?!\n"
- "======reliable RT operation not possible!!======\n");
- else
- fprintf(stderr, "JACK thread succesfully set to SCHED_FIFO\n");
- }
- }
- */
#ifdef VST_SUPPORT
if (loadVST)
fst_adopt_thread();
@@ -148,161 +111,78 @@ static void jack_thread_init (void* ) // data
MusEGlobal::undoSetuid();
}
-/*
-//---------------------------------------------------------
-// processAudio + Midi
-// JACK callback
-//---------------------------------------------------------
-void
-print_triplet(unsigned char *data)
-{
- int a,b,c;
- a = b = c = 0;
- memcpy(&a, data, 1);
- memcpy(&b, data+1, 1);
- memcpy(&c, data+2, 1);
- fprintf(stderr, "%x,%x,%x", a, b, c);
-}
-*/
-
-/*
-void handle_jack_midi_in_events(jack_nframes_t frames)
-{
- char buf = 0;
- int i,j;
- jack_midi_event_t midi_event;
- unsigned char t,n,v;
-
- for(j = 0; j < JACK_MIDI_CHANNELS; j++){
- void *midi_buffer_in = jack_port_get_buffer(midi_port_in[j], frames);
- int event_count = jack_midi_get_event_count(midi_buffer_in);
-
- for(i = 0; i < event_count; i++){
- jack_midi_event_get(&midi_event, midi_buffer_in, i);
- t = midi_event.buffer[0];
- n = midi_event.buffer[1];
- v = midi_event.buffer[2];
- if(((*(midi_event.buffer) & 0xf0)) == 0x90){
- fprintf(stderr, "jack-midi-in-event: ON_ time=%d %u ", midi_event.time,
- midi_event.size);
- print_triplet(midi_event.buffer);
- fprintf(stderr, "\n");
- }else if(((*(midi_event.buffer)) & 0xf0) == 0x80){
- fprintf(stderr, "jack-midi-in-event: OFF time=%d %u ", midi_event.time,
- midi_event.size);
- print_triplet(midi_event.buffer);
- fprintf(stderr, "\n");
- }else{
- fprintf(stderr, "jack-midi-in-event: ??? time=%d %u ", midi_event.time,
- midi_event.size);
- print_triplet(midi_event.buffer);
- fprintf(stderr, "\n");
- }
- jack_midi_in_data[j].buffer[0] = t;
- jack_midi_in_data[j].buffer[1] = n;
- jack_midi_in_data[j].buffer[2] = v;
- jack_midi_in_data[j].buffer[3] = 1;
- fprintf(stderr, "handle_jack_midi_in_events() w\n");
- write(jackmidi_pi[1], &buf, 1);
- fprintf(stderr, "handle_jack_midi_in_events() wd\n");
- }
- }
-}
-
-void handle_jack_midi_out_events(jack_nframes_t frames)
-{
- unsigned char *data;
- void *port_buf;
- int i,j,n,x;
-
- //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);
- 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
- 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
- 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){
- n = jack_midi_out_data[i].give - jack_midi_out_data[i].take;
- }else{
- n = jack_midi_out_data[i].give +
- (JACK_MIDI_BUFFER_SIZE - jack_midi_out_data[i].take);
- }
- 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];
- // 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*)
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)
-// printf("processAudio - >>>>\n");
+ int state_pending = jackAudio->_dummyStatePending; // Snapshots.
+ int pos_pending = jackAudio->_dummyPosPending; //
+ jackAudio->_dummyStatePending = -1; // Reset.
+ jackAudio->_dummyPosPending = -1; //
+
+ jackAudio->_frameCounter += frames;
MusEGlobal::segmentSize = frames;
+
if (MusEGlobal::audio->isRunning())
- MusEGlobal::audio->process((unsigned long)frames);
+ {
+ // Are we not using Jack transport?
+ if(!MusEGlobal::useJackTransport.value())
+ {
+ // STOP -> STOP, STOP -> START_PLAY, PLAY -> START_PLAY all count as 'syncing'.
+ if(((jackAudio->dummyState == Audio::STOP || jackAudio->dummyState == Audio::PLAY) && state_pending == Audio::START_PLAY)
+ || (jackAudio->dummyState == Audio::STOP && state_pending == Audio::STOP) )
+ {
+ jackAudio->_syncTimeout = (float)frames / (float)MusEGlobal::sampleRate; // (Re)start the timeout counter...
+ if(pos_pending != -1)
+ jackAudio->dummyPos = pos_pending; // Set the new dummy position.
+ if((jackAudio->dummyState == Audio::STOP || jackAudio->dummyState == Audio::PLAY) && state_pending == Audio::START_PLAY)
+ jackAudio->dummyState = Audio::START_PLAY;
+ }
+ else // All other states such as START_PLAY -> STOP, PLAY -> STOP.
+ if(state_pending != -1 && state_pending != jackAudio->dummyState)
+ {
+ jackAudio->_syncTimeout = 0.0; // Reset.
+ jackAudio->dummyState = state_pending;
+ }
+
+ // Is the sync timeout counter running?
+ if(jackAudio->_syncTimeout > 0.0)
+ {
+ //printf("Jack processAudio dummy sync: state:%d pending:%d\n", jackAudio->dummyState, state_pending);
+ // Is MusE audio ready to roll?
+ if(MusEGlobal::audio->sync(jackAudio->dummyState, jackAudio->dummyPos))
+ {
+ jackAudio->_syncTimeout = 0.0; // Reset.
+ // We're ready. Switch to PLAY state.
+ if(jackAudio->dummyState == Audio::START_PLAY)
+ jackAudio->dummyState = Audio::PLAY;
+ }
+ else
+ {
+ jackAudio->_syncTimeout += (float)frames / (float)MusEGlobal::sampleRate;
+ if(jackAudio->_syncTimeout > 5.0) // TODO: Make this timeout a 'settings' option so it can be applied both to Jack and here.
+ {
+ if (MusEGlobal::debugMsg)
+ puts("Jack dummy sync timeout! Starting anyway...\n");
+ jackAudio->_syncTimeout = 0.0; // Reset.
+ // We're not ready, but no time left - gotta roll anyway. Switch to PLAY state, similar to how Jack is supposed to work.
+ if(jackAudio->dummyState == Audio::START_PLAY)
+ {
+ jackAudio->dummyState = Audio::PLAY;
+ // Docs say sync will be called with Rolling state when timeout expires.
+ MusEGlobal::audio->sync(jackAudio->dummyState, jackAudio->dummyPos);
+ }
+ }
+ }
+ }
+ }
+
+ //if(jackAudio->getState() != Audio::START_PLAY) // Don't process while we're syncing. TODO: May need to deliver silence in process!
+ MusEGlobal::audio->process((unsigned long)frames);
+ }
else {
if (MusEGlobal::debugMsg)
puts("jack calling when audio is disconnected!\n");
}
-// if (JACK_DEBUG)
-// printf("processAudio - <<<<\n");
+
return 0;
}
@@ -344,13 +224,9 @@ static int processSync(jack_transport_state_t state, jack_position_t* pos, void*
}
unsigned frame = pos->frame;
- //printf("processSync valid:%d frame:%d\n", pos->valid, frame);
-
- // p3.3.23
- //printf("Jack processSync() before MusEGlobal::audio->sync frame:%d\n", frame);
//return MusEGlobal::audio->sync(audioState, frame);
int rv = MusEGlobal::audio->sync(audioState, frame);
- //printf("Jack processSync() after MusEGlobal::audio->sync frame:%d\n", frame);
+ //printf("Jack processSync() after MusEGlobal::audio->sync frame:%d\n", frame);
return rv;
}
@@ -366,7 +242,6 @@ static void timebase_callback(jack_transport_state_t /* state */,
{
//printf("Jack timebase_callback pos->frame:%u MusEGlobal::audio->tickPos:%d MusEGlobal::song->cpos:%d\n", pos->frame, MusEGlobal::audio->tickPos(), MusEGlobal::song->cpos());
- // p3.3.27
//Pos p(pos->frame, false);
Pos p(MusEGlobal::extSyncFlag.value() ? MusEGlobal::audio->tickPos() : pos->frame, MusEGlobal::extSyncFlag.value() ? true : false);
// Can't use song pos - it is only updated every (slow) GUI heartbeat !
@@ -382,7 +257,6 @@ static void timebase_callback(jack_transport_state_t /* state */,
// dummy:
//
- // p3.3.26
//pos->beats_per_bar = 4;
//pos->beat_type = 4;
//pos->ticks_per_beat = 384;
@@ -472,20 +346,7 @@ JackAudioDevice::~JackAudioDevice()
if (JACK_DEBUG)
printf("~JackAudioDevice()\n");
if (_client) {
-
- /*
- // p3.3.35
- for(int i = 0; i < JACK_MIDI_CHANNELS; i++)
- {
- if(midi_port_in[i])
- jack_port_unregister(_client, midi_port_in[i]);
- if(midi_port_out[i])
- jack_port_unregister(_client, midi_port_out[i]);
- }
- */
-
if (jack_client_close(_client)) {
- //error->logError("jack_client_close() failed: %s\n", strerror(errno));
fprintf(stderr,"jack_client_close() failed: %s\n", strerror(errno));
}
}
@@ -518,32 +379,6 @@ int JackAudioDevice::realtimePriority() const
return param.sched_priority;
}
-/*
-//---------------------------------------------------------
-// getJackName()
-//---------------------------------------------------------
-
-char* JackAudioDevice::getJackName()
- {
- return jackRegisteredName;
- }
-*/
-
-/*
-//---------------------------------------------------------
-// clientName()
-//---------------------------------------------------------
-
-const char* JackAudioDevice::clientName()
-{
- //if(_client)
- // return jack_get_client_name(_client);
- //else
- // return "MusE";
- return jackRegisteredName;
-}
-*/
-
//---------------------------------------------------------
// initJackAudio
// return true if JACK not found
@@ -551,15 +386,6 @@ const char* JackAudioDevice::clientName()
bool initJackAudio()
{
- /*
- // p3.3.35
- for(int i = 0; i < JACK_MIDI_CHANNELS; i++)
- {
- midi_port_in[i] = 0;
- midi_port_out[i] = 0;
- }
- */
-
if (JACK_DEBUG)
printf("initJackAudio()\n");
if (MusEGlobal::debugMsg) {
@@ -596,7 +422,7 @@ bool initJackAudio()
if (status & JackVersionError)
printf("jack server has wrong version\n");
printf("cannot create jack client\n");
- MusEGlobal::undoSetuid(); // p3.3.51
+ MusEGlobal::undoSetuid();
return true;
}
@@ -616,39 +442,6 @@ bool initJackAudio()
}
MusEGlobal::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);
- }
- }
- }
- else
- {
- fprintf(stderr, "WARNING NO muse-jack midi connection\n");
- }
- */
-
if (client) {
MusEGlobal::audioDevice = jackAudio;
jackAudio->scanMidiPorts();
@@ -730,8 +523,8 @@ void JackAudioDevice::connectJackMidiPorts()
//void* port = md->clientPort();
if(md->rwFlags() & 1)
{
- void* port = md->outClientPort(); // p3.3.55
- if(port) //
+ void* port = md->outClientPort();
+ if(port)
{
RouteList* rl = md->outRoutes();
for (ciRoute r = rl->begin(); r != rl->end(); ++r)
@@ -743,12 +536,10 @@ void JackAudioDevice::connectJackMidiPorts()
}
}
- // else // p3.3.55 Removed
-
if(md->rwFlags() & 2)
{
- void* port = md->inClientPort(); // p3.3.55
- if(port) //
+ void* port = md->inClientPort();
+ if(port)
{
RouteList* rl = md->inRoutes();
for (ciRoute r = rl->begin(); r != rl->end(); ++r)
@@ -760,117 +551,8 @@ void JackAudioDevice::connectJackMidiPorts()
}
}
}
-
-
- /*
- 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;
- // Ignore our own client ports.
- if(jack_port_is_mine(_client, port))
- {
- if(MusEGlobal::debugMsg)
- printf(" ignoring own port: %s\n", *p);
- 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(MusEGlobal::debugMsg)
- printf(" found port: %s ", buffer);
-
- // 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];
-
- if(MusEGlobal::debugMsg)
- printf("alias: %s\n", 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);
-
- QString name(namep);
-
- if(JACK_DEBUG)
- printf("JackAudioDevice::graphChanged %s\n", name.toLatin1());
-
- for(iMidiDevice imd = MusEGlobal::midiDevices.begin(); imd != MusEGlobal::midiDevices.end(); ++imd)
- {
- // Is it a Jack midi device?
- MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*imd);
- if(!mjd)
- continue;
-
- //if(dev->name() != name)
- // continue;
-
- // Is this port the one created for the Jack midi device?
- if(!mjd->clientJackPort() || (mjd->clientJackPort() != port))
- continue;
-
- jack_port_t* devport = jack_port_by_name(_client, mjd->name().toLatin1());
- if(!devport)
- continue;
-
- int ofl = mjd->openFlags();
-
- if(JACK_DEBUG)
- printf("JackAudioDevice::graphChanged found MidiJackDevice:%s\n", mjd->name().toLatin1());
-
- // Note docs say it can't be both input and output. src, dest
- // If Jack port can receive data from us and we actually want to...
- if((pf & JackPortIsOutput) && (ofl & 1))
- {
- if(JACK_DEBUG)
- printf("JackAudioDevice::graphChanged connecting MusE output\n");
- MusEGlobal::audioDevice->connect(port, devport);
- }
- else
- // If Jack port can send data to us and we actually want it...
- if((pf & JackPortIsInput) && (ofl & 2))
- {
- if(JACK_DEBUG)
- printf("JackAudioDevice::graphChanged connecting MusE input\n");
- MusEGlobal::audioDevice->connect(devport, port);
- }
-
- break;
- }
- }
-
- if(ports)
- free(ports);
-
- */
}
+
//---------------------------------------------------------
// client_registration_callback
//---------------------------------------------------------
@@ -1009,9 +691,6 @@ void JackAudioDevice::graphChanged()
++pn;
}
- // p3.3.37
- //delete ports;
- //free(ports);
jack_free(ports); // p4.0.29
ports = NULL;
@@ -1100,9 +779,6 @@ void JackAudioDevice::graphChanged()
++pn;
}
- // p3.3.37
- //delete ports;
- //free(ports);
jack_free(ports); // p4.0.29
ports = NULL;
@@ -1134,12 +810,9 @@ void JackAudioDevice::graphChanged()
if(md->rwFlags() & 1) // Writable
{
- // p3.3.55
jack_port_t* port = (jack_port_t*)md->outClientPort();
if(port != 0)
{
- //printf("graphChanged() valid out client port\n"); // p3.3.55
-
const char** ports = jack_port_get_all_connections(_client, port);
RouteList* rl = md->outRoutes();
@@ -1160,7 +833,7 @@ void JackAudioDevice::graphChanged()
//if (irl->channel != channel)
// continue;
QString name = irl->name();
- //name += QString(JACK_MIDI_OUT_PORT_SUFFIX); // p3.3.55
+ //name += QString(JACK_MIDI_OUT_PORT_SUFFIX);
QByteArray ba = name.toLatin1();
const char* portName = ba.constData();
bool found = false;
@@ -1224,9 +897,6 @@ void JackAudioDevice::graphChanged()
++pn;
}
- // p3.3.55
- // Done with ports. Free them.
- //free(ports);
jack_free(ports); // p4.0.29
}
}
@@ -1239,11 +909,9 @@ void JackAudioDevice::graphChanged()
if(md->rwFlags() & 2) // Readable
{
- // p3.3.55
jack_port_t* port = (jack_port_t*)md->inClientPort();
if(port != 0)
{
- //printf("graphChanged() valid in client port\n"); // p3.3.55
const char** ports = jack_port_get_all_connections(_client, port);
RouteList* rl = md->inRoutes();
@@ -1326,20 +994,11 @@ void JackAudioDevice::graphChanged()
}
++pn;
}
- // p3.3.55
- // Done with ports. Free them.
- //free(ports);
+
jack_free(ports); // p4.0.29
}
}
}
-
- // p3.3.55 Removed.
- //if(ports)
- // Done with ports. Free them.
- //delete ports;
- // free(ports);
- //ports = NULL;
}
}
@@ -1360,18 +1019,12 @@ void JackAudioDevice::registerClient()
if(!checkJackClient(_client)) return;
jack_set_process_callback(_client, processAudio, 0);
jack_set_sync_callback(_client, processSync, 0);
- // FIXME: FIXME:
- // Added by Tim. p3.3.20
- // Did not help. Seek during play: Jack keeps switching to STOP state after about 1-2 seconds timeout if sync is holding it up.
- // Nothing in MusE seems to be telling it to stop.
- // NOTE: Update: It was a bug in QJackCtl. Fixed now.
//jack_set_sync_timeout(_client, 5000000); // Change default 2 to 5 second sync timeout because prefetch may be very slow esp. with resampling !
jack_on_shutdown(_client, processShutdown, 0);
jack_set_buffer_size_callback(_client, bufsize_callback, 0);
jack_set_sample_rate_callback(_client, srate_callback, 0);
jack_set_port_registration_callback(_client, registration_callback, 0);
- // p3.3.37
jack_set_client_registration_callback(_client, client_registration_callback, 0);
jack_set_port_connect_callback(_client, port_connect_callback, 0);
@@ -1384,7 +1037,6 @@ void JackAudioDevice::registerClient()
// registerInPort
//---------------------------------------------------------
-//void* JackAudioDevice::registerInPort(const char* name)
void* JackAudioDevice::registerInPort(const char* name, bool midi)
{
if (JACK_DEBUG)
@@ -1401,7 +1053,6 @@ void* JackAudioDevice::registerInPort(const char* name, bool midi)
// registerOutPort
//---------------------------------------------------------
-//void* JackAudioDevice::registerOutPort(const char* name)
void* JackAudioDevice::registerOutPort(const char* name, bool midi)
{
if (JACK_DEBUG)
@@ -1452,7 +1103,7 @@ void JackAudioDevice::disconnect(void* src, void* dst)
if (JACK_DEBUG)
printf("JackAudioDevice::disconnect()\n");
if(!checkJackClient(_client)) return;
- if(!src || !dst) // p3.3.55
+ if(!src || !dst)
return;
const char* sn = jack_port_name((jack_port_t*) src);
const char* dn = jack_port_name((jack_port_t*) dst);
@@ -1478,7 +1129,6 @@ void JackAudioDevice::disconnect(void* src, void* dst)
// start
//---------------------------------------------------------
-//void JackAudioDevice::start()
void JackAudioDevice::start(int /*priority*/)
{
if (JACK_DEBUG)
@@ -1488,7 +1138,7 @@ void JackAudioDevice::start(int /*priority*/)
MusEGlobal::doSetuid();
if (jack_activate(_client)) {
- MusEGlobal::undoSetuid(); // p3.3.51
+ MusEGlobal::undoSetuid();
fprintf (stderr, "JACK: cannot activate client\n");
exit(-1);
}
@@ -1530,7 +1180,6 @@ void JackAudioDevice::start(int /*priority*/)
}
}
- // p3.3.37
// Connect the Jack midi client ports to device ports.
connectJackMidiPorts();
@@ -1723,9 +1372,6 @@ void JackAudioDevice::getJackPorts(const char** ports, std::list<QString>& name_
name_list.push_back(qname);
}
- // p3.3.37
- //if(ports)
- //free(ports);
// jack_free(ports); // p4.0.29
//return clientList;
@@ -1744,61 +1390,6 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)
const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput);
- /*
- QString qname;
- for (const char** p = ports; p && *p; ++p) {
- jack_port_t* port = jack_port_by_name(_client, *p);
- //int flags = jack_port_flags(port);
- //if (!(flags & JackPortIsOutput))
- // continue;
- //char buffer[128];
-
- int nsz = jack_port_name_size();
- char buffer[nsz];
-
- strncpy(buffer, *p, nsz);
- //if (strncmp(buffer, "MusE", 4) == 0)
- //{
- // if(MusEGlobal::debugMsg)
- // printf("JackAudioDevice::outputPorts ignoring own MusE port: %s\n", *p);
- // continue;
- //}
-
- // Ignore our own client ports.
- if(jack_port_is_mine(_client, port))
- {
- if(MusEGlobal::debugMsg)
- printf("JackAudioDevice::outputPorts ignoring own port: %s\n", *p);
- continue;
- }
-
- // p3.3.38
- if((aliases == 0) || (aliases == 1))
- {
- //char a1[nsz];
- char a2[nsz];
- char* al[2];
- //aliases[0] = a1;
- al[0] = buffer;
- al[1] = a2;
- int na = jack_port_get_aliases(port, al);
- int a = aliases;
- if(a >= na)
- {
- a = na;
- if(a > 0)
- a--;
- }
- qname = QString(al[a]);
- }
- else
- qname = QString(buffer);
-
- //clientList.push_back(QString(buffer));
- clientList.push_back(qname);
- }
- */
-
if(ports)
{
getJackPorts(ports, clientList, midi, true, aliases); // Get physical ports first.
@@ -1823,61 +1414,6 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)
const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput);
- /*
- QString qname;
- for (const char** p = ports; p && *p; ++p) {
- jack_port_t* port = jack_port_by_name(_client, *p);
- //int flags = jack_port_flags(port);
- //if (!(flags & JackPortIsInput))
- // continue;
- //char buffer[128];
-
- int nsz = jack_port_name_size();
- char buffer[nsz];
-
- strncpy(buffer, *p, nsz);
- //if (strncmp(buffer, "MusE", 4) == 0)
- //{
- // if(MusEGlobal::debugMsg)
- // printf("JackAudioDevice::inputPorts ignoring own MusE port: %s\n", *p);
- // continue;
- //}
-
- // Ignore our own client ports.
- if(jack_port_is_mine(_client, port))
- {
- if(MusEGlobal::debugMsg)
- printf("JackAudioDevice::inputPorts ignoring own port: %s\n", *p);
- continue;
- }
-
- // p3.3.38
- if((aliases == 0) || (aliases == 1))
- {
- //char a1[nsz];
- char a2[nsz];
- char* al[2];
- //aliases[0] = a1;
- al[0] = buffer;
- al[1] = a2;
- int na = jack_port_get_aliases(port, al);
- int a = aliases;
- if(a >= na)
- {
- a = na;
- if(a > 0)
- a--;
- }
- qname = QString(al[a]);
- }
- else
- qname = QString(buffer);
-
- //clientList.push_back(QString(buffer));
- clientList.push_back(qname);
- }
- */
-
if(ports)
{
getJackPorts(ports, clientList, midi, true, aliases); // Get physical ports first.
@@ -1979,37 +1515,6 @@ void JackAudioDevice::setFreewheel(bool f)
}
//---------------------------------------------------------
-// dummySync
-//---------------------------------------------------------
-
-bool JackAudioDevice::dummySync(int state)
-{
- // Roughly segment time length.
- //timespec ts = { 0, (1000000000 * MusEGlobal::segmentSize) / MusEGlobal::sampleRate }; // In nanoseconds.
- unsigned int sl = (1000000 * MusEGlobal::segmentSize) / MusEGlobal::sampleRate; // In microseconds.
-
- double ct = curTime();
- // Wait for a default maximum of 5 seconds.
- // Similar to how Jack is supposed to wait a default of 2 seconds for slow clients.
- // TODO: Make this timeout a 'settings' option so it can be applied both to Jack and here.
- while((curTime() - ct) < 5.0)
- {
- // Is MusE audio ready to roll?
- if(MusEGlobal::audio->sync(state, dummyPos))
- return true;
-
- // Not ready. Wait a 'segment', try again...
- //nanosleep(&ts, NULL);
- usleep(sl); // usleep is supposed to be obsolete!
- }
-
- //if(JACK_DEBUG)
- printf("JackAudioDevice::dummySync Sync timeout - audio not ready!\n");
-
- return false;
-}
-
-//---------------------------------------------------------
// startTransport
//---------------------------------------------------------
@@ -2022,19 +1527,7 @@ void JackAudioDevice::startTransport()
// as if processSync was called.
if(!MusEGlobal::useJackTransport.value())
{
- //dummyState = Audio::START_PLAY;
-
- // Is MusE audio ready to roll?
- //if(dummySync(dummyState))
- if(dummySync(Audio::START_PLAY))
- {
- // MusE audio is ready to roll. Let's play.
- dummyState = Audio::PLAY;
- return;
- }
-
- // Ready or not, we gotta roll. Similar to how Jack is supposed to roll anyway.
- dummyState = Audio::PLAY;
+ _dummyStatePending = Audio::START_PLAY;
return;
}
@@ -2052,11 +1545,9 @@ void JackAudioDevice::stopTransport()
if (JACK_DEBUG)
printf("JackAudioDevice::stopTransport()\n");
- dummyState = Audio::STOP;
-
if(!MusEGlobal::useJackTransport.value())
{
- //dummyState = Audio::STOP;
+ _dummyStatePending = Audio::STOP;
return;
}
@@ -2077,32 +1568,11 @@ void JackAudioDevice::seekTransport(unsigned frame)
if (JACK_DEBUG)
printf("JackAudioDevice::seekTransport() frame:%d\n", frame);
- dummyPos = frame;
if(!MusEGlobal::useJackTransport.value())
{
- // If we're not using Jack's transport, just pass the current state and new frame along
- // as if processSync was called.
- //dummyPos = frame;
- int tempState = dummyState;
- //dummyState = Audio::START_PLAY;
-
- // Is MusE audio ready yet?
- //MusEGlobal::audio->sync(dummyState, dummyPos);
- //if(dummySync(dummyState))
- if(dummySync(Audio::START_PLAY))
- {
- dummyState = tempState;
- return;
- }
-
- // Not ready, resume previous state anyway.
- // FIXME: Observed: Seek during play: Jack transport STOPs on timeout.
- // Docs say when starting play, transport will roll anyway, ready or not (observed),
- // but don't mention what should happen on seek during play.
- // And setting the slow-sync timeout doesn't seem to do anything!
- // NOTE: Update: It was a bug with QJackCtl. Fixed now.
- //dummyState = tempState;
- dummyState = Audio::STOP;
+ _dummyPosPending = frame;
+ // STOP -> STOP means seek in stop mode. PLAY -> START_PLAY means seek in play mode.
+ _dummyStatePending = (dummyState == Audio::STOP ? Audio::STOP : Audio::START_PLAY);
return;
}
@@ -2120,28 +1590,11 @@ void JackAudioDevice::seekTransport(const Pos &p)
if (JACK_DEBUG)
printf("JackAudioDevice::seekTransport() frame:%d\n", p.frame());
- dummyPos = p.frame();
if(!MusEGlobal::useJackTransport.value())
{
- // If we're not using Jack's transport, just pass the current state and new frame along
- // as if processSync was called.
- //dummyPos = p.frame();
- int tempState = dummyState;
- //dummyState = Audio::START_PLAY;
-
- // Is MusE audio ready yet?
- //MusEGlobal::audio->sync(dummyState, dummyPos);
- //if(dummySync(dummyState))
- if(dummySync(Audio::START_PLAY))
- {
- dummyState = tempState;
- return;
- }
-
- // Not ready, resume previous state anyway.
- // FIXME: See fixme in other seekTransport...
- //dummyState = tempState;
- dummyState = Audio::STOP;
+ _dummyPosPending = p.frame();
+ // STOP -> STOP means seek in stop mode. PLAY -> START_PLAY means seek in play mode.
+ _dummyStatePending = (dummyState == Audio::STOP ? Audio::STOP : Audio::START_PLAY);
return;
}
@@ -2380,8 +1833,7 @@ void exitJackAudio()
if (JACK_DEBUG)
printf("exitJackAudio() after delete jackAudio\n");
- // Added by Tim. p3.3.14
- MusEGlobal::audioDevice = NULL;
+ MusEGlobal::audioDevice = NULL; // By Tim
}
} // namespace MusECore
diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h
index c4d37db9..838a20df 100644
--- a/muse2/muse/driver/jackaudio.h
+++ b/muse2/muse/driver/jackaudio.h
@@ -40,13 +40,16 @@ class MidiPlayEvent;
class JackAudioDevice : public AudioDevice {
jack_client_t* _client;
- double sampleTime;
- int samplePos;
+ //double sampleTime;
+ //int samplePos;
+ float _syncTimeout;
jack_transport_state_t transportState;
jack_position_t pos;
char jackRegisteredName[16];
int dummyState;
int dummyPos;
+ volatile int _dummyStatePending;
+ volatile int _dummyPosPending;
// Free-running frame counter incremented always in process.
jack_nframes_t _frameCounter;
@@ -58,14 +61,13 @@ class JackAudioDevice : public AudioDevice {
virtual ~JackAudioDevice();
virtual void nullify_client() { _client = 0; }
- virtual inline int deviceType() const { return JACK_AUDIO; } // p3.3.52
+ virtual inline int deviceType() const { return JACK_AUDIO; }
void scanMidiPorts();
//virtual void start();
virtual void start(int);
virtual void stop ();
- virtual bool dummySync(int state); // Artificial sync when not using Jack transport.
virtual int framePos() const;
virtual unsigned frameTime() const { return _frameCounter; }
@@ -80,8 +82,6 @@ class JackAudioDevice : public AudioDevice {
virtual void registerClient();
virtual const char* clientName() { return jackRegisteredName; }
- //virtual void* registerOutPort(const char* name);
- //virtual void* registerInPort(const char* name);
virtual void* registerOutPort(const char* /*name*/, bool /*midi*/);
virtual void* registerInPort(const char* /*name*/, bool /*midi*/);
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
index 7a12b92d..706fa269 100644
--- a/muse2/muse/driver/jackmidi.cpp
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -24,6 +24,7 @@
#include <QString>
#include <stdio.h>
+#include <string.h>
#include <jack/jack.h>
//#include <jack/midiport.h>
@@ -43,6 +44,8 @@
#include "../mplugins/midiitransform.h"
#include "../mplugins/mitplugin.h"
#include "xml.h"
+#include "gconfig.h"
+#include "track.h"
// Turn on debug messages.
//#define JACK_MIDI_DEBUG
@@ -336,10 +339,10 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)
event.setLoopNum(MusEGlobal::audio->loopCount());
if (MusEGlobal::midiInputTrace) {
- printf("Jack MidiInput: ");
+ printf("MidiIn Jack: <%s>: ", name().toLatin1().constData());
event.dump();
}
-
+
int typ = event.type();
if(_port != -1)
@@ -431,7 +434,8 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
{
MidiRecordEvent event;
event.setB(0);
-
+ event.setPort(_port);
+
// NOTE: From muse_qt4_evolution. Not done here in Muse-2 (yet).
// move all events 2*MusEGlobal::segmentSize into the future to get
// jitterfree playback
@@ -452,6 +456,7 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
int a = *(ev->buffer + 1) & 0x7f;
int b = *(ev->buffer + 2) & 0x7f;
event.setType(type);
+
switch(type) {
case ME_NOTEON:
case ME_NOTEOFF:
@@ -494,7 +499,7 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
return;
case ME_SONGPOS:
if(_port != -1)
- MusEGlobal::midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) >> 2 )); // LSB then MSB
+ MusEGlobal::midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) << 7 )); // LSB then MSB
return;
//case ME_SONGSEL:
//case ME_TUNE_REQ:
@@ -525,11 +530,6 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
return;
}
- if (MusEGlobal::midiInputTrace) {
- printf("MidiInput<%s>: ", name().toLatin1().constData());
- 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
@@ -600,14 +600,6 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
//if(port >= JACK_MIDI_CHANNELS)
// return false;
- //if (midiOutputTrace) {
- // printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().constData());
- // e.dump();
- // }
-
- //if(MusEGlobal::debugMsg)
- // printf("MidiJackDevice::queueEvent\n");
-
if(!_out_client_jackport)
return false;
void* pb = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);
@@ -626,9 +618,14 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
}
#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());
+ printf("MidiJackDevice::queueEvent pos:%d fo:%d ft:%d time:%d type:%d ch:%d A:%d B:%d\n", pos, frameOffset, ft, e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
#endif
+ if (MusEGlobal::midiOutputTrace) {
+ printf("MidiOut: Jack: <%s>: ", name().toLatin1().constData());
+ e.dump();
+ }
+
switch(e.type()) {
case ME_NOTEON:
case ME_NOTEOFF:
@@ -698,14 +695,47 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
}
break;
case ME_SONGPOS:
+ {
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::queueEvent songpos %d\n", e.dataA());
+ #endif
+
+ unsigned char* p = jack_midi_event_reserve(pb, ft, 3);
+ if (p == 0) {
+ #ifdef JACK_MIDI_DEBUG
+ fprintf(stderr, "MidiJackDevice::queueEvent songpos: buffer overflow, stopping until next cycle\n");
+ #endif
+ return false;
+ }
+ int pos = e.dataA();
+ p[0] = e.type();
+ p[1] = pos & 0x7f; // LSB
+ p[2] = (pos >> 7) & 0x7f; // MSB
+ }
+ break;
case ME_CLOCK:
case ME_START:
case ME_CONTINUE:
case ME_STOP:
+ {
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::queueEvent realtime %x\n", e.type());
+ #endif
+
+ unsigned char* p = jack_midi_event_reserve(pb, ft, 1);
+ if (p == 0) {
+ #ifdef JACK_MIDI_DEBUG
+ fprintf(stderr, "MidiJackDevice::queueEvent realtime: buffer overflow, stopping until next cycle\n");
+ #endif
+ return false;
+ }
+ p[0] = e.type();
+ }
+ break;
+ default:
if(MusEGlobal::debugMsg)
printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
- //return false;
- return true; // Absorb the event. Don't want it hanging around in the list. FIXME: Support these? p4.0.15 Tim.
+ return true; // Absorb the event. Don't want it hanging around in the list.
break;
}
@@ -757,12 +787,18 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
// event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);
if (hb != 0xff)
+ {
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))
return false; // p4.0.15 Inform that processing the event in general failed. Ditto all below...
+/// t += 1;
+ }
if (lb != 0xff)
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
+ {
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
return false;
- if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)))
+/// t += 1;
+ }
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0)))
return false;
// }
@@ -815,13 +851,15 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
{
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))
return false;
+/// t += 1;
}
if (lb != 0xff)
{
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
return false;
+/// t += 1;
}
- if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)))
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PROGRAM, pr, 0)))
return false;
// }
@@ -851,7 +889,8 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
int dataL = b & 0x7f;
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlL, dataL)))
return false;
}
else if (a < CTRL_NRPN_OFFSET)
@@ -860,19 +899,22 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
int ctrlL = a & 0x7f;
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))
return false;
- if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))
return false;
+/// t += 1;
- t += 3;
+ //t += 3;
// Select null parameters so that subsequent data controller events do not upset the last *RPN controller.
//sendNullRPNParams(chn, false);
if(nvh != 0xff)
{
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)))
return false;
- t += 1;
+/// t += 1;
}
if(nvl != 0xff)
{
@@ -887,18 +929,21 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
int ctrlL = a & 0x7f;
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))
return false;
- if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))
return false;
+/// t += 1;
- t += 3;
+ //t += 3;
//sendNullRPNParams(chn, true);
if(nvh != 0xff)
{
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)))
return false;
- t += 1;
+/// t += 1;
}
if(nvl != 0xff)
{
@@ -914,20 +959,24 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
int dataL = b & 0x7f;
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))
return false;
- if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))
return false;
+/// t += 1;
- t += 4;
+ //t += 4;
//sendNullRPNParams(chn, false);
if(nvh != 0xff)
{
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)))
return false;
- t += 1;
+/// t += 1;
}
if(nvl != 0xff)
{
@@ -943,20 +992,24 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
int dataL = b & 0x7f;
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))
return false;
- if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))
return false;
- if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))
+/// t += 1;
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))
return false;
+/// t += 1;
- t += 4;
+ //t += 4;
//sendNullRPNParams(chn, true);
if(nvh != 0xff)
{
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)))
return false;
- t += 1;
+/// t += 1;
}
if(nvl != 0xff)
{
@@ -988,8 +1041,16 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
void MidiJackDevice::processMidi()
{
+ //bool stop = stopPending; // Snapshots
+ //bool seek = seekPending; //
+ //seekPending = stopPending = false;
+
processStuckNotes();
+ // Don't process if the device is not assigned to a port.
+ //if(_port == -1)
+ // return;
+
void* port_buf = 0;
if(_out_client_jackport && _writeEnable)
{
@@ -997,65 +1058,294 @@ void MidiJackDevice::processMidi()
jack_midi_clear_buffer(port_buf);
}
+ int port = midiPort();
+ MidiPort* mp = port == -1 ? 0 : &MusEGlobal::midiPorts[port];
+
+ /*
+ bool is_playing = MusEGlobal::audio->isPlaying(); // TODO Check this. It includes LOOP1 and LOOP2 besides PLAY.
+ //bool is_playing = MusEGlobal::audio->isPlaying() || MusEGlobal::audio->isStarting();
+ int pos = MusEGlobal::audio->tickPos();
+ bool ext_sync = MusEGlobal::extSyncFlag.value();
+
+ if(mp)
+ {
+ MidiSyncInfo& si = mp->syncInfo();
+ if(stop)
+ {
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!ext_sync)
+ {
+ // Shall we check open flags?
+ //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+ //if(!(dev->openFlags() & 1))
+ // return;
+
+ // Send MMC stop...
+ if(si.MMCOut())
+ {
+ unsigned char msg[mmcStopMsgLen];
+ memcpy(msg, mmcStopMsg, mmcStopMsgLen);
+ msg[1] = si.idOut();
+ putEvent(MidiPlayEvent(0, 0, ME_SYSEX, msg, mmcStopMsgLen));
+ }
+
+ // Send midi stop...
+ if(si.MRTOut())
+ {
+ putEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0));
+ // Added check of option send continue not start. p3.3.31
+ // Hmm, is this required? Seems to make other devices unhappy.
+ // (Could try now that this is in MidiDevice. p4.0.22 )
+ //if(!si.sendContNotStart())
+ // mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division);
+ }
+ }
+ }
+
+ if(seek)
+ {
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!ext_sync)
+ {
+ // Send midi stop and song position pointer...
+ if(si.MRTOut())
+ {
+ // Shall we check for device write open flag to see if it's ok to send?...
+ //if(!(rwFlags() & 0x1) || !(openFlags() & 1))
+ //if(!(openFlags() & 1))
+ // continue;
+ putEvent(MidiPlayEvent(0, 0, 0, ME_STOP, 0, 0));
+ // Hm, try scheduling these for after stuck notes scheduled below...
+ //putEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0));
+ //if(is_playing)
+ // putEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0));
+ }
+ }
+ }
+ }
+
+ if(stop || (seek && is_playing))
+ {
+ // Clear all notes and handle stuck notes...
+ _playEvents.clear();
+ for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)
+ {
+ MidiPlayEvent ev = *i;
+ ev.setTime(0); // Schedule immediately.
+ putEvent(ev);
+ }
+ _stuckNotes.clear();
+ }
+
+ if(mp)
+ {
+ MidiSyncInfo& si = mp->syncInfo();
+ // Try scheduling these now for after stuck notes scheduled above...
+ if(stop || seek)
+ {
+ // Reset sustain.
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+ putEvent(MidiPlayEvent(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0));
+ }
+ if(seek)
+ {
+ // Send new song position.
+ if(!ext_sync && si.MRTOut())
+ {
+ int beat = (pos * 4) / MusEGlobal::config.division;
+ putEvent(MidiPlayEvent(0, 0, 0, ME_SONGPOS, beat, 0));
+ }
+ // Send new controller values.
+ MidiCtrlValListList* cll = mp->controller();
+ for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
+ {
+ MidiCtrlValList* vl = ivl->second;
+ iMidiCtrlVal imcv = vl->iValue(pos);
+ if(imcv != vl->end()) {
+ Part* p = imcv->second.part;
+ // Don't send if part or track is muted or off.
+ if(!p || p->mute())
+ continue;
+ Track* track = p->track();
+ if(track && (track->isMute() || track->off()))
+ continue;
+ unsigned t = (unsigned)imcv->first;
+ // Do not add values that are outside of the part.
+ if(t >= p->tick() && t < (p->tick() + p->lenTick()))
+ // Use sendEvent to get the optimizations and limiting. But force if there's a value at this exact position.
+ mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val), imcv->first == pos);
+ }
+ }
+ // Send continue.
+ // REMOVE Tim. This is redundant and too early - Audio::startRolling already properly sends it when sync ready.
+ //if(is_playing && !ext_sync && si.MRTOut())
+ // putEvent(MidiPlayEvent(0, 0, 0, ME_CONTINUE, 0, 0));
+ }
+ }
+ */
+
while(!eventFifo.isEmpty())
{
MidiPlayEvent e(eventFifo.peek());
+ //printf("MidiJackDevice::processMidi FIFO event time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
// Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. p4.0.15
if(port_buf && !processEvent(e))
return; // Give up. The Jack buffer is full. Nothing left to do.
eventFifo.remove(); // Successfully processed event. Remove it from FIFO.
}
+ //if(!(stop || (seek && is_playing)))
+ // processStuckNotes();
+
if(_playEvents.empty())
- {
- //printf("MidiJackDevice::processMidi play events empty\n");
return;
- }
iMPEvent i = _playEvents.begin();
for(; i != _playEvents.end(); ++i)
{
//printf("MidiJackDevice::processMidi playEvent time:%d type:%d ch:%d A:%d B:%d\n", i->time(), i->type(), i->channel(), i->dataA(), i->dataB());
// Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
- // Same code as in MidiPort::sendEvent()
- if(_port != -1)
- {
- MidiPort* mp = &MusEGlobal::midiPorts[_port];
- if(i->type() == ME_CONTROLLER)
- {
- int da = i->dataA();
- int db = i->dataB();
- db = mp->limitValToInstrCtlRange(da, db);
- if(!mp->setHwCtrlState(i->channel(), da, db))
- continue;
- //mp->setHwCtrlState(i->channel(), da, db);
- }
- else
- if(i->type() == ME_PITCHBEND)
- {
- //printf("MidiJackDevice::processMidi playEvents ME_PITCHBEND time:%d type:%d ch:%d A:%d B:%d\n", (*i).time(), (*i).type(), (*i).channel(), (*i).dataA(), (*i).dataB());
- int da = mp->limitValToInstrCtlRange(CTRL_PITCH, i->dataA());
- if(!mp->setHwCtrlState(i->channel(), CTRL_PITCH, da))
- continue;
- //mp->setHwCtrlState(i->channel(), CTRL_PITCH, da);
- //(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
- }
- else
- if(i->type() == ME_PROGRAM)
- {
- if(!mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA()))
- continue;
- //mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA());
- }
- }
+ if(mp && !mp->sendHwCtrlState(*i, true)) // Force the event to be sent.
+ continue;
// Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. p4.0.15
if(port_buf && !processEvent(*i))
break;
}
_playEvents.erase(_playEvents.begin(), i);
+}
+
+/*
+//---------------------------------------------------------
+// handleStop
+//---------------------------------------------------------
+
+void MidiJackDevice::handleStop()
+{
+ // If the device is not in use by a port, don't bother it.
+ if(_port == -1)
+ return;
+
+ stopPending = true; // Trigger stop handling in processMidi.
+// //---------------------------------------------------
+// // reset sustain
+// //---------------------------------------------------
+//
+// MidiPort* mp = &MusEGlobal::midiPorts[_port];
+// for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+// {
+// if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+// {
+// //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch);
+// MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
+// putEvent(ev);
+// // Do sendEvent to get the optimizations - send only on a change of value.
+// //mp->sendEvent(ev);
+// }
+// }
+
+// //---------------------------------------------------
+// // send midi stop
+// //---------------------------------------------------
+//
+// // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+// if(!MusEGlobal::extSyncFlag.value())
+// {
+// // Shall we check open flags?
+// //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+// //if(!(dev->openFlags() & 1))
+// // return;
+//
+// MidiSyncInfo& si = mp->syncInfo();
+// if(si.MMCOut())
+// mp->sendMMCStop();
+//
+// if(si.MRTOut())
+// {
+// // Send STOP
+// mp->sendStop();
+//
+// // Added check of option send continue not start. p3.3.31
+// // Hmm, is this required? Seems to make other devices unhappy.
+// // (Could try now that this is in MidiDevice. p4.0.22 )
+// //if(!si.sendContNotStart())
+// // mp->sendSongpos(MusEGlobal::audio->tickPos() * 4 / config.division);
+// }
+// }
+}
+*/
+
+/*
+//---------------------------------------------------------
+// handleSeek
+//---------------------------------------------------------
+
+void MidiJackDevice::handleSeek()
+{
+ // If the device is not in use by a port, don't bother it.
+ if(_port == -1)
+ return;
+
+ seekPending = true; // Trigger seek handling in processMidi.
+
+ //MidiPort* mp = &MusEGlobal::midiPorts[_port];
+ //MidiCtrlValListList* cll = mp->controller();
+ //int pos = MusEGlobal::audio->tickPos();
+
+ //---------------------------------------------------
+ // Send new contoller values
+ //---------------------------------------------------
+
+// for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
+// {
+// MidiCtrlValList* vl = ivl->second;
+// iMidiCtrlVal imcv = vl->iValue(pos);
+// if(imcv != vl->end())
+// {
+// Part* p = imcv->second.part;
+// //printf("MidiAlsaDevice::handleSeek _port:%d ctl:%d num:%d val:%d\n", _port, ivl->first >> 24, vl->num(), imcv->second.val);
+// unsigned t = (unsigned)imcv->first;
+// // Do not add values that are outside of the part.
+// if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) )
+// // Keep this and the section in processMidi() just in case we need to revert...
+// //_playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+// // Hmm, play event list for immediate playback? Try putEvent, putMidiEvent, or sendEvent (for the optimizations) instead.
+// mp->sendEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+// }
+// }
+
+ //---------------------------------------------------
+ // Send STOP and "set song position pointer"
+ //---------------------------------------------------
+
+// // Don't send if external sync is on. The master, and our sync routing system will take care of that. p3.3.31
+// if(!MusEGlobal::extSyncFlag.value())
+// {
+// if(mp->syncInfo().MRTOut())
+// {
+// // Shall we check for device write open flag to see if it's ok to send?...
+// // This means obey what the user has chosen for read/write in the midi port config dialog,
+// // which already takes into account whether the device is writable or not.
+// //if(!(rwFlags() & 0x1) || !(openFlags() & 1))
+// //if(!(openFlags() & 1))
+// // continue;
+//
+// int beat = (pos * 4) / MusEGlobal::config.division;
+//
+// //bool isPlaying = (state == PLAY);
+// bool isPlaying = MusEGlobal::audio->isPlaying(); // TODO Check this it includes LOOP1 and LOOP2 besides PLAY. p4.0.22
+//
+// mp->sendStop();
+// mp->sendSongpos(beat);
+// // REMOVE Tim. This is redundant and too early - Audio::startRolling already properly sends it when sync ready.
+// //if(isPlaying)
+// // mp->sendContinue();
+// }
+// }
}
+*/
//---------------------------------------------------------
// initMidiJack
diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h
index d2c14190..c8f7f901 100644
--- a/muse2/muse/driver/jackmidi.h
+++ b/muse2/muse/driver/jackmidi.h
@@ -74,13 +74,15 @@ class MidiJackDevice : public MidiDevice {
public:
MidiJackDevice(const QString& name);
+ virtual ~MidiJackDevice();
static MidiDevice* createJackMidiDevice(QString name = "", int rwflags = 3); // 1:Writable 2: Readable 3: Writable + Readable
virtual inline int deviceType() const { return JACK_MIDI; }
virtual void setName(const QString&);
+ //virtual void handleStop();
+ //virtual void handleSeek();
virtual void processMidi();
- virtual ~MidiJackDevice();
virtual void recordEvent(MidiRecordEvent&);
diff --git a/muse2/muse/driver/rtctimer.cpp b/muse2/muse/driver/rtctimer.cpp
index 365b8501..c50fadf6 100644
--- a/muse2/muse/driver/rtctimer.cpp
+++ b/muse2/muse/driver/rtctimer.cpp
@@ -99,9 +99,9 @@ unsigned int RtcTimer::setTimerFreq(unsigned int freq)
{
int rc = ioctl(timerFd, RTC_IRQP_SET, freq);
if (rc == -1) {
- fprintf(stderr, "RtcTimer::setTimerFreq(): cannot set tick on /dev/rtc: %s\n",
+ fprintf(stderr, "RtcTimer::setTimerFreq(): cannot set freq %d on /dev/rtc: %s\n", freq,
strerror(errno));
- fprintf(stderr, " precise timer not available\n");
+ fprintf(stderr, " precise timer not available, check file permissions and allowed RTC freq (/sys/class/rtc/rtc0/max_user_freq)\n");
return 0;
}
return freq;
diff --git a/muse2/muse/driver/rtctimer.h b/muse2/muse/driver/rtctimer.h
index 425ea643..2b1921a2 100644
--- a/muse2/muse/driver/rtctimer.h
+++ b/muse2/muse/driver/rtctimer.h
@@ -1,12 +1,12 @@
- //=========================================================
- // MusE
- // Linux Music Editor
- // $Id: rtctimer.h,v 1.1.2.3 2005/08/21 18:11:28 spamatica Exp $
- //
- // Most code moved from midiseq.cpp
- //
- // (C) Copyright -2004 Werner Schweer (werner@seh.de)
- // (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: rtctimer.h,v 1.1.2.3 2005/08/21 18:11:28 spamatica Exp $
+//
+// Most code moved from midiseq.cpp
+//
+// (C) Copyright -2004 Werner Schweer (werner@seh.de)
+// (C) Copyright 2004 Robert Jonsson (rj@spamatica.se)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -22,7 +22,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
- //=========================================================
+//=========================================================
#ifndef __RTCTIMER_H__
#define __RTCTIMER_H__
@@ -59,4 +59,4 @@ class RtcTimer : public Timer{
} // namespace MusECore
-#endif //__ALSATIMER_H__
+#endif //__RTCTIMER_H__