Play Multiple iPod Library Songs On iPhone At The Same Time With Pitch Bending & Other Effects

1.8k views Asked by At

I have been going at this for the past two weeks and it is driving me crazy. I asked this question a couple of days ago (Extract iPod Library raw PCM samples and play with sound effects) and whilst the answer got me half way there I am still stuck.

Basically what I am trying to achieve is load up multiple songs from the iPod library for playback with effects such as pitch bend, eq effects etc...

I have gone down the route of AVPlayer and AVAudioPlayer which are too simple. The only framework I've seen that can play audio with these effects is OpenAL. I have tried a few objective c wrappers (Finch and ObjectAL) Finch does not play compressed audio whilst ObjectAL will only convert it for me if I pass in a URL for the file (which is something I cannot do because I only have an incompatible iPod library URL).

An example of an app that does what I want beautifilly is Tap DJ. It can load up songs from the iPod library fast (unlike TouchDJ and it plays them with all sorts of effects.

Any help would be much appreciated.

1

There are 1 answers

1
Karl On

If you can get the audio data into the raw PCM format that OpenAL likes, you can load it into ObjectAL.

What you need is:

  • The audio data
  • The size in bytes of the data
  • The format of the data (AL_FORMAT_MONO16 or AL_FORMAT_STEREO16)
  • The sample rate

You'll also need an ALSource to play the buffer. If you're using this alongside of OALSimpleAudio (recommended since it will handle devices and contexts for you), you'll need to tell it not to take all of the available sources:

[OALSimpleAudio sharedInstance].reservedSources = 20; // or some number < 32

Create the source (should do this in init):

mySource = [[ALSource source] retain];

You can create an ALBuffer with your custom data like so:

ALBuffer* myBuffer = [ALBuffer bufferWithName:someName
                           data:myAudioData
                           size:audioDataSizeInBytes
                         format:audioFormat
                      frequency:sampleRateInHz];

Now you can play:

[mySource play:myBuffer];

Edit: ALBuffer takes over management of the audio data and will call free() on it when it gets deallocated. So be careful not to double-free :)

Edit 2: I just added "freeDataOnDestroy" property to ALBuffer so you can now control whether it frees the data or not (defaults to YES).

Edit 3: Screw it. I'm going this far, might as well go all the way. Added "playBuffer" method to OALSimpleAudio.

So now you can just stay in OALSimpleAudio for the whole thing:

myBuffer = [[ALBuffer bufferWithName:someName
                           data:myAudioData
                           size:audioDataSizeInBytes
                         format:audioFormat
                      frequency:sampleRateInHz] retain];

...

id<ALSoundSource> source = [[OALSimpleAudio sharedInstance] playBuffer:myBuffer
                                                                volume:1.0
                                                                 pitch:1.0
                                                                   pan:0
                                                                  loop:NO];

[source pitchTo:2.0
       duration:5.0
         target:nil
       selector:nil];
// And so on...