본문 바로가기
Swift

Core Audio Essentials 공식문서 번역 정리

by HaningYa 2024. 5. 29.
728x90
 

Core Audio Essentials

Core Audio Essentials Apple has designed the software interfaces to Core Audio using a layered, cooperative, task-focused approach. Read the first two sections in this chapter for a brief introduction to these interfaces and how they work together. Continu

developer.apple.com

 

Core Audio Essentials

Apple은 계층적이고 협력적이며 작업 중심적인 접근 방식을 사용하여 Core Audio의 소프트웨어 인터페이스를 설계했습니다. 이 장의 처음 두 섹션을 읽어 이러한 인터페이스와 그들이 어떻게 함께 작동하는지 간략히 소개합니다. 계속 읽으면서 Core Audio에 널리 퍼져 있는 디자인 원칙, 사용 패턴 및 프로그래밍 관례를 이해하세요. 이 장의 후반부에서는 Core Audio가 파일, 스트림, 녹음 및 재생, 플러그인과 어떻게 작동하는지 소개합니다.

 

API Architectural Layers

Core Audio의 프로그래밍 인터페이스는 그림 2-1에 나타난 것처럼 세 가지 계층으로 구성되어 있습니다.

Figure 2-1   The three API layers of Core Audio

최하위 계층에는 다음이 포함됩니다:

드라이버와 상호 작용하는 I/O Kit
하드웨어에 대한 장치 독립적, 드라이버 독립적 인터페이스를 제공하는 오디오 하드웨어 추상화 계층(audio HAL)
MIDI 스트림과 장치를 다루기 위한 소프트웨어 추상화를 제공하는 Core MIDI
컴퓨터의 시계에 접근할 수 있는 Host Time Services

Mac 앱은 실시간 성능이 가장 중요한 경우 이러한 기술을 직접 사용할 수 있습니다. 그러나 많은 오디오 애플리케이션은 이 계층에 직접 접근하지 않습니다. 실제로 iOS의 Core Audio는 더 높은 수준의 인터페이스를 사용하여 실시간 오디오를 처리할 수 있는 방법을 제공합니다. 예를 들어, OpenAL은 게임에서 실시간 오디오를 위해 직접 I/O를 사용합니다. 그 결과 모바일 플랫폼에 적합한 작고 최적화된 API 세트가 제공됩니다.

Core Audio의 중간 계층에는 데이터 형식 변환, 디스크 읽기 및 쓰기, 스트림 구문 분석, 플러그인 작업을 위한 서비스가 포함됩니다.

Audio Converter Services는 애플리케이션이 오디오 데이터 형식 변환기를 사용할 수 있게 합니다.
Audio File Services는 디스크 기반 파일에서 오디오 데이터를 읽고 쓸 수 있도록 지원합니다.
Audio Unit Services와 Audio Processing Graph Services는 이퀄라이저와 믹서와 같은 디지털 신호 처리(DSP) 플러그인을 사용할 수 있게 합니다.
Audio File Stream Services는 네트워크 연결을 통해 스트리밍된 파일을 재생하는 애플리케이션을 구축할 수 있도록 합니다.
Core Audio Clock Services는 오디오 및 MIDI 동기화와 시간 기준 변환을 지원합니다.
Audio Format Services(그림에 표시되지 않은 작은 API)는 애플리케이션에서 오디오 데이터 형식을 관리하는 데 도움을 줍니다.
iOS의 Core Audio는 그림 1-2에서 볼 수 있듯이 이러한 서비스 대부분을 지원합니다.

Core Audio의 최상위 계층에는 하위 계층의 기능을 결합한 간소화된 인터페이스가 포함됩니다.

Audio Queue Services는 오디오를 녹음, 재생, 일시 정지, 반복 및 동기화할 수 있게 합니다. 압축 오디오 형식을 처리하기 위해 필요한 경우 코덱을 사용합니다.
AVAudioPlayer 클래스는 오디오 재생, 반복, 되감기 및 빨리 감기를 위한 간단한 Objective-C 인터페이스를 제공합니다.
Extended Audio File Services는 Audio File Services와 Audio Converter Services의 기능을 결합하여 압축 및 비압축 사운드 파일을 읽고 쓰기 위한 통합 인터페이스를 제공합니다.
OpenAL은 위치 기반 오디오를 위한 오픈 소스 OpenAL 표준의 Core Audio 구현입니다. 시스템에서 제공하는 3D Mixer 오디오 유닛을 기반으로 구축되었습니다. 모든 애플리케이션이 OpenAL을 사용할 수 있지만, 게임 개발에 가장 적합합니다.

Frameworks

Core Audio를 구성하는 API 프레임워크는 /System/Library/Frameworks/에 위치해 있습니다. 이 섹션에서는 Core Audio 레이어를 구성하는 요소를 어디에서 찾을 수 있는지 빠르게 파악할 수 있도록 이러한 프레임워크를 나열합니다.

Core Audio 프레임워크는 다른 프레임워크의 상위 개념이 아니라, 동등한 계층에 속해 있다는 점을 주목하세요.

Audio Toolbox 프레임워크 (AudioToolbox.framework): Core Audio의 중간 및 상위 수준 서비스를 위한 인터페이스를 제공합니다. iOS에서는 이 프레임워크에 오디오 세션 서비스(Audio Session Services)가 포함되어 있어, 모바일 전화기와 iPod으로 작동하는 장치에서 애플리케이션의 오디오 동작을 관리할 수 있는 인터페이스를 제공합니다.
Audio Unit 프레임워크 (AudioUnit.framework): 애플리케이션이 오디오 유닛 및 코덱을 포함한 오디오 플러그인을 사용할 수 있게 합니다.
AVFoundation 프레임워크 (AVFoundation.framework): 오디오 재생을 위한 간소화되고 간단한 Objective-C 인터페이스인 AVAudioPlayer 클래스를 제공합니다. 또한, 더 정교한 오디오 처리를 위한 AVAudioEngine 클래스를 제공합니다.
Core Audio 프레임워크 (CoreAudio.framework): Core Audio 전반에서 사용되는 데이터 유형과 저수준 서비스를 위한 인터페이스를 제공합니다.
Core Audio Kit 프레임워크 (CoreAudioKit.framework): 오디오 유닛을 위한 사용자 인터페이스를 생성하기 위한 작은 API를 제공합니다. 이 프레임워크는 iOS에서는 사용할 수 없습니다.
Core MIDI 프레임워크 (CoreMIDI.framework): 애플리케이션이 MIDI 데이터를 처리하고 MIDI 네트워크를 구성할 수 있게 합니다. 이 프레임워크는 iOS에서는 사용할 수 없습니다.
Core MIDI Server 프레임워크 (CoreMIDIServer.framework): MIDI 드라이버가 OS X MIDI 서버와 통신할 수 있게 합니다. 이 프레임워크는 iOS에서는 사용할 수 없습니다.
OpenAL 프레임워크 (OpenAL.framework): 오픈 소스 위치 기반 오디오 기술인 OpenAL을 사용할 수 있는 인터페이스를 제공합니다.

부록 Core Audio 프레임워크에서는 이 모든 프레임워크와 각 프레임워크에 포함된 헤더 파일을 설명합니다.

Proxy Objects

Core Audio는 파일, 스트림, 오디오 플레이어 등을 표현하기 위해 프록시 객체의 개념을 사용합니다. 예를 들어, 디스크에 저장된 오디오 파일을 애플리케이션에서 사용하려면 첫 번째 단계로 AudioFileID 유형의 오디오 파일 객체를 인스턴스화해야 합니다. 이 객체는 AudioFile.h 헤더 파일에서 불투명 데이터 구조로 선언되어 있습니다:

typedef struct OpaqueAudioFileID *AudioFileID;

AudioFileCreateWithURL 함수를 호출하여 오디오 파일 객체를 인스턴스화하고 해당 객체에 연결된 실제 오디오 파일을 생성합니다. 이 함수는 새 오디오 파일 객체에 대한 참조를 반환합니다. 그 시점부터 실제 오디오 파일과 작업할 때는 프록시 객체와 통신하게 됩니다.

이러한 패턴은 Core Audio 전반에 걸쳐 일관되게 적용됩니다. 오디오 파일, iPhone 오디오 세션(Audio Sessions: Cooperating with Core Audio에서 설명됨) 또는 하드웨어 장치를 다룰 때도 마찬가지입니다.

Properties, Scopes, and Elements

대부분의 Core Audio 인터페이스는 객체 상태를 관리하거나 객체 동작을 세밀하게 조정하기 위해 속성 메커니즘을 사용합니다. 속성은 키-값 쌍으로 이루어져 있습니다.

속성 키는 일반적으로 기억하기 쉬운 이름을 가진 열거형 상수입니다. 예를 들어, kAudioFilePropertyFileFormat 또는 kAudioQueueDeviceProperty_NumberChannels와 같습니다.
속성 값은 속성의 목적에 적합한 특정 데이터 유형입니다. 예를 들어, void*, Float64, AudioChannelLayout 구조체 등이 있습니다.

많은 애플에서 정의한 속성이 있으며, 이들의 정의는 다양한 Core Audio 프레임워크 헤더 파일에서 찾을 수 있습니다. 일부 Core Audio 인터페이스, 예를 들어 Audio Unit Services,에서는 사용자 정의 속성을 정의할 수도 있습니다.

Core Audio 인터페이스는 객체에서 속성 값을 검색하고, 쓰기 가능한 속성의 경우 값을 변경하기 위해 접근자 함수를 사용합니다. 속성에 대한 정보를 얻기 위한 세 번째 접근자 함수도 있습니다. 예를 들어, Audio Unit Services의 AudioUnitGetPropertyInfo 함수는 주어진 속성 값 데이터 유형의 크기와 변경 가능한지 여부를 알려줍니다. Audio Queue Services의 AudioQueueGetPropertySize 함수는 지정된 속성 값의 크기를 가져옵니다.

Core Audio 인터페이스는 속성이 변경되었음을 애플리케이션에 알리는 메커니즘을 제공합니다. 이에 대해서는 다음 섹션인 “Callback Functions: Interacting with Core Audio”에서 자세히 설명합니다.

어떤 경우에는 속성이 오디오 객체 전체에 적용됩니다. 예를 들어, 재생 오디오 큐 객체에서 오디오 레벨 미터링을 활성화하려면 kAudioQueueProperty_EnableLevelMetering 속성의 값을 true로 설정합니다.

다른 Core Audio 객체는 내부 구조를 가지고 있으며, 각 부분은 자체 속성 집합을 가질 수 있습니다. 예를 들어, 오디오 유닛은 입력 범위, 출력 범위 및 글로벌 범위를 가집니다. 오디오 유닛의 입력 또는 출력 범위는 하나 이상의 요소로 구성되며, 각각은 오디오 하드웨어의 채널 버스와 유사합니다. AudioUnitGetProperty 함수를 kAudioUnitProperty_AudioChannelLayout 속성과 함께 호출할 때는 정보가 필요한 오디오 유닛뿐만 아니라 범위(입력 또는 출력)와 요소(0, 1, 2 등)를 지정합니다.

Callback Functions: Interacting with Core Audio

