An Overview of Common Tasks

OSXDEV

Jump to: navigation, 찾기

Core Audio Overview로 이동


이 챕터는 Core Audio를 사용해서 할 수있는 몇가지 기본 시나리오에 대해서 설명하고 있습니다. 이런 예는 보통 하는 작업을 Core Audio를 이용해서 어떻게 할 수있나 알려줄 것입니다.

Core Audio가 아주 모듈러하다는 것을 주지하십시오. 하지만 극히 일부에서는 제한이 있을 수있습니다. 그러므로 여기에서 설명된 방법외에도 다른 식으로 구현을 할 필요가 있을 수도 있습니다. 예를 들어, 여러분의 프로그램은 Audio File와 Converter Service 함수를 직접적으로 호출해서 파일에서 데이터를 읽어서 linear PCM으로 변환하거나, 그런 기능을 독립적인 제너레이터 오디오 유닛으로 만들어서 여러분의 프로그램이 그런 유닛을 찾아서 로딩할 수있게 할 수도 있습니다.

목차

[편집] Reading and Writing Audio Data

오디오를 처리하는 프로글매들은 데이터를 디스크나 버퍼에 읽고 쓸 필요가 있을겁니다. 대개의 경우에 있어서 파일 데이터를 읽어서 linear PCM으로 변환할 겁니다. (오디오 유닛등에서 사용하기 위해서) 또한 Extended Audio File API를 이용해서 한번에 똑같은 일을 할 수도 있습니다.

Figure 3-1에서 볼 수있는 것처럼, Extended Audio File API는 Audio File API를 호출해서 오디오 데이터를 읽고 Audio Covnerter API를 호출해서, 데이타가 아직 linear PCM 형태가 아니라는 가정으로, linear PCM으로 변환합니다.


Figure 3-1 Reading audio data
그림:a_core_audio_reading_audio_file.jpg


만약 파일을 읽고 변환하는데 제어권을 더 갖고 싶으면, Audio File이나 Audio Converter 함수들을 직접 호출할 수있습니다. Audio File API를 이용해서 디스크나 버퍼에서 데이터를 읽습니다. 이렇게 읽어들인 것은 아마도 압축된 형식으로 되어 있을텐데, 컨버터를 통해서 linear PCM으로 변환하게 됩니다. 또한 오디오 컨버터를 이용해서 bit depth나 샘플링 레이트 등을 linear PCM 포맷을 유지한 채로 바꿀 수있습니다. 이러한 컨버터 객체를 만들려면 Audio Converter API를 이용하면 됩니다. 이때 입력과 출력 형식을 정해주게 됩니다. 각 포맷은 AudioStreamBasicDescription 구조에 있으며, 이는 Core Audio에서 오디오 데이터를 표현하기 위한 아주 기본적인 데이터 타입입니다. 앞에서도 언급되었다시피, linear PCM으로 변환하고자 하면, Extended Audio File API를 이용해서 오디오 파일 데이터를 컨버터를 만들지 않고도 linear PCM으로 한번에 바꿀 수있습니다.

일단 이렇게 linear PCM으로 변환이 되면 그 데이터는 오디오 유닛이 처리할 수있는 상태가 됩니다. 오디오 유닛을 연결하려면 특정 오디오 유닛 입력에 대해서 callback을 등록해야 합니다. 그 오디오 유닛이 입력 데이터가 필요하면, 제공해준 callback 함수를 호출할 것입니다. 그러면 그 callback 함수는 필요한 오디오 데이터를 제공해주게 됩니다.

만약 오디오 데이터를 출력하고자 한다면, 그것을 출력 유닛에 보내면 됩니다. 출력 유닛은 linear PCM 형식의 데이터만을 받습니다. 출력 유닛은 보통 하드웨어 장비에 대한 프록시입니다. 하지만 꼭 그런건 아닙니다.

