从录制的波形音频文件中删除初始静音

时间:2015-10-26 07:35:48

标签: ios core-audio wave

有人可以帮我删除录制的音频文件中的初始静音吗?

我正在获取wav文件的数据字节,并在忽略前44个头字节后得到0字节的结束范围,这在波形文件中是静默的。

之后从总数据字节,无声音频字节的结束范围和文件的总持续时间,我正在计算音频文件的静音时间,并从音频文件中修剪那么多时间。

但问题仍然是音频文件中还有一些静音部分。

所以不确定我是否错过了什么?

- (double)processAudio:(float)totalFileDuration withFilePathURL:(NSURL *)filePathURL{
    NSMutableData *data = [NSMutableData dataWithContentsOfURL:filePathURL];
    NSMutableData *Wave1= [NSMutableData dataWithData:[data subdataWithRange:NSMakeRange(44, [data length] - 44)]];
    uint8_t * bytePtr = (uint8_t  * )[Wave1 bytes] ;
    NSInteger totalData = [Wave1 length] / sizeof(uint8_t);
    int endRange = 0;
    for (int i = 0 ; i < totalData; i ++){
           /
        if (bytePtr[i] == 0) {
            endRange = i;
        }else
            break;
    }

    double silentAudioDuration =(((float)endRange/(float)totalData)*totalFileDuration);
    return silentAudioDuration;
}
- (void)trimAudioFileWithInputFilePath :(NSString *)inputPath toOutputFilePath : (NSString *)outputPath{
    /
    NSString *strInputFilePath = inputPath;
    NSURL *audioFileInput = [NSURL fileURLWithPath:strInputFilePath];

    /
    NSString *strOutputFilePath = [outputPath stringByDeletingPathExtension];
    strOutputFilePath = [strOutputFilePath stringByAppendingString:@".m4a"];
    NSURL *audioFileOutput = [NSURL fileURLWithPath:strOutputFilePath];
    newPath = strOutputFilePath;

    if (!audioFileInput || !audioFileOutput){
        /
    }

    [[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
    AVAsset *asset = [AVAsset assetWithURL:audioFileInput];
    CMTime audioDuration = asset.duration;
    float audioDurationSeconds = CMTimeGetSeconds(audioDuration);

    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:asset presetName:AVAssetExportPresetAppleM4A];

    if (exportSession == nil){
        /
    }

    /
    float startTrimTime = [self processAudio:audioDurationSeconds withFilePathURL:audioFileInput];
    /
    /
    float endTrimTime = audioDurationSeconds;

    recordingDuration = audioDurationSeconds - startTrimTime;

    CMTime startTime = CMTimeMake((int)(floor(startTrimTime * 100)), 100);
    CMTime stopTime = CMTimeMake((int)(ceil(endTrimTime * 100)), 100);
    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);

    exportSession.outputURL = audioFileOutput;
    exportSession.outputFileType = AVFileTypeAppleM4A;
    exportSession.timeRange = exportTimeRange;

    [exportSession exportAsynchronouslyWithCompletionHandler:^{
         if (AVAssetExportSessionStatusCompleted == exportSession.status){
         }
         else if (AVAssetExportSessionStatusFailed == exportSession.status){
         }
     }];
}

我在这里做错了什么?

2 个答案:

答案 0 :(得分:0)

您的文件中可能没有完全沉默?也许你的样本的值为1或2或3,技术上不是沉默,但它非常安静。

波形文件存储为带符号的数字(如果是16位),无符号(如果是8位)。您正在处理和转换数据为无符号字节:     uint8_t * bytePtr =(uint8_t *)[Wave1 bytes];

您需要知道可以从标题中获取的波形文件的格式。 (它可能使用8位,16位,24位等样本大小)

如果是16位和单声道,则需要使用:

int16_t * ptr = (int16_t) [Wave1 bytes];

您的循环一次计算一个字节,因此您需要将其调整为按帧大小增加。

您也不会考虑单声道/立体声 通常,您的processAudio函数需要更多细节,并应考虑每帧的通道数(立体声/单声道)和样本大小。

以下是iOS类型的wave标头。您可以转换前44个字节并获取标题数据,以便了解您正在处理的内容。

typedef struct waveHeader_t
{
    //RIFF
    char        chunkID[4];             ///< Should always contain "RIFF" BigEndian    //4
    uint32_t    chunkSize;              ///< total file length minus 8  (little endian!!!)    //4
    char        format[4];              ///< should be "WAVE"  Big Endian

    // fmt
    char        subChunk1ID[4];         ///< "fmt " Big Endian                //4
    uint32_t    subChunk1Size;          ///< 16 for PCM format                        //2
    uint16_t    audioFormat;            ///< 1 for PCM format                       //2
    uint16_t    numChannels;            ///< channels                                     //2
    uint32_t    sampleRate;             ///< sampling frequency                           //4
    uint32_t    byteRate;               ///< samplerate * numchannels * bitsperSample/8
    uint16_t    blockAlign;             ///< frame size
    uint16_t    bitsPerSample;          ///< bits per Sample

    char        subChunk2ID[4];         ///< should always contain "data"
    uint32_t    subChunk2Size;          ///< 

    ///< sample data follows this.....
} waveHeader_t;

所以你的待办事项清单是

  • 从标题
  • 中提取字段
  • 具体获取每个频道的频道数和比特数(注意**每个频道的BITS数)
  • 使用适当的大小指针指向数据,并一次循环一帧。 (单声道帧有一个样本,可以是8,16,24等位。立体声帧有两个样本,每个样本可以是8,16或24位。例如LR LR LR LR LR LR将是6帧)

答案 1 :(得分:0)

Apple生成的wave文件的标头长度通常不是44个字节。一些Apple生成的标头长度为4k字节。您必须检查wave RIFF标头以获得额外的FFLR&#39;字节。如果你不跳过这个额外的填充填充物,你最终会沉默大约十分之一秒(或者甚至可能是坏数据)。