많은 Core Audio 인터페이스는 콜백 함수를 사용하여 애플리케이션과 통신할 수 있습니다. Core Audio는 다음과 같은 작업에 콜백을 사용합니다:

애플리케이션에 새로운 오디오 데이터를 전달합니다(예: 녹음 시; 콜백 함수는 이 데이터를 디스크에 씁니다).

애플리케이션에서 새로운 오디오 데이터를 요청합니다(예: 재생 시; 콜백 함수는 디스크에서 데이터를 읽고 제공합니다).

소프트웨어 객체의 상태가 변경되었음을 애플리케이션에 알립니다(콜백 함수는 적절한 조치를 취합니다).

콜백을 이해하는 한 가지 방법은 누가 누구를 호출하는지에 대한 관점을 역전시키는 것입니다. 일반적인 함수 호출, 예를 들어 AudioQueueNewOutput에서는 애플리케이션이 운영 체제 구현에서 Apple이 정의한 동작을 호출합니다. 내부에서 무슨 일이 일어나는지 알 필요는 없습니다. 애플리케이션은 재생 오디오 큐 객체를 요청하고 이를 받습니다. 함수의 헤더 파일에 명시된 인터페이스를 준수하기 때문에 작동합니다.

콜백의 경우, 운영 체제는 원하는 시점에 애플리케이션에서 구현한 동작을 호출합니다. 애플리케이션에서 템플릿에 따라 콜백을 정의하면, 운영 체제가 이를 성공적으로 호출할 수 있습니다. 예를 들어, Audio Queue Services는 콜백에 대한 템플릿을 지정하며, 이를 구현하면 오디오 큐 객체 속성이 변경될 때 메시지를 받고 반응할 수 있습니다. 이 콜백 템플릿은 AudioQueue.h 헤더 파일에 선언되어 있으며, 다음과 같습니다:

typedef void (*AudioQueuePropertyListenerProc) (
    void *inUserData,
    AudioQueueRef inAQ,
    AudioQueuePropertyID inID
);

애플리케이션에서 콜백을 구현하고 사용하려면 두 가지 작업을 수행합니다:

1. 콜백 함수를 구현합니다. 예를 들어, 오디오 큐 속성 리스너 콜백을 구현하여 오디오 큐 객체가 실행 중인지 중지되었는지에 따라 사용자 인터페이스의 제목과 버튼 상태를 업데이트할 수 있습니다.

2. 콜백 함수를 상호 작용하려는 객체에 등록합니다. 콜백을 등록하는 한 가지 방법은 객체 생성 시 함수 호출에서 콜백에 대한 참조를 함수 매개변수로 전달하는 것입니다. 다른 방법은 전용 함수 호출을 사용하여 속성 리스너를 등록하는 것입니다.

다음은 재생 오디오 큐 객체의 속성 변경에 응답하는 속성 리스너 콜백 함수를 구현한 예입니다:

static void propertyListenerCallback (
    void *inUserData,
    AudioQueueRef queueObject,
    AudioQueuePropertyID propertyID
) {
    AudioPlayer *player = (AudioPlayer *)inUserData;
    // 재생 객체에 대한 참조를 얻습니다.
    [player.notificationDelegate updateUserInterfaceOnAudioQueueStateChange:player];
    // notificationDelegate 클래스가 UI 업데이트 메서드를 구현합니다.
}

 

이 콜백 정의는 Objective-C 클래스 정의 외부에 위치합니다. 그래서 함수 본문에는 재생 객체에 대한 참조를 얻는 문장이 있습니다. 이 예제에서는 inUserData 매개변수가 객체입니다. 콜백을 등록할 때 이 참조를 사용할 수 있도록 합니다.

다음은 이 특정 콜백을 등록하는 방법을 보여줍니다:

AudioQueueAddPropertyListener (
    self.queueObject,                // 콜백을 호출할 객체
    kAudioQueueProperty_IsRunning,   // 청취할 속성의 ID
    propertyListenerCallback,        // 콜백 함수에 대한 참조
    self
);

 

Audio Data Formats

Core Audio는 오디오 데이터 형식에 대한 자세한 지식이 필요 없도록 합니다. 이는 코드에서 특정 형식을 처리하기 쉽게 할 뿐만 아니라, 하나의 코드 세트로 운영 체제가 지원하는 모든 형식을 다룰 수 있다는 것을 의미합니다.

참고: 오디오 데이터 형식은 샘플 속도, 비트 깊이 및 패킷화와 같은 오디오 데이터를 설명합니다. 반면, 오디오 파일 형식은 오디오 데이터, 오디오 메타데이터 및 사운드 파일의 파일 시스템 메타데이터가 디스크에 어떻게 배치되는지를 설명합니다. 일부 오디오 파일 형식은 하나의 오디오 데이터 형식만 포함할 수 있습니다(예: MP3 파일은 MP3 오디오 데이터만 포함할 수 있음). 다른 파일 형식은 Apple의 CAF 형식처럼 다양한 오디오 데이터 형식을 포함할 수 있습니다.

Universal Data Types in Core Audio

Core Audio에서는 모든 오디오 데이터 형식을 나타내기 위해 두 가지 범용 데이터 유형을 사용합니다. 이 데이터 유형은 AudioStreamBasicDescription(리스트 2-4)과 AudioStreamPacketDescription(리스트 2-5)입니다. 이 둘은 CoreAudioTypes.h 헤더 파일에 선언되어 있으며 Core Audio 데이터 유형 참조에서 설명됩니다.

Listing 2-4: The AudioStreamBasicDescription data type

struct AudioStreamBasicDescription {
    Float64 mSampleRate;
    UInt32  mFormatID;
    UInt32  mFormatFlags;
    UInt32  mBytesPerPacket;
    UInt32  mFramesPerPacket;
    UInt32  mBytesPerFrame;
    UInt32  mChannelsPerFrame;
    UInt32  mBitsPerChannel;
    UInt32  mReserved;
};
typedef struct AudioStreamBasicDescription  AudioStreamBasicDescription;

이 구조체에서 mReserved 멤버는 항상 0이어야 합니다. 다른 멤버들도 0 값을 가질 수 있습니다. 예를 들어, 압축 오디오 형식은 샘플당 비트 수가 가변적입니다. 이러한 형식에서는 mBitsPerChannel 멤버의 값이 0입니다.

이름에 대해: 이 데이터 유형에는 “stream”이란 단어가 포함되어 있지만, Core Audio에서 오디오 데이터 형식을 나타낼 때마다 사용됩니다. 여기에는 스트리밍되지 않은 표준 파일도 포함됩니다. 이를 “오디오 형식 기본 설명” 데이터 유형으로 생각할 수 있습니다. 이름의 “stream”은 오디오 형식을 하드웨어 또는 소프트웨어에서 오디오 데이터를 이동(즉, 스트리밍)할 때 필요하다는 사실을 나타냅니다.

Core Audio와 관련된 논의에서는 “audio stream basic description”을 줄여서 “ASBD”라고 자주 부르며, 이 문서에서도 그렇게 합니다.

오디오 스트림 패킷 설명 유형은 특정 압축 오디오 데이터 형식에 대해 필요합니다. 이는 오디오 데이터 패킷에서 설명됩니다.

 

Listing 2-5: The AudioStreamPacketDescription data type

struct AudioStreamPacketDescription {
    SInt64  mStartOffset;
    UInt32  mVariableFramesInPacket;
    UInt32  mDataByteSize;
};
typedef struct AudioStreamPacketDescription AudioStreamPacketDescription;

고정 비트 레이트 오디오 데이터(CBR) 형식에서는 이 구조체의 mVariableFramesInPacket 멤버 값이 0입니다.

Obtaining a Sound File’s Data Format

코드에서 ASBD의 멤버를 직접 채울 수 있습니다. 이 경우 구조체의 일부(또는 전부) 멤버에 대한 올바른 값을 모를 수도 있습니다. 이러한 값들을 0으로 설정한 다음 Core Audio 인터페이스를 사용하여 구조체를 완성할 수 있습니다.

예를 들어, 디스크의 사운드 파일에 대한 전체 오디오 스트림 기본 설명을 얻기 위해 Audio File Services를 사용할 수 있습니다(리스트 2-6 참조).

Listing 2-6: Obtaining an audio stream basic description for playing a sound file

- (void) openPlaybackFile: (CFURLRef) soundFile {
    AudioFileOpenURL (
        (CFURLRef) self.audioFileURL,
        0x01,                  // read only
        kAudioFileCAFType,
        &audioFileID
    );

    UInt32 sizeOfPlaybackFormatASBDStruct = sizeof ([self audioFormat]);

    AudioFileGetProperty (
        [self audioFileID],
        kAudioFilePropertyDataFormat,
        &sizeOfPlaybackFormatASBDStruct,
        &audioFormat          // the sound file's ASBD is returned here
    );
}

 

Canonical Audio Data Formats

플랫폼에 따라 Core Audio에는 하나 또는 두 개의 “표준” 오디오 데이터 형식이 있습니다. 이러한 형식은 다음과 같은 의미에서 표준이 될 수 있습니다:

변환에서 중간 형식으로 필요

Core Audio 서비스가 최적화된 형식

ASBD를 지정하지 않을 때의 기본 또는 가정 형식

Core Audio의 표준 형식은 다음과 같습니다:

iOS 입력 및 출력: 16비트 정수 샘플을 사용하는 선형 PCM

iOS 오디오 유닛 및 기타 오디오 처리: 8.24 비트 고정 소수점 샘플을 사용하는 비인터리브 선형 PCM

Mac 입력 및 출력: 32비트 부동 소수점 샘플을 사용하는 선형 PCM

Mac 오디오 유닛 및 기타 오디오 처리: 32비트 부동 소수점 샘플을 사용하는 비인터리브 선형 PCM

다음은 44.1 kHz 샘플 속도를 가진 두 채널의 표준 iPhone 오디오 유닛 샘플 형식을 설명하는 완전한 오디오 스트림 기본 설명 예제입니다.

struct AudioStreamBasicDescription {
    mSampleRate       = 44100.0;
    mFormatID         = kAudioFormatLinearPCM;
    mFormatFlags      = kAudioFormatFlagsAudioUnitCanonical;
    mBitsPerChannel   = 8 * sizeof (AudioUnitSampleType);                    // 32 bits
    mChannelsPerFrame = 2;
    mBytesPerFrame    = mChannelsPerFrame * sizeof (AudioUnitSampleType);    // 8 bytes
    mFramesPerPacket  = 1;
    mBytesPerPacket   = mFramesPerPacket * mBytesPerFrame;                   // 8 bytes
    mReserved         = 0;
};

여기에서 사용된 상수 및 데이터 유형은 CoreAudioTypes.h 헤더 파일에 선언되어 있으며 Core Audio 데이터 유형 참조에서 설명됩니다. 여기에서 AudioUnitSampleType 데이터 유형을 사용하면 ASBD가 플랫폼 독립적이 됩니다.

다음은 Core Audio에서 오디오 데이터 형식을 마무리하는 두 가지 개념인 매직 쿠키와 패킷에 대한 설명입니다.

 

Magic Cookies

