So, I have compiled several routines for recording sound based on some posts here. The posts I referred to here and here , along with reading the sites to which they link.
My setup: I have an existing AUGraph: (multiple AUSamplers -> Mixer -> RemoteIO). AUSamplers are connected to the tracks in the MusicPlayer instance. Everything works fine, but I want to add an entry to it.
Recording works, but the result .caf - step / pace shifted slower +, has poor sound quality. There must be something wrong with the format I specify?
Can someone take a look at this and tell me where I formatted the format incorrectly?
EDIT: Could there be a stereo / mono issue? I want to record in mono.
I set the stream format for the RemoteIO instance:
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;
Then, from the button action, I create a Ref file and attach renderCallback to the RemoteIO instance:
- (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;} }
Finally, in my rendercallback, I write out the data in the postRender phase:
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; }