linear PCM은 중간형태의 포맷으로 사용할 수 있는데, 이로써 여러 다른 변환을 할 수있습니다. 어떤 특정의 변환이 가능한지 판단하려면, A 포맷에서 linear PCM으로 변환 해주는 디코더와 linear PCM에서 B 포맷으로 변환해 주는 인코더가 존재하는지 확인해 봐야합니다. 예를 들어 데이터를 MP3에서 AAC로 변환해 주려면, 두개의 오디오 컨버터가 필요합니다. 즉 하나는 mp3를 linear PCM으로 다른 하나는 linear PCM에서 AAC로 변환하는 것입니다. 이는 Figure 3-2에 나와 있습니다.


Figure 3-2 Converting audio data using two converters
그림:a_core_audio_file_conversion.jpg


Audio File와 Audio Converter API를 사용하는 예는 Core Audio SDK에 있는 SimpleSDK/ConvertFile와 Services/AudioFileTools 샘플을 참조하십시오. 커스텀 오디오 컨버터 코덱을 만들고 싶으시면 AudioCodec 에 있는 샘플을 참조하십시오.

[편집] Interfacing with Hardware Devices

대부분의 오디오 관련 응용 프로그램들은 외부 장비와 연결을 해야 합니다.오디오 데이터를 출력하거나( 앰프/스피커를 통해서 ) 혹은 마이크같은 것을 이용해서 데이터를 얻어내기 위해서 외부 장비와 연결이 필요합니다. 이런 작업은 HAL을 통해서 이루어지게 됩니다. 다행이도, HAL을 억세스하기 위해서 코딩할 필요는 대개 없습니다. Apple이 세가지 기본 오디오 유닛을 제공하는데, 이것들이 대부분의 하드웨어에 대한 필요성을 해결해 줄것입니다. 이런 세 오디오 유닛은, 기본 출력 유닛, 시스템 출력 유닛, 그리고 AUHAL입니다. 여러분의 프로그램은 Component Manager를 호출해서 이런 유닛들을 찾아서 로딩해야 합니다.

[편집] Default and System Output Units

기본 출력 유닛과 시스템 출력 유닛은 오디오 데이터를 사용자가 선택한 기본 출력이나 시스템 사운드나 경고음이 나오는 시스템 출력으로 보냅니다.만약 오디오 유닛을 이런 출력 장비중 하나로 연결하면, 그 유닛의 callback 함수( 때로 render callback이라고도 합니다.)이 출력단에서 데이터를 필요로 할때 호출됩니다. 출력 유닛은 데이터를 HAL을 통해서 적절한 출력 장비로 ㅃ보아 내는데, Figure 3-3에서 나타난바 같이, 다음의 작업들을 자동으로 수행해 줍니다.


Figure 3-3 Inside an output unit 그림:a_core_audio_Inside_output_unit.jpg


  • 필요한 linear PCM 데이터 변환. 출력 유닛은 오디오 데이터를 하드웨어가 필요로 하는 형태의 linear PCM으로 변환하는 컨버터를 가지고 있게 됩니다.
  • 필요한 채널 매핑. 예를 들어 유닛이 두 채널의 데이터를 공급하고 있고, 출력 장비가 다섯개라면, 어떤 채널이 어느 출력으로 나가야 할지 매핑해야 합니다. 이런 것은 출력 유닛의 kAudioOutputUnitProperty_ChannelMap 속성을 이용해서 매핑을 할 수있습니다. 이런 채널 맵을 제공하지 않으면, 기본적으로 첫번째 오디오 채널은 첫번째 장비 채널로, 두번째는 두번째의 것으로.. 하는 식으로 매핑됩니다. 실제의 출력은 Audio MIDI Setup 프로그램에서 어떻게 디바이스 스피커들을 구성했느냐에 따라 결정됩니다.
  • 신호의 시작과 정지. 출력 유닛은 오디오 데이터의 흐름을 시그널 체인에서 제어할 수있는 유일한 오디오 유닛입니다.

기본 출력 유닛을 이용해서 오디오를 재생하는 예는 Core Audio SDK의 SimpleSDK/DefaultOutputUnit를 참조하십시오.

