Skip to content

Commit d51b13e

Browse files
committed
flanger crackles fix
1 parent bb31872 commit d51b13e

1 file changed

Lines changed: 165 additions & 1 deletion

File tree

src/MistralProcessor.cpp

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void MistralAudioProcessor::releaseResources()
3434
{
3535
delayBuffer.clear();
3636
}
37-
37+
/*
3838
void MistralAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
3939
{
4040
juce::ScopedNoDenormals noDenormals;
@@ -100,6 +100,170 @@ void MistralAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce
100100
writePosition = 0;
101101
}
102102
}
103+
*/
104+
105+
/*
106+
void MistralAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
107+
{
108+
juce::ScopedNoDenormals noDenormals;
109+
110+
float targetRate = apvts.getRawParameterValue("rate")->load();
111+
float targetDepth = apvts.getRawParameterValue("depth")->load();
112+
float targetFeedback = apvts.getRawParameterValue("feedback")->load();
113+
114+
targetFeedback = juce::jmin(0.9f, targetFeedback);
115+
116+
// Инициализация сглаженных параметров при первом вызове
117+
static float smoothRate = targetRate;
118+
static float smoothDepth = targetDepth;
119+
static float smoothFeedback = targetFeedback;
120+
121+
// Коэффициент сглаживания (чем меньше, тем плавнее, но медленнее реакция)
122+
const float smoothing = 0.995f; // Быстрая, но плавная реакция (~1 мс)
123+
124+
// Плавное обновление параметров
125+
smoothRate = smoothRate * smoothing + targetRate * (1.0f - smoothing);
126+
smoothDepth = smoothDepth * smoothing + targetDepth * (1.0f - smoothing);
127+
smoothFeedback = smoothFeedback * smoothing + targetFeedback * (1.0f - smoothing);
128+
129+
float rate = smoothRate;
130+
float depth = smoothDepth;
131+
float feedback = smoothFeedback;
132+
133+
float lfoFreq = 0.1f + rate * 4.9f;
134+
135+
float minDelayMs = 0.5f;
136+
float maxDelayMs = 8.0f;
137+
float delayRangeMs = maxDelayMs - minDelayMs;
138+
139+
int numSamples = buffer.getNumSamples();
140+
int numChannels = buffer.getNumChannels();
141+
142+
for (int sample = 0; sample < numSamples; ++sample)
143+
{
144+
float lfo = std::sin(phase);
145+
lfo = (lfo + 1.0f) / 2.0f;
146+
147+
phase += 2.0f * juce::MathConstants<float>::pi * lfoFreq / sampleRate;
148+
if (phase >= juce::MathConstants<float>::twoPi)
149+
phase -= juce::MathConstants<float>::twoPi;
150+
151+
for (int channel = 0; channel < numChannels; ++channel)
152+
{
153+
float delayMs = minDelayMs + lfo * depth * delayRangeMs;
154+
float delaySamples = delayMs * sampleRate / 1000.0f;
155+
156+
float* channelData = buffer.getWritePointer(channel);
157+
float input = channelData[sample];
158+
159+
float readPos = (float)writePosition - delaySamples;
160+
if (readPos < 0) readPos += maxDelaySamples;
161+
162+
int readPosInt = (int)readPos;
163+
float frac = readPos - readPosInt;
164+
int readPosNext = readPosInt + 1;
165+
if (readPosNext >= maxDelaySamples) readPosNext = 0;
166+
167+
float delayed = delayBuffer.getSample(channel, readPosInt) * (1.0f - frac) +
168+
delayBuffer.getSample(channel, readPosNext) * frac;
169+
170+
float writeValue = input + delayed * feedback;
171+
writeValue = juce::jlimit(-1.0f, 1.0f, writeValue);
172+
delayBuffer.setSample(channel, writePosition, writeValue);
173+
174+
float output = input * (1.0f - depth) + delayed * depth;
175+
176+
channelData[sample] = output;
177+
}
178+
179+
writePosition++;
180+
if (writePosition >= maxDelaySamples)
181+
writePosition = 0;
182+
}
183+
}
184+
*/
185+
186+
void MistralAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
187+
{
188+
juce::ScopedNoDenormals noDenormals;
189+
190+
float targetRate = apvts.getRawParameterValue("rate")->load();
191+
float targetDepth = apvts.getRawParameterValue("depth")->load();
192+
float targetFeedback = apvts.getRawParameterValue("feedback")->load();
193+
targetFeedback = juce::jmin(0.9f, targetFeedback);
194+
195+
static float smoothRate = targetRate;
196+
static float smoothDepth = targetDepth;
197+
static float smoothFeedback = targetFeedback;
198+
199+
// Плавное сглаживание (без адаптации для простоты)
200+
const float smoothing = 0.995f;
201+
smoothRate = smoothRate * smoothing + targetRate * (1.0f - smoothing);
202+
smoothDepth = smoothDepth * smoothing + targetDepth * (1.0f - smoothing);
203+
smoothFeedback = smoothFeedback * smoothing + targetFeedback * (1.0f - smoothing);
204+
205+
float rate = smoothRate;
206+
float depth = smoothDepth;
207+
float feedback = smoothFeedback;
208+
209+
float lfoFreq = 0.1f + rate * 4.9f;
210+
211+
float minDelayMs = 0.5f;
212+
float maxDelayMs = 8.0f;
213+
float delayRangeMs = maxDelayMs - minDelayMs;
214+
215+
int numSamples = buffer.getNumSamples();
216+
int numChannels = buffer.getNumChannels();
217+
218+
// === КЛЮЧЕВОЕ ИЗМЕНЕНИЕ: интерполяция позиции чтения ===
219+
static float currentDelaySamples = 0.0f;
220+
221+
for (int sample = 0; sample < numSamples; ++sample)
222+
{
223+
float lfo = std::sin(phase);
224+
lfo = (lfo + 1.0f) / 2.0f;
225+
226+
phase += 2.0f * juce::MathConstants<float>::pi * lfoFreq / sampleRate;
227+
if (phase >= juce::MathConstants<float>::twoPi)
228+
phase -= juce::MathConstants<float>::twoPi;
229+
230+
// Целевая задержка на основе текущего depth
231+
float targetDelaySamples = (minDelayMs + lfo * depth * delayRangeMs) * sampleRate / 1000.0f;
232+
233+
// Плавная интерполяция позиции чтения (устраняет треск!)
234+
currentDelaySamples = currentDelaySamples * 0.99f + targetDelaySamples * 0.01f;
235+
236+
for (int channel = 0; channel < numChannels; ++channel)
237+
{
238+
float* channelData = buffer.getWritePointer(channel);
239+
float input = channelData[sample];
240+
241+
float readPos = (float)writePosition - currentDelaySamples;
242+
if (readPos < 0) readPos += maxDelaySamples;
243+
244+
int readPosInt = (int)readPos;
245+
float frac = readPos - readPosInt;
246+
int readPosNext = readPosInt + 1;
247+
if (readPosNext >= maxDelaySamples) readPosNext = 0;
248+
249+
float delayed = delayBuffer.getSample(channel, readPosInt) * (1.0f - frac) +
250+
delayBuffer.getSample(channel, readPosNext) * frac;
251+
252+
float writeValue = input + delayed * feedback;
253+
writeValue = juce::jlimit(-1.0f, 1.0f, writeValue);
254+
delayBuffer.setSample(channel, writePosition, writeValue);
255+
256+
float output = input * (1.0f - depth) + delayed * depth;
257+
258+
channelData[sample] = output;
259+
}
260+
261+
writePosition++;
262+
if (writePosition >= maxDelaySamples)
263+
writePosition = 0;
264+
}
265+
}
266+
103267

104268
void MistralAudioProcessor::processBlock (juce::AudioBuffer<double>& buffer, juce::MidiBuffer& midiMessages)
105269
{

0 commit comments

Comments
 (0)