@@ -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 | |||