[편집] The AUHAL

만약 입력 장비나 기본 출력 장비가 아닌 다른 하드웨어 장비에 연결할 필요가 있다면, AUHAL을 사용할 필요가 있을겁니다. 비록 출력 장비로 쓸 것을 염두에 두고 만들어졌지만, 입력단에서 kAudioOutputUnitProperty_EnableIO 속성을 세팅함으로써 AUHAL이 입력도 받아 들일 수있도록 할 수있습니다. 더 자세한 사항에 대해서 알아보시려면 Technical Note TN2091: Device Input Using the HAL Output Audio Unit을 참조하시기 바랍니다. 입력을 받아들이기 위해서, AUHAL은 입력 채널 매핑을 지원하며 필요하다면 오디오 컨버터를 사용해서 들어오는 데이터를 linear PCM 포맷으로 변환합니다.

AUHAL은 기본 출력 유닛의 보다더 일반화된 버젼이라고 보시면 됩니다. 오디오 컨버터와 채널 매핑이라는 기능 외에도, kAudioOutputUnitProperty_CurrentDevice 속성을 HAL의 AudioDevice 객체에 대한 ID로 세팅함으로써 장비를 연결할 수있습니다. 일단 연결이 되면, AUHAL을 지정해서 AudioDevice 객체와 연계된 속성들을 조작할 수있습니다. AUHAL은 자동으로 오디오 장비들의 속성에 대한 함수를 전달해 줍니다.

AUHAL 인스턴스는 한번에 한 장비만 연결할 수있습니다. 그러므로 장비가 입력과 출력을 다 받아 들일때만 두개를 동시에 활성화 시킬 수있습니다. 예를 들어, PowerPC 매킨토시를 위한 built-in 오디오는 Mic in을 통해서 오디오 데이터를 받아 들일 수도 있고, 스피커를 통해서 출력을 할 수있도록 되어 있습니다.

Note: USB 오디오 장비나 현재 인텔 매킨토시의 built-in 오디오와 같은 몇몇 오디오 하드웨어들은 입력과 출력이 각각 별도의 오디오 장비로 되어 있습니다. “Using Aggregate Devices”를 보시면 어떻게 이런 별개의 장비들을 한개의 AudioDevice 객체로 합칠 수있는지에 대해서 나와 있습니다.

신호의 흐름을 위해서, 입력과 출력 양쪽으로 구성된 AUHAL은 두개의 오디오 유닛처럼 동작합니다. 예를 들어, 출력이 활성화되어 있으면, AUHAL은 그보다 앞에 있는 오디오 유닛의 render callback을 호출합니다. 만약 오디오 유닛이 어떤 장비로부터 입력 데이터를 필요로 하면, 그 장비의 AUHAL의 render callback을 호출합니다. Figure 3-4 을 보시면 AUHAL이 입출력 양쪽에서 사용되는 것을 볼 수있습니다.


Figure 3-4 The AUHAL used for input and output 그림:A_core_audio_Hal_input_output.jpg‎


외부 장비에서 오는 오디오 신호는 오디오 데이터 스트림으로 변환되어 AUHAL로 가는데, 이를 통해서 또 다른 오디오 유닛으로 보내어 집니다. 효과를 더하거나 다른 오디오 데이터와 합치는 겇과 같은 식으로 데이터를 처리한 후에, 그 출력은 다시 AUHAL로 보내진 다음에, 같은 외부 장비를 통해서 출력이 됩니다.

입력과 출력으로 AUHAL을 사용하는 예에 대해서는 ADC 레퍼런스 라이브러리의 SimplePlayThruComplexPlayThru 코드 샘플을 참조하시기 바랍니다. SimplePlayThru은 한개의 AUHAL 인스턴스를 통해서 입력과 출력을 어떻게 다루는지 보여주며, ComplexPlayThru은 입력으로는 AUHAL을, 출력으로는 기본 출력 유닛을 이용해서 어떻게 입력과 출력을 구현하는지 보여줍니다.

[편집] Using Aggregate Devices

