Scheduling note-offs in javascript...what is a GOOD way?
I need to schedule note offs in a javascript. This works if I only send one note at a time and wait for the previous note to turn off before I send another:
function note(note,vel){
outlet(0,144,note,vel);
noteoff.arguments=[144,note];
noteoff.schedule(500);
}
var noteoff = new Task(note_off,this);
function note_off(status,note){
outlet(0,status,note,0);
}
No surprises there. So, before I embark on something ugly, I'm wondering what a nice, elegant way of doing this is. I've had the thought that I could create an array of Tasks, check to see if a task is busy, if it is, then try the next one in the array, and so on. This would probably work, but it seems a bit of a brute force method, and not very elegant.
Has anyone come up with a good solution for this? Do share!
Peter
Hey Pete,
I tend to stay away from built-in Tasks, just because they've proven troublesome when using multiple js's in the same project in m4l. This is probably something you needn't be wary of in plain-jane Max patches, though. Still, it might help.
I send a metro's output into the js and set up a function inside the js like:
function timer()
{
time = time++;
for(job in tasks)
{
if((tasks[job].time>time)&&(script[tasks[job]] instanceof Function))
{
script[tasks[job]].apply(script[tasks[job]], []);
tasks.splice(job, 1);
}
}
}
The 'script' variable is set up in global code on load like this:
var script = this;
Dunno if this helps you at all....I've gotten a lot of mileage out of it though, and this sort of method has been much more stable and maleable than the built in tasks functionality of the js object.
You probably already know this, but if you are expecting reasonably accurate timing from anything in js, make sure to set the immediate property of these functions to 1....otherwise, nothing but slop.
Cheers :)
Hi James,
That is a good idea...but I think I'll stick with the array of Tasks for now - it's more elegant than I thought it would be. Though, yeah, I do realize I could be opening a can of timing worms. I hope not :)
var noteoffs = new Array();
function loadbang(){
noteoffs = new Array();
for (var i=0;i
and somewhere in a function, after I schedule a note on, I can do this:
//schedule note off
var avail = 0;
while (noteoffs[avail].running || avail==noteoffs.length-1){
avail++
post("navail",avail);
}
noteoffs[avail].arguments = [notehead,notenum];
noteoffs[avail].schedule(dur);
of course, everything falls apart if I run out of Tasks...:)
I would suggest moving as much of the timing outside of the javascript. a delay might work.
I actually think you could accomplish this without js but it is hard to suggest how without knowing more details.(delay object and a trigger would be my go to)
I could accomplish it outside of js with makenote, but I really don't want to go out of js. I like James's approach - a sort of "crystal" for the timer :)
So far, the tasks are doing ok - if it breaks down, I now have a place to turn.
Thanks :) You know, what I used to do (before I discovered js Tasks were unstable in m4l) was to run a single Task which served the same function as the external metronome, and time everything from it...I also generally try to do everything in the js that I can. This all worked fine when only one js was running, but things became unstable with multiple js's. You probably won't have any issues (other than wonky js-style timing without immediate=1), it just makes the script less portable with Tasks embedded.
I'm curious how the Task function is built internally....the problem with my method is that you are calling a function @ every timing interval, which is bound to slow things down. But judging from the behavior I've observed with Tasks, I tend to think the same sort of thing is going on internally anyway when using the builtin methods.
James
Very cool discussion topic! Do you guys actually have full code you can share to learn and understand from?