Help with slider values


#1

Hi everyone!
I am new with JUCE and have been studying other people’s projects to slowly get a feel of how I should be working for audio plugins. Recently, I stumbled onto this very nice project of p-i- on github: https://github.com/p-i-/Piano
and I have been trying to alter it and extend it as a way to play around. I am going to need some help though with the use of sliders. I added two sliders into the MainComponent.cpp so that I can change certain parameters but I can’t manage to get Filters.h (where all the DSP is taking place) to read the values of the sliders. I took a look into the forums here but could not find anything relevant. Any help please? :slight_smile:


#2

might be wise (assuming you did some debugging…) to show some of your code not working as expected…


#3

Here you find one option how you read the value: Slider::getValue().
Another one: Slider::Listener::sliderValueChanged (Slider * slider)
Or via virtual void AudioProcessorValueTreeState::Listener::parameterChanged (const String & parameterID, float newValue)
For more precise answers, you might want to give ore details, or some code, as @ttg said already


#4

Hey @daniel @ttg thanks for the immediate responses!
In the MainComponent.cpp I am just defining two new sliders and in the class constructor I am just specifying them as such:

public: MainContentComponent() : synthPlayer(keyboardState, inputDeviceManager, outputDeviceManager) , keyboardComponent(keyboardState, MidiKeyboardComponent::horizontalKeyboard), dampingSlider(), dampingLabel(),tensionSlider(),tensionLabel()

{
    
	setSize(1024, 300);
	setOpaque(true);

	addAndMakeVisible(keyboardComponent);
    addAndMakeVisible (dampingSlider);
    addAndMakeVisible (dampingLabel);
    addAndMakeVisible (tensionSlider);
    addAndMakeVisible (tensionLabel);
    
    dampingLabel.setText ("Damping", dontSendNotification);
    dampingLabel.attachToComponent (&dampingSlider, true);
    
    tensionLabel.setText ("Tension", dontSendNotification);
    tensionLabel.attachToComponent (&tensionSlider, true);
    
    keyboardComponent.setAvailableRange(21, 108);
    
    dampingSlider.setRange (0.0001, 0.001);
    dampingSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 100, dampingSlider.getTextBoxHeight());
    dampingSlider.setSliderStyle (Slider::LinearBar );
    
    tensionSlider.setRange (60, 300.0);
    tensionSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 100, tensionSlider.getTextBoxHeight());
    tensionSlider.setSliderStyle (Slider::LinearBar );

    dampingSlider.setSkewFactorFromMidPoint (0.0005);
    tensionSlider.setSkewFactorFromMidPoint (150);
}

My problem is (and it might really simple, but I am still new to OOP) how to acquire the updated slider values inside the Synth.h where there are no instances of the MainContentComponent class. Thanks again and sorry if my question is silly…


#5

The simple form is having your variables in the actual AudioProcessor… (Synth.h)
for example “float tension_”

now within the MainComponent you can set synthPlayer.tension_ value.

You should also learn as suggested by @daniel, the logic of listeners/broadcasters.

and with OOP we’d expect encapsulation (I have to admit I come from Java so I’ve seen many variables being kept visible while my common less efficient nature would add setTension(const float newVal) and getTesnion() :wink: )


#6

This is a matter of architecture, you have several valid choices there…

  1. in your mainComponent check when the slider changes and call a new defined “setTensionValue( float t)” in your Synth class. Not very elegant, but works…

  2. make your Synth class a Slider::Listener and attach it to the slider. By inheriting Slider::Listener a callback is defined, which you override to react to it:

     class PiSynthPlayer : public AudioSource, public Slider::Listener 
     {
         // [...]
        void Slider::Listener::sliderValueChanged (Slider * slider) override {
            // if your PiSynthPlayer is attached to more than one slider, you need to figure out here, which calls
            if (slider->getComponentID() == "tension") {
                // if your class was owner of the slider, it would be better to compare the pointers, like:
                // if (slider == tensionSlider)
                    yourFilterStuff->setTension (slider->getValue());
             }
         }
     }
    

And to get the slider connected:

tensionSlider.setComponentID ("tension");  // to recognise your slider in the callback
tensionSlider.addListener (&synthPlayer);

Only thing to keep in mind, the callback is called from the message thread, while the filter is evaluated from the audio thread. For now it should work, because only setting a float is an atomic operation (afaik)

Second note: if you use the default constructor (i.e. with no arguments), then you can leave it out. No need to call dampingSlider() etc. Your MainComponent could look like:

MainContentComponent()
	: synthPlayer(keyboardState, inputDeviceManager, outputDeviceManager),
          keyboardComponent(keyboardState, MidiKeyboardComponent::horizontalKeyboard)
{
    // ...

There are no silly questions :wink:


#7

Cheers to both of you, I am going to try this stuff today!
Many thanks


#8

Did u saw the Slider tutorial from Juce?
The tutorial has nothing to do with your “how i get the slider value into my DSP class” but maybe it make some thinks clearer.
https://www.juce.com/doc/tutorial_slider_values


#9

On the x86 architecture, it is an atomic operation so long as it is naturally aligned. However, when writing in C++, it is undefined behavior to concurrently read/write (race condition) any variable without it being an atomic<> or being wrapped in a critical section. Making all your variables atomic<> is a bit annoying, however otherwise the compiler may make unsound/unexpected optimizations. Technically, the compiler is allowed to do whatever (insert jokes about your program deleting root folders).

Using the correct memory orderings on your atomics<> should produce identical code compared to raw primitives on x86.


#10

hello again :neutral_face:
i tried making my synth a listener and attaching it to the slider, but in the synth I am getting a Non-friend class-member 'sliderValueChanged' cannot have a qualified name error and in the declaration PiSynthPlayer synthPlayer; in the main component I am getting Field type 'PiSynthPlayer' is an abstract class
Any ideas?
thanks !


#11

This means it has methods, that are “pure virtual”, i.e. has no implementation. Most probably the sliderValueChanged method.
That means, you have an error overriding the callback. Maybe post, how you declared the callback?
In the class it should look like:

public:
    void sliderValueChanged (Slider *slider) override {
        // do your stuff
    }

#12

thanks very much i fixed it!
i think I am (slowly) starting to get my head around this…