하드웨어 오디오 장비와 인터페이싱을 할때, Core Audio는 추가적인 수준의 추상화를 할 수있도록 해 줍니다. 즉 여러 장비를 아우르는 장비(aggregate device)를 만들게 되는데, 이는 여러 장비들의 입력과 출력을 합쳐서 한개의 장비처럼 보이게 만드는 것입니다. 예를 들어, 오디오 출력으로 다섯개의 출력을 뽑을 필요가 있으면, 그 중 두개는 한 장비로, 그리고 나머지 세개는 또 다른 장비로 지정해 놓을 수 있습니다. Core Audio는 여러분의 프로그램이 출력들이 마치 한 장비인 것처럼 보게 만들면서도 자동으로 데이터 흐름을 두 장비로 보내게 됩니다. Core Audio는 또한 적절히 오디오를 동기화 시켜주며, 지연을 최소화할 수있도록 해 줍니다. 그렇게 함으로써, 여러분이 보다 더 세세한 다른 일에 집중할 수있도록 해 줍니다.

사용자들은 aggregate 디바이스를, Audio > Open Aggregate Device Editor 메뉴 아이템을 선택함으로써, Audio MIDI Setup 프로그램에서 만들 수있습니다. subdevice들을 선택해서 aggregate 장비로 구성한 후에, 사용자들은 그 장비의 입력과 출력 채널을 흡사 다른 하드웨어 장비처럼 구성할 수있습니다. 이때 사용자는 어떤 서브 디바이스의 클럭이 동기를 위해 마스터 클럭으로 작동해야 하는지 지정해 주어야 합니다.

사용자가 만든 모든 aggregate 장비는 시스템에게는 global합니다. 하지만 여러분은 HAL 서비스 함수를 이용해서 프로그램상에서 어떤 특정 프로그램의 프로세스에만 적용되는 aggregate device를 만들 수있습니다. HAL에서 AudioDevice의 서브 클래스인 AudioAggregateDevice로 aggregate 장비가 보여지게 됩니다.

Note: aggregate 장비는 구현을 숨기기 위해서 사용될 수있습니다. 예를 들어 USB 오디오 장비들은 보통 입력과 출력을 위해서 별도의 드라이버를 필요로 합니다. 이건 별도의 독립된 AudioDevice 객체로 보이게 됩니다. 하지만, global한 aggregate 장비를 만들어 줌으로써, HAL은 그 드라이버들을 한개의 AudioDevice로써 표현할 수있습니다.

aggregate 장비는 그 서브 디바이스들에 대한 정보를 가지고 있게 됩니다. 만약 사용자가 한 서브 디바이스를 없애거나, 호환이 되지 않는 식으로 세팅을 하면, 그 채널은 aggreate에서 사라지게 됩니다. 하지만 그 채널들은, 그 서브 디바이스가 다시 연결되가나 세팅되면 다시 나타납니다.

이런 Aggregate 장비들은 몇몇 제한점을 가지고 있습니다.

  • aggregate 디바이스를 구성하는 모든 서브 디바이스들은 같은 샘플링 레이트로 동작되어야 하며, 그 데이터 스트림들은 서로 섞일 수있어야 합니다.
  • 그 어떤 세팅 가능한 컨트롤도 가질 수없습니다. 예를 들어, 불륨, 뮤트 혹은 입력 소스를 선택하는 기능을 가질 수없습니다. 모든 서브 디바이스가 기본 장비가 아닌한, aggregate 장비를 기본 입력이나 출력 장비로 지정할 수없습니다. 만약 그렇지 않으면, 프로그램은 반드시 aggregate 장비를 명시해 주어야 합니다.
  • 현재로선, 커널 레벨인 IOAudio계열의 드라이버들로 표현되는 장비들만이 aggregate 장비에 추가될 수있습니다.

[편집] Creating Audio Units

오디오 유닛을 만들기 위한 자세한 정보는 Audio Unit Programming Guide을 참조하십시오.

[편집] Hosting Audio Units

