代码之家  ›  专栏  ›  技术社区  ›  David Weiss

从iPhone上的线性PCM中提取振幅数据

  •  10
  • David Weiss  · 技术社区  · 14 年前

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

    我的问题是:

    1. 线性PCM将振幅样本存储为16位值。这是正确的吗?
    2. 音频文件readpacketdata()返回的数据包中如何存储振幅?当记录单线性PCM时,每个样本(在一帧中,在一个数据包中)是否只是用于SINT16的一个数组?字节顺序是什么(big-endian和little-endian)?
    3. 线性PCM振幅的每一步在物理上意味着什么?
    4. 在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!那就不行了 对我有感觉。

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

    // 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]);
    }
    

    感谢您提供的任何见解。这是我第一个使用核心音频的项目,所以请随意撕开我的方法!

    P.S.我试图搜索核心音频列表存档,但请求不断给出错误:( http://search.lists.apple.com/?q=linear+pcm+amplitude&cmd=Search%21&ul=coreaudio-api )

    P.P.S.我看过:

    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

    我还阅读了核心音频概述和大多数音频会话编程指南的全部内容,但我的问题仍然存在。

    2 回复  |  直到 13 年前
        1
  •  7
  •   justin    14 年前

    1)OS X/iPhone文件读取例程允许您确定样本格式,通常是用于lpcm的sint8、sint16、sint32、float32、float64或连续24位有符号int之一。

    2)对于int格式,min_代表负相位的最大振幅,max_代表正相位的最大振幅。0等于沉默。浮点格式在[-1…1]之间进行调制,0与float相同。当读取、写入、记录或使用特定格式时,endianness很重要-文件可能需要特定的格式,您通常希望在本机endianness中操作数据。Apple音频文件libs中的一些例程允许您传递一个表示源端顺序的标志,而不是手动转换它。CAF有点复杂——它就像一个或多个音频文件的元包装器,支持多种类型。

    3)LPCM的振幅表示只是一种强力线性振幅表示(回放不需要转换/解码,振幅步数相等)。

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

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

    您在代码级别犯的一个错误是:您将“outbuffer”作为chars来操作-而不是sint16

        2
  •  2
  •   hotpaw2    14 年前
    1. 如果您要求以您的记录格式提供16位样本,那么您将获得16位样本。但其他格式确实存在于许多核心音频录制/播放API中,并且可能存在于CAF文件格式中。

    2. 在mono中,您只需要得到一个有符号的16位整数数组。您可以在一些核心音频录制API中特别要求使用big或little endian。

    3. 除非要为特定设备型号的麦克风或外部麦克风进行校准(并确保已关闭音频处理/AGC),否则您可能需要将音频级别视为任意缩放。此外,响应也随麦克风方向性和音频而变化。

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