[AS3]SOUND MIXING – SING ALONG, RECORD AND SAVE

August 19, 2011 at 2:18 AM (Actionscript) (, , , , , )


The idea is to achieve sound mixing in actionscript…with actionscript’s recent ability to capture microphone data thought it would be apt to try this by building karaoke app in flash…

1. The background sound is loaded from a playlist..
2. On Click of ‘record’ button the microphone data is captured and mixed with audio playing in the background
3. On background audio finishes playing..the mixed audio encoded into wave and saved to local disk

How mixing of two sound tracks is achieved:
Lets say source_1 and source_2 are two audio tracks, to mix these two audios

var source_1_L:Number=source_1.readFloat();//left channel of audio source_1
var source_1_R:Number=source_1.readFloat();//right channel of audio source_1
var source_2_L:Number=source_1.readFloat();//left channel of audio source_2
var source_2_R:Number=source_1.readFloat();//right channel of audio source_2
var mixed_L:Number=source_1_L+source_2_L;/left channel of mixed audio track
var mixed_R:Number=source_1_R+source_2_R;/right channel of mixed audio track
//!-the added values should be between -1 to 1
//!-to make sure the aded values fall within the limits
mixed_L=mixed_L>1?1:(mixed_L<-1?-1:mixed_L);
mixed_R=mixed_R>1?1:(mixed_R<-1?-1:mixed_R);
//!- [OR]
var mixed_L:Number=(source_1_L/2)+(source_2_L/2);/left channel of mixed audio track
var mixed_R:Number=(source_1_R/2)+(source_2_R/2);/right channel of mixed audio track

//!-now,
 mixedTrack.writeFloat(mixed_L);//mixedTrack is a ByteArray where the mixed audio data is written
 mixedTrack.writeFloat(mixed_R);

Attaching a source and demo of simple karaoke app in flash(cs5):The source code is bit messy and this is not a full application
just proof of concept…
Download the source here:
Link 1:Karaoke.zip
Link 2:Karaoke.zip

Advertisements