Core Audio에서 매직 쿠키는 압축 사운드 파일이나 스트림에 첨부된 불투명한 메타데이터 세트입니다. 이 메타데이터는 디코더가 파일이나 스트림을 올바르게 압축 해제하는 데 필요한 세부 정보를 제공합니다. 매직 쿠키는 블랙 박스로 취급하며, Core Audio 함수에 의해 메타데이터를 복사, 읽기 및 사용합니다.

예를 들어, 리스트 2-7은 사운드 파일에서 매직 쿠키를 얻어 재생 오디오 큐 객체에 제공하는 메서드를 보여줍니다.

Listing 2-7: Using a magic cookie when playing a sound file

- (void) copyMagicCookieToQueue: (AudioQueueRef) queue fromFile: (AudioFileID) file {
    UInt32 propertySize = sizeof (UInt32);

    OSStatus result = AudioFileGetPropertyInfo (
                            file,
                            kAudioFilePropertyMagicCookieData,
                            &propertySize,
                            NULL
                        );

    if (!result && propertySize) {
        char *cookie = (char *) malloc (propertySize);

        AudioFileGetProperty (
            file,
            kAudioFilePropertyMagicCookieData,
            &propertySize,
            cookie
        );

        AudioQueueSetProperty (
            queue,
            kAudioQueueProperty_MagicCookie,
            cookie,
            propertySize
        );

        free (cookie);
    }
}

 

Audio Data Packets

이전 장에서는 패킷을 하나 이상의 프레임 모음으로 정의했습니다. 이는 주어진 오디오 데이터 형식에 대해 의미 있는 최소한의 프레임 세트입니다. 따라서 오디오 파일에서 시간 단위를 나타내는 데 가장 적합한 단위입니다. Core Audio에서는 패킷을 세어 동기화를 수행합니다. 패킷을 사용하여 유용한 오디오 데이터 버퍼 크기를 계산할 수 있습니다(리스트 2-8 참조).

모든 오디오 데이터 형식은 패킷이 구성되는 방식에 따라 정의됩니다. 오디오 스트림 기본 설명 데이터 구조체는 mBytesPerPacketmFramesPerPacket 멤버에서 형식의 패킷에 대한 기본 정보를 설명합니다(리스트 2-4 참조). 추가 정보가 필요한 형식의 경우 오디오 스트림 패킷 설명 데이터 구조체를 사용합니다.

오디오 데이터 형식에는 세 가지 종류의 패킷이 있습니다:

CBR(고정 비트 레이트) 형식(예: 선형 PCM 및 IMA/ADPCM)에서는 모든 패킷의 크기가 동일합니다.

VBR(가변 비트 레이트) 형식(예: AAC, Apple Lossless 및 MP3)에서는 모든 패킷이 동일한 수의 프레임을 가지지만, 각 샘플 값의 비트 수는 다를 수 있습니다.

VFR(가변 프레임 레이트) 형식에서는 패킷의 프레임 수가 가변적입니다. 이 형식은 일반적으로 사용되지 않습니다.

Core Audio에서 VBR 또는 VFR 형식을 사용하려면 오디오 스트림 패킷 설명 구조체를 사용합니다(리스트 2-5 참조). 이 구조체는 사운드

파일의 단일 패킷을 설명합니다. VBR 또는 VFR 사운드 파일을 녹음하거나 재생하려면 파일의 각 패킷에 대해 이러한 구조체의 배열이 필요합니다.

Audio File Services 및 Audio File Stream Services의 인터페이스를 사용하여 패킷을 다룰 수 있습니다. 예를 들어, AudioFile.hAudioFileReadPackets 함수는 디스크에서 사운드 파일을 읽어 버퍼에 패킷 세트를 넣습니다. 동시에 각 패킷을 설명하는 AudioStreamPacketDescription 구조체 배열을 제공합니다.

CBR 및 VBR 형식(즉, 일반적으로 사용되는 모든 형식)에서는 주어진 오디오 파일 또는 스트림에 대해 초당 패킷 수가 고정되어 있습니다. 이는 실용적인 오디오 데이터 버퍼 크기를 계산할 때 유용한 의미를 가집니다. 예를 들어, 다음 메서드는 주어진 오디오 데이터의 지속 시간으로 버퍼를 채우기 위해 읽어야 할 패킷 수를 결정합니다.

Listing 2-8: Calculating playback buffer size based on packetization

- (void) calculateSizesFor: (Float64) seconds {
    UInt32 maxPacketSize;
    UInt32 propertySize = sizeof (maxPacketSize);

    AudioFileGetProperty (
        audioFileID,
        kAudioFilePropertyPacketSizeUpperBound,
        &propertySize,
        &maxPacketSize
    );

    static const int maxBufferSize = 0x10000;   // limit maximum size to 64K
    static const int minBufferSize = 0x4000;    // limit minimum size to 16K

    if (audioFormat.mFramesPerPacket) {
        Float64 numPacketsForTime =
            audioFormat.mSampleRate / audioFormat.mFramesPerPacket * seconds;
        [self setBufferByteSize: numPacketsForTime * maxPacketSize];
    } else {
        // if frames per packet is zero, then the codec doesn't know the
        // relationship between packets and time. Return a default buffer size
        [self setBufferByteSize:
            maxBufferSize > maxPacketSize ? maxBufferSize : maxPacketSize];
    }

    // clamp buffer size to our specified range
    if (bufferByteSize > maxBufferSize && bufferByteSize > maxPacketSize) {
        [self setBufferByteSize: maxBufferSize];
    } else {
        if (bufferByteSize < minBufferSize) {
            [self setBufferByteSize: minBufferSize];
        }
    }

    [self setNumPacketsToRead: self.bufferByteSize / maxPacketSize];
}

Data Format Conversion

오디오 데이터를 한 형식에서 다른 형식으로 변환하려면 오디오 변환기를 사용합니다. 간단한 변환(예: 샘플 속도 변경 또는 인터리브/비인터리브 변환)부터 복잡한 변환(예: 오디오 압축 또는 압축 해제)까지 수행할 수 있습니다. 세 가지 유형의 변환이 가능합니다:

1. 오디오 형식(예: AAC)을 선형 PCM 형식으로 디코딩

2. 선형 PCM 데이터를 다른 오디오 형식으로 변환

3. 선형 PCM의 다양한 변형 간 변환(예: 16비트 정수형 선형 PCM을 8.24 고정 소수점 선형 PCM으로 변환)

Audio Queue Services를 사용할 때(녹음 및 재생에서 설명됨) 적절한 변환기를 자동으로 제공합니다. Audio Codec Services(Mac 전용)는 디지털 권리 관리(DRM) 또는 독점 오디오 형식을 처리하기 위한 특수 오디오 코덱을 생성할 수 있게 합니다. 사용자 정의 코덱을 만든 후 오디오 변환기를 사용하여 접근하고 사용할 수 있습니다.

OS X에서 오디오 변환기를 명시적으로 사용할 때는 특정 변환기 인스턴스와 함께 변환 함수를 호출하고, 입력 데이터를 찾을 위치와 출력을 쓸 위치를 지정합니다. 대부분의 변환은 주기적으로 입력 데이터를 변환기에 제공하기 위한 콜백 함수를 필요로 합니다. 오디오 변환기를 사용하는 예는 SimpleSDK/ConvertFile과 Core Audio SDK의 Services/AudioFileTools에 있는 AFConvert 명령줄 도구를 참조하세요.

Sound Files

애플리케이션에서 사운드 파일을 사용하려면 Core Audio의 중간 수준 서비스 중 하나인 Audio File Services를 사용할 수 있습니다. Audio File Services는 파일에 포함된 오디오 데이터 및 메타데이터에 접근하고 사운드 파일을 생성하기 위한 강력한 추상화를 제공합니다.

기본적인 파일 ID, 파일 유형 및 데이터 형식을 다루는 것 외에도, Audio File Services는 영역 및 마커, 반복, 재생 방향, SMPTE 타임 코드 등을 다룰 수 있게 합니다.

또한 시스템 특성을 발견하기 위해 Audio File Services를 사용할 수 있습니다. 사용하는 함수는 AudioFileGetGlobalInfoSize(원하는 정보를 저장할 메모리를 할당하도록 함)와 AudioFileGetGlobalInfo(그 정보를 가져옴)입니다. AudioFile.h에 선언된 많은 속성을 통해 다음과 같은 시스템 특성을 프로그래밍 방식으로 얻을 수 있습니다:

읽을 수 있는 파일 형식

쓸 수 있는 파일 형식

각 쓰기 가능한 형식에 대해 파일에 넣을 수 있는 오디오 데이터 형식

이 섹션에서는 다음과 같은 두 가지 Core Audio 기술을 소개합니다:

Audio File Stream Services: 오디오 스트림 구문 분석 인터페이스로, 디스크나 네트워크 스트림에서 오디오 데이터를 읽을 수 있게 합니다.

Extended Audio File Services(Mac 전용): Audio File Services 및 Audio Converter Services의 기능을 포함하여 코드를 단순화합니다.

Creating a New Sound File

새 사운드 파일을 생성하여 녹음하려면 다음이 필요합니다:

1. CFURL 또는 NSURL 객체 형태의 파일 시스템 경로

2. AudioFile.h의 Audio File Types 열거형에 선언된 파일 유형 식별자. 예를 들어 CAF 파일을 생성하려면 kAudioFileCAFType 식별자를 사용합니다.

3. 파일에 넣을 오디오 데이터에 대한 오디오 스트림 기본 설명. 많은 경우, 부분 ASBD를 제공한 후 나중에 Audio File Services가 이를 채우도록 요청할 수 있습니다.

이 세 가지 정보를 AudioFileCreateWithURL 함수의 매개변수로 제공하여 파일을 생성하고 AudioFileID 객체를 반환받습니다. 그런 다음 이 객체를 사용하여 사운드 파일과의 상호작용을 계속할 수 있습니다. 함수 호출은 리스트 2-9와 같습니다.

 

Listing 2-9: Creating a sound file

AudioFileCreateWithURL (
    audioFileURL,
    kAudioFileCAFType,
    &audioFormat,
    kAudioFileFlags_EraseFile,
    &audioFileID   // the function provides the new file object here
);

Opening a Sound File

재생을 위해 사운드 파일을 열려면 AudioFileOpenURL 함수를 사용합니다. 이 함수에 파일의 URL, 파일 유형 힌트 상수 및 사용할 파일 접근 권한을 제공합니다. AudioFileOpenURL은 파일에 대한 고유 ID를 반환합니다.

그런 다음 속성 식별자와 함께 AudioFileGetPropertyInfoAudioFileGetProperty 함수를 사용하여 파일에 대해 알아야 할 내용을 검색합니다. 자주 사용되는 속성 식별자는 다음과 같습니다:

kAudioFilePropertyFileFormat
kAudioFilePropertyDataFormat
kAudioFilePropertyMagicCookieData
kAudioFilePropertyChannelLayout

Audio File Services에서 파일에 있는 메타데이터를 얻을 수 있는 많은 식별자가 있습니다. 예를 들어, 영역 마커, 저작권 정보 및 재생 속도 등이 있습니다.

