From b86d0deebc3f3bccfe95e6b958b955e628dbd9ca Mon Sep 17 00:00:00 2001 From: theGreatWhiteShark Date: Wed, 15 May 2024 20:14:33 +0200 Subject: [PATCH 1/2] jack: commonize BBT calculation --- src/muse/driver/jack.cpp | 62 ++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/muse/driver/jack.cpp b/src/muse/driver/jack.cpp index f943234b1..1d1177d3f 100644 --- a/src/muse/driver/jack.cpp +++ b/src/muse/driver/jack.cpp @@ -378,6 +378,39 @@ static int processSync(jack_transport_state_t state, jack_position_t* pos, void* return rv; } +//--------------------------------------------------------- +// pos_to_jack_position +//--------------------------------------------------------- + +static void pos_to_jack_position(const Pos& p, jack_position_t* pos) { + + pos->valid = JackPositionBBT; + int bar, beat, tick; + p.mbt(&bar, &beat, &tick); + pos->bar = bar; + pos->beat = beat; + pos->tick = tick; + + pos->bar_start_tick = Pos(pos->bar, 0, 0).tick(); + pos->bar++; + pos->beat++; + + int z, n; + MusEGlobal::sigmap.timesig(p.tick(), z, n); + pos->beats_per_bar = z; + pos->beat_type = n; + pos->ticks_per_beat = MusEGlobal::config.division; + //pos->ticks_per_beat = 24; + + double tempo = MusEGlobal::tempomap.tempo(p.tick()); + pos->beats_per_minute = ((double)MusEGlobal::tempomap.globalTempo() * 600000.0) / tempo; +#if JACK_DEBUG + fprintf(stderr, "pos_to_jack_position 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); +#endif + + } + //--------------------------------------------------------- // timebase_callback //--------------------------------------------------------- @@ -423,34 +456,13 @@ static void timebase_callback(jack_transport_state_t, Pos p(MusEGlobal::extSyncFlag ? MusEGlobal::audio->tickPos() : pos->frame, MusEGlobal::extSyncFlag ? true : false); // Can't use song pos - it is only updated every (slow) GUI heartbeat ! //Pos p(MusEGlobal::extSyncFlag ? MusEGlobal::song->cpos() : pos->frame, MusEGlobal::extSyncFlag ? true : false); - - pos->valid = JackPositionBBT; - int bar, beat, tick; - p.mbt(&bar, &beat, &tick); - pos->bar = bar; - pos->beat = beat; - pos->tick = tick; - pos->bar_start_tick = Pos(pos->bar, 0, 0).tick(); - pos->bar++; - pos->beat++; - - int z, n; - MusEGlobal::sigmap.timesig(p.tick(), z, n); - pos->beats_per_bar = z; - pos->beat_type = n; - pos->ticks_per_beat = MusEGlobal::config.division; - //pos->ticks_per_beat = 24; - - double tempo = MusEGlobal::tempomap.tempo(p.tick()); - pos->beats_per_minute = ((double)MusEGlobal::tempomap.globalTempo() * 600000.0) / tempo; + pos_to_jack_position(p, pos); + #if JACK_DEBUG - fprintf(stderr, "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()); - fprintf(stderr, " 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); + // fprintf(stderr, "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()); #endif - - } + } //--------------------------------------------------------- // processShutdown From 594944488b30e1b4c9ad8f77b20c420d5fdaebfc Mon Sep 17 00:00:00 2001 From: theGreatWhiteShark Date: Wed, 15 May 2024 20:38:08 +0200 Subject: [PATCH 2/2] jack: fix synchronization while repositioning While using JACK Timebase support and being registered as Timebase master MusE appends the JACKs current transport position with bar, beat, tick, tempo, measure, etc (BBT) information via `timebase_callback`. Other clients can then trigger tempo changes, relocations etc. using these BBT infos. But when repositioning to another location MusE did use the `jack_transport_locate` method of the JACK API, which only sends frame information. Thus, the JACK server will drop BBT support for a single process cycle and other clients need to figure out the new transport position by frame alone (which most probably will not work correctly when they did already handled tempo or measure changes). Instead, MusE does now use `jack_transport_reposition` in case it is registered as Timebase master. Using this method not just the new frame but all BBT information similar to the `timebase_callback` are provided. --- src/muse/driver/jack.cpp | 52 +++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/muse/driver/jack.cpp b/src/muse/driver/jack.cpp index 1d1177d3f..af612c6bc 100644 --- a/src/muse/driver/jack.cpp +++ b/src/muse/driver/jack.cpp @@ -2273,7 +2273,21 @@ void JackAudioDevice::seekTransport(unsigned frame) if(!checkJackClient(_client)) return; // fprintf(stderr, "JACK: seekTransport %d\n", frame); - jack_transport_locate(_client, frame); + + if(MusEGlobal::timebaseMasterState) + { + // We are timebase master. Provide a BBT representation of the new + // position as well. + jack_position_t jp; + Pos p(frame, false); + jp.frame = frame; + pos_to_jack_position(p, &jp); + jack_transport_reposition(_client, &jp); + } + else + { + jack_transport_locate(_client, frame); + } } //--------------------------------------------------------- @@ -2293,29 +2307,19 @@ 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_transport_locate(_client, p.frame()); + if(MusEGlobal::timebaseMasterState) + { + // We are timebase master. Provide a BBT representation of the new + // position as well. + jack_position_t jp; + jp.frame = p.frame(); + pos_to_jack_position(p, &jp); + jack_transport_reposition(_client, &jp); + } + else + { + jack_transport_locate(_client, p.frame()); + } } //---------------------------------------------------------