Quartz 음악 클럭
Quartz Subsystem을 활용한 정밀한 음악 타이밍, BPM 동기화, 양자화 재생
Quartz Subsystem 개요
음악 타이밍을 오디오 렌더 스레드에서 정밀하게 관리하는 시스템
Quartz는 UE5의 오디오 렌더링 스레드에서 동작하는 음악 타이밍 시스템입니다. BPM, 박자를 기반으로 메트로놈을 생성하고, 사운드 재생을 양자화 경계(Quantization Boundary)에 맞춰 스케줄링합니다.
Quartz 핵심 구성 요소
| 구성 요소 | 클래스 | 역할 |
|---|---|---|
| Quartz Subsystem | UQuartzSubsystem | 클럭 생성 및 관리. World Subsystem으로 접근 |
| Quartz Clock | FQuartzClock (내부) | BPM과 박자를 추적하는 메트로놈 |
| Clock Handle | UQuartzClockHandle | Blueprint/C++에서 클럭을 제어하는 핸들 |
| Quantization Boundary | FQuartzQuantizationBoundary | 재생을 맞출 음악적 단위 (비트, 마디 등) |
클럭 생성과 설정
BPM, 박자, 양자화 경계를 설정하여 클럭 생성
// Quartz Subsystem 가져오기
UQuartzSubsystem* QuartzSubsystem =
GetWorld()->GetSubsystem<UQuartzSubsystem>();
// 클럭 설정
FQuartzClockSettings ClockSettings;
ClockSettings.TimeSignature.NumBeats = 4; // 4/4 박자
ClockSettings.TimeSignature.BeatType =
EQuartzTimeSignatureQuantization::QuarterNote;
// 클럭 생성 (이름으로 식별)
UQuartzClockHandle* ClockHandle =
QuartzSubsystem->CreateNewClock(
GetWorld(),
"MusicClock", // 클럭 이름
ClockSettings
);
// BPM 설정
ClockHandle->SetBeatsPerMinute(
GetWorld(),
FQuartzQuantizationBoundary(), // 즉시 적용
FOnQuartzCommandEventBP(),
ClockHandle,
120.0f // 120 BPM
);
Quantization Boundary 옵션
| 단위 | Enum 값 | 120 BPM 기준 간격 |
|---|---|---|
| 마디 (Bar) | Bar | 2.0초 (4/4 기준) |
| 비트 (Beat) | Beat | 0.5초 |
| Half Beat | HalfNote | 1.0초 |
| Quarter Note | QuarterNote | 0.5초 |
| Eighth Note | EighthNote | 0.25초 |
| Sixteenth Note | SixteenthNote | 0.125초 |
| Tick | Tick | 거의 즉시 |
양자화 재생 (Play Quantized)
다음 양자화 경계에 맞춰 사운드를 정밀하게 재생
Play Quantized는 Audio Component의 재생을 다음 양자화 경계(비트, 마디 등)에 맞춰 스케줄링합니다. 이를 통해 여러 스템이 정확히 같은 비트에서 시작하거나, 마디의 첫 박에 맞춰 전환됩니다.
// 다음 마디 시작에 맞춰 재생
FQuartzQuantizationBoundary Boundary;
Boundary.Quantization =
EQuartzCommandQuantization::Bar; // 마디 경계
Boundary.Multiplier = 1.0f;
Boundary.CountingDirection =
EQuartzCommandDelegateSubType::CommandOnQueued;
// Audio Component를 양자화 재생
MusicAudioComp->PlayQuantized(
GetWorld(),
ClockHandle, // Quartz Clock Handle
Boundary, // 양자화 경계
FOnQuartzCommandEventBP() // 콜백 (선택)
);
// 여러 스템을 동시에 양자화 재생 (수직 리믹싱)
for (UAudioComponent* Stem : MusicStems)
{
Stem->PlayQuantized(
GetWorld(), ClockHandle, Boundary,
FOnQuartzCommandEventBP());
}
PlayQuantized의 콜백으로 재생이 실제로 시작된 시점을 알 수 있습니다. 이를 활용하여 시각적 이펙트(비트 동기화 UI)나 다음 구간 준비 로직을 정확한 타이밍에 실행할 수 있습니다.
메트로놈 이벤트 구독
비트, 마디 경계에서 게임플레이 이벤트를 발생시키기
Quartz Clock의 메트로놈 이벤트를 구독하면, 매 비트, 마디에 맞춰 게임 로직을 실행할 수 있습니다. 리듬 게임, 비트 동기화 UI, 음악 기반 레벨 디자인에 활용됩니다.
// 메트로놈 이벤트 델리게이트 구독
ClockHandle->SubscribeToQuantizationEvent(
GetWorld(),
EQuartzCommandQuantization::Beat, // 매 비트마다
OnBeatDelegate, // 콜백 델리게이트
ClockHandle
);
ClockHandle->SubscribeToQuantizationEvent(
GetWorld(),
EQuartzCommandQuantization::Bar, // 매 마디마다
OnBarDelegate,
ClockHandle
);
// 비트 콜백 함수
void UMusicManager::OnBeat(
FName ClockName,
EQuartzCommandQuantization QuantizationType,
int32 NumBars,
int32 Beat,
float BeatFraction)
{
// 비트에 맞춰 시각적 펄스 이펙트
OnMusicBeat.Broadcast(Beat);
// 강박(1번 비트)에서 특별 처리
if (Beat == 1)
{
OnMusicDownbeat.Broadcast(NumBars);
}
}
Quartz는 런타임 BPM 변경을 지원합니다. SetBeatsPerMinute을 호출하면 다음 양자화 경계에서 새 BPM이 적용됩니다. 점진적 BPM 변화(accelerando/ritardando)는 매 마디마다 소량씩 변경하여 구현합니다.
핵심 요약
- Quartz는 오디오 렌더 스레드에서 동작하는 정밀 음악 타이밍 시스템이다
- Clock Handle로 BPM, 박자를 설정하고 메트로놈을 관리한다
- Play Quantized로 다음 비트/마디에 맞춰 사운드를 정밀하게 스케줄링한다
- 메트로놈 이벤트를 구독하여 비트/마디에 동기화된 게임 로직을 실행한다
- 런타임 BPM 변경이 가능하며, 양자화 경계에서 자연스럽게 적용된다
도전 과제
배운 내용을 직접 실습해보세요
UQuartzSubsystem을 통해 Quartz Clock을 생성하고 BPM을 설정하세요. Clock에 Quantization Boundary(Bar, Beat, Eighth 등)를 설정하고, OnQuantizationBoundary 델리게이트로 비트에 맞춰 로그를 출력하세요.
Quartz Clock의 비트에 동기화하여 드럼 패턴을 재생하세요. PlayQuantized()를 사용하여 Kick, Snare, HiHat을 각각 비트에 맞춰 재생하는 간단한 드럼 머신을 구현하세요.
Quartz Clock을 활용하여 리듬 게임의 핵심 시스템을 구현하세요. 음악 비트에 맞춰 노트가 생성되고, 플레이어 입력의 정확도를 Quantization Boundary 기준으로 판정(Perfect, Good, Miss)하는 시스템을 만드세요.