VBR 파일이 길 경우(예: 팟캐스트) 전체 패킷 테이블을 얻는 데 상당한 시간이 걸릴 수 있습니다. 이러한 경우, kAudioFilePropertyPacketSizeUpperBoundkAudioFilePropertyEstimatedDuration과 같은 두 속성 식별자가 유용합니다. 이를 사용하여 VBR 사운드 파일의 지속 시간이나 패킷 수를 대략적으로 추정할 수 있습니다.

Reading From and Writing To a Sound File

OS에서는 보통 Audio File Services를 사용하여 사운드 파일에서 오디오 데이터를 읽고 쓰기 작업을 수행합니다. 읽기와 쓰기는 본질적으로 서로의 거울 이미지입니다. 두 작업 모두 완료될 때까지 차단되며, 바이트 또는 패킷 단위로 작업할 수 있습니다. 그러나 특별한 요구 사항이 없는 한 항상 패킷을 사용하세요.

패킷 단위로 읽고 쓰는 것이 VBR 데이터에 유일한 옵션입니다.
패킷 기반 작업을 사용하면 지속 시간을 계산하기 훨씬 쉬워집니다.

iOS에서 디스크에서 오디오 데이터를 읽기 위한 또 다른 옵션은 Audio File Stream Services입니다. 이 기술에 대한 소개는 이 장의 나중 부분에서 설명됩니다.

Audio Queue Services는 Audio Toolbox 프레임워크의 AudioQueue.h 헤더 파일에 선언되어 있으며, 녹음 및 재생을 위한 Core Audio 인터페이스입니다. Audio Queue Services에 대한 개요는 이 장의 후반부에서 다룰 것입니다.

Extended Audio File Services

Core Audio는 Extended Audio File Services라는 편의 API를 제공합니다. 이 인터페이스는 Audio File Services 및 Audio Converter Services의 필수 기능을 포함하여 선형 PCM으로의 데이터 변환을 자동으로 제공합니다. 자세한 내용은 “Reading and Writing Audio Data”를 참조하세요.

iPhone Audio File Formats

iOS에서 지원하는 오디오 파일 형식은 표 2-1에 나와 있습니다. iOS에서 사용할 수 있는 오디오 데이터 형식에 대한 자세한 내용은 코덱(Codecs)을 참조하세요.

Table 2-1: Supported Audio File Formats in iOS

iOS는 위에 나열된 오디오 파일 형식을 지원하며, 이들 형식은 다양한 오디오 애플리케이션에서 사용할 수 있습니다. 각 형식은 고유한 장점과 사용 사례를 가지고 있으며, 압축 여부와 품질에 따라 다릅니다. 오디오 데이터 형식에 대한 더 많은 정보를 원하시면 Codecs 섹션을 참고하세요.

CAF Files

iOS 및 OS X에는 기본 오디오 파일 형식인 Core Audio Format(CAF) 파일 형식이 있습니다. CAF 형식은 OS X v10.4 “Tiger”에서 도입되었으며 iOS 2.0 이상에서 사용할 수 있습니다. 이 형식은 플랫폼에서 지원되는 모든 오디오 데이터 형식을 포함할 수 있다는 점에서 독특합니다.

CAF 파일은 AIFF 및 WAVE 파일과 달리 크기 제한이 없으며 채널 정보와 텍스트 주석과 같은 다양한 메타데이터를 지원할 수 있습니다. CAF 파일 형식에 대한 자세한 정보는 Apple Core Audio Format Specification 1.0을 참조하세요.

Sound Streams

디스크 기반 사운드 파일과 달리, 오디오 파일 스트림은 시작과 끝에 접근할 수 없는 오디오 데이터입니다. 예를 들어, 인터넷 라디오 플레이어 애플리케이션을 구축할 때 스트림을 만납니다. 제공자는 일반적으로 스트림을 지속적으로 전송하며, 사용자가 재생 버튼을 누르면 애플리케이션은 현재 전송되는 데이터를 기반으로 즉시 재생을 시작해야 합니다. 이는 오디오 패킷의 시작, 중간 또는 끝일 수도 있고, 매직 쿠키일 수도 있습니다.

또한, 사운드 파일과는 달리 스트림 데이터는 항상 신뢰할 수 없을 수 있습니다. 네트워크 상태에 따라 중단, 불연속 또는 일시 중지가 발생할 수 있습니다.

Audio File Stream Services는 애플리케이션이 이러한 복잡한 스트림을 처리할 수 있게 해줍니다. 이 서비스는 구문 분석을 담당합니다.

Audio File Stream Services를 사용하려면 AudioFileStreamID 유형의 오디오 파일 스트림 객체를 생성합니다. 이 객체는 스트림 자체의 프록시 역할을 하며, 속성을 통해 스트림의 상태를 애플리케이션에 알려줍니다(예: kAudioFileStreamProperty_BitRate 속성).

Audio File Stream Services가 구문 분석을 수행하기 때문에 애플리케이션은 전달된 오디오 데이터와 기타 정보를 처리해야 합니다. 이를 위해 두 가지 콜백 함수를 정의합니다.

먼저, 오디오 파일 스트림 객체의 속성 변경에 대한 콜백이 필요합니다. 최소한, kAudioFileStreamProperty_ReadyToProducePackets 속성의 변경에 응답하도록 이 콜백을 작성합니다. 일반적인 시나리오는 다음과 같습니다:

1. 사용자가 재생 버튼을 누르거나 스트림 재생을 요청합니다.

2. Audio File Stream Services가 스트림 구문 분석을 시작합니다.

3. 충분한 오디오 데이터 패킷이 구문 분석되면, Audio File Stream Services는 오디오 파일 스트림 객체의 kAudioFileStreamProperty_ReadyToProducePackets 속성을 true로 설정합니다(실제로는 1로 설정).

4. Audio File Stream Services가 애플리케이션의 속성 리스너 콜백을 호출하고, 속성 ID 값으로 kAudioFileStreamProperty_ReadyToProducePackets를 전달합니다.

5. 속성 리스너 콜백은 적절한 조치를 취합니다(예: 스트림 재생을 위한 오디오 큐 객체 설정).

두 번째로, 오디오 데이터에 대한 콜백이 필요합니다. Audio File Stream Services는 완전한 오디오 데이터 패킷 세트를 수집할 때마다 이 콜백을 호출합니다. 이 콜백은 수신된 오디오를 처리하도록 정의됩니다. 일반적으로 Audio Queue Services에 데이터를 전달하여 즉시 재생합니다. 재생에 대한 자세한 내용은 다음 섹션 “Recording and Playback using Audio Queue Services”를 참조하세요.

Audio Sessions: Cooperating with Core Audio

iOS에서 애플리케이션은 가끔 더 중요한 작업(예: 전화 통화)을 처리해야 하는 장치에서 실행됩니다. 애플리케이션이 사운드를 재생하는 중에 전화가 오면 iPhone은 적절한 조치를 취해야 합니다.

첫 번째로, “적절한 조치”는 사용자 기대를 충족시키는 것입니다. 두 번째로, iPhone은 경쟁 요청을 해결할 때 실행 중인 각 애플리케이션의 현재 상태를 고려해야 합니다.

오디오 세션은 애플리케이션과 iOS 간의 중개자 역할을 합니다. 각 iPhone 애플리케이션에는 정확히 하나의 오디오 세션이 있습니다. 이를 구성하여 애플리케이션의 오디오 의도를 표현합니다. 시작하려면 애플리케이션의 동작 방식에 대한 몇 가지 질문에 답합니다:

전화와 같은 중단에 어떻게 응답하길 원합니까?

애플리케이션의 사운드를 다른 실행 중인 애플리케이션의 사운드와 혼합하거나 다른 애플리케이션의 사운드를 무음 처리할 의도가 있습니까?

사용자가 헤드셋을 꽂거나 뽑을 때와 같이 오디오 경로가 변경되면 애플리케이션이 어떻게 반응해야 합니까?

이 질문에 대한 답을 바탕으로 오디오 세션 인터페이스(AudioToolbox/AudioServices.h에 선언됨)를 사용하여 오디오 세션과 애플리케이션을 구성합니다. 표 2-2는 이 인터페이스가 제공하는 세 가지 프로그래밍 기능을 설명합니다.

Table 2-2: Features provided by the audio session interface

Audio Session Default Behavior

오디오 세션에는 몇 가지 기본 동작이 있습니다. 구체적으로:

사용자가 Ring/Silent 스위치를 무음으로 전환하면 오디오가 무음 처리됩니다.

사용자가 Sleep/Wake 버튼을 눌러 화면을 잠그거나 Auto-Lock 기간이 만료되면 오디오가 무음 처리됩니다.

오디오가 시작되면 이미 재생 중인 iPod 오디오 등 다른 오디오가 무음 처리됩니다.

이 동작 집합은 기본 오디오 세션 카테고리인 kAudioSessionCategory_SoloAmbientSound에 의해 지정됩니다. iOS는 사용자 인터페이스 사운드 효과에서 VOIP(인터넷 전화) 애플리케이션에 사용할 수 있는 동시 오디오 입력 및 출력에 이르기까지 다양한 오디오 요구를 위한 카테고리를 제공합니다. 시작 시 및 애플리케이션 실행 중에 원하는 카테고리를 지정할 수 있습니다.

오디오 세션 기본 동작은 iPhone 오디오 개발을 시작하는 데 충분합니다. 그러나 특정 특별한 경우를 제외하고 기본 동작은 배포용 애플리케이션에는 적합하지 않습니다.

Interruptions: Deactivation and Activation

기본 오디오 세션에 눈에 띄게 없는 기능 중 하나는 중단 후 다시 활성화하는 능력입니다. 오디오 세션에는 활성(active)과 비활성(inactive)이라는 두 가지 주요 상태가 있습니다. 오디오는 오디오 세션이 활성 상태일 때만 작동합니다.

애플리케이션이 시작될 때 기본 오디오 세션은 활성 상태입니다. 그러나 전화가 오면 세션이 즉시 비활성화되고 오디오가 중지됩니다. 이를 중단(interruption)이라고 합니다. 사용자가 전화를 무시하기로 선택하면 애플리케이션은 계속 실행됩니다. 그러나 오디오 세션이 비활성 상태이면 오디오는 작동하지 않습니다.

애플리케이션에서 OpenAL, I/O 오디오 유닛 또는 Audio Queue Services를 사용하는 경우, 중단 리스너 콜백 함수를 작성하고 중단이 끝날 때 오디오 세션을 명시적으로 다시 활성화해야 합니다. Audio Session Programming Guide는 세부 정보와 코드 예제를 제공합니다.

AVAudioPlayer 클래스를 사용하는 경우, 이 클래스는 오디오 세션 재활성화를 처리합니다.

Determining if Audio Input is Available

iOS 기반 장치에서 녹음 애플리케이션은 하드웨어 오디오 입력이 가능한 경우에만 녹음할 수 있습니다. 이를 테스트하려면 오디오 세션 kAudioSessionProperty_AudioInputAvailable 속성을 사용합니다. 이는 iPod touch(2세대)와 같은 장치에서 적절한 액세서리 하드웨어가 연결될 때만 오디오 입력을 사용할 수 있는 경우에 중요합니다. 리스트 2-10은 테스트 방법을 보여줍니다.