플러그인으로 된 오디오 유닛들은 그것들을 로딩시키고 제어해 줄 호스트 프로그램이 필요합니다.

오디오 유닛이 Component Manager 컴포넌트로 되어 있기 때문에, 호스트 프로그램은 Component Manager에게 이런 오디오 유닛을 로딩시켜 달라고 요청해야 합니다. 호스트 프로그램은 다음의 폴더 중 어느 한 곳에 오디오 유닛이 있으면, 찾아서 인스턴스화 할 수있습니다.

  • ~/Library/Audio/Plug-Ins/Components. 여기서 설치된 오디오 유닛은 홈 폴더를 소유한 사용자만 사용할 겁니다.
  • /Library/Audio/Plug-Ins/Components. 여기에 설치된 오디오 유닛은 모든 사용자가 사용가능 합니다.
  • /System/Library/Components. Apple이 제공한 오디오 유닛이 있는 기본 위치입니다.

만약 오디오 유닛이 뭐가 있는지 목록을 뽑아 보시길 원한다면, (예를 들어 사용자에게 보여준다던가..), Component Mangager 함수인 CountComponents을 호출하셔서 특정 타입의 오디오 유닛이 얼마나 많이 있는지 우선 알아 내신후, FindNextComponent를 이용해서 iteration을 하면서 각 유닛에 대한 정보를 알아 내면 됩니다. ComponentDescription 구조는 각 오디오 유닛에 대한 식별자를 가지고 있습니다. 즉 그 타입이나 서브 타입, 그리고 제조자 코드를 가지고 있습니다. Apple이 제공한 오디오 유닛의 Component Manager 타입과 서브 타입들이 어떤게 있는지 알아보시려면 System-Supplied Audio Units을 참고 하십시오. 호스트 프로그램은 OpenComponent를 이용해서 각 유닛을 열수 있습니다. 그래서 오디오 유닛의 기본 입출력 데이터 포맷과 같은 속성 정보를 물어 볼 수있습니다. 이렇게 물어 본 것은 캐슁이 되어 사용자에게 제공 됩니다.

대개의 경우에 있어서 오디오 프로세싱 그래프는 오디오 유닛을 연결하는 가장 간단한 방법입니다. 프로세싱 그래프를 사용하는 한가지 장점은 API가 개개의 Component Manager 함수 호출을 관장해서 오디오 유닛들을 인스턴스화하고 파괴한다는 것입니다. 그패르를 만들려면 NewAUGraph을 호출하십시오. 이 함수는 새 그래프 객체를 반환합니다. 이제 오디오 유닛을 AUGraphNewNode을 호출해서 그래프에 집어 넣을 수있습니다. 이런 그래프는 출력 유닛으로 끝나야만 합니다. 이 출력 유닛은 기본 출력 유닛이나 AUHAL과 같은 하드웨어 인터페이스거나 혹은 일반적인 출력 유닛이면 됩니다.

프로세싱 그래프를 구성할 유닛들을 추가한 후에, AUGraphOpen을 호출 하십시오. 이 함수를 부르는 것은, 그래프에서 각 유닛에 대해서 일일이 OpenComponent을 호출하는 것과 같은 효과를 냅니다. 이때, 채널 레이아웃이나, 샘플링 레이트, 특정 유닛에 한정된 속성, 예를 들어 유닛이 가지고 있는 입/출력의 갯수 같은 오디오 유닛 속성들을 정해 줄 수있습니다.

오디오 유닛 사이를 개별적으로 연결해 주고 싶으면 AUGraphConnectNodeInput을 호출하십시오. 이때 연결할 출력과 입력을 정해주어야 합니다. 오디오 유닛은 한개의 출력 유닛을 가져야만 합니다. 그렇지 않으면 호스트 프로그램이 오디오 프로세싱을 하거나 중지시킬 수있는 방법이 없습니다.

