From 9b49fd363e67d4e7efbc54852cf0cf24312571ce Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 24 Sep 2021 20:07:25 +0100 Subject: [PATCH] VST3: implement time position; enable metronome vst3 build Signed-off-by: falkTX --- distrho/src/DistrhoDefines.h | 4 +- distrho/src/DistrhoPluginVST2.cpp | 2 +- distrho/src/DistrhoPluginVST3.cpp | 97 ++++++++++++++++++++++---- distrho/src/travesty/audio_processor.h | 2 +- examples/Metronome/Makefile | 3 +- 5 files changed, 90 insertions(+), 18 deletions(-) diff --git a/distrho/src/DistrhoDefines.h b/distrho/src/DistrhoDefines.h index ffd407f1..281031c2 100644 --- a/distrho/src/DistrhoDefines.h +++ b/distrho/src/DistrhoDefines.h @@ -109,7 +109,7 @@ #define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; } #define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; } -#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value); break; } +#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); break; } #define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); continue; } #define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); return ret; } @@ -117,7 +117,7 @@ #define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; } #define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; } -#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value); break; } +#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); break; } #define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); continue; } #define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); return ret; } diff --git a/distrho/src/DistrhoPluginVST2.cpp b/distrho/src/DistrhoPluginVST2.cpp index 827a3055..824327a9 100644 --- a/distrho/src/DistrhoPluginVST2.cpp +++ b/distrho/src/DistrhoPluginVST2.cpp @@ -1114,7 +1114,7 @@ public: fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); - // ticksPerBeat is not possible with VST + // ticksPerBeat is not possible with VST2 fTimePosition.bbt.ticksPerBeat = 1920.0; if (vstTimeInfo->flags & kVstTempoValid) diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp index a3a50762..2a6e4153 100644 --- a/distrho/src/DistrhoPluginVST3.cpp +++ b/distrho/src/DistrhoPluginVST3.cpp @@ -677,25 +677,25 @@ public: // ---------------------------------------------------------------------------------------------------------------- // v3_bstream interface calls (for state support) - v3_result read(void* buffer, int32_t num_bytes, int32_t* bytes_read) + v3_result read(void* /*buffer*/, int32_t /*num_bytes*/, int32_t* /*bytes_read*/) { // TODO return V3_NOT_IMPLEMENTED; } - v3_result write(void* buffer, int32_t num_bytes, int32_t* bytes_written) + v3_result write(void* /*buffer*/, int32_t /*num_bytes*/, int32_t* /*bytes_written*/) { // TODO return V3_NOT_IMPLEMENTED; } - v3_result seek(int64_t pos, int32_t seek_mode, int64_t* result) + v3_result seek(int64_t /*pos*/, int32_t /*seek_mode*/, int64_t* /*result*/) { // TODO return V3_NOT_IMPLEMENTED; } - v3_result tell(int64_t* pos) + v3_result tell(int64_t* /*pos*/) { // TODO return V3_NOT_IMPLEMENTED; @@ -771,25 +771,91 @@ public: } #if DISTRHO_PLUGIN_WANT_TIMEPOS - // TODO + // TODO implement v3_process_context_requirements as query_interface of something.. + if (v3_process_context* const ctx = data->ctx) + { + fTimePosition.playing = ctx->state & V3_PROCESS_CTX_PLAYING; + fTimePosition.bbt.valid = ctx->state & (V3_PROCESS_CTX_TEMPO_VALID|V3_PROCESS_CTX_TIME_SIG_VALID); + + // ticksPerBeat is not possible with VST2 + fTimePosition.bbt.ticksPerBeat = 1920.0; + + if (ctx->state & V3_PROCESS_CTX_CONT_TIME_VALID) + fTimePosition.frame = ctx->continuous_time_in_samples; + else + fTimePosition.frame = ctx->project_time_in_samples; + + if (ctx->state & V3_PROCESS_CTX_TEMPO_VALID) + fTimePosition.bbt.beatsPerMinute = ctx->bpm; + else + fTimePosition.bbt.beatsPerMinute = 120.0; + + if (ctx->state & (V3_PROCESS_CTX_PROJECT_TIME_VALID|V3_PROCESS_CTX_TIME_SIG_VALID)) + { + const double ppqPos = std::abs(ctx->project_time_quarters); + const int ppqPerBar = ctx->time_sig_numerator * 4 / ctx->time_sig_denom; + const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * ctx->time_sig_numerator; + const double rest = std::fmod(barBeats, 1.0); + + fTimePosition.bbt.bar = static_cast(ppqPos) / ppqPerBar + 1; + fTimePosition.bbt.beat = static_cast(barBeats - rest + 0.5) + 1; + fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; + fTimePosition.bbt.beatsPerBar = ctx->time_sig_numerator; + fTimePosition.bbt.beatType = ctx->time_sig_denom; + + if (ctx->project_time_quarters < 0.0) + { + --fTimePosition.bbt.bar; + fTimePosition.bbt.beat = ctx->time_sig_numerator - fTimePosition.bbt.beat + 1; + fTimePosition.bbt.tick = fTimePosition.bbt.ticksPerBeat - fTimePosition.bbt.tick - 1; + } + } + else + { + fTimePosition.bbt.bar = 1; + fTimePosition.bbt.beat = 1; + fTimePosition.bbt.tick = 0.0; + fTimePosition.bbt.beatsPerBar = 4.0f; + fTimePosition.bbt.beatType = 4.0f; + } + + fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* + fTimePosition.bbt.beatsPerBar* + (fTimePosition.bbt.bar-1); + + fPlugin.setTimePosition(fTimePosition); + + } #endif - const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS]; - /* */ float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS]; + const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS != 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1]; + /* */ float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS != 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1]; { int32_t i = 0; - for (; i < data->inputs->num_channels; ++i) - inputs[i] = data->inputs->channel_buffers_32[i]; - for (; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) + if (data->inputs != nullptr) + { + for (; i < data->inputs->num_channels; ++i) + { + DISTRHO_SAFE_ASSERT_INT_BREAK(i < DISTRHO_PLUGIN_NUM_INPUTS, i); + inputs[i] = data->inputs->channel_buffers_32[i]; + } + } + for (; i < std::max(1, DISTRHO_PLUGIN_NUM_INPUTS); ++i) inputs[i] = nullptr; // TODO use dummy buffer } { int32_t i = 0; - for (; i < data->outputs->num_channels; ++i) - outputs[i] = data->outputs->channel_buffers_32[i]; - for (; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) + if (data->outputs != nullptr) + { + for (; i < data->outputs->num_channels; ++i) + { + DISTRHO_SAFE_ASSERT_INT_BREAK(i < DISTRHO_PLUGIN_NUM_OUTPUTS, i); + outputs[i] = data->outputs->channel_buffers_32[i]; + } + } + for (; i < std::max(1, DISTRHO_PLUGIN_NUM_OUTPUTS); ++i) outputs[i] = nullptr; // TODO use dummy buffer } @@ -966,6 +1032,11 @@ private: v3_component_handler* fComponentHandler; void* fComponentHandlerArg; + // Temporary data +#if DISTRHO_PLUGIN_WANT_TIMEPOS + TimePosition fTimePosition; +#endif + bool requestParameterValueChange(const uint32_t index, const float value) { DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false); diff --git a/distrho/src/travesty/audio_processor.h b/distrho/src/travesty/audio_processor.h index 2386e637..d1ed5bf3 100644 --- a/distrho/src/travesty/audio_processor.h +++ b/distrho/src/travesty/audio_processor.h @@ -153,7 +153,7 @@ struct v3_process_context { int64_t project_time_in_samples; // with loop int64_t system_time_ns; - int64_t continuous_time_in_samples; // without loop? unclear + int64_t continuous_time_in_samples; // without loop double project_time_quarters; double bar_position_quarters; diff --git a/examples/Metronome/Makefile b/examples/Metronome/Makefile index 72316ea8..c5860dfb 100644 --- a/examples/Metronome/Makefile +++ b/examples/Metronome/Makefile @@ -25,7 +25,8 @@ include ../../Makefile.plugins.mk TARGETS += jack TARGETS += lv2_dsp -TARGETS += vst +TARGETS += vst2 +TARGETS += vst3 all: $(TARGETS)