Fancy Rat Studios

  • Home
  • Games
  • About

05
Feb
2010

Fun with cocosDenshion and Audio Metering [Update]

Lam

For those of you that have gotten a chance to use CocosDenshion, it is the sound engine written by Steve Oldmeadow.
It’s great since loading audio effects and music for us was quite a task beforehand.

Here’s a little demo of what we are going to make in this article shown running on the iPhone simulator.

Well today what we’ll look at is the CDAudioManager class of the CocosDenshion package itself and see if we can produce some neat effects to spice up our games.

Let’s understand CDAudioManager a bit by looking at the comments in the source.

/** CDAudioManager is a wrapper around AVAudioPlayer.
 CDAudioManager is basically a thin wrapper around an AVAudioPlayer object used for playing
 background music and a CDSoundEngine object used for playing sound effects. It manages the
 audio session for you deals with audio session interruption. It is fairly low level and it
 is expected you have some understanding of the underlying technologies. For example, for
 many use cases regarding background music it is expected you will work directly with the
 backgroundMusic AVAudioPlayer which is exposed as a property.

 Requirements:
 - Firmware: OS 2.2 or greater
 - Files: CDAudioManager.*, CocosDenshion.*
 - Frameworks: OpenAL, AudioToolbox, AVFoundation
 @since v0.8
 */

Since it’s a wrapper around AVAudioPlayer we have some functionality for obtaining data that you can use for playback-level metering.

The methods to use for level metering are:

  • the meteringEnabled property
  • -(void)updateMeters
  • -(float)averagePowerForChannel:(NSUInteger)channelNumber
  • -(float)peakPowerForChannel:(NSUInteger)channelNumber

Since we’re just quickly setting up some background audio, let’s do this as simple as possible by using SimpleAudioEngine.

Accessing CDAudioManager

SimpleAudioEngine (as of this post) won’t give us direct access to the audio manager for our background music so let’s quickly add a get method to return the audio manager.

SimpleAudioEngine.m

-(CDAudioManager*)audioManager
{
	return am;
}

Update: The alternative for accessing is through the sharedInstance of audio manager and I’ve now reworked the code to use that instead. So now you don’t need to modify SimpleAudioEngine anymore.

We needed access to CDAudioManager so we can get access to AVAudioPlayer to access metering methods. We do this below:

Updated for performance by weak referencing the AVAudioPlayer instance into a class variable.

audioPlayer_ = [[SimpleAudioEngine sharedEngine] audioManager].backgroundMusic;
audioPlayer_.meteringEnabled = YES;

Well we have enabled metering but what we now need to do is call updateMeters every time we need
to get meter level values. Cocos2D has functionality for scheduling timers so we set that up and call updateMeters.

-(void)tick:(ccTime) dt
{
	[audioPlayer_ updateMeters];
}

While still in the loop where we update our meter, we can now get values for the average and peak power of our background music.

-(void)tick:(ccTime) dt
{
	[audioPlayer_ updateMeters];
	double peakPowerForChannel = 0.f, avgPowerForChannel = 0.f;

	for(ushort i = 0; i < audioPlayer_.numberOfChannels; ++i){
		//	convert the -160 to 0 dB to [0..1] range
		peakPowerForChannel = pow(10, (0.05 * [audioPlayer_ peakPowerForChannel:i]));
		avgPowerForChannel = pow(10, (0.05 * [audioPlayer_ averagePowerForChannel:i]));

		filteredPeak_[i] = filterSmooth_ * peakPowerForChannel + (1.0 - filterSmooth_) * filteredPeak_[i];
		filteredAverage_[i] = filterSmooth_ * avgPowerForChannel + (1.0 - filterSmooth_) * filteredAverage_[i];
	}
}

What I’ve done is set all this up in the class AudioVisualization which will handle all the background audio metering for you. You access the class through the sharedAV method which returns a shared singleton instance.

All you need to do is add your delegate with the method:

-(void)addDelegate:(id<AudioVisualizationProtocol>)delegate forChannel:(ushort)channel;

The forChannel argument specifies the channel you want to meter for your background music. If it is mono then just set it to 0.

Now you just need to implement one of the AudioVisualizationProtocol‘s to receive level values for your delegate.

-(void)avAvgPowerLevelDidChange:(float)level channel:(ushort)aChannel;

That’s pretty much it! Hope you find this as cool as I did when I figured it out.

Just download the example demo file below to try it out.


Download the XCode Demo

This demo uses the fast, easy and open source cocos2d framework.
CocosDenshion is the sound engine for the cocos2d framework if you didn’t know that from reading this whole post =/.

You can leave a response, or trackback from your own site.