만약 오디오 유닛이 사용자 인터페이스를 가지고 있스면, 호스트 프로그램이 그것을 화면에 표시해 주어야 합니다. 오디오 유닛은 Cocoa나 Carbon 기반의 인터페이스(혹은 둘다)를 제공할 수있습니다.보통 이런 유저 인터페이스 코드는 오디오 유닛과 함께 번들로 제공됩니다.

  • 만약 인퍼페이스가 Cocoa로 되어 있으면, NSView의 서브클래스로 되어 있는 커스텀 클래스를 찾기 위해서 kAudioUnitProperty_CocoaUI라는 유닛 속성을 쿼리해야 합니다. 그리고 그 클래스의 인스턴스를 만들어야 합니다.
  • 만약 인터페이스가 카본으로 되어 있으면, 인터페이스 자체가 Component Manager 컴포넌트로 저장됩니다. 그 컴포넌트의 식별자 ( 타입, 서브 타입, 제조자)를 kAudioUnitProperty_GetUIComponentList 속성을 쿼리해서 얻어 내야 합니다. 호스트 프로그램은 이제 주어진 컴포넌트에 대해서 AudioUnitCarbonViewCreate를 호출 함으로써 유저 인터페이스를 인스턴스화하게 됩니다. 이 인터페이스는 HIView로 되어 있는 윈도우 내에 그려지게 됩니다.

시그널 체인을 만든 후에, AUGraphInitialize을 호출함으로써 오디오 유닛을 초기화 합니다. 그렇게 하면, 각 오디오 유닛에 대해서 초기화 함수를 호출하게 되며, 필요한 메모리를 할당하게 됩니다. 그리고 채널 정보를 세팅한다던지 하는 일련의 작업을 하게 됩니다. 이제 AUGraphStart를 호출함으로써 오디오 데이터를 처리하게 합니다.출력 유닛은 이때, 오디오 데이터를 체인에서의 그 전 단계에 있는 유닛에 callback 함수를 호출함으로써 요구하게 됩니다. 이렇게 해서 오디오 소스까지 이 callback이 호출됩니다. 오디오 소스는 제너레이터 유닛이나 AUHAL같은 오디오 유닛일 수도 있고, 호스트 프로그램이, 시그널 체인에서의 첫번째 오디오 유닛의 callback을 kAudioUnitProperty_SetRenderCallback 속성을 이용해서 등록해서 오디오 데이터를 제공할 수도 있습니다.

오디오 유닛이 인스턴스화되는 동안, 호스트 프로그램은 패러미터나 속성의 값이 변하는지 알아내야 할지도 모릅니다. 그래서 호스트 프로그램은 listener 객체를 등록해서 변화가 생겼을때, 공지 받을 수있습니다. 이런 listener를 어떻게 구현하는지에 대해서는 Technical Note TN2104: Handling Audio Unit Events을 참조하시기 바랍니다.

호스트 프로그램이 신호처리를 그만두고 싶을 때는, AUGraphStop을 호출하면 됩니다.

그래프에 있는 모든 오디오 유닛을 非초기화하고 싶을때는, AUGraphUninitialize을 호출하면 됩니다. 이렇게 초기화하지 않은 상태로 돌아갔을때도, 여전히 오디오 유닛의 속성들을 바꿀 수있고, 유닛간의 연결을 하거나 바꿀 수 있습니다. 만약 AUGraphClose을 호출하면, 각 오디오 유닛은 CloseComponent 호출에 의해서 deallocate 됩니다. 하지만 그래프는 여전히 각 유닛이 가지고 있는 노드의 정보를 가지고 있습니다.

프로세싱 그래프를 dispose 시키려면 AUGraphDispose를 호출하십시오. 그래프를 dispose하면 자동으로 그 내부의 오디오 유닛을 다 dispose합니다.

오디오 유닛을 호스팅 하는 예는 Core Audio SDK의 Services/AudioUnitHosting와 Services/CocoaAUHost을 참조하십시오.

오디오 유닛의 유저 인터페이스를 만드는 예는 역시 Core Audio SDK의 AudioUnits/CarbonGenericView를 참조하시면 됩니다.이 예를 이용하면 사용자가 바꿀 수있는 패러미터를 가진 그 어떤 오디오 유닛도 만들 수있습니다.