23 Comments

  1. birenraon said,

    hi I am not able to get sounce code for this Karaoke can you please check it, its giving me virus. i need urgently to check sound mixing portions of it

  2. bataglia said,

    Found the solution:

    var player:WavSound = new WavSound(o);
    player.play();

  3. bataglia said,

    Don’t know if you received my previous comment. How can we playback the recorded data, before converting to wav or uploading to server?

    I’m using your function from here:

    function saveMixedTrack():void
    {
    var tim2:Number=flash.utils.getTimer()
    mixedTrack.position=0
    var o:ByteArray=enco.encode(mixedTrack,2)
    trace(“TIME_TO_ENCODE”,getTimer()-tim2)
    file.save(o,”sample.wav”);
    list.enabled=true;
    }

    where “o” byteArray is passed here:

    function playbackSampleHandler(event:SampleDataEvent):void
    {
    for (var i:int = 0; i < 8192; i++)
    {
    if (o.bytesAvailable < 4)
    {
    break
    }
    var sample:Number = o.readFloat();
    event.data.writeFloat(sample);
    event.data.writeFloat(sample);

    }

    The result is a sound distorted, it's the good one (microphone + bg audio) but very unclear and distorded.

    Thank you for your answer.
    R.

  4. Anonymous said,

    please let me know.

  5. Arvind said,

    Hi,

    Can anyone help me on mixing recorded sound and background video.

    Steps
    1. The background video is loaded from a playlist..
    2. On Click of โ€˜recordโ€™ button the microphone data is captured and mixed with audio/video playing in the background
    3. On background audio/video finishes playing..the mixed audio encoded into wave and saved to local disk

    It is urgent so please reply asap.

    • sathesh said,

      hi,

      your requirement is bit confusing:
      do you want to mix the audio of video with microphone input audio and save the video along with mixed audio or do you want to extract audio from video and mix it with microphone audio and save it as wave, without affecting the video file?

      • Arvind said,

        Hi Sathesh,

        First of all thanks for reply and sorry if my wording is confusing to you.
        My requirement is to “mix the audio of video with microphone input audio and save the video along with mixed audio”

        Regards

      • sathesh said,

        hi,

        If your app is adobe air based then you can use ffmpeg to achieve this..if its web app i don’t have a solution right now, let me find a solution and get back to you

      • Arvind said,

        Hi Sathesh,

        Thanks for reply, I am also planning for ffmpeg.
        If you have the ffmpeg commands to do that, please share with me.

        Regards

  6. Tom said,

    Hey, thanks so much for this. It’s exactly what I was looking for.

    I seem to be getting around a 0.5-1.0second lag with microphone recording when I listen back to exported file.

    any ideas?

    • Tom said,

      actually, its the other way around. Microphone samples are 1 second(ish) early.

  7. Anonymous said,

    Hi,

    can you please check my code here: http://wonderfl.net/c/gyTW
    Mixed sound is distorted after couple of seconds…
    How to fix it?

    Thanks in advance!

    • justflash said,

      hi,

      checked your code…

      issue 1:

      when extracting sound in a loop make sure you keep track of ‘startPosition’, startPosition is 0 when you call extract method firsttime without passing the startPosition parameter and there on it will keep track of amount of samples extracted and use that in next call, but for some reason it doesnt reset when the sound has completed playing, so when you call the extract method on same sound object next time its startposition is not reset to 0 instead it will be the total number of samples hence it returns you 0 when you try to extract it second time

      solution:
      just like buffers, channels.. store the startPosition of each sound object in a array and use it on extract method
      lets say epos is an array set it to zero in your playSound method and in onSoundData method use it like:

      lengths[i] = sounds[i].extract(buffers[i],BUFFER_SIZE,epos[i]);
      epos[i]+=lengths[i];

      issue 2:
      Distortion of sound…

      a) reset buffers[i][buffers[i]=new byteArray()] before populating it with extracted sound data(dont just set position to 0)..

      reason: let say first you are writing 1000 samples to buffers[0] next time lets say you have only 100 samples of data left ..if you just set the position to 0 it will just overwrite first 100 samples and retains the remaining old data…resulting in a junk sound

      b) when adding left and right channels make sure you have enough data to write:

      left += buffers[k].bytesAvailable>=4? buffers[k].readFloat():0;
      right += buffers[k].bytesAvailable>=4?buffers[k].readFloat():0;

      -sathesh

      • Anonymous said,

        Hi Sathesh,

        Thank you on great explanation ๐Ÿ™‚
        I already fixed code: http://wonderfl.net/c/sUqx

        a) This time I’m extracting sound only one time – at the beginning.
        When sounds stops ByteArray must be reseted at the position 0.
        Version with extraction on SampleDataEvent is also working ok.

        b) I am checking EOF with buffers[k].position < buffers[k].length
        Yours version is also working ๐Ÿ˜‰

        Thank you so much!

        – djankey

  8. Supriya Tenany said,

    Hi,

    Thanks for pointing the PHP code to me. I am finally able to save the byte array into a txt. How would I be able to play the byte array from the saved file again?

    • justflash said,

      you can save it as *.wav/or any format with which you have encoded the sound data… and call the file to play it again

      $fp = fopen( 'file.wav', 'wb' );
      fwrite( $fp, $GLOBALS[ 'HTTP_RAW_POST_DATA' ] );
      fclose( $fp );
      
  9. Supriya Tenany said,

    Hi,

    I am unable to POST byteArray to PHP. My AS is coded as you have mentioned, but since there was no PHP in your reply, I have coded it as:

    I get the following error:

    //****************************************
    TypeError: Error #1034: Type Coercion failed: cannot convert flash.events::IOErrorEvent@25f01159 to flash.errors.IOError.
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at flash.net::URLLoader/onComplete()
    //****************************************

    • justflash said,

      hi,
      The php code i pasted didnt appear[must have missed to paste it inside code tag]… here is a link for your reference:
      http://blog.joa-ebert.com/2006/05/01/save-bytearray-to-file-with-php/

      The error you have posted seems to be related to event definition…can you send me the code you are using so that i can check where things going wrong…

      -sathesh

      • chad said,

        Hi , Can you post the source code of the karaoke demo.. i am working on similar program and need to know the logic used in the demo app.

        thanks

  10. Supriya Tenany said,

    Hi,

    I often get this error, which the recorded audio is being mixed and saved.

    Error: Error #1502: A script has executed for longer than the default timeout period of 15 seconds.
    at org.bytearray.micrecorder.encoder::WaveEncoder/create()
    at org.bytearray.micrecorder.encoder::WaveEncoder/encode()
    at sound_mixing_v0_0_1_fla::MainTimeline/saveMixedTrack()
    at sound_mixing_v0_0_1_fla::MainTimeline/onSC()

    Since there is no control over how long a user can choose to record, how do I solve this error? I have increased the timeout considerably, but the wait period is really long and I havent seen anything happen for the past 10 min. What can be done?

  11. Supriya Tenany said,

    Hi,

    Thanks for the reply. I will make changes as you have suggested. Have more requirements to record a video and mix background score with the user video.

  12. Supriya Tenany said,

    Amazing piece of work!!! I am so relieved that I finally found a sound mixer. Is it possible to change the output format (instead of .wav) and upload directly to server?

    • justflash said,

      yes it is possible to upload directly to server:

      Here is an example of acheiving that using PHP

      once the wave data is generated instead of calling the fileReference object to save call below script to save it to server:
      //
      var request:URLRequest = new URLRequest ( ‘http://yourPath/saveSound.php’ );
      var loader: URLLoader = new URLLoader();
      request.contentType = ‘application/octet-stream’;
      request.method = URLRequestMethod.POST;
      request.data = bytes; //this will be the byteArray of wave data
      loader.load( request );

      //

      and saveWave.php will be like:

      //

      To change the output format we need a suitable encoder …for mp3 you can try this [https://github.com/kikko/Shine-MP3-Encoder-on-AS3-Alchemy]…this one converts a wav to mp3, so first you have to convert raw data to wav as in the demo, then encode that wav to a mp3 using the mentioned mp3 encoder…and pass the output bytearray to server as explained above

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: