| @@ -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); | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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); | |||
| } | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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) | |||
| }; | |||
| @@ -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; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||