쿼츠(Quartz) 는 게임과 오디오 로직, 오디오 렌더링 스레드 간의 타이밍 문제를 해결하여 샘플 수준의 정확한 오디오 재생을 제공하는 블루프린트 노출 스케줄링 시스템입니다.
쿼츠는 다양한 용도로 사용할 수 있습니다. 예를 들어, 쿼츠를 사용하여 다음과 같은 작업을 수행할 수 있습니다.
- 다이내믹 음악 시스템을 생성합니다.
- 자동 무기 발사와 같이 타이밍이 중요한 사운드 이펙트 재생을 제어합니다.
지연시간: 쿼츠로 해결되는 문제
언리얼 오디오 엔진 은 디지털 아날로그 컨버터(DAC)라고 하는 출력 하드웨어에 개별적으로 전송되는 버퍼에 오디오 샘플을 렌더링합니다. 이러한 버퍼에는 일반적으로 한 번에 샘플이 수백 개에서 수천 개까지도 포함됩니다.
사운드를 재생하거나 사운드의 파라미터를 변경하는 등의 오디오 렌더링 명령은 일반적으로 오디오 버퍼 렌더 시작 시 사용됩니다. 따라서 렌더링된 버퍼 크기에 따라 새 명령 사용 속도가 달라지며, 발행된 모든 명령에서 인지할 수 있는 지연시간이 발생할 수 있습니다.
예를 들어, 같은 게임 스레드 틱에서 폭발 비주얼 이펙트와 폭발 사운드 이펙트를 트리거하는 경우, 비주얼과 사운드 간의 지연시간은 버퍼 크기에 의해 결정됩니다. 해당 버퍼에 초당 48k 샘플(kHz)로 렌더링된 샘플이 2,048개 포함된 경우, 버퍼의 가청 지연시간은 최대 43밀리초(ms)가 됩니다.
버퍼가 렌더링을 시작한 이후 재생 명령이 발행되면(1 ), 다음 버퍼가 시작될 때까지(3 ) 재생 없이 해당 명령이 이월됩니다(2 ).
또한, 게임 스레드에서 발행된 명령은 오디오 엔진에 도달하는 데 시간이 걸립니다. 앞의 예시에서 스레딩 지연시간이 13ms이고 명령이 버퍼 렌더링 시작 이후 발행되었다면, 최악의 경우 지연시간은 56ms가 될 것입니다.
게다가 게임 스레드 틱은 매우 가변적이고 오디오 스레드 타이밍과 분리되어 있으며, 가비지 컬렉션, 에셋 로딩 등의 과정에서 히치가 발생하기 쉽기 때문에 문제가 더 복잡해질 수 있습니다.
이러한 지연시간 문제는 일부 오디오 애플리케이션에서는 심각하지 않습니다. CPU 로드나 플랫폼 컨스트레인트에 따라 버퍼 크기와 수를 미세조정하여 지연시간을 인지할 수 없을 정도로 줄일 수도 있습니다.
쿼츠 작동 방식
오디오 버퍼 시작 시 렌더링하는 대신 쿼츠는 버퍼 크기나 게임 스레드 타이밍 또는 기타 지연시간 변동 원인과는 독립적으로 시간 값(초)이나 음악 값(악보 마디 또는 비트)에 따라 렌더링을 예약합니다.
사전 스케줄링을 통해 쿼츠는 지연시간을 고려하므로 사운드를 딜레이 없이 샘플 수준의 정확도로 렌더링할 수 있습니다.
쿼츠는 샘플 수준의 정확도를 제공합니다. 다음 버퍼 시작까지 오디오 렌더링을 딜레이하는 대신 버퍼 중간에 명령을 예약할 수 있습니다.
스레드 간 커뮤니케이션 흐름
위의 다이어그램에서 A 는 게임 프레임 틱 디비전이 있는 게임 스레드를 나타내며, B 는 버퍼 디비전이 있는 오디오 렌더링 스레드를 나타냅니다.
스레드 간 커뮤니케이션 흐름은 다음과 같이 진행됩니다.
- 게임 스레드가 쿼츠에 주어진 양자화 바운더리에서 사운드를 재생하도록 요청합니다.
- 쿼츠가 그 요청을 발행하고 향후 렌더링을 큐에 등록합니다.
- 요청이 계산된 시간 동안 보류됩니다.
- 이 요청은 버퍼 시작 이후까지 보류될 수도 있습니다.
- 그런 다음, 주어진 양자화 바운더리에서 요청이 렌더링됩니다.
쿼츠 핵심 콘셉트
쿼츠 클럭(오브젝트)
쿼츠 클럭(Quartz Clock) 은 오디오 렌더링 스레드에 이벤트를 예약하고 트리거하는 역할을 합니다. 쿼츠 서브시스템(Quartz Subsystem) 으로 쿼츠 클럭을 생성하고 쿼츠 클럭 핸들(Quartz Clock Handles) 을 사용하여 쿼츠 클럭을 수정합니다. 각 쿼츠 클럭에는 쿼츠 메트로놈(Quartz Metronome) 이 있습니다.
쿼츠 메트로놈(오브젝트)
쿼츠 메트로놈은 시간 경과를 추적하고 타임 시그니처 및 분당 비트(BPM) 등의 세팅에 따라 향후 명령을 예약하는 오디오 렌더링 스레드의 오브젝트입니다.
쿼츠 클럭 핸들(오브젝트)
쿼츠 클럭 핸들은 오디오 렌더러에서 실행되는 쿼츠 클럭을 제어하는 데 사용되는 게임 스레드의 프록시입니다. 쿼츠 서브시스템에서 쿼츠 클럭 핸들에 액세스할 수 있습니다.
쿼츠 서브시스템(오브젝트)
쿼츠 서브시스템을 통해 클럭 생성, 클럭 존재 검증 및 지연시간 정보 쿼리 등, 특정 클럭에 관련되지 않은 일반 시스템 기능을 이용할 수 있습니다.
Play Quantized(함수)
Play Quantized 는 오디오 컴포넌트 입력을 취해 지정된 타이밍으로 주어진 클럭에서 사운드를 재생하는 함수입니다.
Play Quantized를 호출할 때 양자화된 오디오와 동기화하기 위해 입력 델리게이트를 설정할 수 있습니다.
Subscribe to Quantization Event(함수)
Subscribe to Quantization Event 는 쿼츠 클럭 핸들을 취해 비트마다 알리는 식으로 지정된 양자화 이벤트에 대해 주어진 입력 델리게이트에 알리는 함수입니다.
Subscribe to All Quantization Events 베리언트는 모든 양자화 이벤트에서 트리거됩니다. 이 베리언트를 사용하면 양자화 타입(Quantization Type) 에 Switch 노드를 사용하여 여러 타이밍에 대한 로직을 빌드할 수 있습니다.