diff --git a/c++/carla-backend/carla_engine.cpp b/c++/carla-backend/carla_engine.cpp index 8dbdd46..3eb08cd 100644 --- a/c++/carla-backend/carla_engine.cpp +++ b/c++/carla-backend/carla_engine.cpp @@ -886,6 +886,19 @@ bool CarlaEngineClient::isOk() const return true; } +void CarlaEngineClient::recomputeLatencies() +{ +#ifndef BUILD_BRIDGE + if (carlaOptions.processMode != PROCESS_MODE_CONTINUOUS_RACK) +#endif + { +#ifdef CARLA_ENGINE_JACK + if (handle.type == CarlaEngineTypeJack) + jackbridge_recompute_total_latencies(handle.jackClient); +#endif + } +} + const CarlaEngineBasePort* CarlaEngineClient::addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) { qDebug("CarlaEngineClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); @@ -964,12 +977,23 @@ CarlaEngineAudioPort::CarlaEngineAudioPort(const CarlaEnginePortNativeHandle& ha : CarlaEngineBasePort(handle, isInput) { qDebug("CarlaEngineAudioPort::CarlaEngineAudioPort(%s)", bool2str(isInput)); + latency = 0; } void CarlaEngineAudioPort::initBuffer(CarlaEngine* const /*engine*/) { } +uint32_t CarlaEngineAudioPort::getLatency() const +{ + return latency; +} + +void CarlaEngineAudioPort::setLatency(const uint32_t samples) +{ + latency = samples; +} + #ifdef CARLA_ENGINE_JACK float* CarlaEngineAudioPort::getJackAudioBuffer(uint32_t nframes) { diff --git a/c++/carla-backend/carla_engine.h b/c++/carla-backend/carla_engine.h index 3ad4749..0e73853 100644 --- a/c++/carla-backend/carla_engine.h +++ b/c++/carla-backend/carla_engine.h @@ -426,6 +426,8 @@ public: bool isActive() const; bool isOk() const; + void recomputeLatencies(); + const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput); private: @@ -444,6 +446,11 @@ public: virtual void initBuffer(CarlaEngine* const engine) = 0; + const CarlaEnginePortNativeHandle& getHandle() const + { + return handle; + } + protected: void* buffer; const bool isInput; @@ -458,9 +465,15 @@ public: void initBuffer(CarlaEngine* const engine); + uint32_t getLatency() const; + void setLatency(const uint32_t samples); + #ifdef CARLA_ENGINE_JACK float* getJackAudioBuffer(uint32_t nframes); #endif + +private: + uint32_t latency; }; // control diff --git a/c++/carla-backend/carla_engine_jack.cpp b/c++/carla-backend/carla_engine_jack.cpp index 452b6d0..a55e36f 100644 --- a/c++/carla-backend/carla_engine_jack.cpp +++ b/c++/carla-backend/carla_engine_jack.cpp @@ -79,6 +79,7 @@ public: jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this); jackbridge_set_freewheel_callback(client, carla_jack_freewheel_callback, this); jackbridge_set_process_callback(client, carla_jack_process_callback, this); + jackbridge_set_latency_callback(client, carla_jack_latency_callback, this); jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this); if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK) @@ -186,6 +187,7 @@ public: jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this); jackbridge_set_freewheel_callback(client, carla_jack_freewheel_callback, this); jackbridge_set_process_callback(handle.jackClient, carla_jack_process_callback, this); + jackbridge_set_latency_callback(handle.jackClient, carla_jack_latency_callback, this); jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this); #else if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT) @@ -196,6 +198,7 @@ public: { handle.jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); jackbridge_set_process_callback(handle.jackClient, carla_jack_process_callback_plugin, plugin); + jackbridge_set_latency_callback(handle.jackClient, carla_jack_latency_callback_plugin, plugin); } #endif @@ -457,6 +460,20 @@ protected: #endif } + void handleLatencyCallback() + { +#ifndef BUILD_BRIDGE + if (carlaOptions.processMode != PROCESS_MODE_SINGLE_CLIENT) + return; +#endif + + for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) + { + CarlaPlugin* const plugin = getPluginUnchecked(i); + latencyPlugin(plugin); + } + } + void handleShutdownCallback() { for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) @@ -528,6 +545,23 @@ private: p->process(inBuffer, outBuffer, nframes); } + static void latencyPlugin(CarlaPlugin* const p) + { + for (uint32_t i=0; i < p->aIn.count; i++) + { + const CarlaEngineAudioPort* const port = p->aIn.ports[i]; + jack_port_t* const jackPort = port->getHandle().jackPort; + jack_latency_range_t range; + + jackbridge_port_get_latency_range(jackPort, JackPlaybackLatency, &range); + + range.min += port->getLatency(); + range.max += port->getLatency(); + + jackbridge_port_set_latency_range(jackPort, JackPlaybackLatency, &range); + } + } + static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg) { CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; @@ -570,6 +604,26 @@ private: return 0; } + static void carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg) + { + if (mode != JackPlaybackLatency) + return; + + CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; + _this_->handleLatencyCallback(); + } + + static void carla_jack_latency_callback_plugin(jack_latency_callback_mode_t mode, void* arg) + { + if (mode != JackPlaybackLatency) + return; + + CarlaPlugin* const plugin = (CarlaPlugin*)arg; + + if (plugin && plugin->enabled()) + latencyPlugin(plugin); + } + static void carla_jack_shutdown_callback(void* arg) { CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; diff --git a/c++/carla-backend/dssi.cpp b/c++/carla-backend/dssi.cpp index 68898a3..7fe5532 100644 --- a/c++/carla-backend/dssi.cpp +++ b/c++/carla-backend/dssi.cpp @@ -737,7 +737,13 @@ public: } } - // TODO - adjust latency now + if (hasLatency) + { + for (uint32_t i=0; i < aIn.count; i++) + aIn.ports[i]->setLatency(latency); + + x_client->recomputeLatencies(); + } } reloadPrograms(true); diff --git a/c++/carla-backend/ladspa.cpp b/c++/carla-backend/ladspa.cpp index 2d4868d..3104682 100644 --- a/c++/carla-backend/ladspa.cpp +++ b/c++/carla-backend/ladspa.cpp @@ -706,7 +706,13 @@ public: } } - // TODO - adjust latency now + if (hasLatency) + { + for (uint32_t i=0; i < aIn.count; i++) + aIn.ports[i]->setLatency(latency); + + x_client->recomputeLatencies(); + } } x_client->activate(); diff --git a/c++/carla-backend/lv2.cpp b/c++/carla-backend/lv2.cpp index 9388f8e..64cec8f 100644 --- a/c++/carla-backend/lv2.cpp +++ b/c++/carla-backend/lv2.cpp @@ -1769,7 +1769,13 @@ public: } } - // TODO - adjust latency now + if (hasLatency) + { + for (uint32_t i=0; i < aIn.count; i++) + aIn.ports[i]->setLatency(latency); + + x_client->recomputeLatencies(); + } } reloadPrograms(true); diff --git a/c++/carla-backend/vst.cpp b/c++/carla-backend/vst.cpp index 5d42f3f..5aa4e7d 100644 --- a/c++/carla-backend/vst.cpp +++ b/c++/carla-backend/vst.cpp @@ -731,9 +731,18 @@ public: // check latency { +#ifdef VESTIGE_HEADER + char* const empty3Ptr = &effect->empty3[0]; + int32_t* initialDelayPtr = (int32_t*)empty3Ptr; + uint32_t latency = *initialDelayPtr; +#else uint32_t latency = effect->initialDelay; +#endif + + for (uint32_t i=0; i < aIn.count; i++) + aIn.ports[i]->setLatency(latency); - // TODO - adjust latency now + x_client->recomputeLatencies(); } reloadPrograms(true); diff --git a/c++/carla-jackbridge/carla_jackbridge.cpp b/c++/carla-jackbridge/carla_jackbridge.cpp index 9f1c475..d4f6cfa 100644 --- a/c++/carla-jackbridge/carla_jackbridge.cpp +++ b/c++/carla-jackbridge/carla_jackbridge.cpp @@ -62,6 +62,29 @@ int jackbridge_port_name_size() #endif } +int jackbridge_recompute_total_latencies(jack_client_t* client) +{ +#ifndef JACKBRIDGE_DUMMY + return jack_recompute_total_latencies(client); +#else + return 0; +#endif +} + +void jackbridge_port_get_latency_range(jack_port_t* port, jack_latency_callback_mode_t mode, jack_latency_range_t* range) +{ +#ifndef JACKBRIDGE_DUMMY + jack_port_get_latency_range(port, mode, range); +#endif +} + +void jackbridge_port_set_latency_range(jack_port_t* port, jack_latency_callback_mode_t mode, jack_latency_range_t* range) +{ +#ifndef JACKBRIDGE_DUMMY + jack_port_set_latency_range(port, mode, range); +#endif +} + int jackbridge_activate(jack_client_t* client) { #ifndef JACKBRIDGE_DUMMY @@ -96,6 +119,15 @@ void jackbridge_on_shutdown(jack_client_t* client, JackShutdownCallback shutdown #endif } +void jackbridge_set_latency_callback(jack_client_t* client, JackLatencyCallback latency_callback, void* arg) +{ +#ifndef JACKBRIDGE_DUMMY + return jack_set_latency_callback(client, latency_callback, arg); +#else + return 0; +#endif +} + int jackbridge_set_process_callback(jack_client_t* client, JackProcessCallback process_callback, void* arg) { #ifndef JACKBRIDGE_DUMMY diff --git a/c++/carla-jackbridge/carla_jackbridge.h b/c++/carla-jackbridge/carla_jackbridge.h index 613ab24..0f8f1bc 100644 --- a/c++/carla-jackbridge/carla_jackbridge.h +++ b/c++/carla-jackbridge/carla_jackbridge.h @@ -39,9 +39,13 @@ CARLA_EXPORT int jackbridge_client_close(jack_client_t* client); CARLA_EXPORT int jackbridge_client_name_size(); CARLA_EXPORT char* jackbridge_get_client_name(jack_client_t* client); CARLA_EXPORT int jackbridge_port_name_size(); +CARLA_EXPORT int jackbridge_recompute_total_latencies(jack_client_t* client); +CARLA_EXPORT void jackbridge_port_get_latency_range(jack_port_t* port, jack_latency_callback_mode_t mode, jack_latency_range_t* range); +CARLA_EXPORT void jackbridge_port_set_latency_range(jack_port_t* port, jack_latency_callback_mode_t mode, jack_latency_range_t* range); CARLA_EXPORT int jackbridge_activate(jack_client_t* client); CARLA_EXPORT int jackbridge_deactivate(jack_client_t* client); CARLA_EXPORT void jackbridge_on_shutdown(jack_client_t* client, JackShutdownCallback shutdown_callback, void* arg); +CARLA_EXPORT void jackbridge_set_latency_callback(jack_client_t* client, JackLatencyCallback latency_callback, void* arg); CARLA_EXPORT int jackbridge_set_process_callback(jack_client_t* client, JackProcessCallback process_callback, void* arg); CARLA_EXPORT int jackbridge_set_freewheel_callback(jack_client_t* client, JackFreewheelCallback freewheel_callback, void* arg); CARLA_EXPORT int jackbridge_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCallback bufsize_callback, void* arg); @@ -70,9 +74,13 @@ CARLA_EXPORT jack_transport_state_t jackbridge_transport_query(const jack_client #define jackbridge_client_name_size jack_client_name_size #define jackbridge_get_client_name jack_get_client_name #define jackbridge_port_name_size jack_port_name_size +#define jackbridge_recompute_total_latencies jack_recompute_total_latencies +#define jackbridge_port_get_latency_range jack_port_get_latency_range +#define jackbridge_port_set_latency_range jack_port_set_latency_range #define jackbridge_activate jack_activate #define jackbridge_deactivate jack_deactivate #define jackbridge_on_shutdown jack_on_shutdown +#define jackbridge_set_latency_callback jack_set_latency_callback #define jackbridge_set_process_callback jack_set_process_callback #define jackbridge_set_freewheel_callback jack_set_freewheel_callback #define jackbridge_set_buffer_size_callback jack_set_buffer_size_callback