AS3 unwanted delay between playing audio - actionscript-3

I have a song chopped up into 4 pieces: intro, A, B, ending. I have a program that plays the intro, then the A two times then B two times then back to A again and keeps repeating AABB until I press the ending button. If the ending button is pressed, it finishes the currently playing song piece, plays the ending and stops. It works like a charm except there is a very noticeable, irritating delay in the transition between the song pieces. How can I get rid of the delay and make it play the song pieces right after the previous piece ends? (I'm using actionscript 3.0 in flash cs6, the song pieces are in mp3 format, imported into the library).
Here's the program:
https://dl.dropboxusercontent.com/s/6f9w906x9uja683/Loop%20music%20test.swf
And here's the code I'm using:
import flash.events.MouseEvent;
stop();
//variables
var track_var: Number = 0;
var music_cnl:SoundChannel = new SoundChannel();
var intro_msc:Sound = new intro_mp3();
var a_msc:Sound = new A_mp3();
var b_msc:Sound = new B_mp3();
var outro_msc:Sound = new ending_mp3();
//stopping the movieclips
a_mc.stop();
b_mc.stop();
ending_btn.stop();
//intro
music_cnl = intro_msc.play();
track_var= 1;
intro_mc.gotoAndStop(2);
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
//track selector
function playnext_fn(event:Event){
trace("debug:playnext_fn called");
switch(track_var){
case 0:
//stop
music_cnl.stop();
intro_mc.gotoAndStop(1);
a_mc.gotoAndStop(1);
b_mc.gotoAndStop(1);
ending_btn.gotoAndStop(1);
trace("debug:track value set to",track_var);
ending_btn.removeEventListener(MouseEvent.MOUSE_UP, ending_fn);
break;
case 1:
//first A track
track_var=2;
intro_mc.gotoAndStop(1);
b_mc.gotoAndStop(1);
a_mc.gotoAndStop(2);
music_cnl= a_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn)
trace("debug:track value set to",track_var);
break;
case 2:
//second A track
track_var=3;
music_cnl= a_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
case 3:
//first B track
track_var = 4
a_mc.gotoAndStop(1);
b_mc.gotoAndStop(2);
music_cnl= b_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
case 4:
//second B track
track_var=1;
music_cnl= b_msc.play();
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
case 5:
//ending
a_mc.gotoAndStop(1);
b_mc.gotoAndStop(1);
intro_mc.gotoAndStop(1);
ending_btn.gotoAndStop(2);
music_cnl=outro_msc.play();
track_var=0;
music_cnl.addEventListener(Event.SOUND_COMPLETE, playnext_fn);
trace("debug:track value set to",track_var);
break;
}
}
//ending button
ending_btn.addEventListener(MouseEvent.MOUSE_UP, ending_fn);
function ending_fn(Event:MouseEvent){
track_var=5;
ending_btn.gotoAndStop(2)
trace("debug: ending button pressed|","track value set to",track_var);
}

I don't see a problem with your code (other than the redundant and incorrect syntax regarding
MAX_BUFFERSIZE, but I think this just looks like remnants of trying to resolve the problem!)
What I think is more likely to be causing the problem is your source audio - if it's imported as an MP3, or with a bitrate of 48 this can cause problems with synching.

You can't get rid of the delay using traditional Sound object whether from library, loaded externally, mp3, wav, any bite rate. The Flash Sound API suffers from a bad design and latency is inevitable when playing sounds.
However in your case you might be abe to get away with it by using the SampleEventData and mix together all your tracks. The initial latency can go up to 1000ms but in your case that might be irrelevant since the sync between sound is more important:
http://help.adobe.com/en_US/as3/dev/WSE523B839-C626-4983-B9C0-07CF1A087ED7.html
When playing Sounds in Flash in ANY WAY the latency (the time it takes for the sound to start playing) can go from 60ms to 400ms depending on the system. The recommended industry standard is 30ms making Flash an obsolete technology for any Sound related applications.

Related

How to wait, then do something, in the GameScene

