summaryrefslogtreecommitdiff
path: root/muse2/muse/driver
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
committerFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
commit9c4664d162c537ba4dd4fd8220971c0fb727103a (patch)
tree37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/driver
parente87fedf1be804f7ec774071d844b1f163be30b96 (diff)
final merge
Diffstat (limited to 'muse2/muse/driver')
-rw-r--r--muse2/muse/driver/alsamidi.cpp10
-rw-r--r--muse2/muse/driver/jack.cpp182
-rw-r--r--muse2/muse/driver/jackaudio.h2
-rw-r--r--muse2/muse/driver/jackmidi.cpp38
4 files changed, 168 insertions, 64 deletions
diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp
index f75b9c33..e3e71365 100644
--- a/muse2/muse/driver/alsamidi.cpp
+++ b/muse2/muse/driver/alsamidi.cpp
@@ -1318,24 +1318,24 @@ void alsaProcessMidiInput()
break;
case SND_SEQ_EVENT_CLOCK:
- MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CLOCK);
+ MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CLOCK, curTime());
//mdev->syncInfo().trigMCSyncDetect();
break;
case SND_SEQ_EVENT_START:
- MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_START);
+ MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_START, curTime());
break;
case SND_SEQ_EVENT_CONTINUE:
- MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CONTINUE);
+ MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_CONTINUE, curTime());
break;
case SND_SEQ_EVENT_STOP:
- MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_STOP);
+ MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_STOP, curTime());
break;
case SND_SEQ_EVENT_TICK:
- MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_TICK);
+ MusEGlobal::midiSeq->realtimeSystemInput(curPort, ME_TICK, curTime());
//mdev->syncInfo().trigTickDetect();
break;
diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp
index 4cc8bfb8..05d47955 100644
--- a/muse2/muse/driver/jack.cpp
+++ b/muse2/muse/driver/jack.cpp
@@ -42,6 +42,7 @@
#include "tempo.h"
#include "sync.h"
#include "utils.h"
+#include "gconfig.h"
#include "midi.h"
#include "mididev.h"
@@ -50,7 +51,7 @@
#include "jackmidi.h"
-#define JACK_DEBUG 0
+#define JACK_DEBUG 0
//#include "errorhandler.h"
@@ -176,7 +177,7 @@ int JackAudioDevice::processAudio(jack_nframes_t frames, void*)
}
}
}
-
+
//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);
}
@@ -196,8 +197,21 @@ int JackAudioDevice::processAudio(jack_nframes_t frames, void*)
static int processSync(jack_transport_state_t state, jack_position_t* pos, void*)
{
if (JACK_DEBUG)
- printf("processSync()\n");
+ {
+ printf("processSync frame:%u\n", pos->frame);
+ if(pos->valid & JackPositionBBT)
+ {
+ if(JACK_DEBUG)
+ {
+ printf("processSync BBT:\n bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n",
+ pos->bar, pos->beat, pos->tick, pos->bar_start_tick, pos->beats_per_bar, pos->beat_type, pos->ticks_per_beat, pos->beats_per_minute);
+ if(pos->valid & JackBBTFrameOffset)
+ printf("processSync BBTFrameOffset: %u\n", pos->bbt_offset);
+ }
+ }
+ }
+
if(!MusEGlobal::useJackTransport.value())
return 1;
@@ -237,49 +251,54 @@ static int processSync(jack_transport_state_t state, jack_position_t* pos, void*
//---------------------------------------------------------
static void timebase_callback(jack_transport_state_t /* state */,
- jack_nframes_t /* nframes */,
+ jack_nframes_t nframes,
jack_position_t* pos,
- int /* new_pos */,
+ int new_pos,
void*)
{
- if (JACK_DEBUG)
- printf("Jack timebase_callback pos->frame:%u MusEGlobal::audio->tickPos:%d MusEGlobal::song->cpos:%d\n", pos->frame, MusEGlobal::audio->tickPos(), MusEGlobal::song->cpos());
-
- //Pos p(pos->frame, false);
+
+ if (JACK_DEBUG)
+ {
+ if(pos->valid & JackPositionBBT)
+ printf("timebase_callback BBT:\n bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n",
+ pos->bar, pos->beat, pos->tick, pos->bar_start_tick, pos->beats_per_bar, pos->beat_type, pos->ticks_per_beat, pos->beats_per_minute);
+ if(pos->valid & JackBBTFrameOffset)
+ printf("timebase_callback BBTFrameOffset: %u\n", pos->bbt_offset);
+ if(pos->valid & JackPositionTimecode)
+ printf("timebase_callback JackPositionTimecode: frame_time:%f next_time:%f\n", pos->frame_time, pos->next_time);
+ if(pos->valid & JackAudioVideoRatio)
+ printf("timebase_callback JackAudioVideoRatio: %f\n", pos->audio_frames_per_video_frame);
+ if(pos->valid & JackVideoFrameOffset)
+ printf("timebase_callback JackVideoFrameOffset: %u\n", pos->video_offset);
+ }
+
+ //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 !
//Pos p(MusEGlobal::extSyncFlag.value() ? MusEGlobal::song->cpos() : pos->frame, MusEGlobal::extSyncFlag.value() ? true : false);
pos->valid = JackPositionBBT;
p.mbt(&pos->bar, &pos->beat, &pos->tick);
+ pos->bar_start_tick = Pos(pos->bar, 0, 0).tick();
pos->bar++;
pos->beat++;
- pos->bar_start_tick = Pos(pos->bar, 0, 0).tick();
-
- //
- // dummy:
- //
- //pos->beats_per_bar = 4;
- //pos->beat_type = 4;
- //pos->ticks_per_beat = 384;
- //
- /* // From example client transport.c :
- float time_beats_per_bar = 4.0;
- float time_beat_type = 0.25; // Huh? Inverted? From docs: "Time signature 'denominator'"
- double time_ticks_per_beat = 1920.0; // Huh? Ticks per beat should be 24 etc. not 384 or 1920 etc. Otherwise it would be called 'frames_per_beat'.
- double time_beats_per_minute = 120.0;
- */
- //
int z, n;
AL::sigmap.timesig(p.tick(), z, n);
pos->beats_per_bar = z;
pos->beat_type = n;
- //pos->ticks_per_beat = config.division;
- pos->ticks_per_beat = 24;
+ pos->ticks_per_beat = MusEGlobal::config.division;
+ //pos->ticks_per_beat = 24;
+
+ double tempo = MusEGlobal::tempomap.tempo(p.tick());
+ pos->beats_per_minute = (60000000.0 / tempo) * double(MusEGlobal::tempomap.globalTempo())/100.0;
+ if (JACK_DEBUG)
+ {
+ printf("timebase_callback is new_pos:%d nframes:%u frame:%u tickPos:%d cpos:%d\n", new_pos, nframes, pos->frame, MusEGlobal::audio->tickPos(), MusEGlobal::song->cpos());
+ printf(" new: bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n",
+ pos->bar, pos->beat, pos->tick, pos->bar_start_tick, pos->beats_per_bar, pos->beat_type, pos->ticks_per_beat, pos->beats_per_minute);
+ }
- int tempo = MusEGlobal::tempomap.tempo(p.tick());
- pos->beats_per_minute = (60000000.0 / tempo) * MusEGlobal::tempomap.globalTempo()/100.0;
}
//---------------------------------------------------------
@@ -1226,6 +1245,69 @@ jack_transport_state_t JackAudioDevice::transportQuery(jack_position_t* pos)
}
//---------------------------------------------------------
+// timebaseQuery
+// Given the number of frames in this period, get the bar, beat, tick,
+// and current absolute tick, and number of ticks in this period.
+// Return false if information could not be obtained.
+//---------------------------------------------------------
+
+bool JackAudioDevice::timebaseQuery(unsigned frames, unsigned* bar, unsigned* beat, unsigned* tick, unsigned* curr_abs_tick, unsigned* next_ticks)
+{
+ jack_position_t jp;
+ jack_transport_query(_client, &jp);
+
+ if(JACK_DEBUG)
+ printf("timebaseQuery frame:%u\n", jp.frame);
+
+ if(jp.valid & JackPositionBBT)
+ {
+ if(JACK_DEBUG)
+ {
+ printf("timebaseQuery BBT:\n bar:%d beat:%d tick:%d\n bar_start_tick:%f beats_per_bar:%f beat_type:%f ticks_per_beat:%f beats_per_minute:%f\n",
+ jp.bar, jp.beat, jp.tick, jp.bar_start_tick, jp.beats_per_bar, jp.beat_type, jp.ticks_per_beat, jp.beats_per_minute);
+ if(jp.valid & JackBBTFrameOffset)
+ printf("timebaseQuery BBTFrameOffset: %u\n", jp.bbt_offset);
+ }
+
+ if(jp.ticks_per_beat > 0.0)
+ {
+ unsigned muse_tick = unsigned((double(jp.tick) / jp.ticks_per_beat) * double(MusEGlobal::config.division));
+ unsigned curr_tick = ((jp.bar - 1) * jp.beats_per_bar + (jp.beat - 1)) * double(MusEGlobal::config.division) + muse_tick;
+ // Prefer the reported frame rate over the app's rate if possible.
+ double f_rate = jp.frame_rate != 0 ? jp.frame_rate : MusEGlobal::sampleRate;
+ // beats_per_minute is "supposed" to be quantized to period size - that is, computed
+ // so that mid-period changes are averaged out to produce a single tempo which
+ // produces the same tick in the end. If we can rely on that, we should be good accuracy.
+ unsigned ticks = double(MusEGlobal::config.division) * (jp.beats_per_minute / 60.0) * double(frames) / f_rate;
+
+ if(JACK_DEBUG)
+ printf("timebaseQuery curr_tick:%u f_rate:%f ticks:%u\n", curr_tick, f_rate, ticks);
+
+ if(bar) *bar = jp.bar;
+ if(beat) *beat = jp.beat;
+ if(tick) *tick = muse_tick;
+
+ if(curr_abs_tick) *curr_abs_tick = curr_tick;
+ if(next_ticks) *next_ticks = ticks;
+
+ return true;
+ }
+ }
+
+ if(JACK_DEBUG)
+ {
+ if(jp.valid & JackPositionTimecode)
+ printf("timebaseQuery JackPositionTimecode: frame_time:%f next_time:%f\n", jp.frame_time, jp.next_time);
+ if(jp.valid & JackAudioVideoRatio)
+ printf("timebaseQuery JackAudioVideoRatio: %f\n", jp.audio_frames_per_video_frame);
+ if(jp.valid & JackVideoFrameOffset)
+ printf("timebaseQuery JackVideoFrameOffset: %u\n", jp.video_offset);
+ }
+
+ return false;
+}
+
+//---------------------------------------------------------
// systemTime
// Return system time. Depends on selected clock source.
// With Jack, may be based upon wallclock time, the
@@ -1617,7 +1699,7 @@ void JackAudioDevice::seekTransport(unsigned frame)
void JackAudioDevice::seekTransport(const Pos &p)
{
if (JACK_DEBUG)
- printf("JackAudioDevice::seekTransport() frame:%d\n", p.frame());
+ printf("JackAudioDevice::seekTransport(Pos) frame:%d\n", p.frame());
if(!MusEGlobal::useJackTransport.value())
{
@@ -1628,25 +1710,29 @@ void JackAudioDevice::seekTransport(const Pos &p)
}
if(!checkJackClient(_client)) return;
+
+// TODO: Be friendly to other apps... Sadly not many of us use jack_transport_reposition.
+// This is actually required IF we want the extra position info to show up
+// in the sync callback, otherwise we get just the frame only.
+// This information is shared on the server, it is directly passed around.
+// jack_transport_locate blanks the info from sync until the timebase callback reads
+// it again right after, from some timebase master. See process in audio.cpp
+
+// jack_position_t jp;
+// jp.frame = p.frame();
+//
+// jp.valid = JackPositionBBT;
+// p.mbt(&jp.bar, &jp.beat, &jp.tick);
+// jp.bar_start_tick = Pos(jp.bar, 0, 0).tick();
+// jp.bar++;
+// jp.beat++;
+// jp.beats_per_bar = 5; // TODO Make this correct !
+// jp.beat_type = 8; //
+// jp.ticks_per_beat = MusEGlobal::config.division;
+// int tempo = MusEGlobal::tempomap.tempo(p.tick());
+// jp.beats_per_minute = (60000000.0 / tempo) * MusEGlobal::tempomap.globalTempo()/100.0;
+// jack_transport_reposition(_client, &jp);
- /*
- jack_position_t jp;
- jp.valid = JackPositionBBT;
- p.mbt(&jp.bar, &jp.beat, &jp.tick);
- jp.bar++;
- jp.beat++;
- jp.bar_start_tick = Pos(jp.bar, 0, 0).tick();
- //
- // dummy:
- //
- jp.beats_per_bar = 4;
- jp.beat_type = 4;
- jp.ticks_per_beat = 384;
- int tempo = MusEGlobal::tempomap.tempo(p.tick());
- jp.beats_per_minute = (60000000.0 / tempo) * MusEGlobal::tempomap.globalTempo()/100.0;
-
- jack_transport_reposition(_client, &jp);
- */
jack_transport_locate(_client, p.frame());
}
diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h
index 9640ca81..aab60d88 100644
--- a/muse2/muse/driver/jackaudio.h
+++ b/muse2/muse/driver/jackaudio.h
@@ -80,6 +80,7 @@ class JackAudioDevice : public AudioDevice {
virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1);
virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);
+ jack_client_t* jackClient() const { return _client; }
virtual void registerClient();
virtual const char* clientName() { return jackRegisteredName; }
@@ -105,6 +106,7 @@ class JackAudioDevice : public AudioDevice {
virtual void seekTransport(const Pos &p);
virtual void setFreewheel(bool f);
jack_transport_state_t transportQuery(jack_position_t* pos);
+ bool timebaseQuery(unsigned frames, unsigned* bar, unsigned* beat, unsigned* tick, unsigned* curr_abs_tick, unsigned* next_ticks);
void graphChanged();
void registrationChanged();
void connectJackMidiPorts();
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
index 706fa269..e3e67dfb 100644
--- a/muse2/muse/driver/jackmidi.cpp
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -30,6 +30,7 @@
//#include <jack/midiport.h>
#include "jackmidi.h"
+#include "jackaudio.h"
#include "song.h"
#include "globals.h"
#include "midi.h"
@@ -50,10 +51,6 @@
// Turn on debug messages.
//#define JACK_MIDI_DEBUG
-namespace MusEGlobal {
-extern unsigned int volatile lastExtMidiSyncTick;
-}
-
namespace MusECore {
//---------------------------------------------------------
@@ -422,7 +419,7 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)
// Split the events up into channel fifos. Special 'channel' number 17 for sysex events.
unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel();
- if(_recordFifo[ch].put(MidiPlayEvent(event)))
+ if(_recordFifo[ch].put(event))
printf("MidiJackDevice::recordEvent: fifo channel %d overflow\n", ch);
}
@@ -446,10 +443,18 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
// catch process play
//
- //int frameOffset = MusEGlobal::audio->getFrameOffset();
- unsigned pos = MusEGlobal::audio->pos().frame();
-
- event.setTime(MusEGlobal::extSyncFlag.value() ? MusEGlobal::lastExtMidiSyncTick : (pos + ev->time)); // p3.3.25
+ // These Jack events arrived in the previous period, and it may not have been at the audio position before this one (after a seek).
+ // This is how our ALSA driver works, events there are timestamped asynchronous of any process, referenced to the CURRENT audio
+ // position, so that by the time of the NEXT process, THOSE events have also occured in the previous period.
+ // So, technically this is correct. What MATTERS is how we adjust the times for storage, and/or simultaneous playback in THIS period,
+ // and TEST: we'll need to make sure any non-contiguous previous period is handled correctly by process - will it work OK as is?
+ // If ALSA works OK than this should too...
+#ifdef _AUDIO_USE_TRUE_FRAME_
+ event.setTime(MusEGlobal::audio->previousPos().frame() + ev->time);
+#else
+ event.setTime(MusEGlobal::audio->pos().frame() + ev->time);
+#endif
+ event.setTick(MusEGlobal::lastExtMidiSyncTick);
event.setChannel(*(ev->buffer) & 0xf);
int type = *(ev->buffer) & 0xf0;
@@ -509,9 +514,20 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
case ME_START:
case ME_CONTINUE:
case ME_STOP:
- if(_port != -1)
- MusEGlobal::midiSeq->realtimeSystemInput(_port, type);
+ {
+ if(MusEGlobal::audioDevice && MusEGlobal::audioDevice->deviceType() == JACK_MIDI && _port != -1)
+ {
+ MusECore::JackAudioDevice* jad = static_cast<MusECore::JackAudioDevice*>(MusEGlobal::audioDevice);
+ jack_client_t* jc = jad->jackClient();
+ if(jc)
+ {
+ jack_nframes_t abs_ft = jack_last_frame_time(jc) + ev->time;
+ double abs_ev_t = double(jack_frames_to_time(jc, abs_ft)) / 1000000.0;
+ MusEGlobal::midiSeq->realtimeSystemInput(_port, type, abs_ev_t);
+ }
+ }
return;
+ }
//case ME_SYSEX_END:
//break;
// return;