From 6c3e148fbb3ea1487515fe80838d2accaf22d8f4 Mon Sep 17 00:00:00 2001 From: Dominic Clark Date: Mon, 4 Jul 2022 17:03:17 +0100 Subject: [PATCH] Make VST sync always-on and non-global (#6418) --- include/RemotePluginBase.h | 2 +- include/RemotePluginClient.h | 43 +++++------- include/SetupDialog.h | 2 - include/Song.h | 2 + include/VstSyncController.h | 40 +++-------- include/VstSyncData.h | 1 - plugins/VstBase/RemoteVstPlugin.cpp | 103 ++++++++-------------------- src/core/RemotePlugin.cpp | 2 + src/core/VstSyncController.cpp | 95 +++++++++++++++---------- src/gui/modals/SetupDialog.cpp | 13 ---- 10 files changed, 120 insertions(+), 183 deletions(-) diff --git a/include/RemotePluginBase.h b/include/RemotePluginBase.h index 8ecf47087..0a3601d7c 100644 --- a/include/RemotePluginBase.h +++ b/include/RemotePluginBase.h @@ -26,7 +26,6 @@ #define REMOTE_PLUGIN_BASE_H #include "MidiEvent.h" -#include "VstSyncData.h" #include #include @@ -352,6 +351,7 @@ enum RemoteMessageIDs IdHostInfoGotten, IdInitDone, IdQuit, + IdSyncKey, IdSampleRateInformation, IdBufferSizeInformation, IdInformationUpdated, diff --git a/include/RemotePluginClient.h b/include/RemotePluginClient.h index b96b71b85..2d825486e 100644 --- a/include/RemotePluginClient.h +++ b/include/RemotePluginClient.h @@ -39,6 +39,7 @@ #endif #include "SharedMemory.h" +#include "VstSyncData.h" namespace lmms { @@ -124,8 +125,7 @@ private: void doProcessing(); SharedMemory m_audioBuffer; - SharedMemory m_vstSyncShm; - const VstSyncData* m_vstSyncData; + SharedMemory m_vstSyncData; int m_inputCount; int m_outputCount; @@ -182,7 +182,6 @@ RemotePluginClient::RemotePluginClient( const std::string& _shm_in, const std::s RemotePluginClient::RemotePluginClient( const char * socketPath ) : RemotePluginBase(), #endif - m_vstSyncData( nullptr ), m_inputCount( 0 ), m_outputCount( 0 ), m_sampleRate( 44100 ), @@ -211,26 +210,6 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) : fprintf( stderr, "Could not connect to local server.\n" ); } #endif - - try - { - m_vstSyncShm.attach("usr_bin_lmms"); - m_vstSyncData = m_vstSyncShm.get(); - m_bufferSize = m_vstSyncData->m_bufferSize; - m_sampleRate = m_vstSyncData->m_sampleRate; - } - catch (const std::runtime_error&) - { - // if attaching shared memory fails - sendMessage( IdSampleRateInformation ); - sendMessage( IdBufferSizeInformation ); - if( waitForMessage( IdBufferSizeInformation ).id - != IdBufferSizeInformation ) - { - fprintf( stderr, "Could not get buffer size information\n" ); - } - } - sendMessage( IdHostInfoGotten ); } @@ -253,7 +232,7 @@ RemotePluginClient::~RemotePluginClient() const VstSyncData* RemotePluginClient::getVstSyncData() { - return m_vstSyncData; + return m_vstSyncData.get(); } @@ -268,6 +247,22 @@ bool RemotePluginClient::processMessage( const message & _m ) case IdUndefined: return false; + case IdSyncKey: + try + { + m_vstSyncData.attach(_m.getString(0)); + } + catch (const std::runtime_error& error) + { + debugMessage(std::string{"Failed to attach sync data: "} + error.what() + '\n'); + std::exit(EXIT_FAILURE); + } + m_bufferSize = m_vstSyncData->m_bufferSize; + m_sampleRate = m_vstSyncData->m_sampleRate; + reply_message.id = IdHostInfoGotten; + reply = true; + break; + case IdSampleRateInformation: m_sampleRate = _m.getInt(); updateSampleRate(); diff --git a/include/SetupDialog.h b/include/SetupDialog.h index 9ce6e043d..40d552d63 100644 --- a/include/SetupDialog.h +++ b/include/SetupDialog.h @@ -95,7 +95,6 @@ private slots: void toggleRunningAutoSave(bool enabled); void toggleSmoothScroll(bool enabled); void toggleAnimateAFP(bool enabled); - void toggleSyncVSTPlugins(bool enabled); void vstEmbedMethodChanged(); void toggleVSTAlwaysOnTop(bool en); void toggleDisableAutoQuit(bool enabled); @@ -164,7 +163,6 @@ private: QString m_vstEmbedMethod; LedCheckBox * m_vstAlwaysOnTopCheckBox; bool m_vstAlwaysOnTop; - bool m_syncVSTPlugins; bool m_disableAutoQuit; diff --git a/include/Song.h b/include/Song.h index 422e645bf..569b3ad14 100644 --- a/include/Song.h +++ b/include/Song.h @@ -366,6 +366,8 @@ public: void setScale(unsigned int index, std::shared_ptr newScale); void setKeymap(unsigned int index, std::shared_ptr newMap); + const std::string& syncKey() const noexcept { return m_vstSyncController.sharedMemoryKey(); } + public slots: void playSong(); void record(); diff --git a/include/VstSyncController.h b/include/VstSyncController.h index d5e6617cd..c70bc85c8 100644 --- a/include/VstSyncController.h +++ b/include/VstSyncController.h @@ -40,45 +40,23 @@ class VstSyncController : public QObject Q_OBJECT public: VstSyncController(); - ~VstSyncController() override; - - void setAbsolutePosition( double ticks ); - - void setPlaybackState( bool enabled ) - { - m_syncData->isPlaying = enabled; - } - - void setTempo( int newTempo ); - - void setTimeSignature( int num, int denom ) - { - m_syncData->timeSigNumer = num; - m_syncData->timeSigDenom = denom; - } - - void startCycle( int startTick, int endTick ); - - void stopCycle() - { - m_syncData->isCycle = false; - } - - void setPlaybackJumped( bool jumped ) - { - m_syncData->m_playbackJumped = jumped; - } + void setAbsolutePosition(double ticks); + void setPlaybackState(bool enabled); + void setTempo(int newTempo); + void setTimeSignature(int num, int denom); + void startCycle(int startTick, int endTick); + void stopCycle(); + void setPlaybackJumped(bool jumped); void update(); + const std::string& sharedMemoryKey() const noexcept { return m_syncData.key(); } private slots: void updateSampleRate(); - private: - VstSyncData* m_syncData; - SharedMemory m_shm; + SharedMemory m_syncData; }; diff --git a/include/VstSyncData.h b/include/VstSyncData.h index bf4d42b80..baf3fa7a8 100644 --- a/include/VstSyncData.h +++ b/include/VstSyncData.h @@ -46,7 +46,6 @@ struct VstSyncData int timeSigDenom; bool isPlaying; bool isCycle; - bool hasSHM; float cycleStart; float cycleEnd; bool m_playbackJumped; diff --git a/plugins/VstBase/RemoteVstPlugin.cpp b/plugins/VstBase/RemoteVstPlugin.cpp index 520211f68..a94ea5e3a 100644 --- a/plugins/VstBase/RemoteVstPlugin.cpp +++ b/plugins/VstBase/RemoteVstPlugin.cpp @@ -491,10 +491,7 @@ private: } ; in * m_in; - - const VstSyncData* m_vstSyncData; - -} ; +}; @@ -523,29 +520,10 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) : m_bpm( 0 ), m_currentSamplePos( 0 ), m_currentProgram( -1 ), - m_in( nullptr ), - m_vstSyncData( nullptr ) + m_in( nullptr ) { __plugin = this; - m_vstSyncData = RemotePluginClient::getVstSyncData(); - if( m_vstSyncData == nullptr ) - { - fprintf(stderr, "RemoteVstPlugin.cpp: " - "Failed to initialize shared memory for VST synchronization.\n" - " (VST-host synchronization will be disabled)\n"); - const auto vstSyncData = (VstSyncData*) malloc( sizeof( VstSyncData ) ); - vstSyncData->isPlaying = true; - vstSyncData->timeSigNumer = 4; - vstSyncData->timeSigDenom = 4; - vstSyncData->ppqPos = 0; - vstSyncData->isCycle = false; - vstSyncData->hasSHM = false; - vstSyncData->m_playbackJumped = false; - vstSyncData->m_sampleRate = sampleRate(); - m_vstSyncData = vstSyncData; - } - m_in = ( in* ) new char[ sizeof( in ) ]; m_in->lastppqPos = 0; m_in->m_Timestamp = -1; @@ -572,12 +550,6 @@ RemoteVstPlugin::~RemoteVstPlugin() setResumed( false ); pluginDispatch( effClose ); - if (!m_vstSyncData->hasSHM) - { - delete m_vstSyncData; - m_vstSyncData = nullptr; - } - if( m_libInst != nullptr ) { #ifndef NATIVE_LINUX_VST @@ -1808,86 +1780,71 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, return 0; case audioMasterGetTime: + { SHOW_CALLBACK( "amc: audioMasterGetTime\n" ); // returns const VstTimeInfo* (or 0 if not supported) // should contain a mask indicating which // fields are required (see valid masks above), as some // items may require extensive conversions - // Shared memory was initialised? - see song.cpp - //assert( __plugin->m_vstSyncData != nullptr ); + const auto syncData = __plugin->getVstSyncData(); + assert(syncData != nullptr); memset( &_timeInfo, 0, sizeof( _timeInfo ) ); _timeInfo.samplePos = __plugin->m_currentSamplePos; - _timeInfo.sampleRate = __plugin->m_vstSyncData->hasSHM ? - __plugin->m_vstSyncData->m_sampleRate : - __plugin->sampleRate(); + _timeInfo.sampleRate = syncData->m_sampleRate; _timeInfo.flags = 0; - _timeInfo.tempo = __plugin->m_vstSyncData->hasSHM ? - __plugin->m_vstSyncData->m_bpm : - __plugin->m_bpm; - _timeInfo.timeSigNumerator = __plugin->m_vstSyncData->timeSigNumer; - _timeInfo.timeSigDenominator = __plugin->m_vstSyncData->timeSigDenom; + _timeInfo.tempo = syncData->m_bpm; + _timeInfo.timeSigNumerator = syncData->timeSigNumer; + _timeInfo.timeSigDenominator = syncData->timeSigDenom; _timeInfo.flags |= kVstTempoValid; _timeInfo.flags |= kVstTimeSigValid; - if( __plugin->m_vstSyncData->isCycle ) + if (syncData->isCycle) { - _timeInfo.cycleStartPos = __plugin->m_vstSyncData->cycleStart; - _timeInfo.cycleEndPos = __plugin->m_vstSyncData->cycleEnd; + _timeInfo.cycleStartPos = syncData->cycleStart; + _timeInfo.cycleEndPos = syncData->cycleEnd; _timeInfo.flags |= kVstCyclePosValid; _timeInfo.flags |= kVstTransportCycleActive; } - if( __plugin->m_vstSyncData->ppqPos != - __plugin->m_in->m_Timestamp ) + if (syncData->ppqPos != __plugin->m_in->m_Timestamp) { - _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos; - __plugin->m_in->lastppqPos = __plugin->m_vstSyncData->ppqPos; - __plugin->m_in->m_Timestamp = __plugin->m_vstSyncData->ppqPos; + _timeInfo.ppqPos = syncData->ppqPos; + __plugin->m_in->lastppqPos = syncData->ppqPos; + __plugin->m_in->m_Timestamp = syncData->ppqPos; } - else if( __plugin->m_vstSyncData->isPlaying ) + else if (syncData->isPlaying) { - if( __plugin->m_vstSyncData->hasSHM ) - { - __plugin->m_in->lastppqPos += - __plugin->m_vstSyncData->m_bpm / 60.0 - * __plugin->m_vstSyncData->m_bufferSize - / __plugin->m_vstSyncData->m_sampleRate; - } - else - { - __plugin->m_in->lastppqPos += - __plugin->m_bpm / 60.0 - * __plugin->bufferSize() - / __plugin->sampleRate(); - } + __plugin->m_in->lastppqPos += + syncData->m_bpm / 60.0 + * syncData->m_bufferSize + / syncData->m_sampleRate; _timeInfo.ppqPos = __plugin->m_in->lastppqPos; } -// _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos; +// _timeInfo.ppqPos = syncData->ppqPos; _timeInfo.flags |= kVstPpqPosValid; - if( __plugin->m_vstSyncData->isPlaying ) + if (syncData->isPlaying) { _timeInfo.flags |= kVstTransportPlaying; } - _timeInfo.barStartPos = ( (int) ( _timeInfo.ppqPos / - ( 4 *__plugin->m_vstSyncData->timeSigNumer - / (float) __plugin->m_vstSyncData->timeSigDenom ) ) ) * - ( 4 * __plugin->m_vstSyncData->timeSigNumer - / (float) __plugin->m_vstSyncData->timeSigDenom ); + _timeInfo.barStartPos = ((int) (_timeInfo.ppqPos + / (4 * syncData->timeSigNumer / (float) syncData->timeSigDenom))) + * (4 * syncData->timeSigNumer / (float) syncData->timeSigDenom); _timeInfo.flags |= kVstBarsValid; - if( ( _timeInfo.flags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) != - ( __plugin->m_in->m_lastFlags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) - || __plugin->m_vstSyncData->m_playbackJumped ) + if ((_timeInfo.flags & (kVstTransportPlaying | kVstTransportCycleActive)) + != (__plugin->m_in->m_lastFlags & (kVstTransportPlaying | kVstTransportCycleActive)) + || syncData->m_playbackJumped) { _timeInfo.flags |= kVstTransportChanged; } __plugin->m_in->m_lastFlags = _timeInfo.flags; return (intptr_t) &_timeInfo; + } case audioMasterProcessEvents: SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" ); diff --git a/src/core/RemotePlugin.cpp b/src/core/RemotePlugin.cpp index 62ed9b653..416767011 100644 --- a/src/core/RemotePlugin.cpp +++ b/src/core/RemotePlugin.cpp @@ -36,6 +36,7 @@ #include "BufferManager.h" #include "AudioEngine.h" #include "Engine.h" +#include "Song.h" #include #include @@ -309,6 +310,7 @@ bool RemotePlugin::init(const QString &pluginExecutable, } #endif + sendMessage(message(IdSyncKey).addString(Engine::getSong()->syncKey())); resizeSharedProcessingMemory(); if( waitForInitDoneMsg ) diff --git a/src/core/VstSyncController.cpp b/src/core/VstSyncController.cpp index a08831662..c4b59eb6f 100644 --- a/src/core/VstSyncController.cpp +++ b/src/core/VstSyncController.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "AudioEngine.h" #include "ConfigManager.h" @@ -39,36 +40,16 @@ namespace lmms { -VstSyncController::VstSyncController() : - m_syncData( nullptr ) +VstSyncController::VstSyncController() { - if( ConfigManager::inst()->value( "ui", "syncvstplugins" ).toInt() ) + try { - connect( Engine::audioEngine(), SIGNAL(sampleRateChanged()), this, SLOT(updateSampleRate())); - - try - { - m_shm.create("usr_bin_lmms"); - m_syncData = m_shm.get(); - } - catch (const std::runtime_error& error) - { - qWarning() << "Failed to allocate shared memory for VST sync:" << error.what(); - } + m_syncData.create(QUuid::createUuid().toString().toStdString()); } - else + catch (const std::runtime_error& error) { - qWarning( "VST sync support disabled in your configuration" ); - } - - if( m_syncData == nullptr ) - { - m_syncData = new VstSyncData; - m_syncData->hasSHM = false; - } - else - { - m_syncData->hasSHM = true; + qCritical() << "Failed to allocate shared memory for VST sync:" << error.what(); + return; } m_syncData->isPlaying = false; @@ -76,23 +57,16 @@ VstSyncController::VstSyncController() : m_syncData->timeSigNumer = 4; m_syncData->timeSigDenom = 4; + connect(Engine::audioEngine(), &AudioEngine::sampleRateChanged, this, &VstSyncController::updateSampleRate); updateSampleRate(); } -VstSyncController::~VstSyncController() +void VstSyncController::setAbsolutePosition(double ticks) { - if( m_syncData->hasSHM == false ) - { - delete m_syncData; - } -} + if (!m_syncData) { return; } - - -void VstSyncController::setAbsolutePosition( double ticks ) -{ #ifdef VST_SNC_LATENCY m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 ) - m_syncData->m_latency; #else @@ -102,8 +76,19 @@ void VstSyncController::setAbsolutePosition( double ticks ) -void VstSyncController::setTempo( int newTempo ) +void VstSyncController::setPlaybackState(bool enabled) { + if (!m_syncData) { return; } + + m_syncData->isPlaying = enabled; +} + + + +void VstSyncController::setTempo(int newTempo) +{ + if (!m_syncData) { return; } + m_syncData->m_bpm = newTempo; #ifdef VST_SNC_LATENCY @@ -114,8 +99,20 @@ void VstSyncController::setTempo( int newTempo ) -void VstSyncController::startCycle( int startTick, int endTick ) +void VstSyncController::setTimeSignature(int num, int denom) { + if (!m_syncData) { return; } + + m_syncData->timeSigNumer = num; + m_syncData->timeSigDenom = denom; +} + + + +void VstSyncController::startCycle(int startTick, int endTick) +{ + if (!m_syncData) { return; } + m_syncData->isCycle = true; m_syncData->cycleStart = startTick / (float)48; m_syncData->cycleEnd = endTick / (float)48; @@ -123,8 +120,28 @@ void VstSyncController::startCycle( int startTick, int endTick ) +void VstSyncController::stopCycle() +{ + if (!m_syncData) { return; } + + m_syncData->isCycle = false; +} + + + +void VstSyncController::setPlaybackJumped(bool jumped) +{ + if (!m_syncData) { return; } + + m_syncData->m_playbackJumped = jumped; +} + + + void VstSyncController::update() { + if (!m_syncData) { return; } + m_syncData->m_bufferSize = Engine::audioEngine()->framesPerPeriod(); #ifdef VST_SNC_LATENCY @@ -136,6 +153,8 @@ void VstSyncController::update() void VstSyncController::updateSampleRate() { + if (!m_syncData) { return; } + m_syncData->m_sampleRate = Engine::audioEngine()->processingSampleRate(); #ifdef VST_SNC_LATENCY diff --git a/src/gui/modals/SetupDialog.cpp b/src/gui/modals/SetupDialog.cpp index 9c15f5b53..f6b6428d7 100644 --- a/src/gui/modals/SetupDialog.cpp +++ b/src/gui/modals/SetupDialog.cpp @@ -136,8 +136,6 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : m_vstEmbedMethod(ConfigManager::inst()->vstEmbedMethod()), m_vstAlwaysOnTop(ConfigManager::inst()->value( "ui", "vstalwaysontop").toInt()), - m_syncVSTPlugins(ConfigManager::inst()->value( - "ui", "syncvstplugins", "1").toInt()), m_disableAutoQuit(ConfigManager::inst()->value( "ui", "disableautoquit", "1").toInt()), m_NaNHandler(ConfigManager::inst()->value( @@ -433,9 +431,6 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : connect(m_vstAlwaysOnTopCheckBox, SIGNAL(toggled(bool)), this, SLOT(toggleVSTAlwaysOnTop(bool))); - addLedCheckBox(tr("Sync VST plugins to host playback"), plugins_tw, counter, - m_syncVSTPlugins, SLOT(toggleSyncVSTPlugins(bool)), false); - addLedCheckBox(tr("Keep effects running even without input"), plugins_tw, counter, m_disableAutoQuit, SLOT(toggleDisableAutoQuit(bool)), false); @@ -948,8 +943,6 @@ void SetupDialog::accept() m_vstEmbedComboBox->currentData().toString()); ConfigManager::inst()->setValue("ui", "vstalwaysontop", QString::number(m_vstAlwaysOnTop)); - ConfigManager::inst()->setValue("ui", "syncvstplugins", - QString::number(m_syncVSTPlugins)); ConfigManager::inst()->setValue("ui", "disableautoquit", QString::number(m_disableAutoQuit)); ConfigManager::inst()->setValue("audioengine", "audiodev", @@ -1130,12 +1123,6 @@ void SetupDialog::toggleAnimateAFP(bool enabled) } -void SetupDialog::toggleSyncVSTPlugins(bool enabled) -{ - m_syncVSTPlugins = enabled; -} - - void SetupDialog::vstEmbedMethodChanged() { m_vstEmbedMethod = m_vstEmbedComboBox->currentData().toString();