Listing 2-10: Determining if a mobile device supports audio recording

UInt32 audioInputIsAvailable;
UInt32 propertySize = sizeof (audioInputIsAvailable);

AudioSessionGetProperty (
    kAudioSessionProperty_AudioInputAvailable,
    &propertySize,
    &audioInputIsAvailable // A nonzero value on output means that
                           // audio input is available
);

 

Using Your Audio Session

애플리케이션에는 한 번에 하나의 오디오 세션 카테고리만 있습니다. 따라서 특정 시간에 모든 오디오는 활성 카테고리의 특성을 따릅니다. (이 규칙의 예외는 경고 및 사용자 인터페이스 사운드 효과를 위한 API인 System Sound Services를 사용하여 재생되는 오디오입니다. 이러한 오디오는 항상 가장 낮은 우선순위의 오디오 세션 카테고리를 사용합니다.) 오디오 세션 코드의 동작을 테스트하려면 장치에서 실행해야 합니다.

Playback using the AVAudioPlayer Class

AVAudioPlayer 클래스는 오디오 재생을 위한 간단한 Objective-C 인터페이스를 제공합니다. 애플리케이션이 스테레오 위치 지정이나 정밀한 동기화를 필요로 하지 않으며, 네트워크 스트림에서 캡처된 오디오를 재생하지 않는 경우, Apple은 이 클래스를 사용하여 재생할 것을 권장합니다.

오디오 플레이어를 사용하면 다음을 할 수 있습니다:

모든 길이의 사운드 재생

파일 또는 메모리 버퍼에서 사운드 재생

사운드 반복 재생

여러 사운드 동시 재생

재생 중인 각 사운드의 상대적 재생 레벨 제어

사운드 파일의 특정 지점으로 이동(빠른 감기 및 되감기 기능 지원)

오디오 레벨 미터링에 사용할 데이터 얻기

AVAudioPlayer 클래스는 iOS에서 사용할 수 있는 모든 오디오 형식의 사운드를 재생할 수 있습니다. 이 클래스의 인터페이스에 대한 자세한 설명은 AVAudioPlayer Class Reference를 참조하세요.

AVAudioPlayer 클래스는 OpenAL, I/O 오디오 유닛 및 Audio Queue Services와 달리 Audio Session Services를 사용할 필요가 없습니다. 오디오 플레이어는 중단 후 스스로 재활성화됩니다. 기본 오디오 세션 카테고리가 지정한 동작(예: 화면이 잠기면 오디오가 중지됨)을 원한다면, 오디오 플레이어와 함께 기본 오디오 세션을 성공적으로 사용할 수 있습니다.

재생을 위해 오디오 플레이어를 구성하려면 사운드 파일을 지정하고, 재생 준비를 하고, 델리게이트 객체를 지정합니다. 리스트 2-11의 코드는 일반적으로 애플리케이션의 컨트롤러 클래스의 초기화 메서드에 포함됩니다.

Listing 2-11: Configuring an AVAudioPlayer object

NSString *soundFilePath =
                [[NSBundle mainBundle] pathForResource: @"sound"
                                                ofType: @"wav"];

NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

AVAudioPlayer *newPlayer =
                [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                                                       error: nil];
[fileURL release];

self.player = newPlayer;
[newPlayer release];

[self.player prepareToPlay];
[self.player setDelegate: self];

델리게이트 객체(컨트롤러 객체일 수 있음)를 사용하여 중단을 처리하고 사운드 재생이 완료될 때 사용자 인터페이스를 업데이트합니다. AVAudioPlayer 클래스의 델리게이트 메서드는 AVAudioPlayerDelegate Protocol Reference에서 설명됩니다. 리스트 2-12는 델리게이트 메서드의 간단한 구현을 보여줍니다. 이 코드는 사운드 재생이 완료되었을 때 재생/일시 정지 토글 버튼의 제목을 업데이트합니다.

Listing 2-12: Implementing an AVAudioPlayer delegate method

- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player
                        successfully: (BOOL) flag {
    if (flag == YES) {
        [self.button setTitle: @"Play" forState: UIControlStateNormal];
    }
}

AVAudioPlayer 객체를 재생, 일시 정지 또는 중지하려면 해당 재생 제어 메서드 중 하나를 호출합니다. 재생이 진행 중인지 여부를 playing 속성을 사용하여 테스트할 수 있습니다. 리스트 2-13은 재생을 제어하고 UIButton 객체의 제목을 업데이트하는 기본 재생/일시 정지 토글 메서드를 보여줍니다.

Listing 2-13: Controlling an AVAudioPlayer object

- (IBAction) playOrPause: (id) sender {
    // if already playing, then pause
    if (self.player.playing) {
        [self.button setTitle: @"Play" forState: UIControlStateHighlighted];
        [self.button setTitle: @"Play" forState: UIControlStateNormal];
        [self.player pause];
    // if stopped or paused, start playing
    } else {
        [self.button setTitle: @"Pause" forState: UIControlStateHighlighted];
        [self.button setTitle: @"Pause" forState: UIControlStateNormal];
        [self.player play];
    }
}

AVAudioPlayer 클래스는 선언된 속성 기능을 사용하여 사운드에 대한 정보(예: 재생 타임라인 내의 재생 지점)를 관리하고 재생 옵션(예: 볼륨 및 반복 재생)에 접근합니다. 예를 들어, 오디오 플레이어의 재생 볼륨을 다음과 같이 설정할 수 있습니다:

[self.player setVolume: 1.0];    // available range is 0.0 through 1.0

AVAudioPlayer 클래스에 대한 자세한 내용은 AVAudioPlayer Class Reference를 참조하세요.

Recording and Playback using Audio Queue Services

Audio Queue Services는 오디오를 녹음하고 재생하는 간단하고 낮은 오버헤드의 방법을 제공합니다. 이를 통해 애플리케이션은 하드웨어 인터페이스에 대한 지식 없이 하드웨어 녹음 및 재생 장치(예: 마이크 및 스피커)를 사용할 수 있습니다. 또한 코덱의 작동 방식을 이해하지 않고도 고급 코덱을 사용할 수 있습니다.

고급 인터페이스이지만, Audio Queue Services는 몇 가지 고급 기능을 지원합니다. 예약된 재생 및 동기화를 지원하는 정밀한 타이밍 제어를 제공합니다. 여러 오디오 큐의 재생을 동기화하고, 사운드를 동시에 재생하며, 여러 사운드의 재생 레벨을 독립적으로 제어하고, 반복 재생을 수행할 수 있습니다. Audio Queue Services와 AVAudioPlayer 클래스(Playback using the AVAudioPlayer Class 참조)는 iPhone 또는 iPod touch에서 압축 오디오를 재생하는 유일한 방법입니다.

일반적으로 Audio Queue Services는 Audio File Services(사운드 파일에서 설명됨) 또는 Audio File Stream Services(사운드 스트림에서 설명됨)와 함께 사용합니다.

Audio Queue Callback Functions for Recording and Playback

Audio File Stream Services와 마찬가지로, Audio Queue Services에서는 콜백 함수와 속성을 사용하여 오디오 큐 객체와 상호 작용합니다. 녹음을 위해서는 오디오 데이터 버퍼를 받아들이고 이를 디스크에 쓰는 콜백 함수를 구현합니다. 녹음 오디오 큐 객체는 기록할 새로운 데이터 버퍼가 있을 때 콜백 함수를 호출합니다. 그림 2-2는 이 과정을 단순화한 모습을 보여줍니다.

Figure 2-2: Simplified view of the recording process with Audio Queue Services

재생을 위해서는 오디오 콜백이 반대 역할을 합니다. 재생 오디오 큐 객체가 또 다른 버퍼의 오디오가 필요할 때 콜백이 호출됩니다. 콜백 함수는 디스크에서 지정된 수의 오디오 패킷을 읽어 오디오 큐 객체의 버퍼 중 하나에 전달합니다. 오디오 큐 객체는 해당 버퍼를 차례로 재생합니다. 그림 2-3은 이 과정을 보여줍니다.

Figure 2-3   Playing back using an audio queue object

Creating an Audio Queue Object

Audio Queue Services를 사용하려면 먼저 오디오 큐 객체를 생성해야 합니다. 오디오 큐 객체에는 두 가지 유형이 있으며, 둘 다 AudioQueueRef 데이터 유형을 사용합니다.

녹음 오디오 큐 객체는 AudioQueueNewInput 함수를 사용하여 생성합니다.

재생 오디오 큐 객체는 AudioQueueNewOutput 함수를 사용하여 생성합니다.

재생 오디오 큐 객체를 생성하려면 다음 세 단계를 수행합니다:

1. 재생하려는 데이터의 오디오 형식과 같은 오디오 큐에 필요한 정보를 관리하기 위한 데이터 구조체를 만듭니다.

2. 오디오 큐 버퍼를 관리하기 위한 콜백 함수를 정의합니다. 이 콜백은 Audio File Services를 사용하여 재생할 파일을 읽습니다.

3. AudioQueueNewOutput 함수를 사용하여 재생 오디오 큐를 인스턴스화합니다.

Listing 2-14: Creating an audio queue object

static const int kNumberBuffers = 3;
// Create a data structure to manage information needed by the audio queue
struct myAQStruct {
    AudioFileID                     mAudioFile;
    CAStreamBasicDescription        mDataFormat;
    AudioQueueRef                   mQueue;
    AudioQueueBufferRef             mBuffers[kNumberBuffers];
    SInt64                          mCurrentPacket;
    UInt32                          mNumPacketsToRead;
    AudioStreamPacketDescription    *mPacketDescs;
    bool                            mDone;
};
// Define a playback audio queue callback function
static void AQTestBufferCallback(
    void                   *inUserData,
    AudioQueueRef          inAQ,
    AudioQueueBufferRef    inCompleteAQBuffer
) {
    myAQStruct *myInfo = (myAQStruct *)inUserData;
    if (myInfo->mDone) return;
    UInt32 numBytes;
    UInt32 nPackets = myInfo->mNumPacketsToRead;
 
    AudioFileReadPackets (
        myInfo->mAudioFile,
        false,
        &numBytes,
        myInfo->mPacketDescs,
        myInfo->mCurrentPacket,
        &nPackets,
        inCompleteAQBuffer->mAudioData
    );
    if (nPackets > 0) {
        inCompleteAQBuffer->mAudioDataByteSize = numBytes;
        AudioQueueEnqueueBuffer (
            inAQ,
            inCompleteAQBuffer,
            (myInfo->mPacketDescs ? nPackets : 0),
            myInfo->mPacketDescs
        );
        myInfo->mCurrentPacket += nPackets;
    } else {
        AudioQueueStop (
            myInfo->mQueue,
            false
        );
        myInfo->mDone = true;
    }
}
// Instantiate an audio queue object
AudioQueueNewOutput (
    &myInfo.mDataFormat,
    AQTestBufferCallback,
    &myInfo,
    CFRunLoopGetCurrent(),
    kCFRunLoopCommonModes,
    0,
    &myInfo.mQueue
);

 

Controlling Audio Queue Playback Level

오디오 큐 객체는 재생 레벨을 제어하는 두 가지 방법을 제공합니다.

