在 iPhone 上从线性 PCM 中提取幅度数据

Posted

技术标签:

【中文标题】在 iPhone 上从线性 PCM 中提取幅度数据【英文标题】:Extracting Amplitude Data from Linear PCM on the iPhone 【发布时间】:2010-09-30 17:50:52 【问题描述】:

我无法从 iPhone 上存储在 audio.caf 中的线性 PCM 中提取振幅数据。

我的问题是:

    线性 PCM 将幅度样本存储为 16 位值。这是正确的吗? AudioFileReadPacketData() 返回的数据包中如何存储幅度?录制单声道线性 PCM 时,每个样本(在一帧中,在一个数据包中)不只是 SInt16 的一个数组吗?字节顺序是什么(大端与小端)? 线性 PCM 幅度中的每一步在物理上意味着什么? 在iPhone上录制线性PCM时,中心点是0(SInt16)还是32768(UInt16)?物理波形/气压中的最大值最小值是什么意思?

还有一个额外的问题:是否存在 iPhone 麦克风无法测量的声音/气压波形?

我的代码如下:

// get the audio file proxy object for the audio
AudioFileID fileID;
AudioFileOpenURL((CFURLRef)audioURL, kAudioFileReadPermission, kAudioFileCAFType, &fileID);

// get the number of packets of audio data contained in the file
UInt64 totalPacketCount = [self packetCountForAudioFile:fileID];

// get the size of each packet for this audio file
UInt32 maxPacketSizeInBytes = [self packetSizeForAudioFile:fileID];

// setup to extract the audio data
Boolean inUseCache = false;
UInt32 numberOfPacketsToRead = 4410; // 0.1 seconds of data
UInt32 ioNumPackets = numberOfPacketsToRead;
UInt32 ioNumBytes = maxPacketSizeInBytes * ioNumPackets;
char *outBuffer = malloc(ioNumBytes);
memset(outBuffer, 0, ioNumBytes);

SInt16 signedMinAmplitude = -32768;
SInt16 signedCenterpoint = 0;
SInt16 signedMaxAmplitude = 32767;

SInt16 minAmplitude = signedMaxAmplitude;
SInt16 maxAmplitude = signedMinAmplitude;

// process each and every packet
for (UInt64 packetIndex = 0; packetIndex < totalPacketCount; packetIndex = packetIndex + ioNumPackets)

   // reset the number of packets to get
   ioNumPackets = numberOfPacketsToRead;

   AudioFileReadPacketData(fileID, inUseCache, &ioNumBytes, NULL, packetIndex, &ioNumPackets, outBuffer);

   for (UInt32 batchPacketIndex = 0; batchPacketIndex < ioNumPackets; batchPacketIndex++)
   
      SInt16 packetData = outBuffer[batchPacketIndex * maxPacketSizeInBytes];
      SInt16 absoluteValue = abs(packetData);

      if (absoluteValue < minAmplitude)  minAmplitude = absoluteValue; 
      if (absoluteValue > maxAmplitude)  maxAmplitude = absoluteValue; 
   


NSLog(@"minAmplitude: %hi", minAmplitude);
NSLog(@"maxAmplitude: %hi", maxAmplitude);

使用这段代码,我几乎总是得到最小值 0 和最大值 128!这使得没有 对我有感觉。

我正在使用 AVAudioRecorder 录制音频,如下所示:

