Quantcast
Channel: Fancy Rat Studios
Viewing all articles
Browse latest Browse all 10

Fun with cocosDenshion and Audio Metering [Update]

$
0
0

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.

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 =/.


Viewing all articles
Browse latest Browse all 10

Latest Images

Trending Articles





Latest Images