【问题标题】:iOS: How to trim silence from start and end of .aif audio recording?iOS:如何从 .aif 录音的开始和结束修剪静音?
【发布时间】:2014-03-14 05:17:53
【问题描述】:

我的应用程序包含用户录制简短消息的功能;我想从录音的开头和结尾剪掉所有静音(或者更准确地说,是音量低于给定阈值的任何音频)。

我正在使用 AVAudioRecorder 录制音频,并将其保存到 .aif 文件中。我在其他地方看到过一些方法,通过这些方法我可以让它等待开始录制,直到音频电平达到阈值。这会让我走到一半,但无助于结束最后的沉默。

如果有简单的方法可以做到这一点,我将永远感激不尽!

谢谢。

【问题讨论】:

    标签: ios audio audio-recording avaudiorecorder aiff


    【解决方案1】:

    此项目从麦克风获取音频,在嘈杂的噪音时触发,在安静时取消触发。它还会在末端修剪和淡入/淡出。

    https://github.com/fulldecent/FDSoundActivatedRecorder

    您正在寻找的相关代码:

    - (NSString *)recordedFilePath
    {
        // Prepare output
        NSString *trimmedAudioFileBaseName = [NSString stringWithFormat:@"recordingConverted%x.caf", arc4random()];
        NSString *trimmedAudioFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:trimmedAudioFileBaseName];
        NSFileManager *fileManager = [NSFileManager defaultManager];
        if ([fileManager fileExistsAtPath:trimmedAudioFilePath]) {
            NSError *error;
            if ([fileManager removeItemAtPath:trimmedAudioFilePath error:&error] == NO) {
                NSLog(@"removeItemAtPath %@ error:%@", trimmedAudioFilePath, error);
            }
        }
        NSLog(@"Saving to %@", trimmedAudioFilePath);
    
        AVAsset *avAsset = [AVAsset assetWithURL:self.audioRecorder.url];
        NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
        AVAssetTrack *track = [tracks objectAtIndex:0];
    
        AVAssetExportSession *exportSession = [AVAssetExportSession
                                               exportSessionWithAsset:avAsset
                                               presetName:AVAssetExportPresetAppleM4A];
    
        // create trim time range
        CMTime startTime = CMTimeMake(self.recordingBeginTime*SAVING_SAMPLES_PER_SECOND, SAVING_SAMPLES_PER_SECOND);
        CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, kCMTimePositiveInfinity);
    
        // create fade in time range
        CMTime startFadeInTime = startTime;
        CMTime endFadeInTime = CMTimeMake(self.recordingBeginTime*SAVING_SAMPLES_PER_SECOND + RISE_TRIGGER_INTERVALS*INTERVAL_SECONDS*SAVING_SAMPLES_PER_SECOND, SAVING_SAMPLES_PER_SECOND);
        CMTimeRange fadeInTimeRange = CMTimeRangeFromTimeToTime(startFadeInTime, endFadeInTime);
    
        // setup audio mix
        AVMutableAudioMix *exportAudioMix = [AVMutableAudioMix audioMix];
        AVMutableAudioMixInputParameters *exportAudioMixInputParameters =
        [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:track];
    
        [exportAudioMixInputParameters setVolumeRampFromStartVolume:0.0 toEndVolume:1.0
                                                          timeRange:fadeInTimeRange];
        exportAudioMix.inputParameters = [NSArray
                                          arrayWithObject:exportAudioMixInputParameters];
    
        // configure export session  output with all our parameters
        exportSession.outputURL = [NSURL fileURLWithPath:trimmedAudioFilePath];
        exportSession.outputFileType = AVFileTypeAppleM4A;
        exportSession.timeRange = exportTimeRange;
        exportSession.audioMix = exportAudioMix;
    
        // MAKE THE EXPORT SYNCHRONOUS
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        [exportSession exportAsynchronouslyWithCompletionHandler:^{
            dispatch_semaphore_signal(semaphore);
        }];
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
        if (AVAssetExportSessionStatusCompleted == exportSession.status) {
            NSLog(@"AVAssetExportSessionStatusCompleted");
            return trimmedAudioFilePath;
        } 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 %@", exportSession.error.localizedDescription);
        } else {
            NSLog(@"Export Session Status: %d", exportSession.status);
        }
        return nil;
    }
    

    【讨论】:

    • 你提供的 GitHub 示例给出错误:由于未捕获的异常 'NSInvalidArgumentException' 导致应用程序终止,原因:'*** -[NSURL initFileURLWithPath:]: nil string parameter'
    【解决方案2】:

    我正在使用 AVAudioRecorder 录制音频,并将其保存到 .aif 文件中。我在其他地方看到过一些方法,通过这些方法我可以让它等待开始录制,直到音频电平达到阈值。那会让我走到一半

    如果没有足够的缓冲,那会截断开头。

    我不知道一个简单的方法。在录制并分析所需的起点和终点后,您必须编写一个新的音频文件。如果您非常了解 AIFF 格式(没有多少人知道)并且有一种简单的方法可以读取文件的示例数据,那么修改现有文件会很简单。

    对于基本实现而言,分析阶段非常简单——评估样本数据的平均功效,直到超过您的阈值。反向重复结束。

    【讨论】:

    • 感谢您的回复...我对音频处理几乎一无所知,从编程的角度来说。我知道我需要做的是设置一个阈值,然后从文件的正面和背面修剪所有不符合它的音频。我想知道的是如何使用 ios sdk 和/或任何开源工具来实际做到这一点。
    • @DanM 您可以使用ExtAudioFile API 来读取和写入音频文件并将样本数据转换为您想要的格式(用于分析目的)。没有一个简单的方法——你需要写几百行代码来完成这个。
    猜你喜欢
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 2013-12-16
    • 1970-01-01
    • 2023-03-27
    • 2015-12-04
    相关资源
    最近更新 更多