Component Manager에 대한 더 자세한 정보는 다음의 문서에서 얻을 수있습니다.

[편집] Handling MIDI Data

MIDI 데이터를 다룰 때, 프로그램은 표준 MIDI 파일(SMF)에서 트랙 테이터를 읽어야 할 지도 모릅니다. Music Player 함수인 MusicSequenceLoadSMFWithFlags 나 MusicSequenceLoadSMFDataWithFlags를 사용하면 표준 MIDI 포맷에서 데이터를 읽을 수있습니다. 이에 대해선 Figure 3-5에서 볼 수있습니다.


Figure 3-5 Reading a standard MIDI file
그림:a_core_audio_Midi_file_read_in.jpg


MIDI 파일 타입이나 로딩할 때 세팅한 플래그에 따라서, 한 트랙에 MIDI 데이타를 다 저장하거나, 시퀀스 내의 독립된 트랙에 각 MIDI 채널을 따로 저장할 수도 있습니다. 기본 세팅은 각 MIDI 채널이 시퀀스 내의 새 트랙에 순차적으로 매핑되는 것입니다. 예를 들어 MIDI 데이터가 1, 3, 4 채널을 가지고 있다면, 시퀀스에 세 트랙이 더해지면서, 그 세 트랙은 각각 이 채널들의 MIDI 데이터를 가지고 있게 됩니다. 이 트랙들은 이미 그 시퀀스에 있던 트랙들 뒤에 추가가 되는 것입니다. 시퀀스의 각 트랙은 0부터 시작되는 식으로 인덱싱이 됩니다.

템포 이벤트 같은 시간 정보는 템포 트랙에 포함됩니다.

MIDI 데이터를 시퀀스에 일단 로딩하게 되면, 뮤직 플레이어 인스턴스를 할당해서 재생할 수있습니다. 이것은 Figure 3-6에서 볼 수있습니다.


Figure 3-6 Playing MIDI data
그림:a_core_audio_Midi_file_audio_playback.jpg


시퀀스는 한 오디오 프로세싱 그래프에 연계가 되어야 합니다. 그리고 그 안의 트랙들은그래프 내에서 한개 이상의 악기 유닛에 할당되어 있어야 합니다. (만약 트랙에 매핑 시켜 놓지 않았으면, 그래프의 첫번째 악기 유닛에 모든 MIDI 데이터를 보냅니다. ) 시퀀스에 할당된 뮤직 플레이어는 자동으로 그 그래프의 출력 유닛과 통신을 해서, 출력되는 오디오 데이터가 적절하게 동기되는지 조절해 줍니다. 압축 유닛은, 꼭 필요한건 아니지만, 동적인 번위를 갖는 악기 유닛의 출력이 일정하도록 해 줍니다.

MIDI 데이터는 또한 외부 MIDI 장비나 가상의 소프트웨어 미디 종착지로 보내질 수있습니다. 이에 대해선 Figure 3-7에 나와 있습니다.

MIDI 출력 쪽으로 나가게 되어 있는 트랙은 MIDI 엔드 포인트에 할당되어 있어야 합니다. 뮤직 플레이어는 Core MIDI와 통신을 해서, MIDI 디바이스로의 데이터 흐름이 적절하게 됭기화되도록 보장해 줍니다. Core MIDI는 이제 MIDI Server가 데이터를 MIDI 악기에 보내도록 해 줍니다.


Figure 3-7 Sending MIDI data to a MIDI device
그림:a_core_audio_Midi_device_playthrough.jpg


트랙들로 구성된 시퀀스는 여러개의 악기 유닛들과 MIDI 장비에 할당될 수있습니다. 예를 들어, 몇몇 트랙은 MIDI 장비가 재생하게 할 수있습니다. 이에 대해서는 Figure 3-8에서 확인할 수있습니다.


