目标c中的音频文件格式问题
Posted
技术标签:
【中文标题】目标c中的音频文件格式问题【英文标题】:Audio file format issue in objective c 【发布时间】:2015-08-31 13:31:32 【问题描述】:我使用 AVAudioRecorder 编写了一个音频 WAV(已录制我的声音)文件。最终的文件格式是 WAV 文件。文件已成功保存,我可以听到我的声音。我想将此文件发送到后端服务器(网络服务)。但我的服务器只接受 WAV 中的数据和 FMT 信息。它不接受我的 wav 文件,因为我的 wav 文件信息包含 FLLR、数据、FMT。我已经在 Riffpad 工具中检查了我的 WAV 文件信息。它显示 FLLR、数据、FMT。但我只想要数据和 fmt。因为我的服务器端只接受数据和 FMT。那么请建议如何以编程方式删除我的 wav 文件中的 FLLR?
我的源代码记录:
NSError *error;
// Recording settings
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue: [NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[settings setValue: [NSNumber numberWithFloat:22050] forKey:AVSampleRateKey];
[settings setValue: [NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey]; // mono
[settings setValue: [NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[settings setValue: [NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
//[settings setValue: [NSNumber numberWithInt:16] forKey:AudiosampleType];
// File URL
NSURL *url = [NSURL fileURLWithPath:FILEPATH];
//NSLog(@"Url file path ::: %@",url);
// Create recorder
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (!recorder)
// NSLog(@"Error establishing recorder: %@", error.localizedFailureReason);
return;
【问题讨论】:
你能否跳过 FLLR,如下所示:***.com/questions/6284651/… 感谢您的留言。你能解释一下WS的意思吗? 网络服务。正如链接答案中所建议的那样,您的服务器会更好更简单,只需跳过 FLLR 前面没有办法(目标c)结束? 根据链接的答案,这是Apple实现添加的一些块数据。因此,除非您确切地知道它的作用(也许网络上的一些研究可以告诉您究竟是什么),否则这可能会非常困难。除了 AVAudioRecorder 之外,可能还有另一个元素(在 GitHub 中)可以做到这一点。 【参考方案1】:感谢上帝和您支持的朋友。是的,最后我解决了我的问题。我不知道方法是否正确。但是我的问题解决了。我使用上面的代码录制了语音并保存了我的音频。然后我将再次使用以下代码导出音频。我从https://developer.ibm.com/answers/questions/180732/seems-watson-text-to-speech-service-returns-a-wav.html得到这个代码
-(NSData*) stripAndAddWavHeader:(NSData*) wav
unsigned long wavDataSize = [wav length] - 44;
NSData *WaveFile= [NSMutableData dataWithData:[wav subdataWithRange:NSMakeRange(44, wavDataSize)]];
NSMutableData *newWavData;
newWavData = [self addWavHeader:WaveFile];
return newWavData;
- (NSMutableData *)addWavHeader:(NSData *)wavNoheader
int headerSize = 44;
long totalAudioLen = [wavNoheader length];
long totalDataLen = [wavNoheader length] + headerSize-8;
long longSampleRate = 22050.0;
int channels = 1;
long byteRate = 8 * 44100.0 * channels/8;
Byte *header = (Byte*)malloc(44);
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (Byte) (totalDataLen & 0xff);
header[5] = (Byte) ((totalDataLen >> 8) & 0xff);
header[6] = (Byte) ((totalDataLen >> 16) & 0xff);
header[7] = (Byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (Byte) channels;
header[23] = 0;
header[24] = (Byte) (longSampleRate & 0xff);
header[25] = (Byte) ((longSampleRate >> 8) & 0xff);
header[26] = (Byte) ((longSampleRate >> 16) & 0xff);
header[27] = (Byte) ((longSampleRate >> 24) & 0xff);
header[28] = (Byte) (byteRate & 0xff);
header[29] = (Byte) ((byteRate >> 8) & 0xff);
header[30] = (Byte) ((byteRate >> 16) & 0xff);
header[31] = (Byte) ((byteRate >> 24) & 0xff);
header[32] = (Byte) (2 * 8 / 8); // block align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (Byte) (totalAudioLen & 0xff);
header[41] = (Byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (Byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (Byte) ((totalAudioLen >> 24) & 0xff);
NSMutableData *newWavData = [NSMutableData dataWithBytes:header length:44];
[newWavData appendBytes:[wavNoheader bytes] length:[wavNoheader length]];
return newWavData;
【讨论】:
音频播放不正确。音频质量下降。【参考方案2】:寻找数据边缘的 Swift 解决方案
class MediaUtil
private static func dataToUTF8String(data: NSData, offset: Int, length: Int) -> String?
let range = NSMakeRange(offset, length)
let subdata = data.subdata(with: range)
return String(data: subdata, encoding: String.Encoding.utf8)
private static func dataToUInt32(data: NSData, offset: Int) -> Int
var num: UInt32 = 0
let length = 4
let range = NSMakeRange(offset, length)
data.getBytes(&num, range: range)
return Int(num)
static func repairWAVHeader(data: NSMutableData)->Data
// resources for WAV header format:
// [1] http://unusedino.de/ec64/technical/formats/wav.html
// [2] http://soundfile.sapp.org/doc/WaveFormat/
var newData = Data()
// update RIFF chunk size
let fileLength = data.length
var riffChunkSize = UInt32(fileLength - 8)
let riffChunkSizeRange = NSMakeRange(4, 4)
data.replaceBytes(in: riffChunkSizeRange, withBytes: &riffChunkSize)
// find data subchunk
var subchunkID: String?
var subchunkSize = 0
var fieldOffset = 12
let fieldSize = 4
while true
// prevent running off the end of the byte buffer
if fieldOffset + 2*fieldSize >= data.length
return newData
// read subchunk ID
subchunkID = dataToUTF8String(data: data, offset: fieldOffset, length: fieldSize)
fieldOffset += fieldSize
if subchunkID == "data"
break
// read subchunk size
subchunkSize = dataToUInt32(data: data, offset: fieldOffset)
fieldOffset += fieldSize + subchunkSize
let rllrRange = NSMakeRange(0, fieldOffset)
data.replaceBytes(in: rllrRange, withBytes: nil, length: 0)
newData = newWavHeader(pcmDataLength: data.length)
newData.append(data as Data)
return newData
private static func newWavHeader(pcmDataLength: Int) -> Data
var header = Data()
let headerSize = 44
let bitsPerSample = Int32(16)
let numChannels: Int32 = 1
let sampleRate: Int32 = 16000
// RIFF chunk descriptor
let chunkID = [UInt8]("RIFF".utf8)
header.append(chunkID, count: 4)
var chunkSize = Int32(pcmDataLength + headerSize - 4).littleEndian
let chunkSizePointer = UnsafeBufferPointer(start: &chunkSize, count: 1)
header.append(chunkSizePointer)
let format = [UInt8]("WAVE".utf8)
header.append(format, count: 4)
// "fmt" sub-chunk
let subchunk1ID = [UInt8]("fmt ".utf8)
header.append(subchunk1ID, count: 4)
var subchunk1Size = Int32(16).littleEndian
let subchunk1SizePointer = UnsafeBufferPointer(start: &subchunk1Size, count: 1)
header.append(subchunk1SizePointer)
var audioFormat = Int16(1).littleEndian
let audioFormatPointer = UnsafeBufferPointer(start: &audioFormat, count: 1)
header.append(audioFormatPointer)
var headerNumChannels = Int16(numChannels).littleEndian
let headerNumChannelsPointer = UnsafeBufferPointer(start: &headerNumChannels, count: 1)
header.append(headerNumChannelsPointer)
var headerSampleRate = Int32(sampleRate).littleEndian
let headerSampleRatePointer = UnsafeBufferPointer(start: &headerSampleRate, count: 1)
header.append(headerSampleRatePointer)
var byteRate = Int32(sampleRate * numChannels * bitsPerSample / 8).littleEndian
let byteRatePointer = UnsafeBufferPointer(start: &byteRate, count: 1)
header.append(byteRatePointer)
var blockAlign = Int16(numChannels * bitsPerSample / 8).littleEndian
let blockAlignPointer = UnsafeBufferPointer(start: &blockAlign, count: 1)
header.append(blockAlignPointer)
var headerBitsPerSample = Int16(bitsPerSample).littleEndian
let headerBitsPerSamplePointer = UnsafeBufferPointer(start: &headerBitsPerSample, count: 1)
header.append(headerBitsPerSamplePointer)
// "data" sub-chunk
let subchunk2ID = [UInt8]("data".utf8)
header.append(subchunk2ID, count: 4)
var subchunk2Size = Int32(pcmDataLength).littleEndian
let subchunk2SizePointer = UnsafeBufferPointer(start: &subchunk2Size, count: 1)
header.append(subchunk2SizePointer)
return header
【讨论】:
以上是关于目标c中的音频文件格式问题的主要内容,如果未能解决你的问题,请参考以下文章