Bits & Bytes

Posts Tagged ‘sound’

Generating Sounds in Actionscript 3.0

This program shows how to generate and play a sound. The generated sound is in the form of a sine wave, and it plays whenever the screen is clicked. Left-click the box above to hear the sound play.

The entire code to generate the sound is shown below. The first three lines just output the message “Click To Play.” The next two lines create a Sound object and an integer for the time. The two lines after that set callbacks for generating sound and responding to mouse clicks.

The rest of the program consists of the PlaySound() and Generator() functions. The PlaySound() function initializes the integer that keeps track of the sample time to 0 and then calls play() on the Sound object. The Generator() function writes 8192 samples at a time for the left and right channels; the generated sound is a sine wave that lasts half of a second, since sounds have 44100 samples per second.

// Output the initial instructions to user
var qInstructions:TextField = new TextField();
qInstructions.text = "Click To Play";
addChild(qInstructions);

var qSound:Sound = new Sound();
var iTime:int = 0;

qSound.addEventListener(SampleDataEvent.SAMPLE_DATA, Generator);
stage.addEventListener(MouseEvent.CLICK, PlaySound);

function PlaySound(e:Event):void {
	iTime = 0;
	qSound.play();
}

function Generator(event:SampleDataEvent):void {
	for (var i:int = 0; i < 8192; ++i) {
		// Play for half of a second
		if (iTime >= 22050) {
			return;
		}
		event.data.writeFloat(Math.sin(iTime/25));
		event.data.writeFloat(Math.cos(iTime/25));
		++iTime;
	}
}

Signal Processing Sound Data in Actionscript 3.0

This program demonstrates how to perform a signal processing operation on sound data and play it back. If you left-click the box above, you can hear the clip saying “XoaX.net” that I have been using in the other examples played at double speed. Note that if you want to hear the clip played a second time, you need to refresh the page.

The code is shown below. The first three lines output the “Click To Play” message. The next two lines create two Sound objects. The two lines after those set an event listener that is called when the file loads and then call load() to load the mp3 file.

The remaining code consists of three functions. The first function, FinishedLoading(), is called when the file is loaded since it was set as the callback. The FinishedLoading() function sets PlaySound() as a callback function for mouse clicks. Doing this prevents the PlaySound() from being called before the sound file is loaded.

The second function, PlaySound(), sets the DoubleSpeed() function as a callback when data is requested for the destination sound. Then it calls play(), which triggers a series of data requests as the sound plays.

The third function, DoubleSpeed(), calls the extract() function to retrieve data into the source byte array. Inside the while loop, each pair of source samples is averaged and then written into the destination array. Finally, the destination byte array is written back into the SampleDataEvent object.

// Output the initial instructions to user
var qInstructions:TextField = new TextField();
qInstructions.text = "Click To Play";
addChild(qInstructions);

var qSrc:Sound		= new Sound();
var qDest:Sound		= new Sound();

qSrc.addEventListener(Event.COMPLETE, FinishedLoading);
qSrc.load(new URLRequest("http://www.xoax.net/public/XoaXDotNet.mp3"));

function FinishedLoading(e:Event):void {
	stage.addEventListener(MouseEvent.CLICK, PlaySound);
}

function PlaySound(e:Event):void {
	qDest.addEventListener(SampleDataEvent.SAMPLE_DATA, DoubleSpeed);
	qDest.play();
}

function DoubleSpeed(e:SampleDataEvent) {
	var qSrcBytes:ByteArray = new ByteArray();
	qSrc.extract(qSrcBytes, 8192);
	var qDestBytes:ByteArray = new ByteArray();
	var dLeft:Number = 0;
	var dRight:Number = 0;
	qSrcBytes.position = 0;
	// Read and average two samples
	while (qSrcBytes.bytesAvailable > 0) {
		dLeft = qSrcBytes.readFloat();
		dRight = qSrcBytes.readFloat();
		if (qSrcBytes.bytesAvailable > 0) {
			dLeft = (dLeft + qSrcBytes.readFloat())/2.0;
			dRight = (dRight + qSrcBytes.readFloat())/2.0;
			qDestBytes.writeFloat(dLeft);
			qDestBytes.writeFloat(dRight);
		}
	}
	e.data.writeBytes(qDestBytes);
}

Graphing Sound Data Visualizations in Actionscript 3.0

This program demonstrates how to retrieve and graph a set of samples of sound data. To see the program run, left-click the box above.

The code begins with three lines to output the click instructions. The next three lines create a Sound object, load an mp3 file, and set a callback for when the sound finishes playing. Then we create a ByteArray to store the sound data and set the StartSound() function as a callback for left-clicks.

The rest of the code consists of functions. The StartSound() function begins playing the sound and sets the callback function StartFrame() to get called for every frame of the animation. The SoundFinished() function stops StartFrame() from receiving messages after the sound is finished playing.

The function StartFrame() retrieves the sound data and graphs it. It begins with a call to the static function computeSpectrum() that returns 512 sound samples, 256 for each channel, in the ByteArray qSignal. Next, it clears the old graphics and sets the line style to a green line of width 1 pixel, and calls DrawSignal() twice, once for each channel.

Finally, the DrawSignal() function graphs each of the 256 sound samples. The graph is centered at the y-value dCenterY and the amplitude is scaled by 50 pixels. The scaling means that the samples, which range between -1 and 1, are scaled to the range -50 to 50. We begin each graph with a call to moveTo() so that no line is written from the previous position.

// Output the initial instructions to user
var qInstructions:TextField = new TextField();
qInstructions.text = "Click To Play";
addChild(qInstructions);

var qSound:Sound = new Sound(); 
qSound.load(new URLRequest("http://www.xoax.net/public/XoaXDotNet.mp3"));
qSound.addEventListener(Event.SOUND_COMPLETE, SoundFinished);

var qSignal:ByteArray = new ByteArray();

stage.addEventListener(MouseEvent.CLICK, StartSound);

function StartSound(e:Event):void {
	var qSoundChannel:SoundChannel = qSound.play();
	addEventListener(Event.ENTER_FRAME, StartFrame);
}

function SoundFinished(e:Event):void { 
	removeEventListener(Event.ENTER_FRAME, StartFrame); 
}

function StartFrame(e:Event):void {
	// Get the data for the left and right channels
	SoundMixer.computeSpectrum(qSignal, false, 0);
	graphics.clear();
	graphics.lineStyle(1, 0x00FF00);
	// Graph the left channel on the top
	DrawSignal(50);
	// Graph the right channel on the bottom
	DrawSignal(150);
}

function DrawSignal(dCenterY:Number):void {
	graphics.moveTo(0, dCenterY + 50*qSignal.readFloat());
	for (var i:int = 1; i < 256; i++) { 
		graphics.lineTo(i, dCenterY + 50*qSignal.readFloat()); 
	}
}