// specify mono, 44.1 kHz, Linear PCM with Max Quality as recording format
NSDictionary *recordSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
   [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
   [NSNumber numberWithInt: kAudioFormatLinearPCM], AVFormatIDKey,
   [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
   [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
   nil];

// store the sound file in the app doc folder as calibration.caf
NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *audioFileURL = [NSURL fileURLWithPath:[documentsDir stringByAppendingPathComponent: @"audio.caf"]];

// create the audio recorder
NSError *createAudioRecorderError = nil;
AVAudioRecorder *newAudioRecorder = [[AVAudioRecorder alloc] initWithURL:audioFileURL settings:recordSettings error:&createAudioRecorderError];
[recordSettings release];

if (newAudioRecorder)

   // record the audio
   self.recorder = newAudioRecorder;
   [newAudioRecorder release];

   self.recorder.delegate = self;
   [self.recorder prepareToRecord];
   [self.recorder record];

else

   NSLog(@"%@", [createAudioRecorderError localizedDescription]);

感谢您提供的任何见解。这是我第一个使用 Core Audio 的项目,所以请随意拆解我的方法!

附:我曾尝试搜索 Core Audio 列表档案,但请求一直报错:(http://search.lists.apple.com/?q=linear+pcm+amplitude&cmd=Search%21&ul=coreaudio-api)

附言我看过:

http://en.wikipedia.org/wiki/Sound_pressure

http://en.wikipedia.org/wiki/Linear_PCM

http://wiki.multimedia.cx/index.php?title=PCM

Get the amplitude at a given time within a sound file?

http://music.columbia.edu/pipermail/music-dsp/2002-April/048341.html

我还阅读了完整的核心音频概述和大部分音频会话编程指南,但我的问题仍然存在。

【问题讨论】:

【参考方案1】:

1) os x/iphone 文件读取例程允许您确定样本格式,通常是 SInt8、SInt16、SInt32、Float32、Float64 或用于 LPCM 的连续 24 位有符号 int 之一

2) 对于 int 格式,MIN_FOR_TYPE 表示负相的最大幅度,MAX_FOR_TYPE 表示正相的最大幅度。 0 等于静音。浮点格式在 [-1...1] 之间调制,与浮点数一样为零。在读取、写入、记录或使用特定格式时,字节序很重要 - 文件可能需要特定格式,并且您通常希望以本机字节序处理数据。苹果音频文件库中的一些例程允许您传递表示源字节顺序的标志,而不是手动转换它。 CAF 有点复杂——它就像一个或多个音频文件的元包装器,并且支持多种类型。

3) lpcm 的幅度表示只是一个蛮力线性幅度表示(回放不需要转换/解码,幅度步长相等)。

4) 见#2。这些值与气压无关,它们与 0 dBFS 相关;例如如果您将流直接输出到 DAC,则 int max(如果是浮点,则为 -1/1)表示单个样本将剪辑的电平。

Bonus)它,就像每个 ADC 和组件链在电压方面对它可以处理的输入有限制。此外,采样率定义了可以捕获的最高频率(最高为采样率的一半)。 ADC 可以使用固定或可选择的位深度,但在选择另一个位深度时最大输入电压通常不会改变。

您在代码级别犯的一个错误:您将 `outBuffer' 操作为字符 - 而不是 SInt16

【讨论】:

【参考方案2】:

    如果您要求录制格式中的 16 位样本,那么您将获得 16 位样本。但其他格式确实存在于许多 Core Audio 录制/播放 API 以及可能的 caf 文件格式中。

    在单声道中,您只会得到一个带符号的 16 位整数数组。您可以在某些 Core Audio 录音 API 中专门要求大端或小端。

    除非您要针对特定​​设备型号的麦克风或外部麦克风进行校准(并确保音频处理/AGC 已关闭),否则您可能需要考虑任意缩放音频电平。此外,响应也会随着麦克风的指向性和音频频率而变化。

    16 位音频样本的中心点通常为 0(范围约为 -32k 到 32k)。没有偏见。

【讨论】:

以上是关于在 iPhone 上从线性 PCM 中提取幅度数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Node.js 上从 Web Audio API 播放 PCM 流

使用 Core Audio 从 PCM 原始数据中获取电平值

PCM编码格式

从 MPG123 输出中提取左声道 PCM 数据

如何从网站上从 ESRI Arcgis 抓取/提取数据?

从幅度样本创建音频文件