1. AudioQueueSetParameter 함수를 사용하여 kAudioQueueParam_Volume 매개변수와 함께 재생 레벨을 직접 설정할 수 있습니다. 레벨 변경은 즉시 적용됩니다.

Listing 2-15: Setting playback level directly

Float32 volume = 1;
AudioQueueSetParameter (
    myAQstruct.audioQueueObject,
    kAudioQueueParam_Volume,
    volume
);

2. AudioQueueEnqueueBufferWithParameters 함수를 사용하여 오디오 큐 버퍼의 재생 레벨을 설정할 수 있습니다. 이는 오디오 큐 버퍼가 재생을 시작할 때 적용됩니다.

두 경우 모두 오디오 큐의 레벨 변경은 다시 변경할 때까지 유지됩니다.

Indicating Audio Queue Playback Level

오디오 큐 객체의 현재 재생 레벨은 kAudioQueueProperty_CurrentLevelMeterDB 속성을 쿼리하여 얻을 수 있습니다. 이 속성의 값은 채널당 하나씩의 AudioQueueLevelMeterState 구조체 배열입니다.

Listing 2-16: The AudioQueueLevelMeterState structure

typedef struct AudioQueueLevelMeterState {
    Float32     mAveragePower;
    Float32     mPeakPower;
};  AudioQueueLevelMeterState;

 

Playing Multiple Sounds Simultaneously

여러 사운드를 동시에 재생하려면 각 사운드에 대해 하나의 재생 오디오 큐 객체를 생성합니다. 각 오디오 큐에 대해 AudioQueueEnqueueBufferWithParameters 함수를 사용하여 첫 번째 오디오 버퍼를 동시에 시작하도록 예약합니다.

iPhone 또는 iPod touch에서 사운드를 동시에 재생할 때 오디오 형식은 매우 중요합니다. 특정 압축 형식의 재생은 효율적인 하드웨어 코덱을 사용하므로, 이러한 형식 중 하나만 동시에 재생할 수 있습니다:

AAC

ALAC (Apple Lossless)

MP3

고품질의 사운드를 동시에 재생하려면 선형 PCM 또는 IMA4 오디오를 사용하십시오.

다음 목록은 개별 재생 또는 다중 재생을 위한 iOS의 오디오 형식 지원 방법을 설명합니다:

Linear PCM and IMA/ADPCM (IMA4) audio: iOS에서 여러 선형 PCM 또는 IMA4 형식 사운드를 동시에 재생할 수 있으며, CPU 리소스 문제를 발생시키지 않습니다.

AAC, MP3, and Apple Lossless (ALAC) audio: iPhone 및 iPod touch에서 AAC, MP3, Apple Lossless (ALAC) 사운드의 재생은 효율적인 하드웨어 기반 디코딩을 사용합니다. 이러한 형식의 사운드는 한 번에 하나만 재생할 수 있습니다.

Audio Queue Services를 사용한 녹음 및 재생에 대한 전체 설명과 코드 샘플은 Audio Queue Services Programming Guide에서 확인할 수 있습니다.

Playback with Positioning Using OpenAL

오픈 소스 OpenAL 오디오 API는 Core Audio를 기반으로 하여 재생 중 사운드 위치 지정을 최적화합니다. OpenAL은 OpenGL을 모델로 한 인터페이스를 사용하여 사운드를 재생, 위치 지정, 믹스 및 이동하기 쉽게 합니다. OpenAL과 OpenGL은 공통 좌표계를 공유하여 사운드와 화면 그래픽 객체의 움직임을 동기화할 수 있습니다. OpenAL은 Core Audio의 I/O 오디오 유닛을 직접 사용하여 가장 낮은 지연 시간의 재생을 제공합니다.

이러한 이유로, OpenAL은 iPhone 및 iPod touch에서 게임 애플리케이션의 사운드 효과를 재생하는 데 가장 적합한 선택입니다. OpenAL은 일반적인 iOS 애플리케이션 재생 요구에도 좋은 선택입니다.

iOS의 OpenAL 1.1은 오디오 캡처를 지원하지 않습니다. iOS에서 녹음을 위해서는 Audio Queue Services를 사용하십시오.

OS X의 OpenAL은 OpenAL 1.1 사양과 확장을 구현합니다. iOS의 OpenAL에는 두 가지 Apple 확장이 있습니다:

alBufferDataStaticProcPtr: alBufferData의 사용 패턴을 따르지만 버퍼 데이터 복사를 제거합니다.

alcMacOSXMixerOutputRateProcPtr: 기본 믹서의 샘플 속도를 제어할 수 있습니다.

Mac에서 Core Audio에서 OpenAL을 사용하는 예는 Core Audio SDK의 Services/OpenALExample에서 확인할 수 있습니다.

System Sounds: Alerts and Sound Effects

레벨, 위치 지정, 오디오 세션 또는 기타 제어가 필요하지 않은 짧은 사운드 파일을 재생하려면 Audio Toolbox 프레임워크의 AudioServices.h 헤더 파일에 선언된 System Sound Services를 사용하십시오. 이 인터페이스는 가장 간단한 방식으로 짧은 사운드를 재생하려는 경우에 이상적입니다. iOS에서 System Sound Services를 사용하여 재생되는 사운드는 최대 30초의 길이로 제한됩니다.

iOS에서 AudioServicesPlaySystemSound 함수를 호출하여 지정한 사운드 효과 파일을 즉시 재생할 수 있습니다. 또는 사용자를 알리기 위해 AudioServicesPlayAlertSound를 호출할 수 있습니다. 이 함수들은 사용자가 무음 스위치를 설정한 경우 iPhone에서 진동을 발생시킵니다. (iOS 시뮬레이터나 데스크톱에서는 물론 진동이나 버징이 없습니다.)

AudioServicesPlaySystemSound 함수를 호출할 때 kSystemSoundID_Vibrate 상수를 사용하여 iPhone에서 진동을 명시적으로 호출할 수 있습니다.

AudioServicesPlaySystemSound 함수로 사운드를 재생하려면 먼저 시스템 사운드로 사운드 효과 파일을 등록하여 사운드 ID 객체를 생성해야 합니다. 그런 다음 사운드를 재생할 수 있습니다. 일반적인 사용에서는 사운드를 가끔 또는 반복적으로 재생할 때 애플리케이션이 종료될 때까지 사운드 ID 객체를 유지합니다. 예를 들어 시작 사운드의 경우처럼 사운드를 한 번만 사용한다는 것을 알고 있다면 사운드를 재생한 후 즉시 사운드 ID 객체를 파괴하여 메모리를 해제할 수 있습니다.

다음은 System Sound Services의 인터페이스를 사용하여 사운드를 재생하는 최소 프로그램을 보여줍니다. 사운드 완료 콜백과 이를 설치하는 호출은 사운드를 다시 재생하지 않을 때 사운드를 재생한 후 메모리를 해제하려는 경우에 주로 유용합니다.

Listing 2-17: Playing a short sound

#include <AudioToolbox/AudioToolbox.h>
#include <CoreFoundation/CoreFoundation.h>

// Define a callback to be called when the sound is finished
// playing. Useful when you need to free memory after playing.
static void MyCompletionCallback (
    SystemSoundID  mySSID,
    void * myURLRef
) {
        AudioServicesDisposeSystemSoundID (mySSID);
        CFRelease (myURLRef);
        CFRunLoopStop (CFRunLoopGetCurrent());
}

int main (int argc, const char * argv[]) {
    // Set up the pieces needed to play a sound.
    SystemSoundID    mySSID;
    CFURLRef        myURLRef;
    myURLRef = CFURLCreateWithFileSystemPath (
        kCFAllocatorDefault,
        CFSTR ("../../ComedyHorns.aif"),
        kCFURLPOSIXPathStyle,
        FALSE
    );

    // create a system sound ID to represent the sound file
    OSStatus error = AudioServicesCreateSystemSoundID (myURLRef, &mySSID);

    // Register the sound completion callback.
    // Again, useful when you need to free memory after playing.
    AudioServicesAddSystemSoundCompletion (
        mySSID,
        NULL,
        NULL,
        MyCompletionCallback,
        (void *) myURLRef
    );

    // Play the sound file.
    AudioServicesPlaySystemSound (mySSID);

    // Invoke a run loop on the current thread to keep the application
    // running long enough for the sound to play; the sound completion
    // callback later stops this run loop.
    CFRunLoopRun ();
    return 0;
}

Core Audio Plug-ins: Audio Units and Codecs

Core Audio는 오디오 데이터를 처리하기 위한 플러그인 메커니즘을 가지고 있습니다. iOS에서는 시스템이 이러한 플러그인을 제공합니다. OS X에서는 내장된 플러그인을 사용할 수 있으며 직접 만들 수도 있습니다.

여러 호스트 애플리케이션은 각각 여러 인스턴스의 오디오 유닛 또는 코덱을 사용할 수 있습니다.

Audio Units

iOS에서 오디오 유닛은 애플리케이션이 저지연 입력 및 출력을 달성할 수 있는 메커니즘을 제공합니다. 또한 특정 DSP 기능도 제공합니다.

OS X에서는 오디오 유닛이 GarageBand 및 Logic Studio와 같은 오디오 애플리케이션의 애드온으로 가장 두드러지게 사용됩니다. 이 역할에서 오디오 유닛은 자체 사용자 인터페이스 또는 보기를 가지고 있습니다. iOS의 오디오 유닛은 보기를 가지지 않습니다.

두 플랫폼 모두에서 내장 오디오 유닛의 프로그래밍 이름은 Audio Unit 프레임워크의 AUComponent.h 헤더 파일에 있습니다.

iOS 오디오 유닛은 입력 및 출력에 8.24 비트 고정 소수점 선형 PCM 오디오 데이터를 사용합니다. 예외는 다음 목록에 설명된 데이터 형식 변환 유닛입니다. iOS 오디오 유닛은 다음과 같습니다:

 

3D Mixer Unit: 단일 스테레오 출력을 제공하는 8비트 또는 16비트 선형 PCM의 여러 모노 입력을 허용합니다. 샘플 속도 변환을 수행하고 각 입력 채널에 대한 많은 제어를 제공합니다. 볼륨, 음소거, 팬닝, 거리 감쇠 및 이러한 변경에 대한 속도 제어를 포함합니다. 프로그래밍적으로, 이는 kAudioUnitSubType_AU3DMixerEmbedded 유닛입니다.

Multichannel Mixer Unit: 8.24 비트 고정 소수점 PCM에서 단일 스테레오 출력을 제공하는 16비트 선형 또는 8.24 비트 고정 소수점 PCM의 여러 모노 또는 스테레오 입력을 허용합니다. 각 입력 채널을 음소거 및 음소거 해제하고 볼륨을 제어할 수 있습니다. 프로그래밍적으로, 이는 kAudioUnitSubType_MultiChannelMixer 유닛입니다.

Converter Unit: 샘플 속도, 비트 심도 및 비트 형식(선형에서 고정 소수점) 변환을 제공합니다. iPhone 변환 유닛의 표준 데이터 형식은 8.24 비트 고정 소수점 PCM입니다. 이 형식으로 변환합니다. 프로그래밍적으로, 이는 kAudioUnitSubType_AUConverter 유닛입니다.

