Question

I'm looking for a way to change the pitch of recorded audio as it is saved to disk, or played back (in real time). I understand Audio Units can be used for this. The iPhone offers limited support for Audio Units (for example it's not possible to create/use custom audio units, as far as I can tell), but several out-of-the-box audio units are available, one of which is AUPitch.

How exactly would I use an audio unit (specifically AUPitch)? Do you hook it into an audio queue somehow? Is it possible to chain audio units together (for example, to simultaneously add an echo effect and a change in pitch)?

EDIT: After inspecting the iPhone SDK headers (I think AudioUnit.h, I'm not in front of a Mac at the moment), I noticed that AUPitch is commented out. So it doesn't look like AUPitch is available on the iPhone after all. weep weep

Apple seems to have better organized their iPhone SDK documentation at developer.apple.com of late - now its more difficult to find references to AUPitch, etc.

That said, I'm still interested in quality answers on using Audio Units (in general) on the iPhone.

Was it helpful?

Solution

There are some very good resources here (http://michael.tyson.id.au/2008/11/04/using-remoteio-audio-unit/) for using the RemoteIO Audio Unit. In my experience working with Audio Units on the iPhone, I've found that I can implement a transformation manually in the callback function. In doing so, you might find that solves you problem.

OTHER TIPS

Regarding changing pitch on the iPhone, OpenAL is the way to go. Check out the SoundManager class available from www.71squared.com for a great example of an OpenAL sound engine that supports pitch.

- (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);

}

it will change pitch based on factor

I've used the NewTimePitch audio unit for this before, the Audio Component Description for that is

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

then you can change the pitch parameter with an AudioUnitSetParamater call. For example this changes the pitch by -1000 cents

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

The parameters for this audio unit are as follows

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

but you'll only need to change the pitch parameter for your purposes. For a guide on how to implement this refer to Justin's answer

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top