そこで、ここのいくつかの投稿に基づいて、オーディオを録音するためのいくつかのルーチンをまとめました。私が参照した投稿はhereおよびhereであり、それらが参照するサイトを読んでいます。
私のセットアップ: 既存の AUGraph があります: (いくつかの AUSamplers -> Mixer -> RemoteIO)。AUSampler は MusicPlayer インスタンスのトラックに接続されています。それはすべてうまくいきますが、録音を追加したいと思います。
録音は機能していますが、結果の .caf のピッチ/テンポが遅くなり、音質が悪くなります。指定している形式に何か問題があるのでしょうか?
誰かがこれを見て、フォーマットを間違って設定している場所を教えてもらえますか?
編集:これはステレオ/モノラルの問題でしょうか? モノラルで録音するという意味です。
RemoteIO インスタンスのストリーム形式を次のように設定します。
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = 44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;
// Apply format
result = AudioUnitSetProperty(ioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
kInputBus,
&audioFormat,
sizeof(audioFormat));
次に、ボタン アクションから fileRef を作成し、renderCallback を RemoteIO インスタンスにアタッチします。
- (void)startRecording
{
OSStatus result;
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = 44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *destinationFilePath = [[NSString alloc] initWithFormat: @"%@/output.caf", documentsDirectory];
CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
(__bridge CFStringRef)destinationFilePath,
kCFURLPOSIXPathStyle,
false);
result = ExtAudioFileCreateWithURL(destinationURL,
kAudioFileWAVEType,
&audioFormat,
NULL,
kAudioFileFlags_EraseFile,
&extAudioFileRef);
CFRelease(destinationURL);
NSAssert(result == noErr, @"Couldn't create file for writing");
result = ExtAudioFileSetProperty(extAudioFileRef,
kExtAudioFileProperty_ClientDataFormat,
sizeof(AudioStreamBasicDescription),
&audioFormat);
NSAssert(result == noErr, @"Couldn't create file for format");
result = ExtAudioFileWriteAsync(extAudioFileRef, 0, NULL);
NSAssert(result == noErr, @"Couldn't initialize write buffers for audio file");
printf("Adding render to remoteIO \n");
result = AudioUnitAddRenderNotify(ioUnit, renderCallback, (__bridge void*)self);
if (result) {[self printErrorMessage: @"AudioUnitAddRenderNotify" withStatus: result]; return;}
}
最後に、rendercallback で、postRender フェーズでデータを書き出します。
static OSStatus renderCallback (void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
OSStatus result;
if (*ioActionFlags == kAudioUnitRenderAction_PostRender){
double timeInSeconds = inTimeStamp->mSampleTime / kSampleRate;
printf("%fs inBusNumber: %lu inNumberFrames: %lu \n", timeInSeconds, inBusNumber, inNumberFrames);
MusicPlayerController* THIS = (__bridge MusicPlayerController *)inRefCon;
result = ExtAudioFileWriteAsync(THIS->extAudioFileRef, inNumberFrames, ioData);
if(result) printf("ExtAudioFileWriteAsync %ld \n", result);
}
return noErr;
}