음악, 삶, 개발
processBlock(); 본문
< processBlock() 이란? >
processBlock(); 은 DAW 가 호출하는 AudioProcessor 클래스의 pure virtual 함수이다.
따라서 이 클래스의 서브 클래스는 반드시 이 함수를 정의해줘야한다.
이 함수는 내가 호출하지않고, DAW 가 호출하는 콜백함수이다.
오디오와 미디 프로세싱이 일어나는 가장 초입이라고 할수있다.
< processBlock() 은 언제 호출되는가? >
아래의 오디오 인터페이스 셋팅이 있다고 가정해보자.
Sample Rate : 48000
Buffer Size : 512
Latency : 10.75ms
샘플레이트만 생각하면 1초에 48000번을 샘플링한다.
하지만 오디오 프로세싱은 샘플 하나 하나를 처리하지않고, 일정량을 모아서 처리하는데,
이 일정량이 버퍼사이즈이다.
버퍼사이즈가 512라면, 512개의 샘플이 모였을때 processBlock() 이 실행되는것이다.
이 512개의 샘플들의 모음을 Block 이라고 한다.
48000 을 512 로 나누면 93.75 가 나오는데,
1초에 93번의 processBlock() 이 호출되는것이다.
(하지만 이렇게 93번이 딱 정확히 호출될거라고 생각하고 코딩하면 안된다, DAW 마다 다르기때문.)
우리는 샘플레이트와 버퍼사이즈를 통해 레이턴시를 계산할수있는데,
1000ms / 93 = 10.75 ms 이다.
processBlock(); 의 실행을 그림으로 표현해보았다.
< 하지만.... >
공식 문서를 읽어보면
위의 그림처럼 매번 정확한 버퍼사이즈를 가진 타이밍에 processBlock() 이 실행되지않을것이라고한다.
DAW 의 구현이 전부 틀리기때문.
아래의 공식문서를 읽어보자.
< 공식 문서 >
위의 문서에서 가장 중요한 부분은 이부분이다.
The number of samples in these buffers is NOT guaranteed to be the same for every callback,
and may be more or less than the estimated value given to prepareToPlay().
Your code must be able to cope with variable-sized blocks, or you're going to get clicks and crashes!
Also note that some hosts will occasionally decide to pass a buffer containing zero samples,
so make sure that your algorithm can deal with that!
그 다음 중요한 부분이다.
Be very careful about what you do in this callback -
it's going to be called by the audio thread,
so any kind of interaction with the UI is absolutely out of the question.
If you change a parameter in here and need to tell your UI to update itself,
the best way is probably to inherit from a ChangeBroadcaster,
let the UI components register as listeners,
and then call sendChangeMessage() inside the processBlock() method to send out an asynchronous message. You could also use the AsyncUpdater class in a similar way.
< 절대 ValueTree 를 processBlock() 안에서 읽거나 쓰지말라! >
이와 관련한 Juce Forum 의 글들을 읽어보자.
Sending signal/events from audio to GUI thread?
Safety of ValueTree inside processBlock()
Alternative to accessing ValueTree in processBlock?
Update AudioProcessorValueTreeState from process block
How to access AudioProcessorValueTreeState parameters en masse?
Best way to call async method from processBlock() loop?
Parameter synchronization in GainPlugin example
Tutorial: Visualise the frequencies of a signal in real time