MIDI에서 웨이브로

신시사이저의 주요 작업은 다음 두 단계로 수행됩니다.

  • MIDI 메시지 가져오기

  • 렌더링된 노트를 웨이브 오디오 스트림에 혼합

이 섹션에서는 개념이 커널 모드에서 기본적으로 동일하지만 일반적으로 사용자 모드에서 이 작업을 수행하는 방법을 자세히 설명합니다. 커널 모드 미니포트 드라이버로 동일한 작업을 수행하는 방법에 대한 자세한 내용은 커널 모드 하드웨어 가속 DDI 를 참조하세요.

사용자 모드에서 애플리케이션은 MIDI 메시지를 재생할 준비가 되면 IDirectMusicSynth::P layBuffer 를 호출합니다. 애플리케이션은 적시에 PlayBuffer 를 호출하고 버퍼를 올바르게 타임스탬프하여 신시사이저 대기 시간을 고려해야 합니다. 이 메서드의 구현은 대기 중인 메시지를 검색하고 내부 형식으로 저장합니다. 이 형식은 버퍼와 함께 전달되는 참조 시간을 기반으로 하는 시간으로 스탬프됩니다.

웨이브 싱크는 데이터를 받을 준비가 될 때마다 IDirectMusicSynth::Render 를 호출합니다. 예를 들어 렌더링된 데이터의 대상이 DirectSound 보조 버퍼인 경우 IDirectMusicSynthSink::Activate 구현은 DirectSound PlayBuffer 알림을 기다리는 스레드를 설정할 수 있습니다. DirectSound 버퍼에 데이터가 필요한 경우 DirectSound는 스레드에 알립니다. 이 스레드는 렌더링을 호출하고, IDirectSoundBuffer 개체(Microsoft Windows SDK 설명서에 설명됨)에 대한 포인터를 전달하고 렌더링할 샘플의 수와 위치를 전달합니다.

DirectSound 버퍼는 순환입니다. 버퍼의 끝에서 래핑이 발생하기 때문에 사실상 연속된 영역이 두 조각으로 분할될 가능성을 고려해야 합니다. 일반적으로 웨이브 싱크는 DirectSound 버퍼의 잠긴 부분 각각에 대해 한 번씩 Render 를 두 번 호출하여 분할을 처리하므로 Render 메서드는 연속된 메모리 블록만 처리해야 합니다. 웨이브 싱크는 IDirectSoundBuffer::DirectSound 버퍼에 대한 잠금을 호출하여 버퍼 내의 지역에 대한 쓰기 권한을 요청합니다. 예를 들어 웨이브 싱크가 버퍼 끝에서 1킬로바이트부터 시작하는 2KB의 데이터에 대해 Lock 을 호출하는 경우 호출은 버퍼의 끝까지 마지막 1킬로바이트 및 버퍼의 시작 부분에서 시작하는 다른 1킬로바이트까지 잠급니다. 이 경우 Lock 은 실제로 잠긴 버퍼의 영역을 설명하는 두 개의 포인터와 해당 길이를 반환합니다. 각 포인터는 연속된 메모리 블록을 가리키도록 보장됩니다.

Render 메서드의 구현은 PlayBuffer에서 검색되는 MIDI 메시지에 대한 응답으로 수행해야 하는 작업을 결정합니다. 렌더링에 대한 연속 호출의 dwLength 매개 변수 값에서 메서드는 샘플 시간을 추적하고 현재 렌더링 기간에 유효한 메시지에 대해 작동할 수 있습니다. 메모 표시 메시지가 처리되면 해당 메모 해제 메시지가 수신될 때까지 메서드를 통과할 때마다 노트를 내부적으로 저장하고 다시 렌더링할 수 있습니다.