24 Conversations

  1. Terrance says:
    February 5, 2010 at 11:23 pm

    I plan to make a demo video to help show what the demo code can do, stay tuned.

  2. Dance, cocos2d, dance | cocos2d for iPhone says:
    February 11, 2010 at 8:17 pm

    [...] can read the article here: Fun with CocosDenshion and audio metering And you can download the test project from here: [...]

  3. George Sealy says:
    February 11, 2010 at 9:43 pm

    Nicely written and very useful! Thanks for the tutorial.

  4. Awesome Fun Music-Synced Animation With Video And Code | iPhone Development Tutorials and Programming Tips says:
    February 13, 2010 at 12:54 am

    [...] The full tutorial and code can be found here: Fun with cocosDenshion and Audio Metering [...]

  5. John From Berkeley » links for 2010-02-26 says:
    February 26, 2010 at 5:38 pm

    [...] Fun with cocosDenshion and Audio Metering [Update] | Fancy Rat Studios (tags: music iphone animation programming tutorials opensource) [...]

  6. Weekly Digest for March 16th says:
    March 16, 2010 at 5:31 am

    [...] Fun with cocosDenshion and Audio Metering [Update] | Fancy Rat Studios [...]

  7. Alex says:
    June 3, 2010 at 4:45 pm

    Is there away to select a sound from the iTunes music library rather than embedded song?

  8. Lam says:
    June 3, 2010 at 6:47 pm

    As of right now the way to play music off of the devices library is through the MPMediaPickerController. It’s quite an easy class to setup and get music running. Unfortunately the class does not connect itself with the AVAudioFoundation class which is what we’re using to run the metering code in this post but it if that’s not what you’re looking for then that is the best solution.

  9. ratt says:
    September 16, 2010 at 10:42 am

    Is there a way to use cocosDenshion to start up a background music file at a position other than the start of the song? For instance if I have one track playing and it has played 1:02 minutes, and I want to switch songs but the new one to start at 1:02 minutes (doesnt have to be seamless), is that possible?

  10. Le Quang Vinh says:
    February 11, 2011 at 3:15 am

    Hi Lam,
    I try this your tutorial. How to return positive decibel value?
    [bg averagePowerForChannel:i] : -160 -> 0
    avgPowerForChannel = pow(10, (0.05 * [bg averagePowerForChannel:i]));
    avgPowerForChannel -> [0,1].

    Can you help me return positive decibel value please ?
    Thanks so much !!!

  11. Taz Cole says:
    March 11, 2011 at 6:51 am

    I have updated the original code to work with V0.99.5 of Cocos2d for iPhone.

    You can Download a zip of the updated project from here http://www.silverbacktechsol.co.uk/blogresources/DenshionAudioVisualDemo.zip

  12. Ahsan says:
    April 14, 2011 at 5:46 am

    Hi Lam

    I am facing the problem when I remove the delegate and add the delegate again! I get level = 0.0 in avAvgPowerLevelDidChange.

    Do I need to do something after removing the delegate and before adding it again?

    Thanks
    Ahsan

  13. Lam says:
    April 14, 2011 at 8:08 am

    Logically it should be as simple as adding the instance since addDelegate places the instance into a list and that list is used to notify everyone. There shouldn’t really be any other needed steps.

  14. Ahsan says:
    April 15, 2011 at 12:50 am

    Hi
    I just needed to resetMetering after starting the background music.
    Something like:

    [[SimpleAudioEngine sharedEngine] playBackgroundMusic:fullPath loop:YES];
    [[AudioVisualization sharedAV] resetMetering];
    [[AudioVisualization sharedAV] addDelegate:self forChannel:0];

    Thanks!
    Regards
    Ahsan

  15. Reggie says:
    April 17, 2011 at 1:58 pm

    As of right now the way to play music off of the devices library is through the MPMediaPickerController. It’s quite an easy class to setup and get music running. Unfortunately the class does not connect itself with the AVAudioFoundation class which is what we’re using to run the metering code in this post but it if that’s not what you’re looking for then that is the best solution.
    +1

  16. Lahiru says:
    May 25, 2011 at 10:46 pm

    So, is there no way to run the metering code with a song played from the itunes library?

    Thanks!

  17. Lam says:
    May 26, 2011 at 9:30 am

    Yeah music played through iTunes does not go through AVAudioPlayer so metering can’t be done.

  18. Magic Black Lotus says:
    October 3, 2011 at 2:48 pm

    Black Lotus MTG…

    [...]Fun with cocosDenshion and Audio Metering [Update] | Fancy Rat Studios[...]…

  19. German says:
    October 7, 2011 at 4:30 pm

    Hello…I need somebody who can help me with this…It is possible to make the audio-meter works with music played through iTunes in the ipod (the music stored in the ipod)???…I mean…is there any other possibility to do that??? No just it was made here in this app with AVAudioPlayer…I really need your help with that guys…thank you.

  20. Lam says:
    October 8, 2011 at 11:25 am

    I haven’t looked into it much but I did recall that someone was able to use their ipod library music to create a rhythm game using AVAsset.
    Take a look into into that to see if it helps you.

  21. German says:
    October 9, 2011 at 7:26 pm

    Thank you Lam,I’ll see it…if you find anything else please let me know…thank you again.

  22. FaB. W says:
    February 13, 2012 at 5:06 pm

    Hello !

    I tried with an another music (a caf file with same properties as the one with the demo) but some time the values from avg power and peak power goes wild, they’ren’t between 0 and 1 but more like ~ inf.

    I’m wondering why ? any idea ?

    Thanks !

  23. Lam says:
    February 13, 2012 at 6:44 pm

    I haven’t tried with caf files yet though there may be some issue with the format and AVAudioFoundation but nothing that I know of an answer.

  24. Risa Dratch says:
    May 17, 2012 at 12:37 am

    Great information :)

Converse

Click here to cancel reply.

Games

  • Mini Games

Community

  • About
  • Contact

Sitemap

  • Blog
  • RSS FeedSubscribe in a reader
  • XHTML Strict 1.0

Fancy Rat Studios is proudly powered by WordPress 3.1

Background image courtesy of robertvitulano

© 2010 Fancy Rat Studios. All Rights Reserved.