음악, 삶, 개발
DAW 의 파라미터에 대한 모든것 : 파트2 본문
앞선 포스트에서 우리의 고민 사항은 아래와 같았다.
1. 어디에 나의 파라미터를 추가할것인지?
2. 어떻게 나의 파라미터를 추가할수있는지?
3. 어떻게 나의 VST 출력은 이 파라미터 값을 반영할수있는지?
4. 어떻게 나의 파라미터를 GUI 에 연결할수있는지?
5. 어떻게 나의 파라미터 값을 이 GUI 로 변경할수있는지?
< 해결된 문제 >
1. 어디에 나의 파라미터를 추가할것인지?
2. 어떻게 나의 파라미터를 추가할수있는지?
를 해결하여 아래의 코드를 완성했다.
class VSTPlugin : public juce::AudioProcessor {
public :
VSTPlugin() : apvts(*this, nullptr, juce::Identifier("APVTS"), createParams()) // apvts 초기화!
{
}
// 2. 어떻게 나의 파라미터를 추가할수있는지?
using Params = juce::AudioProcessorValueTreeState::ParameterLayout;
using ParamInt = juce::AudioParameterInt;
Params createParams() {
Params params;
params.add(std::make_unique<ParamInt>("Test", "Test", 0, 10, 0)); // Id, Display Name, Min, Max, Default
return params;
}
private :
juce::AudioProcessorValueTreeState apvts; // 1. 어디에 나의 파라미터를 추가할것인지? apvts 객체 생성!
}
이제 다음 문제들을 해결해보자.
3. 어떻게 나의 VST 출력은 이 파라미터 값을 반영할수있는지?
VST 출력은 곧 audio thread 이다.
결국 audio thread 에서 apvts 에 접근을 해야하는데,
apvts.getRawParameterValue(Stringref paramterID)
apvts.getParameter(Stringref paramterID)
위의 두개의 방법중 하나를 사용한다.
이때 thread 안전성에 대해 걱정을 했는데,
Peter 말에 의하면,
Parameter 는 APVTS 와 약간 독립적으로 존재한다고한다.
따라서 processBlock() 안에서 위의 함수들을 호출하는것은 APVTS 를 읽거나 쓰는것이 아니라고한다.
(이게, APVTS 를 읽는 행위가 아니라면, 무엇이 읽는것이는 추후 물어보고 설명하겠음)
따라서 thread 안전하다고..
< 결과물 >
class VSTPlugin : public juce::AudioProcessor {
public :
VSTPlugin() : apvts(*this, nullptr, juce::Identifier("APVTS"), createParams()) // apvts 초기화!
{
// 3.2 init testParameter
testParameter = apvts.getRawParameterValue("test");
}
// 2. 어떻게 나의 파라미터를 추가할수있는지?
using Params = juce::AudioProcessorValueTreeState::ParameterLayout;
using ParamInt = juce::AudioParameterInt;
Params createParams() {
Params params;
params.add(std::make_unique<ParamInt>("test", "Test", 0, 10, 0)); // Id, Display Name, Min, Max, Default
return params;
}
// 3. 어떻게 나의 VST 출력은 이 파라미터 값을 반영할수있는지?
void processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer& midiBuffer) override {
auto test = *testParameter; // 3.3 get testParameter as dereferencing.
/*
Use test parameter's value here!
*/
}
private :
juce::AudioProcessorValueTreeState apvts; // 1. 어디에 나의 파라미터를 추가할것인지? apvts 객체 생성!
std::atomic<int>* testParameter {nullptr}; // 3.1 create pointer of test parameter.
}
< 추가 : Peter 와의 대화후..>
위의 코드처럼, atomic 포인터를 만들 필요없이 바로 processBlock() 에서 읽어드려도 된다.
class VSTPlugin : public juce::AudioProcessor {
public :
VSTPlugin() : apvts(*this, nullptr, juce::Identifier("APVTS"), createParams()) // apvts 초기화!
{
}
// 2. 어떻게 나의 파라미터를 추가할수있는지?
using Params = juce::AudioProcessorValueTreeState::ParameterLayout;
using ParamInt = juce::AudioParameterInt;
Params createParams() {
Params params;
params.add(std::make_unique<ParamInt>("test", "Test", 0, 10, 0)); // Id, Display Name, Min, Max, Default
return params;
}
// 3. 어떻게 나의 VST 출력은 이 파라미터 값을 반영할수있는지?
void processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer& midiBuffer) override {
auto value = *(apvts.getRawParameterValue("test")); // 포인터 역참조!
/* use value here! */
}
private :
juce::AudioProcessorValueTreeState apvts; // 1. 어디에 나의 파라미터를 추가할것인지? apvts 객체 생성!
}
참고링크 : https://forum.juce.com/t/getrawparametervalue-vs-getparameter/38395
< 다음 단계로..>
1,2,3 단계의 가장 중요한 단계를 해결하였다.
이제 AudioProcessor 의 서브 클래스안에서 해야할 모든것은 끝이 났다.
이 단계들이 선행되어야 GUI 단계에서 뭘 할수있는것이다.