Hi If anyone could point me in the right direction on this, would be great !
I m trying to create a simple sine generator with frequency as a parameter that can be changed by a slider that uses LinearSmoothedValue Class for the smoothing between value jumps.
the sine generator create a sinewave sound ( albeit with some artifacts, but thats a different question ). The slider controls the frequency. But when moving the slider their is crackling.
I’ve tried to use the LinearSmoothedValue class ( creating this Value “smoothedFrequency2”). I’ve looked at how it’s implemented in the Reverb.h class inside Juce. I tried to implement it in the same way and many other wise without success it is still crackling when moving the slider.
I’ve inserted some text code to check if my LinearSmoothedValue object is smoothing at all using the smoothedFrequency2.isSmoothing() … and it looks like its working …
i’ve tried since 2 days but im surely missing something very obvious … below is my code if anyone knows what im doing wrong let me know … best
`PluginProcessor.h
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
=============================================================================='
*/
#ifndef PLUGINPROCESSOR_H_INCLUDED
#define PLUGINPROCESSOR_H_INCLUDED
#include "../JuceLibraryCode/JuceHeader.h"
//==============================================================================
/**
*/
class SinePlugIn2AudioProcessor : public AudioProcessor//,
{
public:
//==============================================================================
SinePlugIn2AudioProcessor();
~SinePlugIn2AudioProcessor();
//==============================================================================
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
void releaseResources() override;
#ifndef JucePlugin_PreferredChannelConfigurations
bool setPreferredBusArrangement (bool isInput, int bus, const AudioChannelSet& preferredSet) override;
#endif
void processBlock (AudioSampleBuffer&, MidiBuffer&) override;
//==============================================================================
AudioProcessorEditor* createEditor() override;
bool hasEditor() const override;
//==============================================================================
const String getName() const override;
bool acceptsMidi() const override;
bool producesMidi() const override;
double getTailLengthSeconds() const override;
//==============================================================================
int getNumPrograms() override;
int getCurrentProgram() override;
void setCurrentProgram (int index) override;
const String getProgramName (int index) override;
void changeProgramName (int index, const String& newName) override;
//==============================================================================
void getStateInformation (MemoryBlock& destData) override;
void setStateInformation (const void* data, int sizeInBytes) override;
double currentSampleRate, angleDelta, currentAngle;
double currentFrequency;
//double currentFrequency, targetFrequency; // Smoothing -
int offset = 0;
void setCurrentFrequency(double LinearSmoothedValue);
LinearSmoothedValue<double>smoothedFrequency;
inline void updateAngleDelta() noexcept;
AudioProcessorParameter *pitchParameter;
AudioProcessorParameter *volumeParameter;
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SinePlugIn2AudioProcessor)
};
#endif // PLUGINPROCESSOR_H_INCLUDED
PluginProcessor.cpp
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
//==============================================================================
SinePlugIn2AudioProcessor::SinePlugIn2AudioProcessor() :
currentAngle(0.0), // 5) initialize class with default values
angleDelta(0.0),
currentSampleRate(0.0),
smoothedPitchValue(100.0),
currentFrequency(500.0) // Smoothing -
//targetFrequency(currentFrequency)
{
// 9) add parameter
addParameter(pitchParameter = new AudioParameterFloat("PitchSliderParameter", "Pitch_Slider", 0.0, 1.0, 0.5));
addParameter(volumeParameter = new AudioParameterFloat("VolumeSliderParameter", "Volume_Slider", 0.0, 1.0, 0.5));
}
SinePlugIn2AudioProcessor::~SinePlugIn2AudioProcessor()
{
}
//==============================================================================
const String SinePlugIn2AudioProcessor::getName() const
{
return JucePlugin_Name;
}
bool SinePlugIn2AudioProcessor::acceptsMidi() const
{
#if JucePlugin_WantsMidiInput
return true;
#else
return false;
#endif
}
bool SinePlugIn2AudioProcessor::producesMidi() const
{
#if JucePlugin_ProducesMidiOutput
return true;
#else
return false;
#endif
}
double SinePlugIn2AudioProcessor::getTailLengthSeconds() const
{
return 0.0;
}
int SinePlugIn2AudioProcessor::getNumPrograms()
{
return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
// so this should be at least 1, even if you're not really implementing programs.
}
int SinePlugIn2AudioProcessor::getCurrentProgram()
{
return 0;
}
void SinePlugIn2AudioProcessor::setCurrentProgram (int index)
{
}
const String SinePlugIn2AudioProcessor::getProgramName (int index)
{
return String();
}
void SinePlugIn2AudioProcessor::changeProgramName (int index, const String& newName)
{
}
//==============================================================================
void SinePlugIn2AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
// Use this method as the place to do any pre-playback
// initialisation that you need..
// 6) override void prepareToPlayfunction() function
currentSampleRate = sampleRate;
updateAngleDelta(); // setting currentSamplerate to sampleRate(which is from set by AudioDevice / Daw)
// update angleDelta();
}
void SinePlugIn2AudioProcessor::releaseResources()
{
// When playback stops, you can use this as an opportunity to free up any
// spare memory, etc.
}
#ifndef JucePlugin_PreferredChannelConfigurations
bool SinePlugIn2AudioProcessor::setPreferredBusArrangement (bool isInput, int bus, const AudioChannelSet& preferredSet)
{
// Reject any bus arrangements that are not compatible with your plugin
const int numChannels = preferredSet.size();
#if JucePlugin_IsMidiEffect
if (numChannels != 0)
return false;
#elif JucePlugin_IsSynth
if (isInput || (numChannels != 1 && numChannels != 2))
return false;
#else
if (numChannels != 1 && numChannels != 2)
return false;
if (! AudioProcessor::setPreferredBusArrangement (! isInput, bus, preferredSet))
return false;
#endif
return AudioProcessor::setPreferredBusArrangement (isInput, bus, preferredSet);
}
#endif
void SinePlugIn2AudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels();
// In case we have more outputs than inputs, this code clears any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
// This is here to avoid people getting screaming feedback
// when they first compile a plugin, but obviously you don't need to keep
// this code if your algorithm always overwrites all the output channels.
// This is the place where you'd normally do the guts of your plugin's
// audio processing...
int const numSamples = buffer.getNumSamples();
for (int channel = 0; channel < totalNumOutputChannels; ++channel)
{
const float level = 0.25f;
float* const channelBuffer = buffer.getWritePointer(channel);
for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
{
const float currentSample = sinf(float(currentAngle*(sample + offset)));
//smoothedSample.setValue(currentSample);
//const float currentSample = (float)std::sin(currentAngle); // Smoothing -
//currentFrequency += frequencyIncrement; // Smoothing -
//updateAngleDelta(); // Smoothing -
updateAngleDelta();
currentAngle = angleDelta;
channelBuffer[sample] = currentSample * level;
}
}
}
offset += numSamples;
}
//==============================================================================
inline void SinePlugIn2AudioProcessor::updateAngleDelta() noexcept
{
const double cyclesPerSample = currentFrequency / currentSampleRate; //xxx //currentFrequency / currentSampleRate;// double(smoothedPitchValue.getNextValue()) / currentSampleRate;
angleDelta = cyclesPerSample * 2.0 * double_Pi;
counter++; // debug counter #1
}
void SinePlugIn2AudioProcessor::setCurrentFrequency(double LinearSmoothedValue)
{
currentFrequency = LinearSmoothedValue;
}
//=============================================================================
//==============================================================================
bool SinePlugIn2AudioProcessor::hasEditor() const
{
return true; // (change this to false if you choose to not supply an editor)
}
AudioProcessorEditor* SinePlugIn2AudioProcessor::createEditor()
{
return new SinePlugIn2AudioProcessorEditor (*this);
}
//==============================================================================
void SinePlugIn2AudioProcessor::getStateInformation (MemoryBlock& destData)
{
// You should use this method to store your parameters in the memory block.
// You could do that either as raw data, or use the XML or ValueTree classes
// as intermediaries to make it easy to save and load complex data.
}
void SinePlugIn2AudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
// You should use this method to restore your parameters from this memory block,
// whose contents will have been created by the getStateInformation() call.
}
//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new SinePlugIn2AudioProcessor();
}
PluginEditor.h
/*
This file was auto-generated!
It contains the basic framework code for a JUCE plugin editor.
*/
#ifndef PLUGINEDITOR_H_INCLUDED
#define PLUGINEDITOR_H_INCLUDED
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h" // 11) make sure PluginProcessor.h is included
#include "PluginEditor.h"
//==============================================================================
/**
*/
class SinePlugIn2AudioProcessorEditor : public AudioProcessorEditor,
public Slider::Listener // 9a) derrive from Slider::Listener Class
// Debug - LinearSmoothed
{
public:
SinePlugIn2AudioProcessorEditor (SinePlugIn2AudioProcessor&);
~SinePlugIn2AudioProcessorEditor();
//==============================================================================
void paint (Graphics&) override;
void resized() override;
void sliderValueChanged(Slider *slider) override;
Label test; // debug label
LinearSmoothedValue<double>smoothedFrequency2;
// Sliders // 7) create Slider Objects
Slider pitchSlider;
Slider volumeSlider;
private:
// This reference is provided as a quick way for your editor to
// access the processor object that created it.
SinePlugIn2AudioProcessor& processor;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SinePlugIn2AudioProcessorEditor)
};
#endif // PLUGINEDITOR_H_INCLUDED
PluginEditor.cpp
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin editor.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
//==============================================================================
SinePlugIn2AudioProcessorEditor::SinePlugIn2AudioProcessorEditor (SinePlugIn2AudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
// Make sure that before the constructor has finished, you've set the
// editor's size to whatever you need it to be.
addAndMakeVisible(pitchSlider);
pitchSlider.setRange(20.0, 5000.0, 1.0); //
pitchSlider.setSkewFactorFromMidPoint(200.0);
pitchSlider.addListener(this);
addAndMakeVisible(volumeSlider);
volumeSlider.setRange(0.0, 1.0, 0.0);
volumeSlider.addListener(this);
addAndMakeVisible(test);
test.setText("test", dontSendNotification);
test.setColour(Label::textColourId, Colours::black);
// editor's size to whatever you need it to be.
const int numberOfRows = p.getNumParameters()+1;
const int height = numberOfRows * 48 + 24;
setSize(600, height);
// set smoothedFrequency // xxx
smoothedFrequency2.reset(processor.currentSampleRate, 0.01);
}
SinePlugIn2AudioProcessorEditor::~SinePlugIn2AudioProcessorEditor()
{
}
//==============================================================================
void SinePlugIn2AudioProcessorEditor::paint (Graphics& g)
{
g.fillAll (Colours::white);
}
void SinePlugIn2AudioProcessorEditor::resized()
{
// This is generally where you'll want to lay out the positions of any
// subcomponents in your editor..
const int unit = 8; // 10b) (this is optional) layout Sliders based on a unit grid.
const int margin = 2 * unit;
const int offsetAdd = 4 * unit;
const int offsetMult = 6 * unit;
const int sliderWidth = 60 * unit;
const int sliderHeight = 3 * unit;
pitchSlider.setBounds(margin, offsetAdd + 0 * offsetMult, sliderWidth, sliderHeight);
volumeSlider.setBounds(margin, offsetAdd + 1 * offsetMult, sliderWidth, sliderHeight);
test.setBounds(margin, offsetAdd + 2 * offsetMult, sliderWidth, sliderHeight); // bug test #1
}
//
void SinePlugIn2AudioProcessorEditor::sliderValueChanged(Slider* slider) // 12b) define SliderValueChanged
{
if (slider == &pitchSlider)
{
processor.setSmoothedPitchValue(pitchSlider.getValue());
processor.pitchParameter->setValue(pitchSlider.getValue());
smoothedFrequency2.setValue(pitchSlider.getValue());
processor.setCurrentFrequency(smoothedFrequency2.getNextValue());
String string;
// Debug - LinearSmoothedValue - if the LinearSmoothedValue is working
if(smoothedFrequency2.isSmoothing())
{
string = "smoothedFrequency is smoothing";
}
else if (smoothedFrequency2.isSmoothing())
{
string = "smoothedFrequency is not smoothing";
}
else
{
string = "nothing happening";
}
test.setText(string += (int(smoothedFrequency2.getTargetValue())), dontSendNotification); // bug test #1
}
}
//==========================================================================