ios多音频混合

ios多音频混合

from:  http://blog.csdn.net/zengconggen/article/details/7842076

ios上音频文件合成有多种方法,一是使用AVAssetExportSession结合AVMutableComposition,二是使用AVAssetReader和AVAssetWriter. 三是转换成pcm数据后处理pcm数据合成。

方法一和方法二在处理速度上相对来说要慢。一般3分半左右音频需要30s左右,特别是合成不同采样率的音频,速度比较慢。下文提供本人自己写的一个类,采用第三种方法合成音频,采用该算法合成的音频,比网络上一般代码提供的音频在合成效果上好。并且处理速度快,ipod touch4上处理4分半音频仅需6s左右。

  1. //  
  2. //  ExtAudioFileMixer.h  
  3. //  AudioManager  
  4. //  
  5. //  Created by zeng songgen on 12-8-7.  
  6. //  Copyright (c) 2012年 Rumtel. All rights reserved.  
  7. //  
  8.   
  9. #import <Foundation/Foundation.h>  
  10.   
  11. @interface ExtAudioFileMixer : NSObject  
  12.   
  13. + (OSStatus)mixAudio:(NSString *)audioPath1  
  14.             andAudio:(NSString *)audioPath2  
  15.               toFile:(NSString *)outputPath  
  16.   preferedSampleRate:(float)sampleRate;  
  17.   
  18. @end  

  1. //  
  2. //  ExtAudioFileMixer.m  
  3. //  AudioManager  
  4. //  
  5. //  Created by zeng songgen on 12-8-7.  
  6. //  Copyright (c) 2012年 Rumtel. All rights reserved.  
  7. //  
  8.   
  9. #import "ExtAudioFileMixer.h"  
  10. #import <AudioToolbox/AudioToolbox.h>  
  11.   
  12. @implementation ExtAudioFileMixer  
  13.   
  14.   
  15.   
  16. + (OSStatus)mixAudio:(NSString *)audioPath1  
  17.             andAudio:(NSString *)audioPath2  
  18.               toFile:(NSString *)outputPath  
  19.   preferedSampleRate:(float)sampleRate  
  20. {  
  21.     OSStatus                            err = noErr;  
  22.     AudioStreamBasicDescription         inputFileFormat1;  
  23.     AudioStreamBasicDescription         inputFileFormat2;  
  24.     AudioStreamBasicDescription         converterFormat;  
  25.     UInt32                              thePropertySize = sizeof(inputFileFormat1);  
  26.     ExtAudioFileRef                     inputAudioFileRef1 = NULL;  
  27.     ExtAudioFileRef                     inputAudioFileRef2 = NULL;  
  28.     ExtAudioFileRef                     outputAudioFileRef = NULL;  
  29.     AudioStreamBasicDescription         outputFileFormat;  
  30.       
  31.     NSURL *inURL1 = [NSURL fileURLWithPath:audioPath1];  
  32.     NSURL *inURL2 = [NSURL fileURLWithPath:audioPath2];  
  33.     NSURL *outURL = [NSURL fileURLWithPath:outputPath];  
  34.       
  35.     // Open input audio file  
  36.       
  37.     err = ExtAudioFileOpenURL((CFURLRef)inURL1, &inputAudioFileRef1);  
  38.     if (err)  
  39.     {  
  40.         goto reterr;  
  41.     }  
  42.     assert(inputAudioFileRef1);  
  43.       
  44.     err = ExtAudioFileOpenURL((CFURLRef)inURL2, &inputAudioFileRef2);  
  45.     if (err)  
  46.     {  
  47.         goto reterr;  
  48.     }  
  49.     assert(inputAudioFileRef2);  
  50.       
  51.     // Get input audio format  
  52.       
  53.     bzero(&inputFileFormat1, sizeof(inputFileFormat1));  
  54.     err = ExtAudioFileGetProperty(inputAudioFileRef1, kExtAudioFileProperty_FileDataFormat,  
  55.                                   &thePropertySize, &inputFileFormat1);  
  56.     if (err)  
  57.     {  
  58.         goto reterr;  
  59.     }  
  60.       
  61.     // only mono or stereo audio files are supported  
  62.       
  63.     if (inputFileFormat1.mChannelsPerFrame > 2)  
  64.     {  
  65.         err = kExtAudioFileError_InvalidDataFormat;  
  66.         goto reterr;  
  67.     }  
  68.       
  69.     bzero(&inputFileFormat2, sizeof(inputFileFormat2));  
  70.     err = ExtAudioFileGetProperty(inputAudioFileRef2, kExtAudioFileProperty_FileDataFormat,  
  71.                                   &thePropertySize, &inputFileFormat2);  
  72.     if (err)  
  73.     {  
  74.         goto reterr;  
  75.     }  
  76.       
  77.     // only mono or stereo audio files are supported  
  78.       
  79.     if (inputFileFormat2.mChannelsPerFrame > 2)  
  80.     {  
  81.         err = kExtAudioFileError_InvalidDataFormat;  
  82.         goto reterr;  
  83.     }  
  84.       
  85.     int numChannels = MAX(inputFileFormat1.mChannelsPerFrame, inputFileFormat2.mChannelsPerFrame);  
  86.       
  87.     // Enable an audio converter on the input audio data by setting  
  88.     // the kExtAudioFileProperty_ClientDataFormat property. Each  
  89.     // read from the input file returns data in linear pcm format.  
  90.       
  91.     AudioFileTypeID audioFileTypeID = kAudioFileCAFType;  
  92.       
  93.     Float64 mSampleRate = sampleRate? sampleRate : MAX(inputFileFormat1.mSampleRate, inputFileFormat2.mSampleRate);  
  94.       
  95.     [self _setDefaultAudioFormatFlags:&converterFormat sampleRate:mSampleRate numChannels:inputFileFormat1.mChannelsPerFrame];  
  96.       
  97.     err = ExtAudioFileSetProperty(inputAudioFileRef1, kExtAudioFileProperty_ClientDataFormat,  
  98.                                   sizeof(converterFormat), &converterFormat);  
  99.     if (err)  
  100.     {  
  101.         goto reterr;  
  102.     }  
  103.     [self _setDefaultAudioFormatFlags:&converterFormat sampleRate:mSampleRate numChannels:inputFileFormat2.mChannelsPerFrame];  
  104.     err = ExtAudioFileSetProperty(inputAudioFileRef2, kExtAudioFileProperty_ClientDataFormat,  
  105.                                   sizeof(converterFormat), &converterFormat);  
  106.     if (err)  
  107.     {  
  108.         goto reterr;  
  109.     }  
  110.     // Handle the case of reading from a mono input file and writing to a stereo  
  111.     // output file by setting up a channel map. The mono output is duplicated  
  112.     // in the left and right channel.  
  113.       
  114.     if (inputFileFormat1.mChannelsPerFrame == 1 && numChannels == 2) {  
  115.         SInt32 channelMap[2] = { 0, 0 };  
  116.           
  117.         // Get the underlying AudioConverterRef  
  118.           
  119.         AudioConverterRef convRef = NULL;  
  120.         UInt32 size = sizeof(AudioConverterRef);  
  121.           
  122.         err = ExtAudioFileGetProperty(inputAudioFileRef1, kExtAudioFileProperty_AudioConverter, &size, &convRef);  
  123.           
  124.         if (err)  
  125.         {  
  126.             goto reterr;  
  127.         }  
  128.           
  129.         assert(convRef);  
  130.           
  131.         err = AudioConverterSetProperty(convRef, kAudioConverterChannelMap, sizeof(channelMap), channelMap);  
  132.           
  133.         if (err)  
  134.         {  
  135.             goto reterr;  
  136.         }  
  137.     }  
  138.     if (inputFileFormat2.mChannelsPerFrame == 1 && numChannels == 2) {  
  139.         SInt32 channelMap[2] = { 0, 0 };  
  140.           
  141.         // Get the underlying AudioConverterRef  
  142.           
  143.         AudioConverterRef convRef = NULL;  
  144.         UInt32 size = sizeof(AudioConverterRef);  
  145.           
  146.         err = ExtAudioFileGetProperty(inputAudioFileRef2, kExtAudioFileProperty_AudioConverter, &size, &convRef);  
  147.           
  148.         if (err)  
  149.         {  
  150.             goto reterr;  
  151.         }  
  152.           
  153.         assert(convRef);  
  154.           
  155.         err = AudioConverterSetProperty(convRef, kAudioConverterChannelMap, sizeof(channelMap), channelMap);  
  156.           
  157.         if (err)  
  158.         {  
  159.             goto reterr;  
  160.         }  
  161.     }  
  162.     // Output file is typically a caff file, but the user could emit some other  
  163.     // common file types. If a file exists already, it is deleted before writing  
  164.     // the new audio file.  
  165.       
  166.     [self _setDefaultAudioFormatFlags:&outputFileFormat sampleRate:mSampleRate numChannels:numChannels];  
  167.       
  168.     UInt32 flags = kAudioFileFlags_EraseFile;  
  169.       
  170.     err = ExtAudioFileCreateWithURL((CFURLRef)outURL, audioFileTypeID, &outputFileFormat,  
  171.                                     NULL, flags, &outputAudioFileRef);  
  172.     if (err)  
  173.     {  
  174.         // -48 means the file exists already  
  175.         goto reterr;  
  176.     }  
  177.     assert(outputAudioFileRef);  
  178.       
  179.     // Enable converter when writing to the output file by setting the client  
  180.     // data format to the pcm converter we created earlier.  
  181.       
  182.     err = ExtAudioFileSetProperty(outputAudioFileRef, kExtAudioFileProperty_ClientDataFormat,  
  183.                                   sizeof(outputFileFormat), &outputFileFormat);  
  184.     if (err)  
  185.     {  
  186.         goto reterr;  
  187.     }  
  188.       
  189.     // Buffer to read from source file and write to dest file  
  190.       
  191.     UInt16 bufferSize = 8192;  
  192.       
  193.     AudioSampleType * buffer1 = malloc(bufferSize);  
  194.     AudioSampleType * buffer2 = malloc(bufferSize);  
  195.     AudioSampleType * outBuffer = malloc(bufferSize);  
  196.       
  197.     AudioBufferList conversionBuffer1;  
  198.     conversionBuffer1.mNumberBuffers = 1;  
  199.     conversionBuffer1.mBuffers[0].mNumberChannels = inputFileFormat1.mChannelsPerFrame;  
  200.     conversionBuffer1.mBuffers[0].mDataByteSize = bufferSize;  
  201.     conversionBuffer1.mBuffers[0].mData = buffer1;  
  202.   
  203.     AudioBufferList conversionBuffer2;  
  204.     conversionBuffer2.mNumberBuffers = 1;  
  205.     conversionBuffer2.mBuffers[0].mNumberChannels = inputFileFormat2.mChannelsPerFrame;  
  206.     conversionBuffer2.mBuffers[0].mDataByteSize = bufferSize;  
  207.     conversionBuffer2.mBuffers[0].mData = buffer2;  
  208.       
  209.     //  
  210.     AudioBufferList outBufferList;  
  211.     outBufferList.mNumberBuffers = 1;  
  212.     outBufferList.mBuffers[0].mNumberChannels = outputFileFormat.mChannelsPerFrame;  
  213.     outBufferList.mBuffers[0].mDataByteSize = bufferSize;  
  214.     outBufferList.mBuffers[0].mData = outBuffer;  
  215.       
  216.     UInt32 numFramesToReadPerTime = INT_MAX;  
  217.     UInt8 bitOffset = 8 * sizeof(AudioSampleType);  
  218.     UInt64 bitMax = (UInt64) (pow(2, bitOffset));  
  219.     UInt64 bitMid = bitMax/2;  
  220.       
  221.       
  222.     while (TRUE) {  
  223.         conversionBuffer1.mBuffers[0].mDataByteSize = bufferSize;  
  224.         conversionBuffer2.mBuffers[0].mDataByteSize = bufferSize;  
  225.         outBufferList.mBuffers[0].mDataByteSize = bufferSize;  
  226.           
  227.         UInt32 frameCount1 = numFramesToReadPerTime;  
  228.         UInt32 frameCount2 = numFramesToReadPerTime;  
  229.           
  230.         if (inputFileFormat1.mBytesPerFrame)  
  231.         {  
  232.             frameCount1 = bufferSize/inputFileFormat1.mBytesPerFrame;  
  233.         }  
  234.         if (inputFileFormat2.mBytesPerFrame)  
  235.         {  
  236.             frameCount2 = bufferSize/inputFileFormat2.mBytesPerFrame;  
  237.         }  
  238.         // Read a chunk of input  
  239.           
  240.         err = ExtAudioFileRead(inputAudioFileRef1, &frameCount1, &conversionBuffer1);  
  241.           
  242.         if (err) {  
  243.             goto reterr;  
  244.         }  
  245.           
  246.         err = ExtAudioFileRead(inputAudioFileRef2, &frameCount2, &conversionBuffer2);  
  247.           
  248.         if (err) {  
  249.             goto reterr;  
  250.         }  
  251.         // If no frames were returned, conversion is finished  
  252.           
  253.         if (frameCount1 == 0 && frameCount2 == 0)  
  254.             break;  
  255.           
  256.         UInt32 frameCount = MAX(frameCount1, frameCount2);  
  257.         UInt32 minFrames = MIN(frameCount1, frameCount2);  
  258.           
  259.         outBufferList.mBuffers[0].mDataByteSize = frameCount * outputFileFormat.mBytesPerFrame;  
  260.           
  261.         UInt32 length = frameCount * 2;  
  262.         for (int j =0; j < length; j++)  
  263.         {  
  264.             if (j/2 < minFrames)  
  265.             {  
  266.                 SInt32 sValue =0;  
  267.                   
  268.                 SInt16 value1 = (SInt16)*(buffer1+j);   //-32768 ~ 32767  
  269.                 SInt16 value2 = (SInt16)*(buffer2+j);   //-32768 ~ 32767  
  270.                   
  271.                 SInt8 sign1 = (value1 == 0)? 0 : abs(value1)/value1;  
  272.                 SInt8 sign2 = (value2== 0)? 0 : abs(value2)/value2;  
  273.                   
  274.                 if (sign1 == sign2)  
  275.                 {  
  276.                     UInt32 tmp = ((value1 * value2) >> (bitOffset -1));  
  277.                       
  278.                     sValue = value1 + value2 - sign1 * tmp;  
  279.                       
  280.                     if (abs(sValue) >= bitMid)  
  281.                     {  
  282.                         sValue = sign1 * (bitMid -  1);  
  283.                     }  
  284.                 }  
  285.                 else  
  286.                 {  
  287.                     SInt32 tmpValue1 = value1 + bitMid;  
  288.                     SInt32 tmpValue2 = value2 + bitMid;  
  289.                       
  290.                     UInt32 tmp = ((tmpValue1 * tmpValue2) >> (bitOffset -1));  
  291.                       
  292.                     if (tmpValue1 < bitMid && tmpValue2 < bitMid)  
  293.                     {  
  294.                         sValue = tmp;  
  295.                     }  
  296.                     else  
  297.                     {  
  298.                         sValue = 2 * (tmpValue1  + tmpValue2 ) - tmp - bitMax;  
  299.                     }  
  300.                     sValue -= bitMid;  
  301.                 }  
  302.                   
  303.                 if (abs(sValue) >= bitMid)  
  304.                 {  
  305.                     SInt8 sign = abs(sValue)/sValue;  
  306.                       
  307.                     sValue = sign * (bitMid -  1);  
  308.                 }  
  309.                   
  310.                 *(outBuffer +j) = sValue;  
  311.             }  
  312.             else{  
  313.                 if (frameCount == frameCount1)  
  314.                 {  
  315.                     //将buffer1中的剩余数据添加到outbuffer  
  316.                     *(outBuffer +j) = *(buffer1 + j);  
  317.                 }  
  318.                 else  
  319.                 {  
  320.                     //将buffer1中的剩余数据添加到outbuffer  
  321.                     *(outBuffer +j) = *(buffer2 + j);  
  322.                 }  
  323.             }  
  324.         }  
  325.           
  326.         // Write pcm data to output file  
  327.         NSLog(@"frame count (%ld, %ld, %ld)", frameCount, frameCount1, frameCount2);  
  328.         err = ExtAudioFileWrite(outputAudioFileRef, frameCount, &outBufferList);  
  329.           
  330.         if (err) {  
  331.             goto reterr;  
  332.         }  
  333.     }  
  334.       
  335. reterr:  
  336.     if (buffer1)  
  337.         free(buffer1);  
  338.       
  339.     if (buffer2)  
  340.         free(buffer2);  
  341.       
  342.     if (outBuffer)  
  343.         free(outBuffer);  
  344.       
  345.     if (inputAudioFileRef1)  
  346.         ExtAudioFileDispose(inputAudioFileRef1);  
  347.       
  348.     if (inputAudioFileRef2)  
  349.         ExtAudioFileDispose(inputAudioFileRef2);  
  350.       
  351.     if (outputAudioFileRef)  
  352.         ExtAudioFileDispose(outputAudioFileRef);  
  353.       
  354.     return err;  
  355. }  
  356.   
  357. // Set flags for default audio format on iPhone OS  
  358.   
  359. + (void) _setDefaultAudioFormatFlags:(AudioStreamBasicDescription*)audioFormatPtr  
  360.                           sampleRate:(Float64)sampleRate  
  361.                          numChannels:(NSUInteger)numChannels  
  362. {  
  363.     bzero(audioFormatPtr, sizeof(AudioStreamBasicDescription));  
  364.       
  365.     audioFormatPtr->mFormatID = kAudioFormatLinearPCM;  
  366.     audioFormatPtr->mSampleRate = sampleRate;  
  367.     audioFormatPtr->mChannelsPerFrame = numChannels;  
  368.     audioFormatPtr->mBytesPerPacket = 2 * numChannels;  
  369.     audioFormatPtr->mFramesPerPacket = 1;  
  370.     audioFormatPtr->mBytesPerFrame = 2 * numChannels;  
  371.     audioFormatPtr->mBitsPerChannel = 16;  
  372.     audioFormatPtr->mFormatFlags = kAudioFormatFlagsNativeEndian |  
  373.     kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;  
  374. }  
  375.   
  376. @end 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值