Changing pitch of sound in realtime

edited April 2013

I have an engine sound that I want to loop and also adjust the pitch of dynamically.

Any idea how I would go about doing something like this? I see the ability to pan and change volume of a AEAudioFilePlayer object, but not pitch.

Any pointers would be appreciated!
Thanks.

Comments

  • You'll probably want to use one of the audio units, like kAudioUnitSubType_NewTimePitch, etc. If you need pre-iOS 6 compatibility, you might wanna take a look at Dirac.

  • Thanks for your help Michael. I've got it working now.

    kAudioUnitSubType_NewTimePitch seems to stretch the time of the sound but keep the pitch the same. kAudioUnitSubType_Varispeed actually does what I needed better.

    Here's the code I used to double the pitch.

    NSError *error = NULL;
    AEAudioUnitFilter *pitch
    = [[AEAudioUnitFilter alloc]
        initWithComponentDescription:AEAudioComponentDescriptionMake(kAudioUnitManufacturer_Apple,
                                                                     kAudioUnitType_FormatConverter,
                                                                     kAudioUnitSubType_Varispeed)
        audioController:_audioController
        error:&error];
    
    AudioUnitSetParameter(pitch.audioUnit, kAudioUnitScope_Global, 0, kVarispeedParam_PlaybackRate, 1.25, 0);
    
    [_audioController addFilter:pitch toChannel:track1];
    
  • edited January 2014

    Great!, but..

    Is it possible to change the sound pitch without changing the speed?

  • Dmitry,

    kNewTimePitchParam_Pitch

    should do the trick for you.

  • edited May 2014

    But it changes the speed and pitch (faster) every time I record.

     [_audioController addInputReceiver:_recorder];
        
        //Add Filter: Changing the pitch
        AEAudioUnitFilter *pitchFilter = [[AEAudioUnitFilter alloc]initWithComponentDescription:AEAudioComponentDescriptionMake(kAudioUnitManufacturer_Apple, kAudioUnitType_FormatConverter,
     kAudioUnitSubType_Varispeed) audioController:_audioController error:&error];
        AudioUnitSetParameter(pitchFilter.audioUnit,
     kAudioUnitScope_Global, 0, 
    kVarispeedParam_PlaybackRate, 1.25, 0);
        [_audioController addFilter:pitchFilter];
    

    Can it keep the speed at original recorded tempo while only altering (higher or lower) the pitch?
    ?

  • edited May 2014

    Solved

  • @anatol can you please tell us how did you solved it ? It would really help us

  • edited December 2014

    @ricky641b - even though it's a bit late, I'll post this for people searching for the answer - I implemented the NewTimePitch approach in TheGameSample Xcode project here: https://github.com/jcypher/TheAmazingAudioEngine/blob/master/TheGameSample/GameScene.swift - code snippet (in Swift) is:

    // This function shows how you can change both pitch and rate independently
        func _doAddNewTimePitchFilter(snd : AEAudioFilePlayer) { // you could add 2 parameters, one for rate and one for pitch
            
            // Make an AudioUnit based filter and use the NewTimePitch audio unit to change pitch AND rate at the same time!
            if let pitchFilter = AEAudioUnitFilter(componentDescription: AEAudioComponentDescriptionMake(
                OSType(kAudioUnitManufacturer_Apple),
                OSType(kAudioUnitType_FormatConverter),
                OSType(kAudioUnitSubType_NewTimePitch)),
                audioController: _audCtrlr, error:nil) {
                    
                    // Random time-stretch
                    var f = AudioUnitParameterValue(randomFloat()) * 0.3 // a value between 0 and 0.3
                    if randomFloat() > 0.5 {
                        f *= -1.0
                    }
                    var status = AudioUnitSetParameter(
                        pitchFilter.audioUnit,              // inUnit : AudioUnit
                        OSType(kNewTimePitchParam_Rate),    // inID: AudioUnitParameterID
                        OSType(kAudioUnitScope_Global),     // inScope: AudioUnitScope
                        0,                                  // inElement: AudioUnitElement
                        1.0 + f,                            // inValue: AudioUnitParameterValue
                        0);                                 // inBufferOffsetInFrames: UInt32
                    
                    if status == noErr {
                        
                        // Random pitch
                        let i = AudioUnitParameterValue(100 + arc4random_uniform(1100)) // we could do anything from 0 to 2400
                        let randomPitch = i * AudioUnitParameterValue((randomFloat() > 0.5 ? 1 : -1))
                        status = AudioUnitSetParameter(
                            pitchFilter.audioUnit,              // inUnit : AudioUnit
                            OSType(kNewTimePitchParam_Pitch),   // inID: AudioUnitParameterID
                            OSType(kAudioUnitScope_Global),     // inScope: AudioUnitScope
                            0,                                  // inElement: AudioUnitElement
                            randomPitch,                        // inValue: AudioUnitParameterValue, +/-2400
                            0);                                 // inBufferOffsetInFrames: UInt32
                        if status == noErr {
                            _audCtrlr.addFilter(pitchFilter, toChannel: snd)
                        }
                    }
            } // END if pitchFilter (NewTimePitch based)
        }
    
    

    (I'm typing this on my phone, else I'd clean the code up ;)

Sign In or Register to comment.