我需要能够将来自多个文件的音频组合成单个缓冲区(立体声)。如果我将每个文件加载到自己的缓冲区中,我的代码将按预期工作。循环遍历多个文件并丢失到一个较大的缓冲区只会播放上一个文件中的段。
每次都可能会复制标头信息,或者每个新文件都覆盖了缓冲区的相同区域。
任何建议都将不胜感激。
下面列出了一些代码。我正在读取加密文件,因此我使用的是NSData和AudioFileOpenWithCallbacks。
// Assign the frame count to the soundStructArray instance variable
UInt64 totalFrames = [[inputNotes.stopTimes lastObject] intValue];
self.soundStructArray[0]->frameCount = (UInt32)totalFrames;
self.soundStructArray[0]->audioDataLeft =
(AudioUnitSampleType *) calloc (totalFrames, sizeof (AudioUnitSampleType));
AudioStreamBasicDescription importFormat = {0};
// if (2 == channelCount) {
self.soundStructArray[0]->isStereo = YES;
self.soundStructArray[0]->audioDataRight =
(AudioUnitSampleType *) calloc (totalFrames, sizeof (AudioUnitSampleType));
// Allocate memory for the buffer list struct according to the number of
// channels it represents.
AudioBufferList *bufferList;
UInt32 channelCount = 2;
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (channelCount - 1)
);
if (NULL == bufferList) {DLog (@"*** malloc failure for allocating bufferList memory"); return;}
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = channelCount;
// initialize the mBuffers member to 0
AudioBuffer emptyBuffer = {0};
size_t arrayIndex;
for (arrayIndex = 0; arrayIndex < channelCount; arrayIndex++) {
bufferList->mBuffers[arrayIndex] = emptyBuffer;
}
// set up the AudioBuffer structs in the buffer list
bufferList->mBuffers[0].mNumberChannels = 1;
bufferList->mBuffers[0].mDataByteSize = (UInt32)totalFrames * sizeof (AudioUnitSampleType);
bufferList->mBuffers[0].mData = self.soundStructArray[0]->audioDataLeft;
if (2 == channelCount) {
bufferList->mBuffers[1].mNumberChannels = 1;
bufferList->mBuffers[1].mDataByteSize = (UInt32)totalFrames * sizeof (AudioUnitSampleType);
bufferList->mBuffers[1].mData = self.soundStructArray[0]->audioDataRight;
}
NSString *fileType = @"m4a";
for (int audioFile = 0; audioFile < inputVoicesCount; ++audioFile) {
@autoreleasepool {
NSData *encData;
NSData *audioData;
AudioFileID refAudioFileID;
DLog (@"readAudioFilesIntoMemory - file %i", audioFile);
NSString *source = [[NSBundle mainBundle] pathForResource:[inputNotes.notes objectAtIndex:audioFile] ofType:fileType];
// NSURL *url = [NSURL encryptedFileURLWithPath:source];
if ([[NSFileManager defaultManager] fileExistsAtPath:source])
{
//File exists
encData = [[NSData alloc] initWithContentsOfFile:source];
if (encData)
{
NSError *error;
audioData = [RNDecryptor decryptData:encData
withPassword:key
error:&error];
}
}
else
{
DLog(@"File does not exist");
}
OSStatus result = AudioFileOpenWithCallbacks((__bridge void *)(audioData), readProc, 0, getSizeProc, NULL, kAudioFileMPEG4Type, &refAudioFileID);
if(result != noErr){
DLog(@"problem in theAudioFileReaderWithData function: result code %i \n", result);
}
// Instantiate an extended audio file object.
ExtAudioFileRef audioFileObject = 0;
result = ExtAudioFileWrapAudioFileID(refAudioFileID, NO, &audioFileObject);
if (result != noErr){
DLog(@"problem in theAudioFileReaderWithData function Wraping the audio FileID: result code %i \n", result);
}
// Get the audio file's number of channels.
AudioStreamBasicDescription fileAudioFormat = {0};
UInt32 formatPropertySize = sizeof (fileAudioFormat);
result = ExtAudioFileGetProperty (
audioFileObject,
kExtAudioFileProperty_FileDataFormat,
&formatPropertySize,
&fileAudioFormat
);
if (noErr != result) {[self printErrorMessage: @"ExtAudioFileGetProperty (file audio format)" withStatus: result]; return;}
importFormat = stereoStreamFormat;
result = ExtAudioFileSetProperty (
audioFileObject,
kExtAudioFileProperty_ClientDataFormat,
sizeof (importFormat),
&importFormat
);
if (noErr != result) {[self printErrorMessage: @"ExtAudioFileSetProperty (client data format)" withStatus: result]; return;}
// Assign the frame count to the soundStructArray instance variable
UInt64 desiredFrames = (UInt64) ([[inputNotes.stopTimes objectAtIndex:audioFile] intValue] - [[inputNotes.startTimes objectAtIndex:audioFile] intValue]);
// Perform a synchronous, sequential read of the audio data out of the file and
// into the soundStructArray[audioFile].audioDataLeft and (if stereo) .audioDataRight members.
UInt32 numberOfPacketsToRead = (UInt32) desiredFrames;
result = ExtAudioFileRead (
audioFileObject,
&numberOfPacketsToRead,
bufferList
);
if (noErr != result) {
[self printErrorMessage: @"ExtAudioFileRead failure - " withStatus: result];
// If reading from the file failed, then free the memory for the sound buffer.
// free (soundStructArray[audioFile].audioDataLeft);
// soundStructArray[audioFile].audioDataLeft = 0;
free (self.soundStructArray[0]->audioDataLeft);
self.soundStructArray[0]->audioDataLeft = 0;
free (self.soundStructArray[0]->audioDataRight);
self.soundStructArray[0]->audioDataRight = 0;
ExtAudioFileDispose (audioFileObject);
return;
}
ExtAudioFileDispose (audioFileObject);
AudioFileClose(refAudioFileID);
}
}//end of @autoreleasepool
free (bufferList);
// Set the sample index to zero, so that playback starts at the
// beginning of the sound.
self.soundStructArray[0]->sampleNumber = 0;
DLog (@"Finished reading all files into memory");
readingFiles = NO;
}