I/O Unit: 필요한 경우 실시간 오디오 입력 및 출력을 제공하고 샘플 속도 변환을 수행합니다. 프로그래밍적으로, 이는 kAudioUnitSubType_RemoteIO 유닛입니다.

iPod EQ Unit: 애플리케이션에서 사용할 수 있는 간단한 이퀄라이저를 제공하며, 내장 iPhone iPod 애플리케이션에서 사용할 수 있는 동일한 프리셋을 제공합니다. iPod EQ 유닛은 8.24 비트 고정 소수점 PCM 입력 및 출력을 사용합니다. 프로그래밍적으로, 이는 kAudioUnitSubType_AUiPodEQ 유닛입니다.

특수한 카테고리의 오디오 유닛인 I/O 유닛은 이러한 오디오 유닛이 중요한 역할을 하기 때문에 Audio Processing Graphs에서 더 자세히 설명됩니다.

OS X는 40개 이상의 오디오 유닛을 제공하며, 모두 OS X의 System-Supplied Audio Units에서 확인할 수 있습니다. 애플리케이션의 구성 요소로 또는 자체 제품으로 고객에게 제공하기 위해 자체 오디오 유닛을 만들 수도 있습니다. 자세한 내용은 Audio Unit Programming Guide를 참조하십시오.

OS X 오디오 유닛은 입력 및 출력에 비인터리브드 32비트 부동 소수점 선형 PCM 데이터를 사용합니다. 데이터 형식 변환기인 오디오 유닛의 경우를 제외하고는 이 형식으로 변환합니다. OS X 오디오 유닛은 다른 선형 PCM 변형도 지원할 수 있습니다. 그러나 선형 PCM 외의 형식은 지원하지 않습니다. 이는 Apple 및 기타 공급업체의 오디오 유닛과의 호환성을 보장합니다. 다른 형식의 오디오 데이터를 선형 PCM으로 변환하려면 오디오 변환기를 사용할 수 있습니다(데이터 형식 변환 참조).

iOS 및 OS X에서 호스트 애플리케이션은 Audio Unit Services의 함수를 사용하여 오디오 유닛을 발견하고 로드합니다. 각 오디오 유닛은 유형, 하위 유형 및 제조업체 코드의 세 가지 요소 조합으로 고유하게 식별됩니다. Apple에서 지정한 유형 코드는 유닛의 일반적인 용도(효과, 생성기 등)를 나타냅니다. 하위 유형은 오디오 유닛이 수행하는 작업을 더 정확하게 설명하지만, 오디오 유닛에 대해 프로그래밍적으로 중요하지 않습니다. 한 회사가 여러 효과 유닛을 제공하는 경우, 각 유닛은 다른 유닛과 구별할 수 있도록 고유한 하위 유형을 가져야 합니다. 제조업체 코드는 오디오 유닛의 개발자로서 자신을 식별합니다.

Apple은 데이터 유형 등록 페이지에서 “제작자 코드”로 제조업체 코드를 등록할 것을 기대합니다.

오디오 유닛은 속성, 범위 및 요소에서 설명한 대로 속성을 사용하여 기능 및 구성 정보를 설명합니다. 각 오디오 유닛 유형에는 Apple에서 정의한 몇 가지 필수 속성이 있지만, 오디오 유닛의 필요에 따라 추가 속성을 자유롭게 추가할 수 있습니다. OS X에서 호스트 애플리케이션은 속성 정보를 사용하여 오디오 유닛의 일반 보기를 만들 수 있으며, 사용자 정의 보기를 오디오 유닛의 통합 조각으로 제공할 수 있습니다.

오디오 유닛은 종종 최종 사용자가 실시간으로 조정할 수 있는 설정에 대한 매개변수 메커니즘도 사용합니다. 이러한 매개변수는 함수의 인수가 아니며, 오디오 유닛 동작에 대한 사용자 조정을 지원하는 메커니즘입니다. 예를 들어, 매개변수 필터 유닛에는 중심 주파수 및 필터 응답 폭과 같은 매개변수가 있을 수 있으며, 이는 뷰를 통해 설정할 수 있습니다.

OS X에서 오디오 유닛의 상태 변화를 모니터링하려면 특정 오디오 유닛 이벤트가 발생할 때 호출되는 콜백 함수(리스너라고도 함)를 애플리케이션이 등록할 수 있습니다. 예를 들어, Mac 애플리케이션은 사용자가 오디오 유닛의 보기에서 슬라이더를 이동할 때 또는 오디오 데이터 흐름이 중단될 때를 알고 싶어할 수 있습니다. 자세한 내용은 Technical Note TN2104: Handling Audio Unit Events를 참조하십시오.

Core Audio SDK(AudioUnits 폴더에 있음)는 일반적인 오디오 유닛 유형(예: 효과 유닛 및 악기 유닛)에 대한 템플릿과 대부분의 Component Manager 플러그인 인터페이스를 구현하는 C++ 프레임워크를 제공합니다. OS X에서 SDK를 사용하여 오디오 유닛을 빌드하는 방법에 대한 자세한 내용은 Audio Unit Programming Guide를 참조하십시오.

Codecs

iOS에서 사용할 수 있는 녹음 및 재생 코덱은 오디오 품질, 애플리케이션 개발의 유연성, 하드웨어 기능 및 배터리 수명을 균형 있게 고려하여 선택됩니다.

iOS에는 두 그룹의 재생 코덱이 있습니다. 첫 번째 그룹은 테이블 2-3에 나열된 형식으로, 제한 없이 사용할 수 있는 고효율 형식입니다. 즉, 이러한 형식의 여러 인스턴스를 동시에 재생할 수 있습니다.

Table 2-3: iOS: unrestricted playback audio formats

iLBC (internet Low Bitrate Codec, also a speech codec)
IMA/ADPCM (also known as IMA-4)
Linear PCM
µLaw and aLaw

두 번째 그룹의 iOS 재생 코덱은 모두 단일 하드웨어 경로를 공유합니다. 따라서 이러한 형식 중 하나의 인스턴스만 한 번에 재생할 수 있습니다.

Table 2-4: iOS: restricted playback audio formats

AAC
Apple Lossless
MP3

iOS에는 테이블 2-5에 나열된 녹음 코덱이 포함되어 있습니다. MP3 또는 AAC 녹음은 사용할 수 없습니다. 이는 이러한 형식의 높은 CPU 오버헤드 및 그로 인한 배터리 소모 때문입니다.

Table 2-5: iOS: recording audio formats

Apple Lossless
iLBC (internet Low Bitrate Codec, a speech codec)
IMA/ADPCM (also known as IMA-4)
Linear PCM
µLaw and aLaw

OS X에서는 다양한 코덱과 지원되는 형식을 사용할 수 있으며, 이는 OS X의 Supported Audio File and Data Formats에 설명되어 있습니다.

OS X는 오디오 데이터 코덱을 사용 및 생성하기 위한 인터페이스도 제공합니다. 이러한 인터페이스는 Audio Toolbox 프레임워크의 AudioConverter.h 헤더 파일 및 Audio Unit 프레임워크의 AudioCodec.h에 선언되어 있습니다. Common Tasks in OS X에서는 이러한 서비스를 사용하는 방법을 설명합니다.

Audio Processing Graphs

오디오 처리 그래프(때로는 AUGraph라고도 함)는 복잡한 작업을 수행하기 위해 일련의 오디오 유닛을 정의하는 것입니다. 예를 들어, 그래프는 신호를 왜곡하고 압축한 다음 사운드 스테이지의 특정 위치로 팬닝할 수 있습니다. 그래프를 정의하면 애플리케이션의 신호 체인에 추가 및 제거할 수 있는 재사용 가능한 처리 모듈을 갖게 됩니다.

처리 그래프는 일반적으로 I/O 유닛(때로는 출력 유닛이라고도 함)에서 끝납니다. I/O 유닛은 종종 하드웨어와 간접적으로(저수준 서비스 통해) 인터페이스하지만, 이는 필수 조건은 아닙니다. I/O 유닛은 대신 출력 신호를 애플리케이션으로 다시 보낼 수 있습니다.

또한 I/O 유닛을 처리 그래프의 헤드 노드라고도 합니다. I/O 유닛은 그래프에서 데이터 흐름을 시작하고 중지할 수 있는 유일한 유닛입니다. 이는 오디오 유닛이 데이터를 얻기 위해 사용하는 이른바 풀 메커니즘의 중요한 측면입니다. 그래프의 각 오디오 유닛은 후속 유닛과 함께 렌더링 콜백을 등록하여 후속 유닛이 오디오 데이터를 요청할 수 있도록 합니다. I/O 유닛이 데이터 흐름을 시작하면(애플리케이션에 의해 트리거됨) 그 렌더 메서드는 체인의 이전 오디오 유닛을 호출하여 데이터를 요청하고, 그 유닛은 다시 그 전의 유닛을 호출하는 방식입니다.

iOS에는 단일 I/O 유닛이 있으며, 이는 Audio Units에서 설명한 바와 같습니다. OS X에서는 이야기가 좀 더 복잡합니다.

 

AUHAL 유닛: 특정 하드웨어 장치에 전용 입력 및 출력을 제공합니다. 자세한 내용은 Technical Note TN2091, Device input using the HAL Output Audio Unit를 참조하십시오.

Generic I/O 유닛: 오디오 처리 그래프의 출력을 애플리케이션에 연결할 수 있습니다. 또한 서브그래프의 헤드 노드로 사용할 수도 있습니다.

System I/O 유닛: 경고 및 사용자 인터페이스 사운드 효과에 사용됩니다.

Default I/O 유닛: 기타 모든 오디오 입력 및 출력에 사용됩니다.

 

Audio MIDI Setup 애플리케이션(Mac 전용; 유틸리티 폴더에 있음)을 사용하면 사용자가 System I/O 및 Default I/O 유닛의 연결을 개별적으로 지시할 수 있습니다.

이 그림은 간단한 오디오 처리 그래프를 보여주며, 신호는 위에서 아래로 흐릅니다.

이 그래프에서는 오디오 데이터가 각 유닛을 통해 처리되며, I/O 유닛이 마지막으로 데이터를 수신하고 처리합니다. 각 유닛은 이전 유닛에서 데이터를 요청하여 데이터 흐름을 유지합니다. 이러한 구조는 복잡한 오디오 처리를 위한 유연하고 확장 가능한 방법을 제공합니다.

Figure 2-4   A simple audio processing graph

오디오 처리 그래프의 각 오디오 유닛은 노드라고 할 수 있습니다. 하나의 노드의 출력을 다른 노드의 입력에 연결하여 처리 그래프 연결을 만듭니다. 중간에 스플리터 유닛을 사용하지 않는 한 단일 출력을 둘 이상의 입력에 연결할 수 없습니다. 그림 2-5는 이를 보여줍니다.

Figure 2-5   How to fan out an audio unit connection

그러나 오디오 유닛은 유형에 따라 여러 출력을 제공하거나 입력을 받을 수 있도록 설계될 수 있습니다. 예를 들어, 스플리터 유닛이 이러한 역할을 합니다.

