gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit bc46fe6d5ef285377a7be9e6a8a2c69ac8a8025d
parent a787f4ae03dea7ac1c405d93e54a73533c1b3225
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sun, 22 May 2022 16:31:36 +0200

add ability to adjust plugin latency

Diffstat:
Msource/jucePlugin/PluginEditor.cpp | 27++++++++++++++++++++++++++-
Msource/jucePlugin/PluginEditor.h | 1+
Msource/jucePlugin/PluginProcessor.cpp | 13+++++++++----
Msource/jucePlugin/PluginProcessor.h | 3+++
Msource/synthLib/plugin.cpp | 19+++++++++++++++----
Msource/synthLib/plugin.h | 4++++
6 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/source/jucePlugin/PluginEditor.cpp b/source/jucePlugin/PluginEditor.cpp @@ -28,8 +28,10 @@ AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudi } loadSkin(skin); - setGuiScale(scale); + + const auto latencyBlocks = config->getIntValue("latencyBlocks", static_cast<int>(processorRef.getPlugin().getLatencyBlocks())); + setLatencyBlocks(latencyBlocks); } void AudioPluginAudioProcessorEditor::loadSkin(const Skin& _skin) @@ -150,8 +152,17 @@ void AudioPluginAudioProcessorEditor::openMenu() scaleMenu.addItem("200%", true, scale == 200, [this] { setGuiScale(200); }); scaleMenu.addItem("300%", true, scale == 300, [this] { setGuiScale(300); }); + const auto latency = processorRef.getPlugin().getLatencyBlocks(); + juce::PopupMenu latencyMenu; + latencyMenu.addItem("0 (DAW will report proper CPU usage)", true, latency == 0, [this] { setLatencyBlocks(0); }); + latencyMenu.addItem("1 (default)", true, latency == 1, [this] { setLatencyBlocks(1); }); + latencyMenu.addItem("2", true, latency == 2, [this] { setLatencyBlocks(2); }); + latencyMenu.addItem("4", true, latency == 4, [this] { setLatencyBlocks(4); }); + latencyMenu.addItem("8", true, latency == 8, [this] { setLatencyBlocks(8); }); + menu.addSubMenu("GUI Skin", skinMenu); menu.addSubMenu("GUI Scale", scaleMenu); + menu.addSubMenu("Latency (blocks)", latencyMenu); menu.showMenuAsync(juce::PopupMenu::Options()); } @@ -198,6 +209,20 @@ void AudioPluginAudioProcessorEditor::writeSkinToConfig(const Skin& _skin) const config->setValue("skinFolder", _skin.folder.c_str()); } +void AudioPluginAudioProcessorEditor::setLatencyBlocks(uint32_t _blocks) const +{ + auto& p = processorRef.getPlugin(); + + if(p.setLatencyBlocks(_blocks)) + { + processorRef.updateLatencySamples(); + + auto* config = processorRef.getController().getConfig(); + config->setValue("latencyBlocks", static_cast<int>(_blocks)); + config->saveIfNeeded(); + } +} + AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor() { m_virusEditor.reset(); diff --git a/source/jucePlugin/PluginEditor.h b/source/jucePlugin/PluginEditor.h @@ -35,6 +35,7 @@ private: void exportCurrentSkin() const; Skin readSkinFromConfig() const; void writeSkinToConfig(const Skin& _skin) const; + void setLatencyBlocks(uint32_t _blocks) const; // This reference is provided as a quick way for your editor to // access the processor object that created it. diff --git a/source/jucePlugin/PluginProcessor.cpp b/source/jucePlugin/PluginProcessor.cpp @@ -93,10 +93,7 @@ void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPer m_plugin.setSamplerate(static_cast<float>(sampleRate)); m_plugin.setBlockSize(samplesPerBlock); - if constexpr(JucePlugin_IsSynth) - setLatencySamples(m_plugin.getLatencyMidiToOutput()); - else - setLatencySamples(m_plugin.getLatencyInputToOutput()); + updateLatencySamples(); } void AudioPluginAudioProcessor::releaseResources() @@ -403,6 +400,14 @@ void AudioPluginAudioProcessor::handleIncomingMidiMessage(juce::MidiInput *sourc } } +void AudioPluginAudioProcessor::updateLatencySamples() +{ + if constexpr(JucePlugin_IsSynth) + setLatencySamples(m_plugin.getLatencyMidiToOutput()); + else + setLatencySamples(m_plugin.getLatencyInputToOutput()); +} + Virus::Controller &AudioPluginAudioProcessor::getController() { if (m_controller == nullptr) diff --git a/source/jucePlugin/PluginProcessor.h b/source/jucePlugin/PluginProcessor.h @@ -63,6 +63,9 @@ public: std::string getRomName() { return juce::File(juce::String(m_romName)).getFileNameWithoutExtension().toStdString(); } + + void updateLatencySamples(); + // _____________ // private: diff --git a/source/synthLib/plugin.cpp b/source/synthLib/plugin.cpp @@ -16,7 +16,6 @@ using namespace synthLib; namespace synthLib { constexpr uint8_t g_stateVersion = 1; - constexpr uint32_t g_extraLatencyBlocks = 1; Plugin::Plugin(Device* _device) : m_device(_device) { @@ -137,6 +136,18 @@ namespace synthLib m_midiIn.push_back(_ev); } + bool Plugin::setLatencyBlocks(uint32_t _latencyBlocks) + { + std::lock_guard lock(m_lock); + + if(m_extraLatencyBlocks == _latencyBlocks) + return false; + + m_extraLatencyBlocks = _latencyBlocks; + updateDeviceLatency(); + return true; + } + void Plugin::processMidiClock(float _bpm, float _ppqPos, bool _isPlaying, size_t _sampleCount) { if(_bpm < 1.0f) @@ -214,7 +225,7 @@ namespace synthLib if(m_blockSize <= 0 || m_hostSamplerate <= 0) return; - const auto latency = static_cast<uint32_t>(std::ceil(static_cast<float>(m_blockSize * g_extraLatencyBlocks) * m_device->getSamplerate() * m_hostSamplerateInv)); + const auto latency = static_cast<uint32_t>(std::ceil(static_cast<float>(m_blockSize * m_extraLatencyBlocks) * m_device->getSamplerate() * m_hostSamplerateInv)); m_device->setExtraLatencySamples(latency); m_deviceLatencyMidiToOutput = static_cast<uint32_t>(static_cast<float>(m_device->getInternalLatencyMidiToOutput()) * m_hostSamplerate / m_device->getSamplerate()); @@ -278,12 +289,12 @@ namespace synthLib uint32_t Plugin::getLatencyMidiToOutput() const { std::lock_guard lock(m_lock); - return m_blockSize * g_extraLatencyBlocks + m_deviceLatencyMidiToOutput + m_resampler.getOutputLatency(); + return m_blockSize * m_extraLatencyBlocks + m_deviceLatencyMidiToOutput + m_resampler.getOutputLatency(); } uint32_t Plugin::getLatencyInputToOutput() const { std::lock_guard lock(m_lock); - return m_blockSize * g_extraLatencyBlocks + m_deviceLatencyInputToOutput + m_resampler.getOutputLatency() + m_resampler.getInputLatency(); + return m_blockSize * m_extraLatencyBlocks + m_deviceLatencyInputToOutput + m_resampler.getOutputLatency() + m_resampler.getInputLatency(); } } diff --git a/source/synthLib/plugin.h b/source/synthLib/plugin.h @@ -36,6 +36,9 @@ namespace synthLib void insertMidiEvent(const SMidiEvent& _ev); + bool setLatencyBlocks(uint32_t _latencyBlocks); + uint32_t getLatencyBlocks() const { return m_extraLatencyBlocks; } + private: void processMidiClock(float _bpm, float _ppqPos, bool _isPlaying, size_t _sampleCount); float* getDummyBuffer(size_t _minimumSize); @@ -69,5 +72,6 @@ namespace synthLib bool m_isPlaying = false; bool m_needsStart = false; double m_clockTickPos = 0.0; + uint32_t m_extraLatencyBlocks = 1; }; }