AVAudioRecorder不写出正确的WAV文件标题

我正在iPhone上使用AVAudioRecorder录制设备麦克风的audio,然后操作录制。

为了确保我正确地从文件中读取样本,我使用python的wave模块来查看它是否返回相同的样本。

但是,当试图打开由AVAudioRecorder保存的wav文件时,python的wave模块返回“fmt chunk和/或data chunk missing”。

这些是我用来logging文件的设置:

[audioSettings setObject:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey]; [audioSettings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey]; [audioSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey]; [audioSettings setObject:[NSNumber numberWithFloat:4096] forKey:AVSampleRateKey]; [audioSettings setObject:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey]; [audioSettings setObject:[NSNumber numberWithBool:YES] forKey:AVLinearPCMIsNonInterleaved]; [audioSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey]; 

之后,我只是打电话recordForDuration实际上做logging。

录制成功 – 我可以播放文件等,我可以使用AudioFile服务读取示例,但是我无法validation它,因为我无法用Python的wave模块打开文件。

这是该文件的前128个字节的样子:

 1215N:~/Downloads$ od -c --read-bytes 128 testFile.wav 0000000 RIFF x H 001 \0 WAVE fmt 0000020 020 \0 \0 \0 001 \0 001 \0 @ 037 \0 \0 200 > \0 \0 0000040 002 \0 020 \0 FLLR 314 017 \0 \0 \0 \0 \0 \0 0000060 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 * 0000200 

任何想法,我需要做的,以确保AVAudioRecorder写出正确的WAV标题?

苹果软件通常在"fmt "子块之后和"data"子块之前创build具有非标准(但“规格”一致) "FLLR"子块的WAVE文件。 我假设“FLLR”代表“填充”,我假定子块的目的是启用某种数据alignment优化。 子块通常长度约为4000个字节,但其实际长度可以根据前面的数据长度而变化。

向WAVE文件中添加任意子块通常被认为是符合规范的,因为WAVE是RIFF的一个子集,而RIFF文件处理中的常见做法是忽略具有不可识别标识符的块和子块。 标识符"FLLR"是“非标准的”,所以任何遇到它的软件都应该忽略它。

这里有相当多的软件比WAVE格式要严格得多,我怀疑你使用的软件库可能是其中的一个软件。 例如,我已经看到软件假定audio字节总是以偏移量44开始 – 这是一个不正确的假设。

实际上,在WAVE文件中查找audio字节必须通过查找RIFF内"data"子块的位置和大小来完成; 这是在WAVE文件中findaudio字节的正确方法。

正确读取WAVE文件必须真正开始作为定位和识别RIFF子块的练习。 RIFF子文件有一个8字节的标题:标识符/名称字段4个字节,传统上用人类可读的ASCII字符(例如"fmt " )填充,4字节的小端无符号整数指定字节数子块的数据有效载荷 – 子块的数据有效载荷紧跟在它的8字节标题之后。

WAVE文件格式将某些子块标识符(或“名称”)保留为对WAVE格式有意义。 每个WAVE文件中至less必须出现两个子文件:

  1. "fmt " – 具有此标识符的子块具有有效载荷,该载荷描述audio格式的基本信息:采样率,比特深度等
  2. "data" – 具有该标识符的子块在其有效载荷中具有实际的audio字节

"fact"是下一个最常见的子块标识符。 它通常在使用压缩编解码器的WAVE文件中find,例如μ律。 查看这个爱好者网页 ,了解更多关于当前在野外使用的各种子块标识符的信息,以及关于它们的有效载荷结构的信息。

从纯RIFF的angular度来看,子文件不需要以任何特定的顺序出现在文件中,也不需要以任何特定的固定偏移量出现。 但实际上,几乎所有的软件都希望"fmt "子块是第一个子块。 这是实用性的一个让步:在数据stream的早期知道WAVE包含的audio格式是很方便的 – 例如,这使得从networkingstream播放波形文件变得更容易。 如果WAVE文件使用压缩格式,例如μ-law,则通常假定"fact"子块将直接出现在"fmt "

在指定格式的块之后,应该放弃关于子块位置,sorting和命名的假设。 此时,软件应该按名称(例如"data" )查找预期的子块。 如果遇到具有无法识别名称的子块(例如"FLLR" ),则应简单地忽略子块并忽略它们。 跳过子块需要读取其长度,以便跳过正确的字节数。

苹果用"FLLR"做的事情有点不寻常,我不惊讶有些软件被它"FLLR"了。 我怀疑你正在使用的图书馆根本没有准备处理"FLLR"子块的存在。 我会认为这是图书馆的一个缺陷。 图书馆作者犯的错误大概是这样的:

  1. 他们可能期望"data"子块出现在文件开头的前N个字节内,其中N小于〜4kB。 他们可能放弃寻找是否必须扫描太多的文件。 苹果"FLLR"子块将"data"子块推到文件中大于"FLLR"的位置。

  2. 他们可能期望"data"子块在RIFF内具有特定的序号子块位置或字节偏移量。 也许他们希望"data""fmt "之后立即出现。 不过,这是处理RIFF文件的不正确方法。 不应假定"data"子块的顺序位置和/或偏移位置。

只要我们谈论正确的WAVE文件处理,我不妨提醒大家,audio字节( data子块的有效载荷)可能不会完全运行到文件的末尾。 可以在data有效载荷之后插入子文件夹。 一些程序使用它来在文件末尾存储文本“注释”字段。 如果从data有效载荷的开始直到EOF盲目地读取,则可以将一些元数据子块作为audio引入,这在回放结束时听起来像是“点击”。 您需要尊重data子块的长度字段,并在消耗了整个数据有效负载后停止读取audio,而不是在您点击EOF时停止。

你在磁盘上录制的文件的名称是什么? 我有一个类似的问题,只是解决了.wav到我的文件名的末尾…我想AVAudioRecorder需要一个扩展来弄清楚事情。