有人可以帮我删除录制的音频文件中的初始静音吗?
我正在获取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){
}
}];
}
我在这里做错了什么?
答案 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;
所以你的待办事项清单是
答案 1 :(得分:0)
Apple生成的wave文件的标头长度通常不是44个字节。一些Apple生成的标头长度为4k字节。您必须检查wave RIFF标头以获得额外的FFLR&#39;字节。如果你不跳过这个额外的填充填充物,你最终会沉默大约十分之一秒(或者甚至可能是坏数据)。