SKAction has waiting for duration abilities, for a period of time on a node. And seems to perform actions on nodes. Like moveTo, etc.
If I don't want that, rather I'd prefer to call functions within GameScene after a period of time, how do I do that with SpriteKit in the GameScene, not on a Sprite or other Node?
Are SKActions the way to do this? The only way to do this?
Yes. This question IS that ridiculously simple. I lack the heuristics and terminology to find an answer. Just keep looping around on how SKAction waits are calls on SKSprites for things like scale, rotation, etc, after time. Which isn't want I want/need.
Update:
Desired outcome, inside GameScene
doSetupStuff() // does some stuff...
waitForAWhile() // somehow wait, perhaps do somethings in here, while waiting
doSomethingElse() // does this after the waitForAWhile has waited
UPDATE 2:
What I think happens, again, inside didMove(to view...)
func wait(){
let timeToPause = SKAction.wait(forDuration: 3)
run(timeToPause)
}
let wontwait = SKAction.wait(forDuration: 3)
run(wontwait)
thisFunction(willnot: WAIT"it starts immediately")
wait()
thisFunction(forcedToWait: "for wait()'s nested action to complete")
UPDATE 3:
Found a way to get the delay without using SKActions. It's a little crude and brutal, but makes more sense to me than SKActions, so far:
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
print("I waited ten seconds before printing this!")
}
An option, as you cited, is to manage this externally. The way I typically manage this sort of thing is to have an externally run update cycle. One that
To drive this updater, you could use either CADisplayLink (which is what I use right now with my OpenGL renderer) or a dispatch source timer (which I have used with my SpriteKit engine). When you use an updated, you want to calculate the delta time. The tick handler could look something like:
func tickHandler() {
let currTime = NSDate().timeIntervalSince1970
let dt = lastTime - currTime // lastTime is a data member of the class
// Call all updaters here, pretend "updater" is a known updater class
updater.update(dt)
}
And updater's update method would look something like:
func update(deltaTime:NSTimeInterval) {
// Do your magic
}
I typically have a main overall updater running independent of what people are calling scenes. Example usage would be something like having an attract mode like in old school arcade games. There they show title screen, sample game play, high scores, rinse and repeat. Scenes would be title, game play, high score. Here you can your main updater manage the time and coordinate the construction/destruction/switching of the scenes. Note this implies having an overall scene manager (which is actually quite handy to have).
For your case, you could use this updater to drive the GameScene updater. It's updater could look something like:
func update(deltaTime:NSTimeInterval) {
switch state {
case .SetupState:
// noop?
println("I'm in setup") // Shown just so you can see there is a setup state
case .WaitState:
waitTime += deltaTime
if waitTime >= kWaitTime {
// Do whats you gots to do
doSomethingElse()
state = .NextState
}
case .NextState:
// blah blah blah blah
}
}
So the flow to do this call path from your driver (CADisplayLink or dispatch source) would be something like:
tickHandler -> master updater -> game scene updater
Some will def find this is perhaps a little heavy handed. I, on the other hand, find this very helpful. While there is obviously some time management and the loss of being able to fire and forget, it can help provide more control for orchestrating pieces, as well as arbitrarily changing state without having to worry about killing already queued actions. There is also nothing that says you still cannot mix SKAction. When I did use SpriteKit, I did all my updating this way along with some dispatched items. I only used SKAction to update hierarchy. Keep in mind that I used my own animation and physics system. So at least for me I had a lot less dependency on SpriteKit (it effectively was just a renderer for me).
Note you have to have your own means to handle pause and coming to foreground where your timer will need to be resynced (you only need to worry about tickHandler). Breakpoints also will cause time jumps.
You can use below function
#define ANIM_TIME 2
SKAction *customACtion = [SKAction customActionWithDuration: ANIM_TIME actionBlock:^(SKNode *node, CGFloat elapsedTime) {
// Do Something Here
}];
Another way to make something happen after a certain period of time is to make use of the 'current time' parm passed to update(). The following code will spawn a boss at intervals ranging from 20 to 30 seconds.
In your property definitions:
var timeOfLastBoss: CFTimeInterval = -1 //Indicate no boss yet
var timePerBoss = CFTimeInterval()
.
.
.
didMoveToView() {
...
timePerBoss = CFTimeInterval(Int.random(20...30))
'''
}
.
.
.
func update(currentTime: CFTimeInterval) {
...
spawnBossForUpdate(currentTime)
...
}
'
'
'
func spawnBossForUpdate(currentTime : CFTimeInterval) {
if ( timeOfLastBoss == -1 ) {timeOfLastBoss = currentTime}
if (currentTime - timeOfLastBoss < timePerBoss) {return}
// Rest of 'spawnBoss code
self.timePerBoss = CFTimeInterval(Int.random(20...30))
self.timeOfLastBoss = currentTime
}
One way, using SKActions, in Swift 3.0, looks like this:
DEFINE: aPatientlyWaitingFunction() at the top level of
GameScene class.
To cause a delay to happen before calling the above function, inside
didMove(to view...)
three ways I've found to do this using Actions:
All three ways seem to accomplish the exact same thing:
let timeToWait: TimeInterval = 3 // is seconds in SKAction thinking time
let waitSomeTime = SKAction.wait(forDuration: timeToWait)
// 1st way __________________________________________
// with a completion handler, the function can be called after Action
run(waitSomeTime) {self.aPatientlyWaitingFunction()}
// 2nd way __________________________________________
// as a completion to be done after action, in the run invocation:
run(waitSomeTime, completion: aPatientlyWaitingFunction)
// 3rd way __________________________________________
// alternatively, as part of a sequence of actions...
// Create a sequence, by making a run action from waitSomeTime and...
let thenDoThis = SKAction.run(aPatientlyWaitingFunction)
// then activate sequence, which does one action, then the next
run(SKAction.sequence([waitSomeTime, thenDoThis]))
// OR... for something different ____________________
////////////////////////////////////////////////////////
DispatchQueue.main.asyncAfter(deadline: .now() + timeToWait) {
self.aPatientlyWaitingFunction()
print("DispatchQueue waited for 3 seconds")
}

Dynamic Text of a Movie Clip is not updating

I have a stage set up with a "movie clip" in the frame named jackpotNote. In that movie clip (or symbol), there is a dynamic text field named "jackpotAmt".
What is supposed to happen is that I'm to press the Space Bar on my keyboard and it will trigger the Movie Clip to play out. What's also supposed to happen is that the text is supposed to change as well, here is the current coding:
if (event.keyCode == Keyboard.SPACE) {
if (jackpotNote.visible == true) {
trace("Jackpot amount already shown. Ignored.");
} else {
jackpotNote.visible = true;
jackpotSymbol.visible = true;
//jackpotSymbol.jackpotAmt.text = currency_str + String(jackpotamt_int);
if (jackpotamt_int < 100000) jackpotSymbol.jackpotAmt.text = currency_str + String(jackpotamt_int);
else if (jackpotamt_int >= 100000 && jackpotamt_int <= 999999) jackpotSymbol.jackpotAmt.text = String(jackpotamt_int);
else jackpotSymbol.jackpotAmt.text = currency_str + "1MIL+";
dingsound.play();
jackpotSymbol.play(); // DO NOT START PLAYING
jackpotSymbol.gotoAndPlay(1);
trace("Jackpot amount shown.");
}
}
However when I trigger this event, the following happens:
The sound effect jackpotSymbol.play() plays as normal.
The jackpotSymbol becomes visible.
However, the text is not changed in the following line: jackpotSymbol.jackpotAmt.text = currency_str + String(jackpotamt_int);
This used to run well on Adobe Flash Professional CS6, however when I upgrade to Adobe Animate CC... it broke. (I had to remove all of the TLF fields and make them dynamic again.)
What is missing to make all of this work?

CCPhysicsjoint not keeping the 2 bodies intact

I want to add a particle body(say Fire) before another physics body(the arrow).
So, i am using the spring joint to keep them joined with stiffness around 20000, but still its starting the correct way and the particle-body swings away form the arrow. Here's my code:
fire part
CCParticleSystem *explosion= [CCParticleSystem particleWithFile:#"bomb.plist"];
explosion.position = ccpAdd(projectilePos, ccp(16,0));
explosion.physicsBody.mass=1.0;
explosion.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:16.0 andCenter:explosion.anchorPointInPoints];
explosion.physicsBody.type=CCPhysicsBodyTypeDynamic;
explosion.physicsBody.affectedByGravity=FALSE;
explosion.physicsBody.allowsRotation=FALSE; //so that fire flames go upwards only, and not rotate
[physicsWorld addChild:explosion];
explosion.physicsBody.collisionMask=#[];
arrow part
CCSprite *tempSprite;
tempSprite = [CCSprite spriteWithImageNamed:#"arrow3#2x.png"];
[tempSprite setScale:0.05];
[tempSprite setScaleY:0.15];
tempSprite.rotation=rotation;
tempSprite.position=dummyBow.position;
tempSprite.name=[NSString stringWithFormat:#"%#,%d",[lifeOfSprite[1] objectForKey:#"name"],[[lifeOfSprite[1] objectForKey:#"life"] intValue]];
tempSprite.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, tempSprite.contentSize} cornerRadius:0]; // 1
tempSprite.physicsBody.collisionGroup = #"playerGroup";
tempSprite.physicsBody.collisionType = #"projectileCollision";
[physicsWorld addChild:tempSprite z:0];
projectile.physicsBody.mass=100;
now the joint part
[CCPhysicsJoint connectedSpringJointWithBodyA:playerBomb.physicsBody bodyB:projectile.physicsBody anchorA:ccp(1,1) anchorB:ccp(600,0) restLength:0.f stiffness:20000.f damping:60.f];
(debugDraw)
the fire should come at the front, but swings back from front by spring effect
Can anyone tell where's the problem?
Thanks in advance.

Finding out loading time of webelements in a webpage using selenium webdriver

I have a webpage(HTML 5) in which there are 4 charts, each of which taking different time to load once the static content in the page comes up. The Loading is shown in the webpage using a 'rendering' circle image for all the 4 charts. I want to find out how much time each of the charts were showing the 'rendering' circle. Please help me in getting a solution using selenium webdriver.
It is the crude way but it must work.
Create a infinite loop with 1 second wait and in each iteration check if the chart is loaded or not. Once all four charts are loaded or if you have timeout value come out of loop.
In this case there is possibility of error of 1 sec. If your chart is loading fast or want to reduce the margin of error reduce the wait from 1 sec to 100msec.
Pseudo code :[May use this to write better code]
boolean[] chartLoaded = {false,false,false,false};
int[] chartLoadTime = {0,0,0,0};
int counter = 0;
while(counter < 100)
{
counter++;
if(isLoaded(chart1))
{
chartLoaded[0] = true;
chartLoadTime[0]++;
}
//Do this for other three charts also
if(chartLoaded[0] && chartLoaded[1] && chartLoaded[2] && chartLoaded[3])
break;
}

How to translate multiple labeled movieclip of Actionscript to Starling?

I'm new to starling and this may sound like a noob question but here goes nothing.
Imagine the following scenario (in Flash):
A movieclip named test
Test has 80 frames
Test has 4 labels at 20 frames each
When I script test in my project. I make it loop from label 0-1 (frames 1-19). Then I tell it to loop on label 2 on a certain event.
This way, I do not add or remove a movieclip or instantiate things just one.
Now, if I think about implementing it in starling. I'm thinking make 4 movieclips in flash. Export them as sprite sheets and then make four movieclips in the script. Add whichever moviclip needs to play in the juggler and similarly removechild it at that time.
This way, I'm adding the overhead cost of 'addchild' and 'removechild' everytime I want to switch between those animations. Is that a more cost effective way?
I presume you want to export a single clip, but control multipe(4 animations) rather than a single one. If this is the case, I wrote a few JSFL scripts a couple of years ago (when CS6 wasn't around to export spritesheets) which exported the main timeline of an .fla document as an image sequence, but used the frame labels in the filenames. This made it easy to integrate with TexturePacker. You can see video of it here.
Here's a JSFL snippet which will export a frame sequence with names generated based frame labels which should make it easy to manage in TexturePacker:
var d = (FLfile.getPlatform() == 'macos') ? '/' : '\\'; //delimiter
var doc = fl.getDocumentDOM(); //document
var tl = doc.getTimeline();tl.setSelectedLayers(0,true); //timeline
var cl = tl.layers[0]; //current layer
var numFrames = cl.frameCount;
var className = prompt("Name for your sequence", toClassName(doc.name.substr(0,doc.name.length-4)));
className = className.split('.')[0];//just in case the user adds .as
className = toClassName(className);//remove non alphabet chars
var docPath = doc.pathURI.substr(0,doc.pathURI.length - doc.name.length);
var exportPath = docPath+className+'_export'+d;
if(!FLfile.exists(exportPath)) FLfile.createFolder(exportPath);
fl.outputPanel.clear();
for(i = 0 ; i < numFrames; i++) {
if(cl.frames[i].name != ''){//if frame is labelled
tl.setSelectedFrames(i,i,true);
doc.exportPNG(exportPath+cl.frames[i].name+lpad(''+i,4)+'.png',true,true);
}
}
fl.trace("export complete!");
function lpad(number, length){
var result = '' + number;
while (result.length < length) result = '0' + result;
return result;
}
function toClassName(input){
return input.replace(/[^a-zA-Z]/g, "");
}
Also, I suggest having a look at generator tools like Dynamic-Texture-Atlas-Generator, Fruitfly, etc.