Hi, I updated my wavetable synth to run each synthesizer instance in a different audioprocessor so I can do different dsp on each of them. Right after doing this a crackling noise appeared even if I turn down the volume of the other synth. Does anybody have an idea what might cause this?
PluginProcessor.cpp:
void GeoHeadAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
ignoreUnused(samplesPerBlock);
lastSampleRate = sampleRate;
createWaveformTemplates();
setParameters();
if (*modeParameter == 1.0f || 2.0f || 3.0f)
{
createWavetableCardioid(modeParameter, pointParameter, factorParameter, courseParameter, measureParameter, 0);
createWavetableCardioid(modeParameter_1, pointParameter_1, factorParameter_1, courseParameter_1, measureParameter_1, 1);
} else
{
//Create wavetable draw
}
proc0.setWavetable(&waveforms);
proc1.setWavetable(&waveforms);
proc0.setParameters(parameters.getRawParameterValue("ATTACK_ID"),
parameters.getRawParameterValue("DECAY_ID"),
parameters.getRawParameterValue("SUSTAIN_ID"),
parameters.getRawParameterValue("RELEASE_ID"),
parameters.getRawParameterValue("GAIN_ID"),
parameters.getRawParameterValue("TUNE_ID"),
parameters.getRawParameterValue("LEFT_BOUND_ID"),
parameters.getRawParameterValue("RIGHT_BOUND_ID")
);
proc1.setParameters(parameters.getRawParameterValue("ATTACK_ID_1"),
parameters.getRawParameterValue("DECAY_ID_1"),
parameters.getRawParameterValue("SUSTAIN_ID_1"),
parameters.getRawParameterValue("RELEASE_ID_1"),
parameters.getRawParameterValue("GAIN_ID_1"),
parameters.getRawParameterValue("TUNE_ID_1"),
parameters.getRawParameterValue("LEFT_BOUND_ID_1"),
parameters.getRawParameterValue("RIGHT_BOUND_ID_1")
);
proc0.prepareToPlay(sampleRate, lastSampleRate);
proc1.prepareToPlay(sampleRate, lastSampleRate);
}
void GeoHeadAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
juce::ScopedNoDenormals noDenormals;
//auto totalNumInputChannels = getTotalNumInputChannels();
//auto totalNumOutputChannels = getTotalNumOutputChannels();
buffer.clear();
proc0.processBlock(buffer, midiMessages);
proc1.processBlock(buffer, midiMessages);
}
OscillatorProcessor.h:
#pragma once
#include <JuceHeader.h>
#include "ProcessorBase.h"
#include "SynthSound.h"
#include "SynthVoice.h"
class OscillatorProcessor : public ProcessorBase
{
public:
OscillatorProcessor(int osc_id)
{
id = osc_id;
synth.clearVoices();
for (int i = 0; i < 5; i++)
{
synth.addVoice(new SynthVoice());
std::cout << i << std::endl;
}
synth.clearSounds();
synth.addSound(new SynthSound());
}
void prepareToPlay (double sampleRate, int samplesPerBlock) override
{
lastSampleRate = sampleRate;
synth.setCurrentPlaybackSampleRate(lastSampleRate);
}
void processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer& midiMessages) override
{
for (int i = 0; i < synth.getNumVoices(); i++)
{
//if myVoice sucessfully casts as a SynthVoice*, get the voice and set the params
if ((voice = dynamic_cast<SynthVoice*>(synth.getVoice(i))))
{
voice->setSampleRate(lastSampleRate);
voice->setWavetable(wavetable, id);
voice->setADSRParameters(att, dec, sus, rel);
voice->setGain(gain);
voice->setTableRange(first_sample, last_sample);
voice->setTuning(tune);
}
synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples());
}
}
void setWavetable(std::array<std::array<float, 1081>, 2>* wavetable_h)
{
wavetable = wavetable_h;
}
void setParameters (std::atomic<float>* attack, std::atomic<float>* decay,
std::atomic<float>* sustain, std::atomic<float>* release,
std::atomic<float>* gain_value, std::atomic<float>* tuning,
std::atomic<float>* start_sample ,std::atomic<float>* stop_sample)
{
att = attack;
dec = decay;
sus = sustain;
rel = release;
gain = gain_value;
tune = tuning;
first_sample = start_sample;
last_sample = stop_sample;
}
void reset() override
{
}
private:
double lastSampleRate;
Synthesiser synth;
SynthVoice* voice;
int id;
std::atomic<float>* att = nullptr;
std::atomic<float>* dec = nullptr;
std::atomic<float>*sus = nullptr;
std::atomic<float>* rel = nullptr;
std::atomic<float>* gain = nullptr;
std::atomic<float>* first_sample = nullptr;
std::atomic<float>* last_sample = nullptr;
std::atomic<float>* tune = nullptr;
std::array<std::array<float, 1081>, 2> instantiator = {{ {0}, {0} }};
std::array<std::array<float, 1081>, 2>* wavetable = &instantiator;
};
SynthVoice.h:
#pragma once
#include <JuceHeader.h>
#include "SynthSound.h"
class SynthVoice : public SynthesiserVoice
{
public:
bool canPlaySound (SynthesiserSound* sound) override
{
return dynamic_cast <SynthSound*>(sound) != nullptr;
}
void setPitchBend(int pitchWheelPos)
{
if (pitchWheelPos > 8192)
{
// shifting up
pitchBend = float(pitchWheelPos - 8192) / (16383 - 8192);
}
else
{
// shifting down
pitchBend = float(8192 - pitchWheelPos) / -8192; // negative number
}
}
float pitchBendCents()
{
if (pitchBend >= 0.0f)
{
// shifting up
return pitchBend * pitchBendUpSemitones * 100;
}
else
{
// shifting down
return pitchBend * pitchBendDownSemitones * 100;
}
}
static double noteHz(int midiNoteNumber, double centsOffset)
{
double hertz = MidiMessage::getMidiNoteInHertz(midiNoteNumber);
hertz *= std::pow(2.0, centsOffset / 1200);
return hertz;
}
//=======================================================
void startNote (int midiNoteNumber, float velocity, SynthesiserSound* sound, int currentPitchWheelPosition) override
{
adsr.noteOn();
noteNumber = midiNoteNumber;
setPitchBend(currentPitchWheelPosition);
frequency = noteHz(noteNumber, pitchBendCents());
level = velocity;
phase_0 = 0.0f;
}
//=======================================================
void stopNote (float velocity, bool allowTailOff) override
{
adsr.noteOff();
if (velocity == 0)
clearCurrentNote();
}
//=======================================================
void pitchWheelMoved (int newPitchWheelValue) override
{
setPitchBend(newPitchWheelValue);
frequency = noteHz(noteNumber, pitchBendCents());
}
//=======================================================
void controllerMoved (int controllerNumber, int newControllerValue) override
{
}
void setSampleRate(double lastSampleRate)
{
samplerate = lastSampleRate;
adsr.setSampleRate(samplerate);
}
void setWavetable(std::array<std::array<float, 1081>, 2>* wavetable_h, int id_h)
{
wavetable = wavetable_h;
id = id_h;
}
void setADSRParameters (std::atomic<float>* attack, std::atomic<float>* decay, std::atomic<float>* sustain, std::atomic<float>* release)
{
adsr_parameters.attack = *attack;
adsr_parameters.decay = *decay;
adsr_parameters.sustain = *sustain;
adsr_parameters.release = *release;
}
void setGain(std::atomic<float>* gain_value)
{
gain = *gain_value;
}
void setTableRange(std::atomic<float>* start_sample ,std::atomic<float>* stop_sample)
{
first_sample = static_cast<int> (*start_sample);
wt_size = static_cast<int> (*stop_sample - *start_sample);
}
void setTuning(std::atomic<float>* tuning)
{
tune = *tuning;
if (tune > -1 && tune < 1 )
{
tune_holder = fabs(tune)+ 1;
} else
{
tune_holder = fabs(tune) * 2;
}
}
void renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
if(tune < 0){increment = (frequency / tune_holder) * wt_size / samplerate;}
else{ increment = (frequency * tune_holder) * wt_size / samplerate;}
adsr.setParameters(adsr_parameters);
for (int sample = 0; sample < numSamples; ++sample)
{
for (int channel = 0; channel < outputBuffer.getNumChannels(); ++channel)
{
outputBuffer.addSample(channel, startSample, (*wavetable)[id][first_sample + (int) phase_0] * level * adsr.getNextSample() * gain );
phase_0 = fmod(phase_0 + increment,wt_size);
}
++startSample;
}
}
private:
float level = 0.0f;
double frequency = 0.0;
int noteNumber;
float pitchBend = 0.0f;
float pitchBendUpSemitones = 2.0f;
float pitchBendDownSemitones = 2.0f;
float gain;
int wt_size = 1080;
int first_sample = 0;
float phase_0 = 0.0f;
float increment = 0.0f;
double samplerate = 44100;
std::array<std::array<float, 1081>, 2> instantiator = {{ {0}, {0} }};
std::array<std::array<float, 1081>, 2>* wavetable = &instantiator;
int id;
ADSR adsr;
ADSR::Parameters adsr_parameters;
float tune = 0.0f;
float tune_holder = 0.0f;
};
