Audio Unitを使おう

プロフェッショナルプログラマーよりの転載です。

Audio Unit というのは, Core Audio のオーディオ処理の機能を持つ1つの単位のこと。Input, Effect, Output などが Audio Unit になります。 詳しい説明は, 各所ありますのでこれくらいです。

Mac OS X と, iOS ではプログラムの書き方が違います。
Mac OS Xでは, My Codex Leister さんの第03回.Audio Unitを使って音を鳴らす(前準備) のサンプルが完璧です。

My Codex Leister さんでも言及のとおり, iOSでは, kAudioUnitType_Generatorつまり, 入力を発生させるような Audio Unit がないような気がします。

Output, Effect あたりはできそうな気がします。
コンポーネントの違い

Mac OS X AudioUnit.framework ComponentDescription
iOS AudioToolbox.framework AudioComponentDescripton

iOSでは, AudioComponentDescription

struct AudioComponentDescription
{
    OSType  componentType;
    OSType  componentSubStype;
    OSType  componentManufacturer;
    UInt32  componentFlags;
    UInt32  componentFlagsMask;
};
typedef struct AudioComponentDescription AudioComponentDescription;

を使って, AudioComponent を取り出します。
その違い以外は, ほぼ Mac OS Xと同じコードです。

iOS で, Audio Unit で sin波を発生させて聞いてみるサンプルです。

サンプル

AudioUnitViewController.h

#import "ViewController.h"
#import <AudioToolbox/AudioToolbox.h>

#define kRate 44100
#define kFreq 440

@interface AudioUnitViewController : ViewController

@property (nonatomic)AudioUnit unit;
@property (nonatomic)float phase;

- (IBAction)startClick:(id)sender;
- (IBAction)stopClick:(id)sender;
@end

AudioUnitViewController.m


#import “AudioUnitViewController.h”

@interface AudioUnitViewController ()

@end

@implementation AudioUnitViewController

@synthesize unit;

– (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}

– (void)viewDidLoad
{
[super viewDidLoad];
}

– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

OSStatus AuRenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
//NSLog(@”inNumberFrames: %ld”, inNumberFrames);
//NSLog(@”Bufs %ld”, ioData->mNumberBuffers);

AudioUnitViewController *controller = (__bridge AudioUnitViewController *)inRefCon;

float *buf = ioData->mBuffers[0].mData;
float freq = kFreq * 2 * M_PI / kRate;

for ( int i=0; i < inNumberFrames; i++ ) { float wave = sin(controller.phase); *buf++ = wave; controller.phase += freq; } return noErr; } -(void)audioUnit { OSStatus status; AudioComponentDescription cd; cd.componentType = kAudioUnitType_Output; cd.componentSubType = kAudioUnitSubType_RemoteIO; cd.componentManufacturer = kAudioUnitManufacturer_Apple; cd.componentFlags = 0; cd.componentFlagsMask = 0; // Find compoent and create instance AudioComponent comp = AudioComponentFindNext(NULL, &cd); status = AudioComponentInstanceNew(comp, &unit); // Set Callback AURenderCallbackStruct input; input.inputProc = AuRenderCallback; input.inputProcRefCon = (__bridge void *)(self); status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(input)); status = AudioUnitInitialize(unit); status = AudioOutputUnitStart(unit); self.phase = 0; } -(void)stop { AudioOutputUnitStop(unit); } - (IBAction)startClick:(id)sender { [self audioUnit]; } - (IBAction)stopClick:(id)sender { [self stop]; } @end [/cpp] UIはボタンを入れたのみ。ボタンを押すと, Output用のAudioUnitを作成して, スタートします。 Callbackでは, 生成したsin波を入れて再生させます。