commit 4eadf87f607cc26ece3da8e56abc12421cad19a9
parent 7798f8b3d7bcbf24daa45596b666cf4410e1c84e
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Fri, 25 Oct 2024 00:13:04 +0200
correctly apply latency when plugin is bypassed
Diffstat:
6 files changed, 97 insertions(+), 0 deletions(-)
diff --git a/doc/changelog.txt b/doc/changelog.txt
@@ -30,6 +30,9 @@ Framework:
For backwards compatibility, it is also possible to copy ROMs next to the
plugins as it was before
+- [Fix] FX plugins didn't apply latency when being processed as bypassed, causing the
+ signal to appear early
+
NodalRed2x:
- [Imp] Added indicator around knobs to show the current VMMap parameter value
diff --git a/source/jucePluginLib/CMakeLists.txt b/source/jucePluginLib/CMakeLists.txt
@@ -7,6 +7,7 @@ file(TOUCH_NOCREATE ${CMAKE_CURRENT_LIST_DIR}/version.h.in)
file(TOUCH_NOCREATE ${CMAKE_CURRENT_LIST_DIR}/versionDateTime.h.in)
set(SOURCES
+ bypassBuffer.cpp bypassBuffer.h
createVersionDateTime.cmake
clipboard.cpp clipboard.h
controller.cpp controller.h
diff --git a/source/jucePluginLib/bypassBuffer.cpp b/source/jucePluginLib/bypassBuffer.cpp
@@ -0,0 +1,5 @@
+#include "bypassBuffer.h"
+
+namespace pluginLib
+{
+}
diff --git a/source/jucePluginLib/bypassBuffer.h b/source/jucePluginLib/bypassBuffer.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <vector>
+
+#include "dsp56kEmu/ringbuffer.h"
+
+namespace pluginLib
+{
+ class BypassBuffer
+ {
+ public:
+ using ChannelBuffer = dsp56k::RingBuffer<float, 32768, false, true>;
+
+ void write(const float* _data, uint32_t _channel, uint32_t _samples, uint32_t _latency)
+ {
+ if(_channel >= m_channels.size())
+ {
+ m_channels.resize(_channel + 1);
+ m_latency.resize(_channel + 1);
+ }
+
+ auto& ch = m_channels[_channel];
+ auto& latency = m_latency[_channel];
+
+ while(_latency > latency)
+ {
+ ++latency;
+ ch.push_back(0.0f);
+ }
+
+ while(_latency < latency)
+ {
+ --latency;
+ ch.pop_front();
+ }
+
+ for(uint32_t i=0; i<_samples; ++i)
+ ch.push_back(_data[i]);
+ }
+
+ void read(float* _output, uint32_t _channel, const uint32_t _samples)
+ {
+ if(_channel >= m_channels.size())
+ return;
+
+ for(uint32_t i=0; i<_samples; ++i)
+ _output[i] = m_channels[_channel].pop_front();
+ }
+
+ private:
+ std::vector<ChannelBuffer> m_channels;
+ std::vector<uint32_t> m_latency;
+ };
+}
diff --git a/source/jucePluginLib/processor.cpp b/source/jucePluginLib/processor.cpp
@@ -583,6 +583,37 @@ namespace pluginLib
}
}
+ void Processor::processBlockBypassed(juce::AudioBuffer<float>& _buffer, juce::MidiBuffer& _midiMessages)
+ {
+ if(getProperties().isSynth || getTotalNumInputChannels() <= 0)
+ {
+ _buffer.clear(0, _buffer.getNumSamples());
+ return;
+ }
+
+ const auto sampleCount = static_cast<uint32_t>(_buffer.getNumSamples());
+ const auto outCount = static_cast<uint32_t>(getTotalNumOutputChannels());
+ const auto inCount = static_cast<uint32_t>(getTotalNumInputChannels());
+
+ uint32_t inCh = 0;
+
+ for(uint32_t outCh=0; outCh<outCount; ++outCh)
+ {
+ auto* input = _buffer.getReadPointer(static_cast<int>(inCh));
+ auto* output = _buffer.getWritePointer(static_cast<int>(outCh));
+
+ m_bypassBuffer.write(input, outCh, sampleCount, getLatencySamples());
+ m_bypassBuffer.read(output, outCh, sampleCount);
+
+ ++inCh;
+
+ if(inCh >= inCount)
+ inCh = 0;
+ }
+
+// AudioProcessor::processBlockBypassed(_buffer, _midiMessages);
+ }
+
#if !SYNTHLIB_DEMO_MODE
void Processor::setState(const void* _data, const size_t _sizeInBytes)
{
diff --git a/source/jucePluginLib/processor.h b/source/jucePluginLib/processor.h
@@ -3,6 +3,7 @@
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_audio_devices/juce_audio_devices.h>
+#include "bypassBuffer.h"
#include "controller.h"
#include "midiports.h"
@@ -137,6 +138,7 @@ namespace pluginLib
bool producesMidi() const override;
bool isMidiEffect() const override;
void processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) override;
+ void processBlockBypassed(juce::AudioBuffer<float>& _buffer, juce::MidiBuffer& _midiMessages) override;
#if !SYNTHLIB_DEMO_MODE
void setState(const void *_data, size_t _sizeInBytes);
@@ -172,5 +174,6 @@ namespace pluginLib
float m_preferredDeviceSamplerate = 0.0f;
float m_hostSamplerate = 0.0f;
MidiPorts m_midiPorts;
+ BypassBuffer m_bypassBuffer;
};
}