Core Audio Programming Interfaces
OSXDEV
Core Audio는 Mac OS X에서 모든 오디오 관련 작업을 처리해 주는 서비스입니다. 그래서 여러가지 일을 해주는 파트로 나누어져 있습니다. 이 장에서는 Core Audio의 그런 여러가지 기능에 대한 인터페이스에 대해서 설명을 하고 있습니다.
이 문서에서 API라는 것은 한 헤더 파일에 정의된 프로그래밍 인터페이스를 의미하고, service라는 것은 다수의 헤더 파일에 나누어서 정의된 인터페이스를 의미합니다.
Core Audio 프레임 워크에 정의된 인터페이스들을 다 보시려면 Core Audio Frameworks을 참조하십시오..
목차 |
[편집] Audio Unit Services
Audio Unit Services를 이용하면 오디오 유닛을 만들고 다룰 수있습니다.이 인터페이스는 AudioUnit.framework와 AudioToolbox.framework에 나와 있는 함수, 데이터 타입, 그리고 상수들로 구성되어 있습니다.
- AudioUnit.h
- AUComponent.h
- AudioOutputUnit.h
- AudioUnitParameters.h
- AudioUnitProperties.h
- AudioUnitCarbonView.h
- AUCocoaUIView.h
- MusicDevice.h
- AudioUnitUtilities.h (in AudioToolbox.framework)
Audio unit은 오디오 신호를 만들거나 다루기 위한 플러그인인데, Component Manager의 컴포넌트로 되어 있습니다. 이런 유닛을 가지게 될 프로그램에서(호스트 프로그램)에서 여러개의 동일한 유닛을 띄울 수가 있습니다. 이런 유닛들은 오디오 신호를 처리하는 단계에서 실질적으로 어디에나 삽입할 수있습니다.
오디오 유닛은 다른 업체들이 만드는 유닛들과 호환성을 유지하기 위해서 noninterleaved 32-bit floating-point linear PCM 포맷을 지원해야만 합니다. 다른 포맷의 linear PCM을 지원할 수도 있습니다. 지금 당장은 linear PCM 외의 다른 것은 지원하고 있지 않습니다. 다른 포맷으로 되어 있는 오디오 데이터를 linear PCM으로 변환하고자 하시면 오디오 컨버터(Audio Converters and Codecs 참조 )를 사용하시면 됩니다.
Note: Audio File과 Converter Service는 커스텀 파일 포맷이나 데이터 변환을 위해서 Component Manger 컴포넌트들을 사용합니다. 하지만 이런 컴포넌트들은 오디오 유닛은 아닙니다. 호스트 프로그램은 반드시 Component Manger 컬을 사용해서 오디오 유닛을 찾아서 로딩해야 합니다. 각 오디오 유닛은 Component Manager 타입과 서브 타입, 그리고 제조자의 코드를 이용해서 찾을 수 있습니다. 타입은 해당 유닛의 일반적인 목적, 즉 effect 유닛이냐 generator 유닛이냐 하는 것등을 나타냅니다. 서브 타입은 특정 제조자가 만든, 주어진 타입의 유닛을 찾아낼 때 쓰는 임의의 값입니다. 예를 들자면, 여러분의 회사가 여러 effect 유닛을 만들었다고 합시다. 각 유닛은 그 만의 서브 타입을 가져서 다른 유닛과 구별할 수있도록 되어 있습니다. Apple은 표준적인 오디오 유닛 타입을 정의해 두었습니다. 하지만 여러분은 원하는 대로 어떤 서브 타입이던지 만들 수있습니다.
Audio unit들이 할 수 있는 기능과 구성에 대한 정보는 properties를 이용해서 알아낼 수있습니다.속성들(properties)는 시간이 변해도 변하지 않는 특성들을 기술해 놓은 key-value 쌍으로된 값입니다. 예를 들자면 오디오 유닛에 있는 채널의 갯수라던가, 지원하는 오디오 데이터 스트림 포맷이던가, 샘플링 레이트, 혹은 커스텀 Cocoa view를 지원하는가 아닌가 하는 정보 등이 그런 거라고 하겠습니다. 각 오디오 유닛은 Apple이 정의해 놓은 몇개의 필수적인 속성들이 있는데, 여러분은 이 역시 용도에 따라 여러분 만의 속성을 추가할 수있습니다. 호스트 프로그램은 한 유닛의 유저 인터페이스를 만들기 위해서 속성 정보를 이용할 수있습니다. 하지만 많은 경우에 있어서, 복잡한 오디오 유닛들은 그 자신의 커스텀 유저 인터페이스를 제공합니다.
또한 오디오 유닛들은 여러가지 parameters들을 가지고 있습니다. 이런 패러미터들의 타입은 그 오디오 유닛이 할 수있는 능력에 따라 결정 됩니다. 패러미터들은 실시간에 사용자들이 바꿀 수있는 세팅들을 보통 반영하게 됩니다. 예를 들어, parametric filter 오디오 유닛은 주파수의 중간과 필터 응답의 폭을 결정하는, 유저 인터페이스에서 세팅할 수있는 패러미터를 가지고 있을 수 있습니다. 반면에 악기 유닛은 현재 MIDI나 이벤트 데이터의 상태를 나타내는 패러미터를 사용할 수 있습니다.
시그널 체인은 출력 유닛으로 끝나는 오디오 유닛들로 보통 이루어져 있습니다. 출력 유닛은 하드웨어와 보통 연결되는데, ( AUHAL은 그런 출력 유닛의 예입니다. ) 꼭 그래야 하는 것은 아닙니다. 출력 유닛은 독립적으로 데이터의 흐름을 시작하고 중지 시킬 수있는 점에서 다른 오디오 유닛과는 다릅니다. 표준 오디오 유닛은 데이터를 얻어 내기 위해서 "pull" 메커니즘을 사용하고 있습니다. 각 오디오 유닛들은 오디오 체인에서 그 다음에 따라올 유닛을 callback으로 등록해 놓습니다. 출력 유닛이 호스트 프로그램에 의해서 데이터를 흘려 보내기 시작할때, 그것의 렌더(render) 함수는 그 체인에서 앞서 있는 유닛에 데이터를 요구하게 됩니다. 그러면 그 앞의 유닛은 역시 그 앞의 것에 요구하게 됩니다.
호스트 프로그램은 오디오 프로세싱 그래프의 형식으로 오디오 유닛들을 합쳐서, 더 큰 신호 처리 모듈을 구성할 수있습니다. 프로세싱 그래프에서 유닛들을 합치면 자동으로 callback 링크를 만들어서 그 체인에서 데이터가 흐를 수있게 합니다. Audio Processing Graph API에 더 자세한 내용이 나와 있으니 참조하기 바랍니다.
오디오 유의 상태 변화를 모티터하기 위해서, 응응 프로그램은 callback 혹은 listener를 등록할 수있습니다. 이것은 어떤 특정 오디오 유닛 이벤트가 발생하면 호출됩니다. 예를 들어, 어떤 프로그램이 한 패러미터의 값이 언제 바뀌는지 혹은 데이터 흐름이 인터럽트 되었는지 알고 싶다고 할대 같은 경우 말입니다. Technical Note TN2104: Handling Audio Unit Events을 보시면 이에 대해서 더 자세히 나와 있습니다.
Core Audio SDK의 AudioUnits 폴더에는 Component Manager 플러그 인을 만들기 위한 C++ 프레임워크와 함께, 보통 쓰이는 오디오 유닛의 타임들에 대한 템플렛도 들어 있습니다. 예를 들어 effect 유닛이나 악기 유닛과 같은 것들이 있습니다.
이 SDK를 이용해서 오디오 유닛을 만드는 방법에 대해서 더 알아보려면 Audio Unit Programming Guide을 참조하시기 바랍니다.
[편집] Audio Processing Graph API
Audio Processing Graph API는 오디오 유닛을 호스팅하는 프로그램을 만드느는 프로그래머들이 오디오 프로세싱 그래프를 만들고 다룰 수 있도록 해 줍니다. 이 API는 함수, 데이터 타입, 그리고 상수들로 구성되어 있는데, 이 것들은 AudioToolbox.framework의 AUGraph.h에 정의되어 있습니다.
AUGraph라고도 부르는 오디오 프로세싱 그래프는 특정한 작업을 수행하기 위해서 일련의 오디오 유닛 체인을 정의합니다. 이렇게 함으로써 시그널 체인에서 종종 수행하는 작업에 대한 프러그인이 가능한 모듈을 만들 수있습니다. 예를 들어, 어떤 그래프에는 여러개의 오디오 유닛을 엮어서 신호를 distort시키고, 압축 시킨후, 전체 사운드의 특정 영역으로 pan시킬 수있습니다. 그리고 이런 그래프를 AUHAL 유닛으로 마무리해서, 처리된 소리를 앰프나 스피커같은 하드웨어 장비에 전송할 수있습니다. 오디오 프로세싱 그래프는 오디오 유닛을 연결해서 신호를 처리하는 프로그램에서 유용하게 사용할 수있습니다만, 신호 처리 자체를 구현하는 용도로는 적합하지 않습니다. Figure 2-1에선 간단한 오디오 프로세싱 그래프를 보여줍니다.
Figure 2-1 A simple audio processing graph
오디오 프로세싱 그래프에 있는 각 오디오 유닛은 node라고 부릅니다. 한 노드의 출력단을 다른 노드의 입력에 연결하는 식으로 그패르를 만들어 나가게 됩니다. 이때 한 오디오 유닛의 출력을 여러개의 입력으로 연결할 수없습니다. 단 splitter 유닛을 넣으면 가능합니다. 이에 대해서는 Figure 2-2에서 알 수있습니다. 하지만 한 오디오 유닛은 그 타입에 따라 여러개의 출력이나 입력을 가질 수있습니다.
Figure 2-2 Incorrect and correct ways to fan out a connection
Audio Processing Graph API를 사용하면 서브 그래프들을 합쳐서 더 큰 그래프에 넣을 수도 있는데, 이때 그 서브 그래프는 큰 그래프에서 한 노드로 나타나게 됩니다. 이에 대해서는 Figure 2-3에서 볼 수있습니다.
Figure 2-3 A subgraph within a larger audio processing graph
각 그래프나 서브 그래프는 반드시 출력 오디오 유닛으로 끝맺어야 합니다. 서브 그래프의 경우엔, 시그널 패스는 반드시, 어떤 하드웨어에도 연결되지 않는, 일반적인 출력 유닛으로 끝아야 합니다.
오디오 프로세싱 그래프를 이용하지 않고 프로그램 상에서 오디오 유닛을 연결하는게 가능하지만, 그걸 이용하면 그래프를 동적으로 변경할 수있으며, 이로 인해서 오디오 데이터를 처리하면서 시그널 패스를 바꿀 수 있습니다. 추가로 그래프가 오디오 유닛들의 연결관계를 나타내주는 것이기 때문에, 오디오 유닛을 인스턴스화하지 않고도 그래프를 만들고 수정할 수있습니다.
[편집] Audio File and Converter Services
Audio File and Converter Services를 사용하면 파일이나 버퍼에 오디오 데이터를 읽고 쓸 수있으며 다른 포맷으로 데이터를 변환할 수있습니다. 이 서비스는 AudioToolbox.framework와 AudioUnit.framework에 있는 함수와 데이터 타입, 그리고 상수로 구성되어 있습니다.
- ExtendedAudioFile.h
- AudioFile.h
- AudioFormat.h
- AudioConverter.h
- AudioCodec.h (located in AudioUnit.framework).
- CAFFile.h
많은 경우에 있어서, 오디오 데이터를 읽고 쓰는데는 가장 간단한 방법으로 Extended Audio File API를 쓰게 될겁니다. 이 API를 이용해서 읽은 파일은 자동적으로 압축이 풀리고 linear PCM 포맷으로 바뀌게 됩니다. 이 포맷은 오디오 유닛들이 사용하는 네이티브 포맷입니다. 이와 유사하게 함수 하나를 호출함으로써 linear PCM 오디오 데이터를 파일에 압축되고 변환된 형식으로 저장할 수도 있습니다. Supported Audio File and Data Formats은 Core Audio가 기본적으로 제공하는 파일 포맷이 나열되어 있습니다. 이 중 몇몇 포맷은 사용에 제한이 있는데, 예를 들어, Core Audio는 MP3 파일을 읽을 수는 있지만 쓸 수는 없습니다. 그리고 AC-3 파일은 스테레오 데이터 스트림으로만 ( 5.1 서라운드가 아니고 ) 디코딩될 수있습니다.
파일을 읽고, 쓰고, 변환하는데 좀더 제어권을 가지고 싶다면, AudioFile.h의 Audio File과 AudioConverter.h의 Audio Converter API를 직접 억세스 하면 됩니다. Audio File API를 사용할 때, 오디오 파일 객체로 표현되는 오디오 데이터 소스는 실제로도 파일일 수있지만, 메모리에 있는 버퍼일 수도 있습니다. 여기에 더해서 비공개 파일 포맷으로 읽거나 쓸 필요가 있을때는, Audio File API가 발견하고 로딩할 수있는 Component Manger의 커스텀 컴포넌트를 사용해서 포맷을 변환 할 수있습니다. 예를 들어, 여러분의 파일 포맷이 DRM을 포함하고 있다면 그것을 처리해 주는 커스텀 컴포넌트를 만들어서 처리하게 됩니다.
[편집] Audio Converters and Codecs
오디오 컨버터를 이용하면 오디오 데이터를 다른 형식으로 변환할 수 있습니다. 예를 들어, 샘플링 레이트와 오디오 데이터 스트림을 인터리빙, 혹은 디인터리빙하는 것을 바꾸는 간단한 변환을 할 수있습니다. 혹은 오디오를 압축이나 압축 해제하는 복잡한 작업도 할 수있습니다. 세가지 형태의 변환이 가능한데, 그것은 다음과 같습니다.
- AAC 포맷과 같은 오디오 포맷을 linear PCM 포맷으로 디코딩 하기
- linear PCM data을 다른 오디오 포맷으로 인코딩하기
- 다른 스타일의 linear PCM으로 변환하기 (예를 들어, 16비트 signed 정수형 linear PCM을 32비트의 실수형 linear PCM으로 변환하기).
Audio Converter API를 사용하면 오디오 컨버터를 만들거나 조작할 수있습니다. 이 API와 기본으로 제공되는 컨버터를 이용해서 가장 보편적으로 쓰이는 여러 오디오 포맷들을 다룰 수있습니다. 한번에 한개 이상의 컨버터를 사용할 수있으며, 변환 함수를 호출할때, 어떤 컨버터를 사용할지 명시해 줄 수있습니다. 각 오디오 컨버터는 그 컨버터의 특성을 알려주는 속성을 가지고 있습니다. 예를 들어, 채널 매핑 속성은 입력 채널이 어떻게 출력 채널에 매핑되는지를 알려 줍니다.
특정한 컨버터 인스턴스를 가진 변환 함수를 호출함으로써 데이터를 변환할 수있습니다. 이때 어디서 입력 데이터를 찾아서 어디에 출력해야 할지 명시하게 됩니다. 대부분의 변환은 주기적으로 입력 데이터를 컨버터에 보내 주기 위해서 callback 함수를 필요로 합니다.
오디오 코덱은 오디오 번버터가 오디오 포맷을 인코딩하거나 디코딩하기 위해서 로딩하는 Component Manager 컴포넌트입니다. 전형적으로 한 코덱은 linear PCM으로 인코딩되거나 디코딩될 수있습니다. Audio Codec API는 이런 오디오 코덱을 구현하기 위한 Component Manager 인터페이스를 제공합니다. 커스텀 코덱을 만든 후, 오디오 컨버터를 이용해서 사용을 할 수있습니다. Supported Audio File and Data Formats을 읽어보시면 압축된 포맷과 linear PCM을 상호 변환해 주는 표준적인 Core Audio 코덱이 어떤게 있나 볼 수있습니다.
이런 오디오 컨버터를 사용하는 예는 Core Audio SDK의 Services/AudioFileTools에 있는 SimpleSDK/ConvertFile과 AFConvert 툴에 나와 있습니다.
[편집] File Format Information
읽고, 쓰고, 변환하는 것에 더해서, Audio File and Covnerter Service는 파일 타입과 그 파일이 가지고 있는 오디오 데이터에 대한 유용한 정보를 얻을 수있게 해줍니다. 예를 들어 다음과 같은 데이터를 Audio File API를 이용해서 얻을 수있습니다.
- Core Audio가 읽고 쓸 수있는 파일 타입
- Core Audio가 읽고 쓸 수있는 데이터 포맷
- 주어진 파일 타입의 이름
- 주어진 파일 타입에 할당된 파일 익스텐션
Audio File API를 이용하면 파일에 할당된 프로퍼티를 읽거나 지정할 수있습니다. 이런 프로퍼티의 예는 파일에 저장된 데이터 포맷이나 장르, 연주가, 카피라이트에 관련된 정보 같은 것을 포함하는 CFDictionary같은게 있겠습니다.
[편집] Audio Metadata
오디오 데이터를 다룰때, 종종 어떤 특정한 정보를 알아야지만 그 데이터를 처리할 수있는 가장 최적의 방법을 알 수있습니다. AudioFormat.h에 있는 Audio Format API는 다양한 오디오 구조체에 저장된 정보를 알아낼 수있게 해 줍니다. 예를 들어 다음과 같은 특성을 알아 낼수 있습니다.
- 특정 채널 레이아웃과 관련된 정보( 채널의 갯수, 이름, 입력에서 출력으로의 매핑 등)
- 채널 레이아웃간에 매핑을 하는데 필요한 panning matrix 정보
- 샘플링 레이트, 비트 레이트, 혹은 기타 기본 정보들
이런 정보외에도, Audio Format API를 통해서 Core Audio에 관련된 시스템 정보, 예를 들어 사용가능한 오디오 코넷등과 같은 정보도 알아낼 수있습니다.
[편집] Core Audio File Format
비록 기술적으로 Core Audio 프로그래밍 인터페이스에 속하진 않지만, Core Audio 파일 포맷(CAF)는 강력하고 유연한 파일 포맷으로써, 오디오 데이터를 저장하기 위한 목적으로 애플이 정의해 놓았습니다. CAF 파일들은 AIFF나 AIFF-C, 그리고 WAVE 파일처럼 그 크기에 제한을 받지 않으며 채널 정보나 텍스트 어노테이션과 같은 다양한 메타 데이터를 가지고 있을 수있습니다. CAF 포맷은 대단히 유연해서 어떤 데이터 형태라도 포함할 수있는데, 심지어 아직 존재하지 않는 포맷도 가지고 있을 수 있습니다. 이에 대해서 더 자세히 아시고 싶으시면 Apple Core Audio Format Specification 1.0을 참조하십시오.
[편집] Hardware Abstraction Layer (HAL) Services
Core Audio는 하드웨어를 추상화 해주는 레이어(HAL)을 두어서 일관적이고 예측 가능한 인터페이스를 응용 프로그램에 제공해 주어, 하드웨어를 제어할 수있게 해 줍니다. 각 하드웨어는 HAL에서 AudioDevice 타입으로 된 오디오 장비 객체로 표현이 됩니다. 응용 프로그램은 동기를 맞추어주거나 지연 시간을 조정해주기 위해서 타이밍에 대한 정보를 얻으려고 오디오 장비 객체에 질의를 던질 수있습니다.
HAL Services는 CoreAudio.framework에 정의된 다음의 헤더 파일들에 있는 함수와 데이터 타입, 그리고 상수로 구성되어 있습니다.
- AudioDriverPlugin.h
- AudioHardware.h
- AudioHardwarePlugin.h
- CoreAudioTypes.h (Contains data types and constants used by all Core Audio interfaces)
- HostTime.h
대부분의 개발자들은 Apple의 AUHAL 유닛이 하드웨어 인터페이싱을 위해 필요한 일을 대개 해줄 수있다는 것을 아시게 될것입니다. 그래서 HAL 서비스를 직접적으로 억세스할 필요가 없습니다. AUHAL은 지정된 오디오 장비 객체에 오디오 데이터를 전송하고 채널 매핑을 해 줍니다.AUHAL와 출력 유닛을 사용하는데 필요한 정보는 Interfacing with Hardware Devices을 참조하십시오.
[편집] Music Player API
Music Player API는 뮤직 트랙의 집합을 나열하고 재생할 수있게 해줍니다. 이 API는 AudioToolbox.framework의 MusicPlayer.h에 정의된 함수와 데이터 타입, 그리고 상수로 구성되어 있습니다.
track은 MusicTrack으로 표현되어지는 특정한 MIDI 스트림이나 이벤트 데이터입니다. 트랙은 시간에 기반한 이벤트들이 나열되어 있는 것입니다. 이런 것들은 MIDI 데이터나 Core Audio 이벤트 데이터나, 혹은 여러분이 직접 만든 커스텀 이벤트 메시지일 수있습니다. 트랙의 집합은 sequence라고 합니다. 이것은 MusicSequence 타입으로 되어 있습니다. 시퀀스는 언제나 템포 트랙을 추가적으로 가지고 있게 됩니다. 이 템포트랙은 그 시퀀스 내의 모든 트랙들의 재생을 동기화 해 줍니다. 여러분의 프로그램은 동적으로 시퀀스에 트랙을 더하거나, 지우고 혹은 편집할 수있습니다. 각 시퀀스는 그것을 전담하는 MusicPlayer 타입으로 되어 있는 music player 객체에 할당이 되어 있어야 합니다. 이 것은 시퀀스 내의 모든 트랙을 전체적으로 콘트롤 해주는 역할을 합니다.
트랙은 한 악기를 위한 악보라고 생각하시면 됩니다. 즉 어떤 음표를 얼마나 오랫동안 플레이할 것인가를 나타내주게 됩니다. 시퀀스는 여러 악기들을 위한 악보가 다 나타나 있는 전체 악보와 비슷합니다. 악기 유닛이나 외부 MIDI 장비들은 이런 악보에 나와 있는 악기라고 볼 수있습니다. 그러면 뮤직 플레이어는 모든 연주자들은 관장하는 지휘자라고 할 수있겠습니다.
뮤직 플레이어가 재생하는 트랙 데이터는 오디오 프로세싱 그래프나 외부 MIDI 장비나, 혹은 그런 것들을 조합한 것에 보내질 수있습니다. 오디오 프로세싱 그래프는 한개 이상의 악기 유닛을 통해서 트랙 데이터를 받을 수있는데, 이런 악기 유닛은 이벤트나 MIDI 데이터를 오디오 신호로 바꾸어 주는 역할을 합니다. 뮤직 플레이어는 자동으로 해당 그래프의 출력 오디오 유닛이나 Core MID와 통신을 하면서 오디오 출력이 적절하게 동기화 되도록 해줍니다.
트랙 데이터는 음악 정보를 표현할 필요는 없습니다. 예를 들어, 특별한 Core Audio 이벤트가 오디오 유닛의 패러미터 값에서 벌어지는 변화를 표현하고 있을 수있습니다. panner 오디오 유닛에 할당된 트랙은 아마 패러미터 이벤트를, 시간이 흐름에 따라 사운드스테이지에서 그 소리의 소스를 이동시킬 수도 있을 겁니다. 트랙은 또한 여러분이 만든 고유의 이벤트를 포함해서 여러분의 응용 프로그램에서 정의된 callback을 호출할 수도 있습니다.
Music Player API를 사용해서 MIDI 데이터를 재생하시려면 Handling MIDI Data을 참조하시기 바랍니다.
[편집] Core MIDI Services and MIDI Server Services
Core Audio는 MIDI를 지원하기 위해서 Core MIDI를 사용합니다. 이 서비스는 CoreMIDI.framework에 있는 함수와 데이터 타입, 그리고 상수들로 구성되어 있습니다.
- MIDIServices.h
- MIDISetup.h
- MIDIThruConnection.h
- MIDIDriver.h
Core MIDI 서비스는 응용 프로그램과 오디오 유닛이 MIDI 장비와 통신하는데 필요한 인터페이스를 포함하고 있습니다. MIDI 네트워크와 상호동작을 하기 위해서 여러가지의 추상적인 표현을 이용하고 있습니다.
MIDIEndpointRef에 정의된 MIDI endpoint는 표준 16채널 MIDI 데이터 스트림의 소스와 목표지를 나타내게 됩니다. 그리고 Core Audio 서비스와 상호 동작시키는데 있어서 중요한 것입니다. 예를 들어, Music Player API가 사용하는 트랙과 엔드포인트를 연결시켜서 MIDI 데이터를 녹음하거나 재생할 수있습니다. 이 MIDI 엔드 포인트는 표준 MIDI 케이블 연결의 논리적인 표현입니다. 하지만 응용프로그램은 이것을 가상 소스나 목적지로 설정해서 MIDI 데이터를 보내거나 받을 수있습니다.
MIDI 드라이버는 여러 엔드포인트를 합쳐서 논리적 그룹을 만들 수있는데, 이를 MIDI entities (MIDIEntityRef)라고 부릅니다. 예를 들어, MIDI-in과 MIDI-out 엔드포인트를 엮어서 MIDI 엔티티로 구성하는게 좋을 수있는데, 이렇게 하면 장비와 응용 프로그램간에 양방향 통신을 위해서 편할겁니다.
물리적인 MIDI 장비들은 Core MIDI device 객체에 의해서 표현됩니다. (MIDIDeviceRef) 각 디바이스 객체들은 한개 이상의 MIDI 엔티티를 포함합니다.
Core MIDI는 MIDI 서버와 통신을 하는데, 이 서버는 응용 프로그램과 MIDI 장비간에 IDI 데이터를 전달해주는 역할을 합니다. 이 MIDI 서버는 한 프로세스로서 동작합니다. Figure 2-4에서 Core MIDI와 MIDI 서버간의 관계를 볼 수있습니다.
Figure 2-4 Core MIDI and Core MIDI Server
응용 프로그램이 중간에서 매개자 역할을 하는 MIDI 커뮤니케이션을 제공하는 것에 더해, MIDI 서버는 MIDI thru 연결도 지원합니다. 즉 호스트 프로그램의 관여없이 장비간에 통신이 가능합니다.
만약 여러분이 MIDI 장비를 제조한다면, MIDI 서버를 위해서, CFBundle로 패키징된 CFPlugin 프러그인을 만들어서 제공해야 할겁니다. 이런 번들은 커널 수즌의 I/O 킷 드라이버와 교통을 할 수있도록 해줍니다. Figure 2-5 은 어떻게 Core MIDI와 Core MIDI 서버가 그 밑의 하드웨어와 어떻게 상호 동작하는지 보여줍니다.
Figure 2-5 MIDI Server interface with I/O Kit
각 MIDI 장비를 위한 드라이버들은 보통 커널 바깥에 존재합니다. 그리고 MIDI 서버 프로세스를 돌리게 됩니다. 이런 드라이버들은 밑에 있는 프로토콜을 기본 I/O 킷 드라이버와 상호 동작을 합니다. MIDI 드라이버들은 raw 디바이이스 데이터를 Core MIDI에 사용 가능한 형식으로 보내는 역할을 해야 합니다. Core MIDI는 그런 데이터를 받아서, 여러분의 프로그램에 지정된 MIDI 엔드포인트를 통해서 보냅니다. 이 엔드포인트는 외장 장비의 MIDI 포트를 추상화한 것이 되겠습니다.
하지만 PCI 카드로 되어 있는 MIDI 장비는 user-space 드라이버를 통해서만 제어하는 것은 불가능합니다. 이런 PCI 카드를 위해서, 커스텀 유저 클라이언트를 제공하려면 커널 익스텐션을 만들어야 합니다. 이러한 클라이언트는 PCI 장비를 제어하거나 ( user-space 드라이버에 간단한 메세지 큐를 제공함으로써 ) 혹은 user-space 드라이버가 요청을 하면 PCI 장비의 어드레스 범위를 MIDI 서버의 어드레스에 매핑해야 합니다. 그렇게 함으로써 user-space 드라이버가 PCI 장비를 제어할 수있습니다.
user-space MIDI 드라이버의 구현 예는 Core Audio SDK의 MIDI/SampleUSBDriver를 보십시오
[편집] Core Audio Clock API
AudioToolbox.framework의 CoreAudioClock.h 헤더 파일에 정의된 Core Audio Clock API는 프로그램이나 장비를 동기화할 때 쓸 수있는 레퍼런스 클락을 제공합니다. 이 시계는 독자적으로 있을 수 있는 시간 소스(timing source) 일 수도 있으며, MIDI beat clock이나 MIDI time code와 같은 외부의 트리거(trigger)와 동기화 될 수도 있습니다. 이런 시계를 여러분이 직접 움직이게 하거나 정지 시킬 수있으며, 혹은 특정 이벤트가 발생할때 응답으로써 활성내지 비활성 시킬 수도 있습니다.
생성된 클락 타임을 여러가지 형식으로 얻어 낼 수있는데, 예를들어 초, 비트(beats), SMPTE 타임, 오디오 샘플 타임, 그리고 bar-beat 타밍과 같은 식으로 얻어 낼 수있습니다. bar-beat 타임은 화면에 musical bar나 beat 그리고 subbeat로 표시하기에 좋은 방식으로 시간을 표현해 줍니다. Core Audio Clock API는 또한 한 시간 형식을 다른 것으로 변환하는 함수와 bar-beat나 SMPTE 시간을 표시해주는 함수를 가지고 있습니다. Figure 2-6은 여러가지 Core Audio Clock 형식들간의 관계를 보여주고 있습니다.
Figure 2-6 Some Core Audio Clock formats
하드웨어 시간은 시스템 클럭인 호스트 시간이나 HAL에서 AudioDevice객체로 표현되는 외부 오디오 장비에서 얻어진 오디오 타임의 절대 시간을 의미합니다. 현재의 호스트 타임을 알려면 mach_absolute_time이나 AbsoluteTime을 호출하면 됩니다. 오디오 타임은 샘플 숫자로 표현된, 해당 오디오 장비의 현재 시간입니다. 샘플 숫자의 변화하는 rate는 그 오디오 장비의 샘플링 rate에 따라 다릅니다.
미디어 타임은 오디오 데이터들을 위한 보편적인 타이밍 방법입니다. 표준적으로는 초로 표기를 하는데, double-precision의 실수값으로 표현 됩니다. 하지만 템포 멥(map)을 이용하면 초를 musical bar-beat로 바꾸거나 SMPTE 오프셋을 사용해서 초를 SMPTE 초로 바꿀 수있습니다.
미디어 타임은 실제 시간과는 상관이 없는 것입니다. 예를 들어, 한 오디오 파일의 길이가 10초이지만, 재생 속도를 높이면 5초만 걸릴 수도 있는 것입니다. Figure 2-6에 있는 손잡이(knob)은 절대시간, 혹은 실제 시간과 미디어에 기초한 시간관의 상관 관계를 조절해 줄 수있다는 것을 보여줍니다. 예를 들어 bar-beat 표현은 음악의 리듬을 나타내주며 어떤 음표를 언제 재생해 주어야 하는가를 나타냅니다. 하지만 얼마나 오랫동안 해 주어야하는지는 나타내지 않습니다. 그것을 알아내려면, 재생 속도(playback rate)를 알아야 하는데, 초당 몇 비트(beat)로 나타내질 것입니다. 이와 비슷하게 SMPTE 시간을 실제 시간과 연계시키는 것도 프레임 레이트와 프레임 드롭이 생기는지 아닌지도 영향을 미칩니다.
[편집] OpenAL (Open Audio Library)
Core Audio는 오픈소스인 OpenAL 스펙을 담고 있습니다. OpenAL은 3차원 공간에 사운드를 위치시키고 조작할 수있는 크로스 플랫폼 API입니다. 예를들어, 게임에서 사운드 효과를 3차원 공간의 어느 지점에 위치시키고, 그것을 이동시키거나, 다채널 오디오의 사운드 공간을 만들 수도 있습니다. 청취자 주변에 사운드를 위치시키는 단순한 용도뿐 아니라, 안개나 물과 같은 것을 통과해서 멀리서 들려 오는 듯한 효과도 만들어 낼 수 있고, 도플러 효과도 낼 수있습니다.
OpenAL 코딩 스타일과 문법은 OpenGL의 그것처럼 만들어졌습니다. 차이점은 빛 대신에 소리를 대상으로 한다는 것이죠. 그래서 OpenGL 프로그래머들은 개념을 잡는게 쉬울겁니다.
Core Audio에 있는 OpenAL을 사용하는 예는 Core Audio SDK의 Services/OpenALExample 폴더를 참조해 보십시오. 더 자세히 알고 싶다면 openal.org을 참조하시기 바랍니다.
[편집] System Sound API
The System Sound API는 응용 프로그램에서 표준 시스템 사운드를 재생할 수있는 간단한 방법을 제공합니다. 이것을 사용하려면 SystemSound.h을 이용해야 하는데, 이는 Core Audio 프레임워크가 아닌데에 있는 유일한 Core Audio 헤더 파일입니다. CoreServices/OSServices 프레임워크에서 이 헤더 파일을 찾을 수있습니다.
System Sound API를 사용하는 법에 대해서 더 알아보려면 Technical Note 2102: The System Sound APIs for Mac OS X v10.2, 10.3, and Later를 참조하시기 바랍니다.




