Parameters are driving me crazy


#1

Hi guys,

I'm really struggling trying to get parameters working between "human and machine" values. I searched the forum and tried different approaches I found, but unsuccessfully... and that's frustrating with something that should be really straightforward.

Problems:
- AudioProcessorParameter works with 0..1 values
- GUI and host parameters must show human readable values with units

I can do all the normalisation/denormalisation successfully.. but the issues (the frustraing ones) are others.

I overloaded AudioProcessorParameter class with MyScaledParameter : public AudioProcessor parameter.. 
1) If I put that class on top of PluginProcessor.cpp I can't use custom members since I must declare the parameters with AudioProcessorParameter*, but I can reference the current AudioProcessor to call custom members in it, but I can't get getText to show the parameters the way I want.

2) If I put that class in a separate .h file, I can declare the parameters using my custom class MyScaledParameter* instead of AudioProcessorParameter*. This is working ALMOST perfectly. I can create new members, overload getText and so on.. but I can't get a reference to the current AudioProcessor to work. 

If any good sound could point me to the right direction, I'll be really grateful. 

Thanks!


#2

You might wanna check out this thread:

http://www.juce.com/forum/topic/how-catch-parameter-change-while-controls-view-instead-cocoa-view

I explained a concept using a c++11 lambda or a calable type approach. 

 

So you could have the constructor of your custom parameter class take in a lambda as a call back function (which could be called every time setValue is called for example) and capture a value copy of the this pointer to the AudioProcessor in your AudioProcessor constructor. Also a nice way of updating a dsp module inside a parameter setValue call. 

 

So if you had a filterCutoff param and then a filter class with a method filter.setCutoffFrequency(float newCutoff), you cOULD effectivley pass in this function using a lambda to your filterCutoffParam constructor so that it was called every time filterCutoffParam.setValue() is called. (I can message you with a code example of this approach or something if it doesn't make sense)

Or why not just have your custom parameter class take in a AudioProcessor pointer/reference in its constructor ? 

Then in your AudioProcessor constructor do something like AudioProcessor.addParameter (myParameter = new MyCustomerParamter(*this)). where the this pointer refers to the AudioProcessor instance. Similar to the way you would pass the owning processor/filter into the constructor of your editor class. 

 

Josh 

 


#3

Thanks Josh. I already tried to understand the thread you linked, but it's too advanced to me for now. 

Honestly, I don't want to create a new class for every type of parameter I'm gonna use.. so I'm aiming to have one parameter class to manage everything I need.

Check this: https://www.dropbox.com/s/4fr5bqo8bkd4vvt/LC_Parameters.zip?dl=0

That's working almost perfectly, but I cannot pass an AudioProcessor reference to it, since it has not been declared yet. I tried passing a generic AudioProcessor&, but obviously I can't access the custom members I have in the current project. 


#4

Hey Zioaxiom. 

 

So in your code you have a member variable in your AudioProcessor class:

ScaledFloatParameter* gain;

 

Then in the constructor of your AudioProcessor you have the following line:

addParameter (gain = new ScaledFloatParameter(40.0, "Gain", 0.0, 100.0, 1, "%"));

 

If i understand rightly you want to be able to get a reference to the AudioProcessor that owns/manages your ScaledFloatParameter instance from within the ScaledFloatParameter class/code ? 

If thats all you need then why not just change your ScaledFloatParameter constructor to the following (change in bold): 

ScaledFloatParameter(float defaultParameterValue, const String& paramName, const float start, const float end, const float skew, const String& paramUnit, AudioProcessor& owningProcessor);

Then just add an AudioProcessor& owningProcessor member variable to your ScaledFloatParameter class. 

 

Then in your AudioProcessor consturctor change your code to (change in bold):

addParameter (gain = new ScaledFloatParameter(40.0, "Gain", 0.0, 100.0, 1, "%", *this));

 

Here *this refers to the AudioProcessor. 

 

Hopefully that makes sense. 

 


#5

If you don't understand how the this pointer works inside the AudioProcessor constructor do a little research on references and pointers and the this pointer in c++. 

 

But also look at this code in your own PluginProcessor.cpp code:

 

AudioProcessorEditor* ParametersAudioProcessor::createEditor() 
{
    return new ParametersAudioProcessorEditor(*this)
}

 

and then your PluginEditor's constructor: 

ParametersAudioProcessorEditor (ParametersAudioProcessor&);

 

Hopefully that demonstrated the idea enough. 

 

Josh 


#6

Thanks Josh, but I already tried that approach before. I can pass the "this" reference, but since refers to AudioProcessor (and not, let's say, ParameterAudioProcessor), I can't access my custom members inside the processor. Maybe I can try casting, but doesn't looks like a safe idea.


#7

 

Hey zioaxim, 

You could go for casting and its probably a more commonly used solution for this kind of C++ problem than it should be. 

It's hard to give exact advice without knowing what kind of things you want to access within your AudioProcessor from your derived parameter class but it might be worth having a look into the lambda/callback approach again. With a little reading its not too hard to understand. 

Here's some code I've used in an AudioProcessor constructor for playing around with. Note the callback function in bold. Might give you an idea of the approach. 

auto cutoffParamCallback = [this] (float cutoff) {this->filter1->setCutoffFrequency(cutoff);}; 

addParameter (filterCutoffParam = new CustomAudioParameter(defaultMinFilterFrequency, defaultMaxFilterFrequency,CustomAudioParameter::ParamterTypes::VOLT_OCTAVE_PARAM, "FilterCutoff", cutoffParamCallback));

#8

Thanks Josh, I'll definitely dig into this.


#9

You saved my day, Josh. It works really good. Thanks again!


#10

Hey Zioaxiom, 

Brilliant,  glad it works!

I'm going to post up a little plugin with an example of how to draw a filter frequency response display in JUCE asap for people to take a look at and it uses this approach for the parameters so feel free to look through/modify the source when its up if its of any use to you. 

Cheers

Josh