Time-Stamped 이벤트
신디사이저 타이밍의 큰 그림은 재생해야 할 때 정확하게 메모를 보내는 대신 각 노트가 타임스탬프가 찍어 버퍼에 배치된다는 것입니다. 그런 다음 이 버퍼는 타임스탬프로 지정된 시간의 2밀리초 이내에 처리되고 재생됩니다. (타이밍 확인은 수백 나노초 단위이지만 이 논의에 더 편리한 시간 단위인 밀리초 측면에서 설명하겠습니다.)
대기 시간은 대기 시간 클록을 통해 시스템에 알려지기 때문에 타임스탬프는 이벤트를 큐에 떨어뜨리고 대기 시간이 낮기를 바라는 것이 아니라 버퍼에서 적절한 시간에 재생되기를 대기할 수 있습니다.
master 클록은 COM IReferenceClock 인터페이스를 구현합니다(Microsoft Windows SDK 설명서에 설명됨). 시스템의 모든 디바이스는 이 참조 시간을 사용합니다.
Microsoft의 웨이브 싱크 구현은 20밀리초마다 절전 모드를 해제하는 스레드를 빌드합니다. 스레드의 작업은 다른 버퍼를 만들어 DirectSound에 전달하는 것입니다. 해당 버퍼를 만들기 위해 이 버퍼는 신시사이저를 호출하고 지정된 양의 음악 데이터를 렌더링하도록 요청합니다. 요청하는 양은 스레드가 절전 모드 해제되는 실제 시간에 따라 결정되며 정확히 20밀리초가 될 가능성은 낮습니다.
실제로 신시사이저에 전달되는 것은 단순히 PCM 버퍼에 데이터 쓰기를 시작할 메모리의 위치에 대한 포인터와 쓸 데이터의 양을 지정하는 길이 매개 변수입니다. 그런 다음, 신디사이저는 PCM 데이터를 이 버퍼에 쓰고 지정된 양까지 채울 수 있습니다. 즉, 지정된 길이에 도달할 때까지 시작 주소에서 렌더링됩니다. 해당 메모리 블록은 DirectSoundBuffer(기본 사례)일 수 있지만 DirectShow 그래프 또는 웨이브 싱크에서 정의한 다른 대상일 수도 있습니다.
PCM 버퍼는 개념적으로 순환적입니다(즉, 지속적으로 반복됨). 신시사이저는 소리를 설명하는 16비트 숫자를 버퍼의 연속 조각으로 렌더링합니다. 싱크가 정확히 20밀리초마다 절전 모드를 해제할 수 없으므로 스레드가 깨어날 때마다 조각 크기가 약간 다릅니다. 따라서 스레드가 절전 모드에서 해제할 때마다 절전 모드로 돌아가기 전에 버퍼를 통해 얼마나 멀리 진행해야 하는지 결정하기 위해 대기합니다.
애플리케이션의 관점에서 synth 포트 드라이버 자체에는 웨이브 싱크에서 시계를 가져오는 IDirectMusicSynth::GetLatencyClock 함수가 있습니다. 따라서 두 개의 시계가 있습니다.
웨이브 싱크를 포함한 모든 사람이 듣는 master 시계입니다.
애플리케이션에서 대기 시간 클록을 제공하는 DirectMusic 포트로 표시되는 웨이브 싱크에 의해 구현되는 대기 시간 클록입니다.
즉, 애플리케이션은 대기 시간 클록을 요청하지만 시계는 웨이브 싱크가 아닌 DirectMusic 포트 추상화에서 오는 것으로 간주합니다.
이 대기 시간 클록에서 반환되는 시간은 신디사이저가 버퍼의 해당 지점까지 이미 렌더링되었기 때문에 버퍼를 렌더링할 수 있는 가장 빠른 시간입니다. 신디사이저가 마지막 쓰기에서 더 작은 버퍼를 렌더링했다면 대기 시간도 더 작아질 것입니다.
따라서 웨이브 싱크는 신디사이저에서 IDirectMusicSynth::Render 를 호출하여 버퍼를 표시하고 렌더링된 데이터로 채워지게 요청합니다. 다음 그림과 같이 synth는 IDirectMusicSynth::P layBuffer 함수 호출의 결과로 들어오는 모든 타임스탬프 이벤트를 사용합니다.
각 입력 버퍼에는 타임스탬프를 찍은 메시지가 포함됩니다. 이러한 각 메시지는 타임스탬프를 통해 지정된 시간에 버퍼로 렌더링될 큐에 배치됩니다.
이 모델의 중요한 점 중 하나는 타임스탬프를 제외한 특정 순서가 없다는 것입니다. 이러한 이벤트는 스트리밍되므로 렌더링하기 전에 언제든지 큐에 추가할 수 있습니다. 모든 것은 시간에 관한 이벤트 기반입니다. 예를 들어 참조 시간이 현재 400 시간 단위인 경우 400 시간에 발생하는 모든 타임스탬프가 지금 발생합니다. 지금부터 10개 단위가 발생하는 이벤트 타임스탬프는 410시간에 발생합니다.