Looping audio in midijs? - javascript

I'm trying to use MIDIjs to play audio (specifically because I'm using WAD.js, which uses it). Unfortunately I can't figure out how to loop audio, there's a frustrating lack of documentation, and I'm not finding anything in the source code. At the very least I'd like to know when the file has naturally ended to restart using MIDIjs.play(), but I'm not even seeing anything for that.
I'd appreciate it if someone pointed me towards a solution, thank you.

Correct, there's no loop function (that's documented anywhere here).
However, we can at least simulate it with MIDIjs.player_callback, which is called every 100ms with an object that looks like { time : number }. This is time in seconds elapsed. We can combine this with get_duration to detect the end of playback.
function playAutoReset(url)
{
// get_duration requires a callback as it returns nothing.
MIDIjs.get_duration(url, function (duration)
{
console.info(`Duration: ${duration}`);
// Start the initial play
MIDIjs.play(url);
// This lets us keep track of current play time in seconds
MIDIjs.player_callback = function (mes)
{
if (mes.time / duration >= 1)
{
console.info('End reached');
// This plays the audio again
MIDIjs.play(url);
}
};
});
}
Note:
This does call play each time, so it will probably re-download the source (the docs seem to imply that this is always the case). If you want something more network-efficient, you may want to look into XHRs/AJAX and creating an object URL, as the docs do specify that play takes a URL. However, I thought this would be the simplest solution, and it does show what you have to do to play the midi track again when it ends.

I had this same issue and wasn't entirely satisfied with the workaround in the other answer because of how it reloaded the file every time the url was passed into a MIDIjs function and it seemed to loop slightly too early.
So, I started digging into the MIDIjs source, which also has a map file, but I didn't bother trying to maximize/deobfuscate it. I noticed a couple mentions of loop that are set by second parameter t in function X. I wasn't sure, but thought maybe X was play, so I tried it.
MIDIjs.play(url, true);
It worked!
Since I'm working with Kotlin/JS, here's my external code:
external object MIDIjs {
fun play(url: String, loop: Boolean = definedExternally)
fun stop()
}
Call it in Kotlin exactly the same way, without the semicolon.
MIDIjs.play(url, true)

Related

When in the Chrome Debugger, is there anyway to reference data or functions inside an anonymous function block?

