2013年2月11日月曜日

Audio Unitを使おう(iOS)

まだまだ勉強がたりないです。さて, Audio Unitです。

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

Mac OS X と, iOS ではプログラムの書き方が違います。
Mac OS Xでは, こちら のサンプルが完璧です。

これを参考にさせていただきながら, iOSとどのように違うのか, やってみました。

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

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

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

iOSでは,

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];
// Do any additional setup after loading the view.
}

- (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





0 件のコメント:

コメントを投稿