Figure 3-8 Playing both MIDI devices and a virtual instrument
그림:a_core_audio_Midi_file_big_picture.jpg


뮤직 플레이어는 자동으로 오디오 프로세싱 그래프의 출력 유닛과 Core MIDI를 코디네이트해서 출력이 동기화되도록 보장해 줍니다.

또 다른 보통 사용되어지는 패턴은, 새 MIDI 입력을 받는 동안 기존의 트랙 데이터를 재생하는 경우인데, Figure 3-9에서 볼 수있습니다.


Figure 3-9 Accepting new track input
그림:A_core_audio_Midi_file_recording.jpg‎


이미 있는 데이터를 재생하는 것은 오디오 프로세싱 그래프를 통해서 앞의 과정과 동일하게 처리되는데, 오디오 프로레싱 그래프는 오디오 데이터를 출력 유닛으로 보냅니다. 외부 MIDI 장비에서 들어오는 새 데이터는 Core MIDI를 통해서 지정된 엔드 포인트로 보내지게 됩니다. 여러분의 프로그램은 이 새로 들어오는 데이터를 죽 훑으면서 MIDI 이벤트를 새 트랙이나 이미 있는 트랙에 써야 합니다. 뮤직 플레이어 API는 새 트랙을 시퀀스에 추가하는 함수를 가지고 있으며, time-stamping이 된 MIDI 이벤트나 다른 메시지를 트랙에 쓰는 함수들도 가지고 있습니다.

MIDI 데이터를 다루고 재생하는 예는 Core Audio SDK의 다음 예를 참조하십시오.

  • MIDI/SampleTools, MIDI 데이터를 보내고 받는 간단한 예를 보여 줍니다.
  • SimpleSDK/PlaySoftMIDI, MIDI 데이터를 한개의 악기 유닛과 한개의 출력 유닛으로 구성된 간단한 프로세싱 그래프에 보내는 예입니다.
  • SimpleSDK/PlaySequence, MIDI 파일을 읽어서 시퀀스에 첨가하며, 뮤직 플레이어를 이용해서 재생하는 예입니다.

[편집] Handling Both Audio and MIDI Data

때때로 오디오 데이터를 MIDI 데이터로 만든 합성된 오디오와 섞어서 그 결과를 재생하는게 필요할 겁니다. 예를 들어, 많은 게임들의 오디오는 디스크에 파일로 저장된 배경 음악과, 발자국 소리나, 총소리처럼 어떤 이벤트가 발생했을때 나오는 잡음처럼 MIDI 데이터로 구성된 소리 등으로 구성이 됩니다. Figure 3-10을 보시면, 어떻게 Core Audio를 이용해서 그 둘을 섞을 수있는지 알 수있습니다.


Figure 3-10 Combining audio and MIDI data
그림:a_core_audio_Mixing_audio_sources.jpg


사운드트랙 오디오 데이터는 디스크나 메모리에서 가져와서, Extended Audio File API를 이용해서 linear PCM으로 변환합니다. MIDI 데이터는, 뮤직 시퀀스에서 트랙으로 저장이 되는데, 가상의 악기 유닛으로 보내집니다. 가상의 악기 유닛의 출력은 linear PCM 포맷으로 되어 있고, 사운드 트랙 데이터와 합쳐질 수있습니다. 이 예에서는 3D 믹서 유닛을 사용하는데, 3차원 공간에서 소리가 어디서 나는지 그 위치를 바꿀 수있습니다. 이 트랙들 중 하나는 이벤트 데이터를 믹서 유닛에 보내는데, 이때 위치 패러미터의 값을 바꿔서 소리가 나는 위치가 시간이 지남에 따라 바뀌는 효과를 내 줍니다. 응용 프로그램은 게임 플레이어의 움직임을 주시해야 하며, 이벤트를 특별한 movement 트랙에 필요할 때마다 넣어 주어야 합니다.

파일로 된 오디오 데이터를 로딩하고 재생하는 것에 대해서는 Core Audio SDK의 SimpleSDK/PlayFile를 참조하십시오.