I'm trying to debug something live on a customer website and my code is all inside an anonymous function block. I don't know if there's anyway to reach that code to execute functions or look at variables in there. I can't put a breakpoint either because this code is dynamically generated each time the page is refreshed and the breakpoint doesn't stick.
(function() {
var Date = "14 September 2022 14:44:55"; // different every refresh for example
var Holder = {
var Items = {
item1: "Value1",
item2: "Value2"
};
function getItem(name) {
return Items[name];
};
function setItem(name, value) {
Items[name] = value;
};
setTimeout(DoSomething(), 2000);
})();
That's not the actual code, just a bare minimum example to illustrate the problem.
Is there anyway to get reach getItem() or Items?
Without a breakpoint that code probably runs to completion then POOF it's all gone anyway.
Redefine setTimeout
If it really is the case that the code inside the anonymous function calls other browser methods, you might be able to insert a detour at runtime that you can then put a breakpoint on.
For this to work, you will need to be able to inject new code into the page before the anonymous code, because there's no other way to invoke the IIFE.
Your example code uses setTimeout, so here's what I would try to insert:
let realSetTimeout = window.setTimeout
window.setTimeout = (...args) => {
debugger
return realSetTimeout(...args)
}
Lots of unrelated code might be calling setTimeout, in which case this could break the page or just make debugging really tedious. In that case, you might make it only debug if one of the setTimeout args has a value that's used in your example, e.g.:
// only break for our timeout
if(args[1] === 2000) debugger
Something like that might not trigger for only your code, but it would hugely reduce the number of other codepaths that get interrupted on their journey through the commonly-used browser capability.
Alternatively, use Charles Proxy to rewrite the body of the HTML page before it enters your browser. You could manually insert a debugger call directly into the anonymous function. Charles is not free, but I think they have a demo that might let you do this. If you do this professionally, it's probably a good purchase anyway. Your employer might even pay for the license.
If you can't use Charles (or a similar tool), you could instead set up a local proxy server using Node which does the rewrite for you. Something like that might only take an hour to throw together. But that is a bigger task, and deserves its own question if you need help with that.
No unfortunately.
The variables inside of the anonymous object are created in a scope which is inaccessible from the outside.
One of the main benefits of using a closure!
You’ll have to find a way to insert your own code inside of it by modifying the function that is generating those objects. If you can’t do that, then you’ll have to take the fork in the road and find another way.

Call function without actually executing it

So I have such a weird question and I don't know if this is possible, but I will give it a shot anyways.
We have implemented OneTrust, which is a third-party cookie consent vendor and it works great and all, but we have one small hiccup that we are trying to resolve.
So within the below function:
toggleVideo: function (videoWrapper, src, cover, type, element) {
var videoElement = video.buildVideo(src, type);
// We build out video-player element
videoWrapper.html(videoElement);
// We define our variables
let onetrust = window.OneTrust;
let onetrust_obj = window.ONETRUST_MODULE;
let target = videoWrapper.html(videoElement).children('iframe');
console.log(onetrust.Close());
// Now we wait and observe for a src attribute and then show the video.
onetrust_obj.src_observer(target, function() {
video.toggle_show(videoWrapper, cover);
});
},
We have an <iframe> element that when clicked play, will wait for consent to execute - The problem is that it needs to "refresh" OneTrust so that it can change the data-src to src attribute (This is all handled using OneTrust JS, so I have no control).
When I add in the console.log(onetrust.Close());, it works just as intended and resumes playing the video when consent is given, the downfall is that it outputs an error in the console. If I remove it, the videos will not play after consent is given.
I don't want to actually execute the onetrust.Close() method as it will close the banner.
OneTrust doesn't have a proper way to "Refresh" their initialization, the techs told me that this was a one-off case, where they don't even know how to handle it.
My questions:
Is there a way that I can properly call onetrust.Close() (Seems to be the only call that actually engages the video to play after) without actually executing it?
If not, is there a way that I can somehow similarly log it, but not actually log it in the console?
Thanks all!
Strange one, may be a race-condition issue so making your code run in the next procedural iteration may resolve the issue - this can be done by adding a setTimeout with no timer value.
setTimeout(() => {
onetrust_obj.src_observer(target, function() {
video.toggle_show(videoWrapper, cover);
});
});
Alternatively, it may be worth digging into the onetrust.Close() method to see if there are any public utilities that may help 'refresh' the context you are working in.
Another idea would be to see what happens after if you ran the onetrust_obj.src_observer code block again.
EDIT: I would like to be clear that I'm just trying to help resolve debugging this, without seeing a working environment it's difficult to offer suggestions 😄

CreateJS' PreloadJS progress event inaccurate

I'm trying to load some assets using the PreloadJS class from the CreateJS suite, but when very first progress event fired reports e.loaded and e.progress as 0.83, the numbers then decrease over the next few event before finally going back up again.
t.assets = new createjs.LoadQueue();
t.assets.installPlugin(createjs.Sound);
t.assets.setMaxConnections(10);
t.assets.addEventListener("progress", function(e){
console.log(e.loaded);
});
t.assets.addEventListener("complete", function(){
callback();
});
t.assets.loadManifest([
{ id: 'facebook_btn', src: 'img/ingame/facebook_white_btn.png' },
{ id: 'twitter_btn', src: 'img/ingame/twitter_white_btn.png' },
{ id: 'embed_btn', src: 'img/ingame/embed_white_btn.png' },
]);
I get these results in the console
0.8333333333333334
0.7142857142857143
0.625
0.5555555555555556
0.5
0.45454545454545453
0.4984983736293216
0.5894074645384125
0.6363636363636364
0.6663361591119469
0.7572452500210378
0.8261679748749072
0.9170770657839982
0.9390634318392196
1
Is this because it's working through the manifest initally and doesn't take into account everything right away?
Is checking the the progress is going the correct way before displaying these results in a preloader a good method of making sure it's sorted itself out?
Essentially the manifest is just providing a convienient way to deal with a batch of assets without you having to loop through them yourself. Have a look at the code, it's almost the same as the loadFile method, but loops through the array of objects. So it's not doing anything fancy in terms of better calculating the progress.
http://createjs.com/Docs/PreloadJS/files/.._src_preloadjs_LoadQueue.js.html#l898
You have a couple options though to make it look more accurate.
If you're not loading much and it's only going to take a few seconds you might just want to not use the progress event. Instead you can just catch load errors or other hangups.
If you are loading lots of things and it could take some time then consider waiting a few seconds before displaying the progress. That gives the manifest time to add enough stuff that it should just be moving in a positive direction towards 1.

get var name from this or self reference javascript

I see that there are some other questions that seem to be on a similar topic but none have an answer that will help me with my particular problem. I have made a thread library in in JavaScript built around the setTimeout and setInterval functions. This is working very well except that my thread library requires that the name of thread is past to the thread i.e when I instantiate the thread it looks like this.
t = new Thread(payload, "t")
payload is an object that defines the what the thread will do when it gets a chance to execute. This allows me to abstract the task of the thread from the underlying threads "plumbing". In any case my problem that I have to pass name of thread because setTimeout and setInterval take a JavaScript command as a string i.e setTimeout("doStuff", 0). As I use my thread library in more applications passing the name to the thread is becoming more of a pain. So I would like to be able to avoid this by getting the name of the thread from within the thread class like this:
var myThreadName = this.someMagicFunction();
or
var myThreadName = someMagicFunction(this);
or some other fantastic method if anyone has any ideas for me I would be most grateful.
Actually, both can take a function as the first parameter, and this is the recommended usage (since the string versions do an eval).
setTimeout(doStuff, 0);
In your case, you might be able to do something like:
setTimeout(function(){
t.payload();
}, 0);
depending how the Thread object looks.
See the MDC documentation (setTimeout, setInterval).
You can pass a function to setTimeout as long as it is argument-free, i.e.
function takeme()
{
alert('workin?');
}
setTimeout(takeme, 100);
and if it is not, then you can try
function takeme(x)
{
alert(x);
}
var test = 1;
setTimeout(function(){ takeme(test); }, 100);
But if you really need to extract a function name, then please see this post. Not exactly the same, but somewhat related.

What are the inner workings of the Selenium waitFor mechanism?

I am trying to customize the behavior of Selenium's click command, (via user-extentions.js), by intercepting calls to doClick(locator). Basically I need to delay click actions whenever our application's "busy indicator" is being displayed.
(Now the standard answer for this kind of thing is to insert a waitFor into the script for those situations. Indeed, we currently have zillions of them throughout our scripts. I'm trying to eliminate those.)
Detecting the page element is the trivial part. The tricky part is getting the script to actually wait. My promising looking, but failed attempt looks like this:
var nativeClick = Selenium.prototype.doClick;
Selenium.prototype.doClick = function(locator) {
this.doWaitForCondition("!selenium.browserbot.findElementOrNull('busy-indicator')", 5000);
return nativeClick.call(this, locator);
}
The doWaitForCondition gets called before every click, but it does not wait when the condition evaluates to false. nativeClick always gets called immediately, and so no delay is introduced. I suspect that the doWaitForCondition function doesn't actually do any waiting per se, but rather establishes the conditions for it within the command execution loop. And in this case the click command is already in play, and I'm trying to run a command within a command.
Can somebody shed some light on how Selenium command execution and waitFor works, or offer suggestions on how this might be done?
I have finally solved this. And with an approach that is much better than trying to intercept click processing in its various forms. My refined goal is: to delay execution of script command completion when our application is "busy".
How Selenium command processing works:
Upon completion, each selenium command returns an ActionResult object, (see ActionHandler.prototype.execute). The terminationCondition attribute on this object is a function that determines when it is okay for selenium to proceed to the next command, (TestLoop.prototype.continueTestWhenConditionIsTrue). Basically, selenium repeatedly executes the condition function until it yields true. The result object it quite trivial:
function ActionResult(terminationCondition) {
this.terminationCondition = terminationCondition;
}
Customizing it:
I want to delay execution any time myAppIsBusy() returns true. Of course all of the standard delays need to remain in place as well, like waiting for page loads, and explicit waitFor conditions as scripted. The solution is to redefine the selenium result object in my user-extensions.js, as follows:
function ActionResult(terminationCondition) {
this.terminationCondition = function() {
// a null terminationCondition means okay to continue
return (!terminationCondition || terminationCondition()) && !myAppIsBusy();
}
}
The great thing is that this is at a low enough level that it works for the IDE, as well as for RC.
Note that this does not affect Accessor or Assert command types, which return different result objects. But that should be fine, because those commands don't effect the state of the application.
Well, a look at the java drivers com.thoughtworks.selenium.Wait class reveals this:
public void wait(String message, long timeoutInMilliseconds, long intervalInMilliseconds) {
long start = System.currentTimeMillis();
long end = start + timeoutInMilliseconds;
while (System.currentTimeMillis() < end) {
if (until()) return;
try {
Thread.sleep(intervalInMilliseconds);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
throw new WaitTimedOutException(message);
}
I am not to deep into selenium but I excpect that every waitXXX Method points to this.
So, Selenium is working with Thread.sleep(). While this might not look like an ideal solution it shows at least that you cant make it worse by using Thread.sleep() on your own if neccessary. ;-)

Categories

Resources