오디오 처리 그래프 서비스를 사용하여 서브그래프를 더 큰 그래프로 결합할 수 있으며, 이 경우 서브그래프는 더 큰 그래프에서 단일 노드로 나타납니다. 그림 2-6은 이를 보여줍니다.

 

Figure 2-6   A subgraph connection

각 그래프 또는 서브그래프는 I/O 유닛으로 끝나야 합니다. 애플리케이션에 출력을 제공하는 서브그래프나 그래프는 하드웨어에 연결되지 않는 제너릭 I/O 유닛으로 끝나야 합니다.

오디오 처리 그래프를 사용하지 않고도 프로그래밍 방식으로 오디오 유닛을 연결할 수 있지만, 이는 거의 좋은 생각이 아닙니다. 그래프는 중요한 이점을 제공합니다. 그래프를 동적으로 수정할 수 있어 데이터를 처리하는 동안 신호 경로를 변경할 수 있습니다. 또한 그래프는 오디오 유닛의 상호 연결을 캡슐화하므로, 그래프를 인스턴스화할 때 참조되는 각 오디오 유닛을 명시적으로 인스턴스화하는 대신 한 번의 단계로 그래프를 인스턴스화할 수 있습니다.

 

MIDI Services in OS X

Core Audio는 MIDI 지원을 위해 Core MIDI Services를 사용합니다. 이러한 서비스는 CoreMIDI.framework의 다음 헤더 파일에 선언된 함수, 데이터 타입 및 상수로 구성됩니다:

MIDIServices.h

MIDISetup.h

MIDIThruConnection.h

MIDIDriver.h

Core MIDI Services는 애플리케이션과 오디오 유닛이 MIDI 장치와 통신할 수 있는 인터페이스를 정의합니다. 이 서비스는 애플리케이션이 MIDI 네트워크와 상호 작용할 수 있도록 여러 추상화를 사용합니다.

MIDI 엔드포인트(불투명 타입 MIDIEndpointRef로 정의됨)는 표준 16채널 MIDI 데이터 스트림의 소스 또는 대상으로 작동합니다. 엔드포인트를 Music Player Services에서 사용되는 트랙과 연결하여 MIDI 데이터를 녹음하거나 재생할 수 있습니다. MIDI 엔드포인트는 표준 MIDI 케이블 연결을 위한 프록시 객체입니다. 그러나 MIDI 엔드포인트는 반드시 물리적 장치에 대응할 필요는 없으며, 애플리케이션이 가상 소스 또는 대상으로 설정되어 MIDI 데이터를 송수신할 수 있습니다.

MIDI 드라이버는 종종 여러 엔드포인트를 논리적 그룹으로 결합하여 MIDI 엔티티(MIDIEntityRef)라고 합니다. 예를 들어, MIDI-in 엔드포인트와 MIDI-out 엔드포인트를 하나의 MIDI 엔티티로 그룹화하여 장치 또는 애플리케이션과의 양방향 통신을 쉽게 참조할 수 있습니다.

각 물리적 MIDI 장치(단일 MIDI 연결이 아님)는 Core MIDI 장치 객체(MIDIDeviceRef)로 나타납니다. 각 장치 객체는 하나 이상의 MIDI 엔티티를 포함할 수 있습니다.

Core MIDI는 애플리케이션과 장치 간에 MIDI 데이터를 전달하는 실제 작업을 수행하는 MIDI Server와 통신합니다. MIDI Server는 애플리케이션과 독립된 자체 프로세스로 실행됩니다. 그림 2-7은 Core MIDI와 MIDI Server 간의 관계를 보여줍니다.

Figure 2-7   Core MIDI and Core MIDI Server

MIDI Server는 애플리케이션에 구애받지 않는 MIDI 통신 기반을 제공할 뿐만 아니라, 호스트 애플리케이션을 거치지 않고도 장치 간 체이닝을 가능하게 하는 MIDI 쓰루(MIDI thru) 연결도 처리합니다.

MIDI 장치 제조업체인 경우, 커널 레벨 I/O Kit 드라이버와 상호 작용하기 위해 CFBundle에 패키지된 CFPlugin 플러그인을 MIDI Server에 제공해야 할 수도 있습니다. 그림 2-8은 Core MIDI와 Core MIDI Server가 기본 하드웨어와 어떻게 상호 작용하는지 보여줍니다.

참고: USB MIDI 클래스 호환 장치를 생성하는 경우, Apple에서 제공하는 USB 드라이버가 하드웨어를 지원하므로 자체 드라이버를 작성할 필요가 없습니다.

 

Figure 2-8   MIDI Server interface with I/O Kit

각 MIDI 장치의 드라이버는 일반적으로 커널 외부에 존재하며, MIDI Server 프로세스에서 실행됩니다. 이러한 드라이버는 기본 프로토콜(예: USB 및 FireWire)을 위한 기본 I/O Kit 드라이버와 상호 작용합니다. MIDI 드라이버는 원시 장치 데이터를 Core MIDI가 사용할 수 있는 형식으로 제공하는 역할을 합니다. 그런 다음 Core MIDI는 지정된 MIDI 엔드포인트를 통해 MIDI 정보를 애플리케이션에 전달합니다. 이 엔드포인트는 외부 장치의 MIDI 포트를 추상적으로 나타낸 것입니다.

그러나 PCI 카드의 MIDI 장치는 사용자 공간 드라이버만으로 완전히 제어할 수 없습니다. PCI 카드의 경우, 사용자 클라이언트를 제공하는 커널 확장을 생성해야 합니다. 이 클라이언트는 PCI 장치를 직접 제어하거나, 요청 시 사용자 공간 드라이버가 PCI 장치의 주소 범위를 MIDI 서버의 주소에 매핑하도록 해야 합니다. 이를 통해 사용자 공간 드라이버가 PCI 장치를 직접 제어할 수 있습니다.

사용자 공간 MIDI 드라이버 구현 예제는 Core Audio SDK의 MIDI/SampleUSBDriver에서 확인할 수 있습니다.

Music Player Services in OS X

Music Player Services를 사용하면 MIDI 음악 트랙 컬렉션을 정렬하고 재생할 수 있습니다.

트랙은 MIDI 또는 이벤트 데이터 스트림(MusicTrack 데이터 타입으로 표현됨)입니다. 트랙은 시간 기반 이벤트 시리즈를 포함하며, 이는 MIDI 데이터, Core Audio 이벤트 데이터 또는 사용자 정의 이벤트 메시지일 수 있습니다. 트랙을 하나의 악기를 위한 악보로 생각할 수 있습니다.

시퀀스는 트랙의 컬렉션(MusicSequence 데이터 타입으로 표현됨)입니다. 시퀀스는 항상 모든 트랙을 동기화하는 데 사용되는 별도의 템포 트랙을 포함합니다. 시퀀스를 여러 악기를 위한 악보를 모은 음악 악보로 생각할 수 있습니다. Mac 애플리케이션은 시퀀스에서 트랙을 동적으로 추가, 삭제 또는 편집할 수 있습니다.

시퀀스를 재생하려면 시퀀스를 음악 플레이어 객체(MusicPlayer 타입)에 할당합니다. 음악 플레이어 객체는 지휘자 역할을 하여 시퀀스의 재생을 제어합니다. 사운드를 생성하려면 각 트랙을 악기 유닛 또는 외부 MIDI 장치로 보냅니다.

트랙 데이터는 반드시 음악 정보를 나타낼 필요는 없습니다. 대신 트랙을 사용하여 오디오 유닛 자동화를 구현할 수 있습니다. 예를 들어, 패너 유닛에 할당된 트랙은 사운드 스테이지에서 사운드 소스의 위치를 제어할 수 있습니다. 트랙은 애플리케이션 정의 콜백을 트리거하는 독점적인 사용자 이벤트도 포함할 수 있습니다.

MIDI 데이터를 재생하는 데 Music Player Services를 사용하는 방법에 대한 자세한 내용은 Handling MIDI Data를 참조하십시오.

Timing Services in OS X

Core Audio Clock Services는 애플리케이션과 장치를 동기화하는 데 사용할 수 있는 기준 시계를 제공합니다. 이 시계는 독립형 타이밍 소스일 수도 있고, MIDI 비트 시계 또는 MIDI 타임 코드와 같은 외부 트리거와 동기화될 수도 있습니다. 시계를 직접 시작하고 중지할 수 있으며, 특정 이벤트에 따라 시계가 활성화되거나 비활성화되도록 설정할 수도 있습니다.

생성된 시계 시간을 초, 비트, SMPTE 시간, 오디오 샘플 시간, 바-비트 시간 등 여러 형식으로 얻을 수 있습니다. 바-비트 시간은 음악의 마디, 박자, 세부 박자 단위로 화면에 쉽게 표시할 수 있는 형식으로 시간을 설명합니다. Core Audio Clock Services는 한 시간 형식을 다른 형식으로 변환하고 바-비트 또는 SMPTE 시간을 표시하는 유틸리티 함수도 포함합니다. 그림 2-9는 다양한 Core Audio Clock 형식 간의 상호 관계를 보여줍니다.

\Figure 2-9   Some Core Audio Clock formats

하드웨어 시간은 호스트 시간(시스템 시계) 또는 외부 오디오 장치에서 얻은 오디오 시간(예: HAL의 AudioDevice 객체로 나타냄)에서 절대 시간 값을 나타냅니다. 현재 호스트 시간을 결정하려면 mach_absolute_time 또는 UpTime을 호출합니다. 오디오 시간은 샘플 번호로 표현되는 오디오 장치의 현재 시간입니다. 샘플 번호의 변화율은 오디오 장치의 샘플링 속도에 따라 달라집니다.

미디어 시간은 오디오 데이터의 일반적인 타이밍 방법을 나타냅니다. 표준 표현은 초 단위로, 배정밀도 부동 소수점 값으로 표현됩니다. 그러나 템포 맵을 사용하여 초를 음악적 바-비트 시간으로 변환하거나 SMPTE 오프셋을 적용하여 초를 SMPTE 초로 변환할 수 있습니다.

미디어 시간이 실제 시간과 일치할 필요는 없습니다. 예를 들어, 10초 길이의 오디오 파일이 재생 속도를 두 배로 높이면 5초 만에 재생됩니다. iOS에서만 제공되는 Services의 노브는 절대(“실제”) 시간과 미디어 기반 시간 간의 상관 관계를 조정할 수 있음을 나타냅니다. 예를 들어, 바-비트 표기법은 음악 라인의 리듬과 어떤 음표를 언제 연주할지를 나타내지만, 연주 시간이 얼마나 걸리는지는 나타내지 않습니다. 이를 결정하려면 초당 비트 수와 같은 재생 속도를 알아야 합니다. 마찬가지로, SMPTE 시간과 실제 시간의 대응은 프레임 속도 및 프레임이 드롭되는지 여부와 같은 요소에 따라 달라집니다.

728x90

'Swift' 카테고리의 다른 글

Swift Closure (일급객체 함수)  (0) 2021.03.25
Swift where syntax  (0) 2020.10.27
Swift High Order Function Summary  (0) 2020.10.06
[DI] Initializer로 Swift 의존성 주입하기  (0) 2020.09.03
ARC - Automatic Reference Counting  (0) 2020.08.24

댓글