iPhone:以编程方式混合两个音频文件



我想有两个音频文件和混合和播放它的编程。当我在播放第一个音频文件时,经过一段时间(动态时间),我需要在播放第一个音频文件时添加第二个小音频文件,然后最后我需要将其保存为设备上的一个音频文件。它应该播放音频文件与混音器音频我包括第二个。

我已经通过了许多论坛,但不能得到线索究竟如何实现这一点?

有人能澄清我下面的疑问吗?

  1. 在这种情况下,我应该使用什么音频文件/格式?我可以使用。avi文件吗?
  2. 如何添加第二个音频后的动态时间设置到第一个音频文件编程?例如:如果第一个音频总时间是2分钟,我可能需要在第一个文件的1分钟或1.5分钟或55秒内混合第二个音频文件(3秒音频)。其动态。
  3. 如何保存设备上的最终输出音频文件?如果我以编程方式保存音频文件,我可以再次播放吗?

我不知道如何做到这一点。请提出你的想法!

    打开每个音频文件
  • 读取标题信息
  • 将未压缩的原始音频作为每个文件的int数组存储到内存中
  • 从文件1的数组开始,你想在file2中混合,循环,将file2的int值添加到file1中,确保"剪辑"高于或低于最大值的任何值(这就是你如何混合音频…是的,它是简单)。如果file2较长,则必须使第一个数组足够长,以完全容纳file2的其余部分。
  • 写入新的头信息,然后从你添加file2的数组中写入音频。
  • 如果涉及到压缩或者文件不适合内存,你可能不得不实现一个更复杂的缓冲方案。

在这种情况下,我应该使用什么音频文件/格式?我可以使用。avi文件吗?

可以选择压缩格式或非压缩格式。常见的非压缩格式包括Wav和AIFF。CAF可以表示压缩和非压缩数据。.avi不是一个选项(由操作系统提供)。

如果文件很大并且存储空间(磁盘上)是一个问题,您可以考虑将AAC格式保存为CAF(或简单地。m4a)。对于大多数应用来说,16位采样就足够了,你也可以通过以适当的采样率保存这些文件来节省空间,内存和cpu(参考:cd是44.1kHz)。

由于ExtAudioFile接口抽象了转换过程,您不应该更改您的程序来比较您的发行版的压缩和非压缩格式的大小和速度差异(CAF中的AAC对于正常应用程序来说很好)。

非压缩CD质量的音频将消耗约5.3 MB每分钟,每个通道。因此,如果您有2个立体声音频文件,每个文件长3分钟,以及一个3分钟的目标缓冲区,那么您的内存需求将在50 MB左右。

因为你有"分钟"的音频,你可能需要考虑避免一次将所有音频数据加载到内存中。为了读取、操作和组合音频,您将需要在内存中使用非压缩表示,因此压缩格式在这里没有帮助。同样,将压缩表示转换为pcm需要大量资源;读取压缩文件,虽然字节更少,但可能会花费更多(或更少)的时间。

如何添加第二个音频后的动态时间设置到第一个音频文件编程?例如:如果第一个音频总时间是2分钟,我可能需要在第一个文件的1分钟或1.5分钟或55秒内混合第二个音频文件(3秒音频)。其动态。

要读取文件并将其转换为您想要使用的格式,请使用ExtAudioFile api -这将为您转换为目标示例格式。内存中常见的PCM样本表示包括SInt32SInt16float,但这可能因应用程序和硬件(iOS以外)而有很大差异。ExtAudioFile api也可以将压缩格式转换为PCM,如果需要的话。

您的输入音频文件应该具有相同的采样率。如果没有,你将不得不重新采样音频,这是一个复杂的过程,也需要大量的资源(如果做得正确/准确)。如果您需要支持重采样,请将分配给完成此任务的时间加倍(此处不详细说明过程)。

要添加声音,您需要从文件中请求PCM样本,处理并写入输出文件(或内存中的缓冲区)。

要确定何时添加其他声音,您将需要获得输入文件的采样率(通过ExtAudioFileGetProperty)。如果您想以55秒的速度将第二个声音写入目标缓冲区,那么您将开始以采样号SampleRate * 55添加声音,其中SampleRate是您正在读取的文件的采样率。

要混合音频,您只需使用这个表单(伪代码):

