Recording and playback actions with AS3

754 Views Asked by At

i am making a drawing app which allow users to draw freely on the canvas, there will be sound coming out on certain range of coordinates x,y. my goal is to allow users to record and playback the whole actions later on and watch it like a video. I am able to make the drawing strokes working though, but i have problems regarding the recording and playback part, especially recording of the internal audio. i have searched around for very long and i found this very similar to my concept

this is one of the great example that i have found which is done by ronnie http://ronnieswietek.com/piano/piano_example.swf the source: http://ronnieswietek.com/piano/piano_example.fla

is there any way for me to replace the piano keys as drawing strokes which generate sounds based on coordinates and record and playback the strokes and sounds just like the example?

I am stuck and confused trying to figure out a way to do it..

1

There are 1 best solutions below

2
On

If you can execute code to do your draw strokes, then all you need to do is timestamp the execution of those stroke commands. There are a number of ways you could approach this. I've written an example (just for you).

You can paste this into a new Flash document and run it.

/* First we'll create some variables */

var recording:Array = new Array(); // This is where we'll store all the instances of user action.
var playStart:Number = 0; // Playback will depend on whether this variable is greater than 0.
stage.addEventListener(Event.ENTER_FRAME, tic); // This will run once every frame update.

/* Next we'll create some helper functions */

function createButton(name:String, hue:uint):MovieClip {
    // We'll use this to make some fancy buttons.
    var box:MovieClip = new MovieClip();
    var shape:Sprite = new Sprite();
    shape.graphics.beginFill(hue);
    shape.graphics.drawRect(0, 0, 100, 25);
    box.addChild(shape);

    var txt:TextField = new TextField();
    txt.text = name;
    txt.x = 10;
    txt.y = 3;
    txt.mouseEnabled = false;
    box.addChild(txt);

    return box;
}

function drawCircle(X:Number, Y:Number, Hue:uint = 0x000000):void {
    // This creates circles on stage.
    var circle:Shape = new Shape();
    circle.graphics.beginFill(Hue);
    circle.graphics.drawCircle(0, 0, 10);
    circle.graphics.endFill();
    circle.x = X;
    circle.y = Y;
    addChild(circle);
}


/* Now lets create some buttons; Record, Stop, and Play. And rig'em up to some actions. */

var recordBtn:MovieClip = createButton("Record", 0x10ab00);
addChild(recordBtn);
recordBtn.addEventListener("mouseUp", startRecording);

var stopRecordBtn:MovieClip = createButton("Stop", 0xe90000);
stopRecordBtn.x = 101;
addChild(stopRecordBtn);
stopRecordBtn.addEventListener("mouseUp", stopRecording);

var playBtn:MovieClip = createButton("Play", 0x0069ab);
playBtn.x = 202;
addChild(playBtn);
playBtn.addEventListener("mouseUp", playRecording);


/* In the same order, we'll create those functions */

function startRecording(e:Event):void {
    // Here we'll store a timestampe of when the recording started.
    recording[0] = flash.utils.getTimer();
    // Register for mouseclicks on the stage; we need some kind of input to track.
    stage.addEventListener("mouseUp", recordAction);
}

function stopRecording(e:Event):void {
    // Conversely, we stop recording by not listening anymore.
    stage.removeEventListener("mouseUp", recordAction);
}

function playRecording(e:Event):void {
    // Just like recording, we keep track of when we started.
    playStart = flash.utils.getTimer();
}


function recordAction(e:Event):void {
    if (recording.length >= 1) {
        // First, we create the timestamp, and other relavent info.
        var tick:Object = {
            "time":flash.utils.getTimer(),
            "x":e["stageX"],
            "y":e["stageY"]
        }

        // And store it in our numerical index
        recording.push(tick);
        trace("Time: " + (tick.time - recording[0]) + " Coords: " + tick.x + "," + tick.y);

        // Then we do whatever action we were supposed to do (draw line, play sound, etc.).  Here, we'll draw a circle at the mouse coordinates.
        drawCircle(tick.x, tick.y);
    }
}

function tic(e:Event):void {
    if (playStart > 0) { // Assuming we've indexed a start time...
        if (recording.length > 1) { // and we actually have actions to playback.
            // We'll first normalize those bizzare numbers to a zero starting number.
            var nextAction:Number = recording[1].time - recording[0];
            var playHead:Number = flash.utils.getTimer() - playStart;
            if (playHead > nextAction) {
                // Now that we've matched the time, we execute the same action we did before.
                drawCircle(recording[1].x, recording[1].y, 0xFFFFFF);
                // ... and in this example, I'm removing that instance since we no longer need it.
                recording.splice(1, 1);
            }
        } else {
            // If the length of the recording reaches zero, we'll automatically stop playback too.
            playStart = 0;
        }
    }

}