如何在 iPhone 上使用音频单元

Posted

技术标签:

【中文标题】如何在 iPhone 上使用音频单元【英文标题】:How to use an Audio Unit on the iPhone 【发布时间】:2009-06-25 15:09:24 【问题描述】:

我正在寻找一种方法来更改录制的音频的音高,因为它被保存到磁盘或回放(实时)。我了解音频单元可用于此目的。 iPhone 对音频单元的支持有限(例如,据我所知,无法创建/使用自定义音频单元),但有几个开箱即用的音频单元可用,其中之一是 AUPitch。

我将如何使用音频单元(特别是 AUPitch)?您是否以某种方式将其连接到音频队列中?是否可以将音频单元链接在一起(例如,同时添加回声效果和音高变化)?

编辑:检查 iPhone SDK 标头后(我认为 AudioUnit.h,我现在不在 Mac 前),我注意到 AUPitch 已被注释掉。所以看起来 AUPitch 毕竟不能在 iPhone 上使用。

Apple 最近似乎在 developer.apple.com 上更好地组织了他们的 iPhone SDK 文档 - 现在更难找到对 AUPitch 等的引用。

也就是说,我仍然对在 iPhone 上使用音频单元(通常)的高质量答案感兴趣。

【问题讨论】:

【参考方案1】:

这里有一些非常好的资源 (http://michael.tyson.id.au/2008/11/04/using-remoteio-audio-unit/) 用于使用 RemoteIO 音频单元。根据我在 iPhone 上使用音频单元的经验,我发现我可以在回调函数中手动实现转换。这样做,您可能会发现这可以解决您的问题。

【讨论】:

【参考方案2】:

关于在 iPhone 上改变音调,OpenAL 是要走的路。查看 www.71squared.com 上的 SoundManager 类,了解支持音高的 OpenAL 声音引擎的一个很好的示例。

【讨论】:

请记住,OpenAL 只支持实时音频音高变化,意味着您无法保存更改后的音频【参考方案3】:
- (void)modifySpeedOf:(CFURLRef)inputURL byFactor:(float)factor andWriteTo:(CFURLRef)outputURL 

    ExtAudioFileRef inputFile = NULL;
    ExtAudioFileRef outputFile = NULL;

    AudiostreamBasicDescription destFormat;

    destFormat.mFormatID = kAudioFormatLinearPCM;
    destFormat.mFormatFlags = kAudioFormatFlagsCanonical;
    destFormat.mSampleRate = 44100 * factor;
    destFormat.mBytesPerPacket = 2;
    destFormat.mFramesPerPacket = 1;
    destFormat.mBytesPerFrame = 2;
    destFormat.mChannelsPerFrame = 1;
    destFormat.mBitsPerChannel = 16;
    destFormat.mReserved = 0;

    ExtAudioFileCreateWithURL(outputURL, kAudioFileCAFType,
                              &destFormat, NULL, kAudioFileFlags_EraseFile, &outputFile);

    ExtAudioFileOpenURL(inputURL, &inputFile);

    //find out how many frames is this file long
    SInt64 length = 0;
    UInt32 dataSize2 = (UInt32)sizeof(length);
    ExtAudioFileGetProperty(inputFile,
                            kExtAudioFileProperty_FileLengthFrames, &dataSize2, &length);

    SInt16 *buffer = (SInt16*)malloc(kBufferSize * sizeof(SInt16));

    UInt32 totalFramecount = 0;

    AudioBufferList bufferList;
    bufferList.mNumberBuffers = 1;
    bufferList.mBuffers[0].mNumberChannels = 1;
    bufferList.mBuffers[0].mData = buffer; // pointer to buffer of audio data
    bufferList.mBuffers[0].mDataByteSize = kBufferSize *
    sizeof(SInt16); // number of bytes in the buffer

    while(true) 

        UInt32 frameCount = kBufferSize * sizeof(SInt16) / 2;
        // Read a chunk of input
        ExtAudioFileRead(inputFile, &frameCount, &bufferList);
        totalFramecount += frameCount;

        if (!frameCount || totalFramecount >= length) 
            //termination condition
            break;
        
        ExtAudioFileWrite(outputFile, frameCount, &bufferList);
    

    free(buffer);

    ExtAudioFileDispose(inputFile);
    ExtAudioFileDispose(outputFile);


它将根据因素改变音高

【讨论】:

【参考方案4】:

我之前用过 NewTimePitch 音频单元,音频组件描述是

var newTimePitchDesc = AudioComponentDescription(componentType: kAudioUnitType_FormatConverter,
        componentSubType: kAudioUnitSubType_NewTimePitch,
        componentManufacturer: kAudioUnitManufacturer_Apple,
        componentFlags: 0,
        componentFlagsMask: 0)

然后您可以通过调用 AudioUnitSetParamater 来更改音高参数。例如,这会将音高更改 -1000 美分

err = AudioUnitSetParameter(newTimePitchAudioUnit,
        kNewTimePitchParam_Pitch,
        kAudioUnitScope_Global,
        0,
        -1000,
        0)

此音频单元的参数如下

    // Parameters for AUNewTimePitch
enum 
      // Global, rate, 1/32 -> 32.0, 1.0
  kNewTimePitchParam_Rate                         = 0,
      // Global, Cents, -2400 -> 2400, 1.0
  kNewTimePitchParam_Pitch                        = 1,
      // Global, generic, 3.0 -> 32.0, 8.0
  kNewTimePitchParam_Overlap                      = 4,
      // Global, Boolean, 0->1, 1
  kNewTimePitchParam_EnablePeakLocking            = 6
;

但您只需要更改音高参数即可。有关如何实现此功能的指南,请参阅贾斯汀的回答

【讨论】:

以上是关于如何在 iPhone 上使用音频单元的主要内容,如果未能解决你的问题,请参考以下文章

在 iPhone 上拆分音频单元流

如何在 iPad/iPhone 上通过蓝牙耳机录制音频?

如何在 iPhone 上录制 AMR 音频格式?

如何在 iPhone 扬声器上强制播放音频?

如何在 iPhone 上播放一排数字作为音频?

如何在 iPhone 上时移音频