我想將2個CAF文件本地轉換爲一個文件。這兩個CAF文件是單聲道流,理想情況下,我希望它們是一個立體聲文件,這樣我就可以從一個聲道獲得麥克風,從另一個聲道獲得揚聲器。如何在iOS中將2個單聲道文件轉換爲單個立體聲文件?
我最初是通過使用AVAssetTrack和AVMutableCompositionTracks開始的,但是我無法解決混音問題。我的合併文件是一個單一的單一流,交錯兩個文件。所以我選擇了AVAudioEngine路線。
從我的理解,我可以通過我的兩個文件作爲輸入節點,將它們連接到混音器,並有一個能夠獲得立體聲混音的輸出節點。輸出文件具有立體聲佈局,但沒有音頻數據似乎寫入它,因爲我可以在Audacity中打開它並查看立體聲佈局。在installTapOnBus調用周圍放置dipatch sephamore信號也沒有多大幫助。 CoreAudio一直是一個難以理解的挑戰,因此我們將不勝感激。
// obtain path of microphone and speaker files
NSString *micPath = [[NSBundle mainBundle] pathForResource:@"microphone" ofType:@"caf"];
NSString *spkPath = [[NSBundle mainBundle] pathForResource:@"speaker" ofType:@"caf"];
NSURL *micURL = [NSURL fileURLWithPath:micPath];
NSURL *spkURL = [NSURL fileURLWithPath:spkPath];
// create engine
AVAudioEngine *engine = [[AVAudioEngine alloc] init];
AVAudioFormat *stereoFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:16000 channels:2];
AVAudioMixerNode *mainMixer = engine.mainMixerNode;
// create audio files
AVAudioFile *audioFile1 = [[AVAudioFile alloc] initForReading:micURL error:nil];
AVAudioFile *audioFile2 = [[AVAudioFile alloc] initForReading:spkURL error:nil];
// create player input nodes
AVAudioPlayerNode *apNode1 = [[AVAudioPlayerNode alloc] init];
AVAudioPlayerNode *apNode2 = [[AVAudioPlayerNode alloc] init];
// attach nodes to the engine
[engine attachNode:apNode1];
[engine attachNode:apNode2];
// connect player nodes to engine's main mixer
stereoFormat = [mainMixer outputFormatForBus:0];
[engine connect:apNode1 to:mainMixer fromBus:0 toBus:0 format:audioFile1.processingFormat];
[engine connect:apNode2 to:mainMixer fromBus:0 toBus:1 format:audioFile2.processingFormat];
[engine connect:mainMixer to:engine.outputNode format:stereoFormat];
// start the engine
NSError *error = nil;
if(![engine startAndReturnError:&error]){
NSLog(@"Engine failed to start.");
}
// create output file
NSString *mergedAudioFile = [[micPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"merged.caf"];
[[NSFileManager defaultManager] removeItemAtPath:mergedAudioFile error:&error];
NSURL *mergedURL = [NSURL fileURLWithPath:mergedAudioFile];
AVAudioFile *outputFile = [[AVAudioFile alloc] initForWriting:mergedURL settings:[engine.inputNode inputFormatForBus:0].settings error:&error];
// write from buffer to output file
[mainMixer installTapOnBus:0 bufferSize:4096 format:[mainMixer outputFormatForBus:0] block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when){
NSError *error;
BOOL success;
NSLog(@"Writing");
if((outputFile.length < audioFile1.length) || (outputFile.length < audioFile2.length)){
success = [outputFile writeFromBuffer:buffer error:&error];
NSCAssert(success, @"error writing buffer data to file, %@", [error localizedDescription]);
if(error){
NSLog(@"Error: %@", error);
}
}
else{
[mainMixer removeTapOnBus:0];
NSLog(@"Done writing");
}
}];
}
你持有的強引用你寫的AVAudioFile? – dave234
@ Dave,outputFile在寫入之前不存在。在強引用方面,我將audioFile設置爲寫入mergedURL,這是mergedAudioFile的fileURLWithPath。沒有其他對象/變量引用outputFile,並且在installTapOnBus調用之後我沒有銷燬它。 – A21
這種方法的一個弱點是,你將不得不等待文件的持續時間被渲染爲一個。這就是說,如果你堅持使用AVAudioEngine,你可能會試着讓這兩個文件先玩。然後,一旦該步驟完成,安裝輕擊並寫入文件。但如果我自己做,我會使用C API。 – dave234