Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1075929 Posts in 44152 Topics- by 36120 Members - Latest Member: Royalhandstudios

December 29, 2014, 03:59:05 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Dynamic audio manipulation in AS3
Pages: [1]
Print
Author Topic: Dynamic audio manipulation in AS3  (Read 3417 times)
JMickle
Level 10
*****


lqikq come home


View Profile
« on: October 30, 2011, 02:16:01 PM »

OK so I'm actually pretty amateur at as3, mainly making stuff using flashpunk. I do know my way around it without pretty well, but not spectacularly good at any complicated stuff.

I've been thinking about doing a music based flash game, for instance including a collectable that played a sound at a specific pitch. But I want to avoid having lots of sound files at different pitches, because I am certain that it would be possible to just play the same sound at different frequencies.

I had a look at the sound functions in flash but the only things you APPEAR to be able to do are change the volume and pan of a sound.

What I _did_ find is the Sound.extract() function, which extracts the raw data into a bytearray. This excites me Smiley Maybe I could go into the data and say... delete every other byte resulting in a double speed (i.e one octave higher) sound?

Could anyone help me out? I'll be posting anything I find out as I go.
Logged

JMickle
Level 10
*****


lqikq come home


View Profile
« Reply #1 on: October 30, 2011, 02:47:47 PM »

my first experiment ended horribly in me crashing flash.

I attempted to extract the sound data from a sound file I created, then read every other byte into another sound object, as an attempt to double the pitch of the original sound.

Code:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Timer;

/**
* ...
* @author JMickle
*/
public class Main extends Sprite
{

public var tim:Timer = new Timer(1000, 3);
public var snd:Sound = new Sound(new URLRequest("http://dl.dropbox.com/u/8943931/snd.mp3"));
public var snd2:Sound = new Sound();



public function Main():void
{
tim.start();
tim.addEventListener(TimerEvent.TIMER, timeDone);

snd2.addEventListener(SampleDataEvent.SAMPLE_DATA, soundFunction);

}

public function timeDone(e:TimerEvent):void
{
if (tim.currentCount == 1) snd.play();
if (tim.currentCount == 2) snd2.play();
if (tim.currentCount == 3) snd.play();
}

public function soundFunction(e:SampleDataEvent):void
{
var bit:ByteArray = new ByteArray();
snd.extract(bit, 8192);
for (var i:int = 0; i < 8192; i += 2) {
e.data.writeFloat(bit.readFloat());
bit.position += 1;
}
}
}

}

This however doesn't work. Sad
Logged

Triplefox
Level 9
****



View Profile WWW Email
« Reply #2 on: October 30, 2011, 08:50:37 PM »

This should set you in the right direction.

1. Until Flash 11 the API for going between Sound and Bytearray was incomplete(could not construct a Sound on-the-fly). Shouldn't affect you, but one to know.
2. Flash achieves stereo sound by interleaving the two channels in a single stream. (byte 0 is left, byte 1 is right, etc.)
3. SampleDataEvent wants a certain minimum number of bytes in the buffer. You have to fill that many or more, or it's "unfinished."
Logged

dustin
Level 6
*


View Profile Email
« Reply #3 on: October 30, 2011, 11:15:45 PM »

This is all FP10 stuff fyi.  This is my custom sound class.  You give it a Sound and a number, the number corresponds to what note you want the sound to be (so 3 is a higher note then 2 is a higher note then 1).  The notes I picked were just the relative frequencies of a scale I liked and you can change them up and it should still work fine....

This is what a typical usage of it might look like...

new MySound(new Bang(), 3); //this creates and plays the bang sound with a note of 3

Code:
package
{

public class MySound
{

import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.utils.ByteArray;
var speed:Number = 1;

var notes:Array = [329.63,369.99,392,440,493.88,523.25,622.25];

public function set playbackSpeed(value:int):void
{
var base = notes[0];
var result = notes[value];
speed = result/base;


}

private var _mp3:Sound;
private var _loadedMP3Samples:ByteArray;
private var _dynamicSound:Sound;

private var _phase:Number;
private var _numSamples:int;

public function MySound(s:Sound,sp:int=0)
{
playLoadedSound(s);
var base = notes[0];

var result = notes[sp%notes.length];

speed = result/base;
if(sp>notes.length){
speed=speed*2;
}
trace("creating a sound");
}


public function playLoadedSound(s:Sound):void
{
var bytes:ByteArray = new ByteArray();
s.extract(bytes, int(s.length * 44.1));
play(bytes);

}

public function stop():void
{
if (_dynamicSound)
{
_dynamicSound.removeEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
_dynamicSound = null;
}
}



private function play(bytes:ByteArray):void
{
stop();
_dynamicSound = new Sound();
_dynamicSound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);

_loadedMP3Samples = bytes;
_numSamples = bytes.length / 8;

_phase = 0;
_dynamicSound.play();
}

private function onSampleData( event:SampleDataEvent ):void
{
var l:Number;
var r:Number;

var outputLength:int = 0;
while (outputLength < 2048)
{
// until we have filled up enough output buffer

// move to the correct location in our loaded samples ByteArray
_loadedMP3Samples.position = int(_phase) * 8;// 4 bytes per float and two channels so the actual position in the ByteArray is a factor of 8 bigger than the phase

// read out the left and right channels at this position
if(_loadedMP3Samples.position<_loadedMP3Samples.length){
l = _loadedMP3Samples.readFloat();
r = _loadedMP3Samples.readFloat();
}else{
_dynamicSound.removeEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);

l=0;
r=0;
}

// write the samples to our output buffer
event.data.writeFloat(l);
event.data.writeFloat(r);

outputLength++;

// advance the phase by the speed...
_phase +=  speed;

}
}

}

}

