前言

阅读此教程需要一定的C++和JUCE基础。
我的Bilibili频道:香芋派Taro
我的个人博客:taropie0224.github.io
我的公众号:香芋派的烘焙坊
我的音频技术交流群:1136403177
我的个人微信:JazzyTaroPie

其实我一直觉得JUCE官方做的教程很烂…官网上的tutorial甚至还是在用xml做参数存储,目前最常用的apvts连一个影子都没见着,所以在这里整理一下。

新建一个Plugin模版

PluginProcessor.h

在public中添加以下成员函数:

1
2
3
4
5
public:
......
static juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();

juce::AudioProcessorValueTreeState apvts { *this, nullptr, "Parameters", createParameterLayout() };

PluginProcessor.cpp

总共有四种参数类型,分别是int, float, bool和choice

AudioParameterFloat

写法一

1
2
3
4
5
6
7
8
9
10
11
12
juce::AudioProcessorValueTreeState::ParameterLayout yourPluginsNameAudioProcessor::createParameterLayout()
{
juce::AudioProcessorValueTreeState::ParameterLayout layout;

layout.add (std::make_unique<juce::AudioParameterFloat> ("parameterID",
"parameterName",
juce::NormalisableRange<float> (rangeStart, rangeEnd, intervalValue, skewFactor),
defaultValue,
parameterLabel,
parameterCategory,
stringFromValue,
valueFromString));

你肯定注意到了AudioParameterFloat这个函数,官方doc中的定义如下:

  • parameterID
    极为重要,它代表了你准备定义的这个参数的身份证,无论是在外面调用这个数据,还是在后面设计sliderAttachment跟slider绑定都需要用到它。
  • parameterName
    顾名思义啦
  • NormalisableRange
    他也有四个参数,分别是最小值、最大值、变动范围精度、斜率、(其实还有第五个,就是是否反对称,反正我是没用过这个)。注意都是float。
  • defaultValue
    参数的默认值
  • parameterLabel
    一般直接使用String(),如果你想给参数加上单位的话,可以用”Hz”这样的写法代替
  • parameterCategory
    一般直接使用AudioProcessorParameter::genericParameter
  • stringFromValue
    一个lambda表达式,可以把值转化成字符串并定义字符串的最大长度,用于在界面上显示参数的值。
  • valueFromString
    一个lambda表达式,可以把字符串转化成值,用于让用户输入。

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
layout.add (std::make_unique<juce::AudioParameterFloat> ("Room Size",
"Room Size",
juce::NormalisableRange<float> (0.0f, 1.0f, 0.001f, 1.0f),
0.5f,
juce::String(),
juce::AudioProcessorParameter::genericParameter,
[](float value, int) {
if (value * 100 < 10.0f)
return juce::String (value * 100, 2);
else if (value * 100 < 100.0f)
return juce::String (value * 100, 1);
else
return juce::String (value * 100, 0); },
nullptr));

这是混响中RoomSize参数的一个例子,其中,最小值为0,最大值为1,变动范围精度为0.001,斜率为1,默认值为0.5。
你会发现使用了stringFromValue的一个lambda表达式,这里解释一下用意。 由于参数在设计时时准备用百分比表示的,所以先乘上100。然后会比较是个位数还是两位数,如果是个位数的话就显示小数点后两位,十位数的话就显示小数点后一位。这样能保持数值总体的长度不变,是一个保持美观的小细节。

写法二


这种写法较为简单,也是最常用的写法,只需要五个参数,分别是ID,Name,最小值,最大值和默认值。
举个例子

1
2
3
4
5
layout.add (std::make_unique<juce::AudioParameterFloat> ("Room Size",
"Room Size",
0.0f,
1.0f,
0.5f));

AudioParameterInt

基本与float的写法一相同,只是所有的float都变成了int,这里略过

AudioParameterChoice

JUCE的官方doc中定义如下:

其实也基本大同小异,直接举个例子看吧:

1
layout.add (std::make_unique<juce::AudioParameterChoice> ("OSC", "Oscillator", juce::StringArray { "Sine", "Saw", "Square" }, 0));

以振荡器为例,这里列出了三种波形的选项,以及默认的波形为0,就是数组中的第一个,即Sine正弦波。

AudioParameterBool

JUCE的官方doc中定义如下:

多用于配合botton使用,举个例子,混响中的freeze开关:

1
layout.add (std::make_unique<juce::AudioParameterBool> ("Freeze", "Freeze", false));

与组件的绑定

AudioParameterFloat/AudioParameterInt

以Gain效果器为例,在Plugin.h中的private部分创建slider和对应的attachment:

1
2
juce::Slider gainSlider;
std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> gainSliderAttachment;

在Plugin.cpp中的构造函数中完成绑定(最后一行):

1
2
3
4
5
gainSlider.setSliderStyle(juce::Slider::SliderStyle::LinearHorizontal);
gainSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, true, 100, 50);
addAndMakeVisible (gainSlider);

gainSliderAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(audioProcessor.apvts, "Gain", gainSlider);

其中用到的函数是juce::AudioProcessorValueTreeState::SliderAttachment,里面的三个参数分别是你创建的APVTS名称,parameterID和需要绑定的slider的名称。

AudioParameterChoice

以Osc选择为例,在Plugin.h中的private部分创建ComboBox和对应的attachment:

1
2
juce::ComboBox oscSelector;
std::unique_ptr<juce::AudioProcessorValueTreeState::ComboBoxAttachment> oscSelAttachment;

在Plugin.cpp中的构造函数中完成绑定:

1
2
3
4
5
juce::StringArray oscChoices { "Sine", "Saw", "Square" };
oscSelector.addItemList (oscChoices, 1);
oscSelector.setSelectedItemIndex (0);
addAndMakeVisible (oscSelector);
oscSelAttachment = std::make_unique<juce::AudioProcessorValueTreeState::ComboBoxAttachment>(apvts, oscId, oscSelector);

AudioParameterBool

以reverb中的freeze button选择为例,在Plugin.h中的private部分创建TextButton/ToggleButton和对应的attachment:

1
2
juce::TextButton freezeButton;
juce::AudioProcessorValueTreeState::ButtonAttachment freezeAttachment;

在Plugin.cpp中的构造函数中完成绑定:

freezeAttachment = std::make_unique<juce::AudioProcessorValueTreeState::ButtonAttachment>(apvts, "Freeze", freezeButton);