summaryrefslogtreecommitdiff
path: root/muse2/muse/driver/jack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/muse/driver/jack.cpp')
-rw-r--r--muse2/muse/driver/jack.cpp182
1 files changed, 134 insertions, 48 deletions
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());
}