Par*_*was 2 c c++ audio objective-c ios
我试图在原始PCM数据之上添加一个wav标题,以使其可以通过AVAudioPlayer播放.但我在iOS上使用Objective-C/Swift找不到任何解决方案或源代码.虽然我发现了这个,但它没有正确的答案.
但是我在这里发现了一段代码,它在C中并且还包含一些问题.wav文件无法正常播放,该文件是从该代码生成的.
到目前为止,我已经给出了我编码的代码.
int NumChannels = AUDIO_CHANNELS_PER_FRAME;
short BitsPerSample = AUDIO_BITS_PER_CHANNEL;
int SamplingRate = AUDIO_SAMPLE_RATE;
int numOfSamples = [[NSData dataWithContentsOfFile:filePath] length];
int ByteRate = NumChannels*BitsPerSample*SamplingRate/8;
short BlockAlign = NumChannels*BitsPerSample/8;
int DataSize = NumChannels*numOfSamples*BitsPerSample/8;
int chunkSize = 16;
int totalSize = 36 + DataSize;
short audioFormat = 1;
if((fout = fopen([wavFilePath cStringUsingEncoding:1], "w")) == NULL)
{
printf("Error opening out file ");
}
fwrite("RIFF", sizeof(char), 4,fout);
fwrite(&totalSize, sizeof(int), 1, fout);
fwrite("WAVE", sizeof(char), 4, fout);
fwrite("fmt ", sizeof(char), 3, fout);
fwrite(&chunkSize, sizeof(int),1,fout);
fwrite(&audioFormat, sizeof(short), 1, fout);
fwrite(&NumChannels, sizeof(short),1,fout);
fwrite(&SamplingRate, sizeof(int), 1, fout);
fwrite(&ByteRate, sizeof(int), 1, fout);
fwrite(&BlockAlign, sizeof(short), 1, fout);
fwrite(&BitsPerSample, sizeof(short), 1, fout);
fwrite("data", sizeof(char), 3, fout);
fwrite(&DataSize, sizeof(int), 1, fout);
Run Code Online (Sandbox Code Playgroud)
文件播放速度太快,声音失真,只播放前10到20秒左右.我认为,wav标头没有正确生成(因为我能够使用AudioUnit/AudioQueue播放相同的PCM数据/缓冲区).那么我的代码中缺少什么?任何帮助将受到高度赞赏.
提前致谢.
Par*_*was 10
好的,我正在回答我自己的问题,如果它可以帮助其他人.经过几天不知疲倦的尝试,终于让它运转起来了.下面是一个用Objective-C和C编写的完整函数.它将文件路径作为参数,包含直接从麦克风捕获的RAW PCM数据,并返回包含PCM数据的文件路径,后跟相应的wav头信息.然后,您可以使用AVAudioPlayer或AVPlayer播放该文件.这是代码......
- (NSURL *) getAndCreatePlayableFileFromPcmData:(NSString *)filePath
{
NSString *wavFileName = [[filePath lastPathComponent] stringByDeletingPathExtension];
NSString *wavFileFullName = [NSString stringWithFormat:@"%@.wav",wavFileName];
[self createFileWithName:wavFileFullName];
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
NSString *wavFilePath = [docsDir stringByAppendingPathComponent:wavFileFullName];
NSLog(@"PCM file path : %@",filePath);
FILE *fout;
short NumChannels = AUDIO_CHANNELS_PER_FRAME;
short BitsPerSample = AUDIO_BITS_PER_CHANNEL;
int SamplingRate = AUDIO_SAMPLE_RATE;
int numOfSamples = [[NSData dataWithContentsOfFile:filePath] length];
int ByteRate = NumChannels*BitsPerSample*SamplingRate/8;
short BlockAlign = NumChannels*BitsPerSample/8;
int DataSize = NumChannels*numOfSamples*BitsPerSample/8;
int chunkSize = 16;
int totalSize = 46 + DataSize;
short audioFormat = 1;
if((fout = fopen([wavFilePath cStringUsingEncoding:1], "w")) == NULL)
{
printf("Error opening out file ");
}
fwrite("RIFF", sizeof(char), 4,fout);
fwrite(&totalSize, sizeof(int), 1, fout);
fwrite("WAVE", sizeof(char), 4, fout);
fwrite("fmt ", sizeof(char), 4, fout);
fwrite(&chunkSize, sizeof(int),1,fout);
fwrite(&audioFormat, sizeof(short), 1, fout);
fwrite(&NumChannels, sizeof(short),1,fout);
fwrite(&SamplingRate, sizeof(int), 1, fout);
fwrite(&ByteRate, sizeof(int), 1, fout);
fwrite(&BlockAlign, sizeof(short), 1, fout);
fwrite(&BitsPerSample, sizeof(short), 1, fout);
fwrite("data", sizeof(char), 4, fout);
fwrite(&DataSize, sizeof(int), 1, fout);
fclose(fout);
NSMutableData *pamdata = [NSMutableData dataWithContentsOfFile:filePath];
NSFileHandle *handle;
handle = [NSFileHandle fileHandleForUpdatingAtPath:wavFilePath];
[handle seekToEndOfFile];
[handle writeData:pamdata];
[handle closeFile];
return [NSURL URLWithString:wavFilePath];
}
Run Code Online (Sandbox Code Playgroud)
但该功能仅适用于以下音频设置.
// Audio settings.
#define AUDIO_SAMPLE_RATE 8000
#define AUDIO_FRAMES_PER_PACKET 1
#define AUDIO_CHANNELS_PER_FRAME 1
#define AUDIO_BITS_PER_CHANNEL 16
#define AUDIO_BYTES_PER_PACKET 2
#define AUDIO_BYTES_PER_FRAME 2
Run Code Online (Sandbox Code Playgroud)
非常有帮助的问题和答案,非常感谢。
这个快速版本适合有需要的人:
static func createWAV(from pcmFilePath: String, to wavFilePath: String) -> Bool {
// Make sure that the path does not contain non-ascii characters
guard let fout = fopen(wavFilePath.cString(using: .ascii), "w") else { return false }
guard let pcmData = try? Data(contentsOf: URL(fileURLWithPath: pcmFilePath)) else { return false }
var numChannels: CShort = 1
let numChannelsInt: CInt = 1
var bitsPerSample: CShort = 16
let bitsPerSampleInt: CInt = 16
var samplingRate: CInt = 16000
let numOfSamples = CInt(pcmData.count)
var byteRate = numChannelsInt * bitsPerSampleInt * samplingRate / 8
var blockAlign = numChannelsInt * bitsPerSampleInt / 8
var dataSize = numChannelsInt * numOfSamples * bitsPerSampleInt / 8
var chunkSize: CInt = 16
var totalSize = 46 + dataSize
var audioFormat: CShort = 1
fwrite("RIFF".cString(using: .ascii), MemoryLayout<CChar>.size, 4, fout)
fwrite(&totalSize, MemoryLayout<CInt>.size, 1, fout)
fwrite("WAVE".cString(using: .ascii), MemoryLayout<CChar>.size, 4, fout);
fwrite("fmt ".cString(using: .ascii), MemoryLayout<CChar>.size, 4, fout);
fwrite(&chunkSize, MemoryLayout<CInt>.size,1,fout);
fwrite(&audioFormat, MemoryLayout<CShort>.size, 1, fout);
fwrite(&numChannels, MemoryLayout<CShort>.size,1,fout);
fwrite(&samplingRate, MemoryLayout<CInt>.size, 1, fout);
fwrite(&byteRate, MemoryLayout<CInt>.size, 1, fout);
fwrite(&blockAlign, MemoryLayout<CShort>.size, 1, fout);
fwrite(&bitsPerSample, MemoryLayout<CShort>.size, 1, fout);
fwrite("data".cString(using: .ascii), MemoryLayout<CChar>.size, 4, fout);
fwrite(&dataSize, MemoryLayout<CInt>.size, 1, fout);
fclose(fout);
guard let handle = FileHandle(forUpdatingAtPath: wavFilePath) else { return false }
handle.seekToEndOfFile()
handle.write(pcmData)
handle.closeFile()
return true
}
Run Code Online (Sandbox Code Playgroud)