mixing 2 sounds from ByteArray
Asked Answered
B

3

6

I have build a mixer and save all the sequence in an array and then play it again, now I want to save the mix as an MP3, I have looked for any way to save the mix and the answer is to load the sounds as byteArrays (sound.extract) I have acomplish that but I don't really know how to store all the sounds in just one ByteArray in order to save it as MP3, I got this code just for example, loading 2 audio files and store them in separate ByteArrays, and play each sound, does any body know how to store the 2 byteArrays in just one?

var mySound:Sound = new Sound(); 
var sourceSnd:Sound = new Sound(); 
var urlReq:URLRequest = new URLRequest("Track1.mp3"); 
sourceSnd.load(urlReq); 
sourceSnd.addEventListener(Event.COMPLETE, loaded); 
function loaded(event:Event):void 
{ 
    mySound.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound); 
    //mySound.play(); 
} 

var mySound2:Sound = new Sound(); 
var sourceSnd2:Sound = new Sound(); 
var urlReq2:URLRequest = new URLRequest("Track2.mp3"); 
sourceSnd2.load(urlReq2); 
sourceSnd2.addEventListener(Event.COMPLETE, loaded2); 
function loaded2(event:Event):void 
{ 
    mySound2.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound2); 
    mySound2.play(); 
    mySound.play(); 
} 



function processSound(event:SampleDataEvent):void 
{ 
        var bytes:ByteArray = new ByteArray(); 
        sourceSnd.extract(bytes, 8192); 
    event.data.writeBytes(bytes); 
} 

function processSound2(event:SampleDataEvent):void 
{ 
        var bytes:ByteArray = new ByteArray(); 
        sourceSnd2.extract(bytes, 8192); 
    event.data.writeBytes(bytes); 
} 
Belier answered 28/3, 2011 at 0:12 Comment(1)
Hey luosKrad, I'm having the same challenges you had when you asked this question, could you share some light. What was your final solution, and what could you NOT solve. Thank you !Lamellirostral
C
7

been working on a similar system for a while, I'll do my best to give you some direction:

Your example code is not really mixing the MP3's - it's creating 2 more sounds to playback the loaded MP3's via the SampleDataEvent. What you need to do is create just one "output" Sound file that will hold/playback the resulting mixed sound. You can easily save that data as it happens and subsequently save that file as a new WAV/MP3/what-have-you.

real/psuedo-code (read:lazy) :

output = new Sound();

output.addEventListener( SampleDataEvent.SAMPLE_DATA , mixAudio );

song1 = new Sound / load the first mp3

song2 = new Sound / load the second mp3

// a byteArray for "recording" the output and subsequent file creation
recordedBytes = new ByteArray();

either wait until both mp3's are completely loaded, or run an enter-frame to determine when both Sounds are no longer buffering (Sound.isBuffering )

when the mp3's are ready:

// numbers to store some values

var left1:Number;
var right1:Number;

var left2:Number;
var right2:Number;

// bytearrays for extracting and mixing
var bytes1:ByteArray = new ByteArray( );
var bytes2:ByteArray = new ByteArray( );

// start the show
output.play();


function mixAudio( e:SampleDataEvent ):void{
  //set bytearray positions to 0

  bytes1.position = 0;
  bytes2.position = 0;

  //extract

  song1.extract( bytes1, 8192 );
  song2.extract( bytes2, 8192 );

  // reset bytearray positions to 0 for reading the floats

  bytes1.position = 0;
  bytes2.position = 0;

  // run through all the bytes/floats

  var b:int = 0;

  while( b < 8192 ){

     left1 = bytes1.readFloat();  // gets "left" signal
     right1 = bytes1.readFloat(); // gets "right" signal

     left2 = bytes2.readFloat();
     right2 = bytes2.readFloat();


     // mix!

     var newLeft:Number = ( left1 + left2 ) * .5; 
     var newRight:Number = ( right1 + right2 ) * .5;

     // write the new stuff to the output sound's

     e.data.writeFloat( newLeft );
     e.data.writeFloat( newRight );

     // write numbers to the "recording" byteArray
     recordedBytes.writeFloat( newLeft );
     recordedBytes.writeFloat( newRight );

     b++;

  }
}

Yes - you should really cap the possible output at -1/1. Do it. This is extremely un-optimized!

Ok. so that's the easy part! The tough part is really converting the final byteArray to MP3. The audio exists within Flash as PCM/uncompressed data, MP3 is obviously a compressed format. This "answer" is already way too long and all this info I've gleaned from several very smart folks.

You can easily adapt 'MicRecorder' to be a generic Sound data recorder: http://www.bytearray.org/?p=1858

converting to MP3 will be a bitch: Thibault has another post on ByteArray.org - search for LAME MP3.

Excellent example/resource: http://www.anttikupila.com/flash/soundfx-out-of-the-box-audio-filters-with-actionscript-3/

Look up Andre Michelle's open source 'Tonfall' project on Google code.

Look up Kevin Goldsmith's blog and labs - he's got great example on utilizing Pixel Bender with all this madness.

hope this helps!

PS - taking a cue from Andre, the optimal length of the audio buffer should be 3072. Give it a try on your machine!

Cataplasia answered 29/3, 2011 at 16:43 Comment(3)
Hey Nick, thanks for all the info I will try with your pseudoCode, about how to save the MP3 I have solved that with a library from fr.kikko github.com/kikko/Shine-MP3-Encoder-on-AS3-Alchemy My next step is to use the pixel blenderBelier
About the MicRecorder I used this as my first option and it workded beautifull but I realized that only my Lap had a microphone installed on the soundboard and it uses as a mic line so in other users won't work check this file: grupoogl.com/beat/wav2mp3/ATR_Recorder.swfBelier
Hey luosKrad, I'm having the same challenges you had when you asked this question, could you share some light. What was your final solution, and what could you NOT solve. Thank you !Lamellirostral
L
2

If I understand your question properly, you need read the floating point data for each sample, sum them, and write the resulting value into your new audio stream. This would give a stright 50/50 mix.

I don't have access to a machine with a compiler right now, but it should be something like this (assuming bytes1 and bytes2 are two ByteArray objects of equal length):

for (int bcnt = bytes1.size(); bcnt; bcnt--)
    bytes1.setByte(bcnt - 1, bytes2.getByte(bcnt - 1) + bytes1.getByte(bcnt - 1));

Of course, you would probably want to do some sort of overflow check, but that should be enough to put you on the right track.

Luci answered 28/3, 2011 at 0:18 Comment(1)
Yes, I also think that if I sum and write should work but I'm not sure how to do the sum of the byeArrays how to extract the bytes from each byteArray and then how to sum them, thats the thing I don't understandBelier
F
0

if you have uncompressed audio, you can just add up the values of individual array elements in your ByteArray's. But you also have to handle capping for max/min values (no overflows). Pretty sure there is nothing equivalent for mixing MP3s - so you might have to decode, mix, and encode to MP3 again.

Faxen answered 28/3, 2011 at 0:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.