電子ガジェットいろいろ

電子系のガジェットやアプリ開発等の話題を書いてます

CoreAudioの使い方メモ

メモ用に最小の手順で書いています。
ここで書いた内容をクラス化すると使いやすいです。

"View-based Application"で"AUTest"としてプロジェクトを作成しAUTestViewControllerクラスへ直接コードを書いていく例です。
実行すると440Hz(ラ)の音が鳴るだけです。

AudioToolkitフレームワークの追加

プロジェクトへ

AUTestViewController.h

AudioUnitの機能を使うために、"AudioUnit/AudioUnit.h"をインポートします。
クラス内で使う変数と、コールバック用のメソッドの宣言をします。
また、コールバック用のメソッド内で使う変数を@propertyで宣言します。

#import <UIKit/UIKit.h>

#import <AudioUnit/AudioUnit.h>    // 追加

@interface AUTestViewController : UIViewController {
    AudioUnit au;           // AudioUnit
    double    phase;        // 位相の保存
    Float64   SampleRate;   // サンプリングレート
    UInt32    BitRate;      // ビットレート
    Float64   frequency;    // 再生する音程の周波数
}

@property (nonatomic) double phase;
@property (nonatomic) Float64 SampleRate;
@property (nonatomic) Float64 frequency;

static OSStatus renderer(void *inRef,
                         AudioUnitRenderActionFlags *ioActionFlags,
                         const AudioTimeStamp* inTimeStamp,
                         UInt32 inBusNumber,
                         UInt32 inNumberFrames,
                         AudioBufferList *ioData);
@end

AUTestViewController.m

コールバック用のメソッド内で使う変数を@synthesizeで宣言します。

@synthesize phase;
@synthesize SampleRate;
@synthesize frequency;

メモとして、viewDidLoadメソッドの中へ準備から再生開始までを一気に書いた例です。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // サンプリングレートの設定
    SampleRate = 44100.0f;  // 44.1KHz
    
    // ビットレートの設定
    BitRate = 8;  // 8bit
    
    // 再生する音程の周波数
    frequency = 440.0;  // A(ラ)
    
    // AudioComponentのAudioComponentDescriptionを用意する
    AudioComponentDescription acd;
    acd.componentType = kAudioUnitType_Output;
    acd.componentSubType = kAudioUnitSubType_RemoteIO;
    acd.componentManufacturer = kAudioUnitManufacturer_Apple;
    acd.componentFlags = 0;
    acd.componentFlagsMask = 0;
    
    // AudioComponentの定義を取得
    AudioComponent ac = AudioComponentFindNext(NULL, &acd);
    
    // AudioComponentをインスタンス化
    AudioComponentInstanceNew(ac, &au);
    
    // AudioComponentを初期化
    AudioUnitInitialize(au);
    
    // コールバックの設定
    AURenderCallbackStruct CallbackStruct;
    CallbackStruct.inputProc = renderer;     // ここでコールバック時に実行するメソッドを指定
    CallbackStruct.inputProcRefCon = (__bridge void*)self;
    
    // コールバックの設定をAudioUnitへ設定
    AudioUnitSetProperty(au, 
                         kAudioUnitProperty_SetRenderCallback,
                         kAudioUnitScope_Input,
                         0,
                         &CallbackStruct,
                         sizeof(AURenderCallbackStruct));
    
    // AudioStreamBasicDescription(ASBD)の設定
    AudioStreamBasicDescription asbd;
    asbd.mSampleRate = SampleRate;
    asbd.mFormatID = kAudioFormatLinearPCM;
    asbd.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
    asbd.mChannelsPerFrame = 2;
    asbd.mBytesPerPacket = sizeof(AudioUnitSampleType);
    asbd.mBytesPerFrame = sizeof(AudioUnitSampleType);
    asbd.mFramesPerPacket = 1;
    asbd.mBitsPerChannel = BitRate * sizeof(AudioUnitSampleType);
    asbd.mReserved = 0;
    
    // AudioUnitにASBDを設定
    AudioUnitSetProperty(au,
                         kAudioUnitProperty_StreamFormat,
                         kAudioUnitScope_Input,
                         0,
                         &asbd,
                         sizeof(asbd));
    
    // 再生開始
    AudioOutputUnitStart(au);
    
}

コールバックで実行されるメソッドです。
サイン波を出力する処理を行っています。

static OSStatus renderer(void *inRef,
                         AudioUnitRenderActionFlags *ioActionFlags,
                         const AudioTimeStamp* inTimeStamp,
                         UInt32 inBusNumber,
                         UInt32 inNumberFrames,
                         AudioBufferList *ioData) {

    // RenderOutputのインスタンスにキャストする
    AUTestViewController* def = (__bridge AUTestViewController*)inRef;

    // サイン波の計算に使う数値の用意
    float freq = def.frequency * 2.0 * M_PI / def.SampleRate;
    
    // 値を書き込むポインタ
    AudioUnitSampleType *outL = ioData->mBuffers[0].mData;
    AudioUnitSampleType *outR = ioData->mBuffers[1].mData;
    
    for (int i = 0; i < inNumberFrames; i++) {
        // 周波数を計算
        float wave = sin(def.phase);
        AudioUnitSampleType sample = wave * (1 << kAudioUnitSampleFractionBits);
        *outL++ = sample;
        *outR++ = sample;
        def.phase += freq;
    }
        
    return noErr;
    
};

最後にメモリを使用した開放します。
viewDidUnloadに書いた例です

- (void)viewDidUnload
{
    // 再生停止
    AudioOutputUnitStop(au);
    
    // AudioUnitの解放
    AudioUnitUninitialize(au);
    AudioComponentInstanceDispose(au);
    
    [super viewDidUnload];
}

iPhone Core Audioプログラミング

iPhone Core Audioプログラミング