views:

56

answers:

2

I'm trying to create a parametric equalizer in Flash. I've been looking for a way to read audio data and mess around with the samples before Flash plays them on the fly. Loading a sound in one Sound object and using Sound.extract() to read the data, processing it, then play a second second empty Sound object and writing the data to its sampleData event seems to be the way to do it (please correct me if I am wrong or there is a better way).

Is there a way to use Sound.extract() while the Sound object is still loading a sound file? I don't want to have to wait for the entire sound file to load before it plays. Unfortunately, whenever I use Sound.extract() while the Sound object is still loading, it returns a zero-length byte array.

Is there a way to wait for enough samples to load first before playing? I imagine I'd have the same problem again when the Flash movie eats through all the loaded samples while the sound file is still loading.

Here's a simplified version of my code. It's working so far, but only when I wait for the Sound object to fire an Event.COMPLETE event.

var inputSound:Sound = new Sound();
inputSound.load("somefile.mp3");
inputSound.addEventListener(Event.COMPLETE, loadComplete);

var outputSound:Sound = new Sound();
outputSound.addEventListener(SampleDataEvent.SAMPLE_DATA, processSamples);
var sc:SoundChannel;

/*if I called ouputSound.play() right now, it wouldn't work.*/

function loadComplete(e:Event) : void
{
    sc = outputSound.play();
}

function processSamples(e:SampleDataEvent) : void
{
    var samples:ByteArray = new ByteArray();
    var len:int = snd.extract(samples, 8192);
    var sample:Number;
    var i:int = 0;

    trace(len.toString());

    samples.position = 0;

    //TODO: Sound Processing here

    //The following code plays a sine wave over the input sound as a test

    while (samples.bytesAvailable)
    {
        i++;
        sample = samples.readFloat();
        sample += Math.sin(i * Math.PI / 256) * 0.5;
        e.data.writeFloat(sample);
        sample = samples.readFloat();
        sample += Math.sin(i * Math.PI / 256) * 0.5;
        e.data.writeFloat(sample);
    }
}

EDIT: If I try using the PROGRESS event, I'm going to need to do a lot more low level stuff to implement buffering and whatnot (anything else I need to account for?). Could someone help me out with that? Also, is there a way to tell the position of a sample in milliseconds? Do I have to assume that all sound files are 44.1 kHz stereo (they may not be), or is there a better way?

A: 

...............

fuck
Oh god damn it. Not a good day for me. I'll see if I can figure this out and I'll get back to you.
wryyyyyyyyyy
Well I tried that and got a little bit further. I'm still having trouble though. I need to keep track of where in the sound file I am in both milliseconds and sample numbers. Is there a way to convert from one to the other?
wryyyyyyyyyy
A: 

check out the solution in this post here

http://stackoverflow.com/questions/3250452/how-to-compute-viewport-from-scrollbar

You don't need to extract the entire track into a bytearray. You only really need to get what you need when you need it.

If you really want to extract the track in one go you can use

sound.extract(yourbytearray,sound.lenght*44.1)

// lenght *44.1 gives you the number of samples if the mp3 is encoded at 44100

one you have all your pcm data, in your processsamples handler instead of calling sound extract you would do something like

if(yourbytearray.bytesAvailable==0)
{
  yourbytearray.position==0
}

var left:Number = youbytearray.readFloat

var right:Number = youbytearray.readFloat

//process the left with eq

//process the right with eq

event.data.writeFloat(left);
event.data.writeFloat(right);

Extracting all the audio at once would probably be the easiest but you'll run into memory problem for mp3s longer than about 8 minutes.

On the whole samples milliseconds thing.....

bytearray.position / bytearray.lenght gives you where in the song you are.

Divide that by 44100 and it will give you the number of milliseconds.

Ask more questions if you need me to clear anything up

dubbeat
I have solved the main part of my problem by checking if there is enough data loaded to fill the sample buffer, and if not, it waits until 5000 ms of audio is available and outputs silence instead.However, is it safe to assume everything will be encoded in 44.1 kHz as I'm currently doing? The sound files will be user selected. If it's not safe to do so, is there an easy way to find the sample rate, and is there a way to change the sample rate of an empty sound object, or would I have to interpolate and convert it to 44.1 kHz on the fly?
wryyyyyyyyyy
90% of the time you'll find an mp3 is encoded at 44.1 but it's not always the case. You coulde read the mp3 header when your loading it and determine the encoding rate there to be safe
dubbeat