Hopefully that is somewhat helpful...
Logged
JMickle
Level 10
*****


lqikq come home


View Profile
« Reply #4 on: October 31, 2011, 11:13:14 AM »

@triplefox ah I this is useful information. i also had no clue about the stereo thing either.

@dustin I think you may be the best thing in existence right now :D thnsk!

EDIT: I can't seem to get it to work Sad

Code:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.utils.Timer;

/**
* ...
* @author JMickle
*/
public class Main extends Sprite
{

public var tim:Timer = new Timer(1000,7);
public var snd:Sound = new Sound(new URLRequest("http://dl.dropbox.com/u/8943931/snd.mp3"));



public function Main():void
{
tim.start();
tim.addEventListener(TimerEvent.TIMER, timeDone);


}

public function timeDone(e:TimerEvent):void
{
if (tim.currentCount == 1) snd.play();
if (tim.currentCount == 2) new MySound(snd, 0);
if (tim.currentCount == 3) new MySound(snd, 3);
if (tim.currentCount == 4) new MySound(new blip(), 5);
if (tim.currentCount == 5) new MySound(new blip(), 1);
}


}

}
I dropped it in like this, but I only hear the first two sounds, and not any others. the blip class is just an extended Sound class, that should act exactly the same as the snd...



EDIT2: found this: http://www.kelvinluck.com/2008/11/first-steps-with-flash-10-audio-programming/
« Last Edit: October 31, 2011, 11:29:53 AM by JMickle » Logged

SFBTom
Level 1
*



View Profile WWW
« Reply #5 on: November 01, 2011, 03:07:45 PM »

If the sounds are fairly simple videogame-ey sound effects, you might want to take a look at my as3sfxr library. It can generate and play sound effects at runtime, and changing the frequency is just one variable change. Pick your sound in the tool, then copy and paste it right into your code, done!

This should set you in the right direction.

1. Until Flash 11 the API for going between Sound and Bytearray was incomplete(could not construct a Sound on-the-fly). Shouldn't affect you, but one to know.
2. Flash achieves stereo sound by interleaving the two channels in a single stream. (byte 0 is left, byte 1 is right, etc.)
3. SampleDataEvent wants a certain minimum number of bytes in the buffer. You have to fill that many or more, or it's "unfinished."

Not quite right on 2 & 3.

2. It's actually alternating floats for each channel, which are 4 bytes each. So bytes 0-3 are the left channel, 4-7 are the right channel, 8-11 are left again and so on.

3. Its true that you need a minimum number of samples per event - 2048 samples in fact (1 sample is both floats for stereo channels, so 8 bytes per sample), but there's also a maximum: 8192 samples. The sweet spot however is 3072 samples, which gives you the best balance of short latency and fast execution. It's also worth noting that for any sound, the first number of samples you pass it must be matched every event, or the sound will be assumed to be over and will stop.
Logged

JMickle
Level 10
*****


lqikq come home


View Profile
« Reply #6 on: November 02, 2011, 10:49:20 AM »

@sfbtom- brilliant! I never thought about looking at as3fxr, even though it seems like an obvious choice now.

will report on how i get on with it
Logged

SFBTom
Level 1
*



View Profile WWW
« Reply #7 on: November 04, 2011, 01:38:23 PM »

@sfbtom- brilliant! I never thought about looking at as3fxr, even though it seems like an obvious choice now.

will report on how i get on with it

Cool! If you need any help, feel free to hit me up.
Logged

zamp
Level 1
*



View Profile
« Reply #8 on: November 05, 2011, 08:50:54 AM »

You might want to look at Standing Wave 3
You can easily add filters to sounds and much much more.

Quote
Standing Wave 3 is an AS3 code library designed for high level control of
the Flash Player's SampleDataEvent API for streaming audio output. It
is based on a subset of the audio engine used by the Noteflight Score
Editor (see http://www.noteflight.com).

The goal of StandingWave is to encapsulate the following kinds of
objects, permitting them to be easily chained together and combined to
produce complex, dynamic audio output:

- audio sources (MP3 or WAV files, algorithmic sound generators...)
- audio filters (echo, envelope shaping, equalization...)
- timed sequences of audio sources, which may be hierarchically composed
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic