From b10f6aadbff9758ae6e0302dcdc030459643acbe Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 7 Apr 2017 12:50:25 +0200 Subject: [PATCH] Implement JACK timebase master; Cleanup --- source/backend/engine/CarlaEngine.cpp | 6 +- source/backend/engine/CarlaEngineInternal.cpp | 101 +++++++++++++----- source/backend/engine/CarlaEngineInternal.hpp | 10 +- source/backend/engine/CarlaEngineJack.cpp | 64 ++++++----- source/backend/engine/CarlaEngineNative.cpp | 2 +- 5 files changed, 126 insertions(+), 57 deletions(-) diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index dbfa92f50..9de5bcfcd 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -1343,19 +1343,19 @@ void CarlaEngine::setFileCallback(const FileCallbackFunc func, void* const ptr) void CarlaEngine::transportPlay() noexcept { - pData->time.playing = true; + pData->timeInfo.playing = true; pData->time.fillEngineTimeInfo(pData->timeInfo, 0); } void CarlaEngine::transportPause() noexcept { - pData->time.playing = false; + pData->timeInfo.playing = false; pData->time.fillEngineTimeInfo(pData->timeInfo, 0); } void CarlaEngine::transportRelocate(const uint64_t frame) noexcept { - pData->time.frame = frame; + pData->timeInfo.frame = frame; pData->time.fillEngineTimeInfo(pData->timeInfo, 0); } diff --git a/source/backend/engine/CarlaEngineInternal.cpp b/source/backend/engine/CarlaEngineInternal.cpp index 779fc18ac..fe1ab2293 100644 --- a/source/backend/engine/CarlaEngineInternal.cpp +++ b/source/backend/engine/CarlaEngineInternal.cpp @@ -1,6 +1,6 @@ /* * Carla Plugin Host - * Copyright (C) 2011-2014 Filipe Coelho + * Copyright (C) 2011-2017 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,6 +18,8 @@ #include "CarlaEngineInternal.hpp" #include "CarlaPlugin.hpp" +#include "jackbridge/JackBridge.hpp" + CARLA_BACKEND_START_NAMESPACE // ----------------------------------------------------------------------- @@ -60,16 +62,15 @@ void EngineInternalEvents::clear() noexcept static const float kTicksPerBeat = 1920.0f; EngineInternalTime::EngineInternalTime() noexcept - : playing(false), - frame(0), - bpm(120.0), + : bpm(120.0), sampleRate(0.0), + tick(0.0), #ifdef BUILD_BRIDGE - tick(0.0) {} + needsReset(true) {} #else - tick(0.0), - hylia(nullptr), - hylia_enabled(0) + needsReset(true), + hylia_enabled(false), + hylia(nullptr) { carla_zeroStruct(hylia_time); } @@ -86,11 +87,9 @@ void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t { CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),); - info.playing = playing; - info.frame = frame; - info.usecs = 0; + info.usecs = 0; - if (newFrames == 0) + if (newFrames == 0 || needsReset) { info.valid = EngineTimeInfo::kValidBBT; info.bbt.beatsPerBar = 4.0f; @@ -101,20 +100,17 @@ void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t double abs_beat, abs_tick; #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE) - if (hylia_enabled > 0 && hylia_time.bpm > 0.0) + if (hylia_enabled && hylia_time.beats >= 0.0) { const double beats = hylia_time.beats; - if (beats < 0.0) - return; - abs_beat = std::floor(beats); abs_tick = beats * kTicksPerBeat; } else #endif { - const double min = frame / (sampleRate * 60.0); + const double min = info.frame / (sampleRate * 60.0); abs_tick = min * bpm * kTicksPerBeat; abs_beat = abs_tick / kTicksPerBeat; } @@ -143,6 +139,64 @@ void EngineInternalTime::fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t } info.bbt.tick = (int)(tick + 0.5); + needsReset = false; +} + +void EngineInternalTime::fillJackTimeInfo(jack_position_t* const pos, const uint32_t newFrames) noexcept +{ + CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),); + + if (newFrames == 0 || needsReset) + { + pos->valid = JackPositionBBT; + pos->beats_per_bar = 4.0f; + pos->beat_type = 4.0f; + pos->ticks_per_beat = kTicksPerBeat; + pos->beats_per_minute = bpm; + + double abs_beat, abs_tick; + +#if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE) + if (hylia_enabled && hylia_time.beats >= 0.0) + { + const double beats = hylia_time.beats; + + abs_beat = std::floor(beats); + abs_tick = beats * kTicksPerBeat; + } + else +#endif + { + const double min = pos->frame / (sampleRate * 60.0); + abs_tick = min * bpm * kTicksPerBeat; + abs_beat = abs_tick / kTicksPerBeat; + } + + pos->bar = abs_beat / pos->beats_per_bar; + pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; + tick = abs_tick - (abs_beat * kTicksPerBeat); + pos->bar_start_tick = pos->bar * pos->beats_per_bar * kTicksPerBeat; + pos->bar++; + } + else + { + tick += newFrames * kTicksPerBeat * bpm / (sampleRate * 60); + + while (tick >= kTicksPerBeat) + { + tick -= kTicksPerBeat; + + if (++pos->beat > pos->beats_per_bar) + { + pos->beat = 1; + ++pos->bar; + pos->bar_start_tick += pos->beats_per_bar * pos->ticks_per_beat; + } + } + } + + pos->tick = (int)(tick + 0.5); + needsReset = false; } // ----------------------------------------------------------------------- @@ -339,11 +393,10 @@ void CarlaEngine::ProtectedData::close() void CarlaEngine::ProtectedData::initTime() { - time.playing = false; - time.frame = 0; time.bpm = 120.0; time.sampleRate = sampleRate; time.tick = 0.0; + time.needsReset = true; time.fillEngineTimeInfo(timeInfo, 0); #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE) @@ -451,15 +504,15 @@ PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine, const ui bufferSize(bufSize) { #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE) - if (pData->time.hylia_enabled > 0) + if (pData->time.hylia_enabled) { hylia_process(pData->time.hylia, bufferSize, &pData->time.hylia_time); const double new_bpm = pData->time.hylia_time.bpm; - if (new_bpm > 0.0 && (pData->time.bpm != new_bpm || ++pData->time.hylia_enabled > 50)) + if (new_bpm > 0.0 && pData->time.bpm != new_bpm) { pData->time.bpm = new_bpm; - pData->time.hylia_enabled = 1; + pData->time.needsReset = true; if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) pData->time.fillEngineTimeInfo(pData->timeInfo, 0); @@ -472,9 +525,9 @@ PendingRtEventsRunner::~PendingRtEventsRunner() noexcept { pData->doNextPluginAction(true); - if (pData->time.playing && pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) + if (pData->timeInfo.playing && pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) { - pData->time.frame += bufferSize; + pData->timeInfo.frame += bufferSize; pData->time.fillEngineTimeInfo(pData->timeInfo, bufferSize); } } diff --git a/source/backend/engine/CarlaEngineInternal.hpp b/source/backend/engine/CarlaEngineInternal.hpp index fbc04f58b..88f8d64d6 100644 --- a/source/backend/engine/CarlaEngineInternal.hpp +++ b/source/backend/engine/CarlaEngineInternal.hpp @@ -1,6 +1,6 @@ /* * Carla Plugin Host - * Copyright (C) 2011-2014 Filipe Coelho + * Copyright (C) 2011-2017 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -27,6 +27,8 @@ // FIXME only use CARLA_PREVENT_HEAP_ALLOCATION for structs // maybe separate macro +typedef struct _jack_position jack_position_t; + CARLA_BACKEND_START_NAMESPACE // ----------------------------------------------------------------------- @@ -112,15 +114,14 @@ private: // InternalTime struct EngineInternalTime { - bool playing; - uint64_t frame; double bpm; double sampleRate; double tick; + bool needsReset; #ifndef BUILD_BRIDGE + bool hylia_enabled; hylia_t* hylia; - int hylia_enabled; hylia_time_info_t hylia_time; #endif @@ -128,6 +129,7 @@ struct EngineInternalTime { ~EngineInternalTime() noexcept; void fillEngineTimeInfo(EngineTimeInfo& info, const uint32_t newFrames) noexcept; + void fillJackTimeInfo(jack_position_t* const pos, const uint32_t newFrames) noexcept; CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalTime) }; diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index d1af13027..75f80ccf8 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -811,8 +811,6 @@ public: CarlaThread("CarlaEngineJackCallbacks"), #endif fClient(nullptr), - fTransportPos(), - fTransportState(JackTransportStopped), fExternalPatchbay(true), fFreewheel(false), #ifdef BUILD_BRIDGE @@ -837,8 +835,6 @@ public: // FIXME: Always enable JACK transport for now pData->options.transportMode = ENGINE_TRANSPORT_MODE_JACK; - - carla_zeroStruct(fTransportPos); } ~CarlaEngineJack() noexcept override @@ -895,11 +891,8 @@ public: carla_debug("CarlaEngineJack::init(\"%s\")", clientName); fFreewheel = false; - fTransportState = JackTransportStopped; fExternalPatchbay = true; - carla_zeroStruct(fTransportPos); - CarlaString truncatedClientName(clientName); truncatedClientName.truncate(getMaxClientNameSize()); @@ -961,6 +954,7 @@ public: jackbridge_set_freewheel_callback(fClient, carla_jack_freewheel_callback, this); jackbridge_set_latency_callback(fClient, carla_jack_latency_callback, this); jackbridge_set_process_callback(fClient, carla_jack_process_callback, this); + jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this); jackbridge_on_shutdown(fClient, carla_jack_shutdown_callback, this); if (pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY) @@ -1378,6 +1372,13 @@ public: if (fClient != nullptr) { + if ((pData->timeInfo.valid & EngineTimeInfo::kValidBBT) == 0x0) + { + // old timebase master no longer active, make ourselves master again + pData->time.needsReset = true; + jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this); + } + try { jackbridge_transport_start(fClient); } catch(...) {} @@ -1511,28 +1512,30 @@ protected: if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) return; - fTransportPos.unique_1 = fTransportPos.unique_2 + 1; // invalidate + jack_position_t jpos; - fTransportState = jackbridge_transport_query(fClient, &fTransportPos); + // invalidate + jpos.unique_1 = 1; + jpos.unique_2 = 2; - pData->timeInfo.playing = (fTransportState == JackTransportRolling); + pData->timeInfo.playing = (jackbridge_transport_query(fClient, &jpos) == JackTransportRolling); - if (fTransportPos.unique_1 == fTransportPos.unique_2) + if (jpos.unique_1 == jpos.unique_2) { - pData->timeInfo.frame = fTransportPos.frame; - pData->timeInfo.usecs = fTransportPos.usecs; + pData->timeInfo.frame = jpos.frame; + pData->timeInfo.usecs = jpos.usecs; - if (fTransportPos.valid & JackPositionBBT) + if (jpos.valid & JackPositionBBT) { pData->timeInfo.valid = EngineTimeInfo::kValidBBT; - pData->timeInfo.bbt.bar = fTransportPos.bar; - pData->timeInfo.bbt.beat = fTransportPos.beat; - pData->timeInfo.bbt.tick = fTransportPos.tick; - pData->timeInfo.bbt.barStartTick = fTransportPos.bar_start_tick; - pData->timeInfo.bbt.beatsPerBar = fTransportPos.beats_per_bar; - pData->timeInfo.bbt.beatType = fTransportPos.beat_type; - pData->timeInfo.bbt.ticksPerBeat = fTransportPos.ticks_per_beat; - pData->timeInfo.bbt.beatsPerMinute = fTransportPos.beats_per_minute; + pData->timeInfo.bbt.bar = jpos.bar; + pData->timeInfo.bbt.beat = jpos.beat; + pData->timeInfo.bbt.tick = jpos.tick; + pData->timeInfo.bbt.barStartTick = jpos.bar_start_tick; + pData->timeInfo.bbt.beatsPerBar = jpos.beats_per_bar; + pData->timeInfo.bbt.beatType = jpos.beat_type; + pData->timeInfo.bbt.ticksPerBeat = jpos.ticks_per_beat; + pData->timeInfo.bbt.beatsPerMinute = jpos.beats_per_minute; } else { @@ -1722,6 +1725,14 @@ protected: } #ifndef BUILD_BRIDGE + void handleJackTimebaseCallback(jack_nframes_t nframes, jack_position_t* const pos, const int new_pos) + { + if (new_pos) + nframes = 0; + + pData->time.fillJackTimeInfo(pos, nframes); + } + void handleJackClientRegistrationCallback(const char* const name, const bool reg) { CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); @@ -1955,9 +1966,7 @@ protected: // ------------------------------------------------------------------- private: - jack_client_t* fClient; - jack_position_t fTransportPos; - uint32_t fTransportState; + jack_client_t* fClient; bool fExternalPatchbay; bool fFreewheel; @@ -2421,6 +2430,11 @@ private: } #ifndef BUILD_BRIDGE + static void JACKBRIDGE_API carla_jack_timebase_callback(jack_transport_state_t, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg) __attribute__((annotate("realtime"))) + { + handlePtr->handleJackTimebaseCallback(nframes, pos, new_pos); + } + static void JACKBRIDGE_API carla_jack_client_registration_callback(const char* name, int reg, void* arg) { PostPonedJackEvent ev; diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 4ddd37cfd..e918a0776 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -1,6 +1,6 @@ /* * Carla Plugin Host - * Copyright (C) 2011-2014 Filipe Coelho + * Copyright (C) 2011-2017 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as