mixed[i] = fileA[i] + fileB[i];

,但你必须确保你避免溢出/下溢和其他算术错误。通常,您将使用一些整数值来执行此过程,因为浮点计算可能需要很长时间(当有很多浮点计算时)。对于某些应用程序,您可以只移动和添加而不用担心溢出—这将有效地减少每个输入的一半,然后再添加它们。结果的振幅是1/2。如果您可以控制文件的内容(例如,它们都作为资源捆绑在一起),那么您可以简单地确保文件中的峰值样本没有超过满量程值的一半(约-6dBFS)。当然,保存为float可以解决这个问题,但代价是引入更高的CPU、内存和文件i/o需求。

此时,您将打开2个文件用于读取,打开一个文件用于写入,然后有一些小的临时缓冲区用于在写入输出文件之前处理和混合输入。为了提高效率,您应该分块执行这些请求(例如,从每个文件读取1024个样本,处理这些样本,写1024个样本)。这些api不能保证很多关于缓存和缓冲的效率。

如何在设备上保存最终输出的音频文件?如果我以编程方式保存音频文件,我可以再次播放吗?

ExtAudioFile api将满足您的读写需求。是的,你可以稍后再读/播放。

Hello你可以使用av foundation

- (BOOL) combineVoices1
{
    NSError *error = nil;
    BOOL ok = NO;

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,    NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    CMTime nextClipStartTime = kCMTimeZero;
    //Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
    AVMutableComposition *composition = [[AVMutableComposition alloc] init];
    AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack setPreferredVolume:0.8];
    NSString *soundOne  =[[NSBundle mainBundle]pathForResource:@"test1" ofType:@"caf"];
    NSURL *url = [NSURL fileURLWithPath:soundOne];
    AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
    NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *clipAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];
    AVMutableCompositionTrack *compositionAudioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack setPreferredVolume:0.3];
    NSString *soundOne1  =[[NSBundle mainBundle]pathForResource:@"test" ofType:@"caf"];
    NSURL *url1 = [NSURL fileURLWithPath:soundOne1];
    AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:url1 options:nil];
    NSArray *tracks1 = [avAsset1 tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *clipAudioTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack1 atTime:kCMTimeZero error:nil];

    AVMutableCompositionTrack *compositionAudioTrack2 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack2 setPreferredVolume:1.0];
    NSString *soundOne2  =[[NSBundle mainBundle]pathForResource:@"song" ofType:@"caf"];
    NSURL *url2 = [NSURL fileURLWithPath:soundOne2];
    AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:url2 options:nil];
    NSArray *tracks2 = [avAsset2 tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *clipAudioTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:clipAudioTrack2 atTime:kCMTimeZero error:nil];

    AVAssetExportSession *exportSession = [AVAssetExportSession
                                           exportSessionWithAsset:composition
                                           presetName:AVAssetExportPresetAppleM4A];
    if (nil == exportSession) return NO;
    NSString *soundOneNew = [documentsDirectory stringByAppendingPathComponent:@"combined10.m4a"];
    //NSLog(@"Output file path - %@",soundOneNew);
    // configure export session  output with all our parameters
    exportSession.outputURL = [NSURL fileURLWithPath:soundOneNew]; // output path
    exportSession.outputFileType = AVFileTypeAppleM4A; // output file type
    // perform the export
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        if (AVAssetExportSessionStatusCompleted == exportSession.status) {
            NSLog(@"AVAssetExportSessionStatusCompleted");
        } else if (AVAssetExportSessionStatusFailed == exportSession.status) {
            // a failure may happen because of an event out of your control
            // for example, an interruption like a phone call comming in
            // make sure and handle this case appropriately
            NSLog(@"AVAssetExportSessionStatusFailed");
        } else {
            NSLog(@"Export Session Status: %d", exportSession.status);
        }
    }];

    return YES;

}

如果你打算一次播放多个声音,一定要使用*。caf格式。苹果推荐它同时播放多种声音。就编程混合它们而言,我假设你只是想让它们同时播放。当一个声音正在播放时,只需告诉另一个声音在你想要的任何时间播放即可。要设置一个特定的时间,请使用NSTimer (NSTimer类参考)并创建一个方法,以便在计时器触发时播放声音。

最新更新