Slice Tool & Looper

Source code available here
Note: This example uses Minimal Comps by Keith Peters
Audio by: Flying Lotus

Unlike other audio experiments I’ve been working on, this prototype uses pre-recorded audio. It extracts the raw byte data from an mp3 and draws each of the samples from left to right. The algorithm reads small chunks of the data on each frame and renders it. It is possible to read the entire track all at once but this causes they player to hang while it is calculating. The top render represents the selected portion of the audio track and the lower render represents the entire track. The slider allows you to vary the amount of detail in the rendered wave form. A value of 1 means that every single sample in the selected track is being rendered. For longer tracks, this can cause somewhat sluggish drawing. A value of 1000 means that every thousandth sample is being rendered, hence the waveform loses detail.

The basic algorithm for drawing chunks of audio data looks something like the following pseudo-code:

var n:Number;
var bytes:ByteArray = new ByteArray();
var length:int = position + CHUNK_SIZE < outsample ? CHUNK_SIZE  : outsample - position;
insound.extract( bytes, length, position );
bytes.position = 0;			
while( bytes.position < bytes.length )
{
	// -- average left and right channles
	n = bytes.readFloat() + bytes.readFloat();
	n *= .5;
		
	// -- this modulus allows us to only draw every other nth sample
	if( position % detail == 0 )
	{
		r.lineTo( xpos, n * 100 );
		xpos += lineLength;
	}
				
	// -- increment the position
	position ++;
}
			
if( position == outsample ) {
	// -- all done
	return;	
}

You can drag the little red in/out markers side to side to select the portion of the audio you want to loop. You can also drag the entire scrubber ( bluish area ) around. Pressing play causes the selected audio to begin looping. Previous to the dynamic sound features, achieving a seamless audio loop was nearly impossible on the Flash Platform. Now that we have the Sound.extract it is possible. Using extract in tandem with the Event.SOUND_COMPLETE event, a simple audio ring buffer can be created, as demonstrated by the pseudo-code below:

protected function play():void
{
	loopflag = false;
	outsound.addEventListener( SampleDataEvent.SAMPLE_DATA, onSampleData );
	channel = outsound.play();
	channel.addEventListener( Event.SOUND_COMPLETE, onSoundComplete );
}
		
// -- keep filling the buffer with data
protected function onSampleData( event:SampleDataEvent ):void
{
	var bytes:ByteArray = new ByteArray();
	var length:int = BUFFER_SIZE;
			
	if( loopflag ) return;
			
	if( position + event.position + BUFFER_SIZE > outsample ) 
        {
                // -- if the next iteration would extend beyond the current 
                // -- selection reset the length var so that only the number of 
                // -- samples to finish the loop are extracted
                length =  outsample - ( position + event.position );
                loopflag = true;
	}
			
	insound.extract( bytes, length, _position + event.position );		
	event.data.writeBytes( bytes );
}
		
// -- starts audio as soon as there are no more samples in the buffer
protected function onSoundComplete( event:Event ):void {
	play();
}

The above code snippets are just samples. Full source code is available at the makemachine google code repository.

Posted in Actionscript, Audio | Tagged , , , , , , , , , , , , , , , | 8 Comments

8 Responses to Slice Tool & Looper

  1. olivier says:

    Hi,
    Do you think we could implement the same solution for the m4a audio format?
    We need a solution that would work for both format mp3 and m4a
    Thank you

  2. Jeremy says:

    Hi Olivier,

    Good question. In general, yes the approach should work because after all, all that is really happening is that data is being spliced from one array and pushed into another. The “in and out” points of the loop are just a window over the original data. Your first task would be to find out if the Flash Player Sound object can load an mp4. I haven’t attempted this before. If it can, then there is one less step you will have to think about. If it can’t, you will need to load the file using another type of loader, probably the URLLoader. With this object you can load byte data. Once loaded you will need to parse the data from the ByteArray supplied by the loader. From there you could apply the same approach as I took in slicing mp3 data.

  3. olivier says:

    Hi Jeremy, thank you for your reply.
    Sound can’t open m4a files since different codec are used for mp3 and m4a.
    m4a can only be played in flash with NetStream class, so the question is can we manage the same from NetStream?

  4. Jeremy says:

    Ah, it is streaming… hmm.. Have you tried loading the entire file via the URLLoader as I mentioned? Or, you may be able to approximate the effect simply by seeking to in and out points. I am not experienced very experienced with the gritty details of the NetStream class. Good luck!

  5. Ricardo says:

    Could you upload the. Fla?
    thanks

  6. Jeremy says:

    There is no .fla file for this. Everything you see is generated with code. You can view that here.

  7. Ricardo says:

    Using Flash Builder, but not as import and call those classes. Can you help me? would greatly appreciate it.

  8. Dimitris says:

    I’ll try and make this to use workers that are now available in AS3!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>