fbpx
Skip to main content

MIDI Forum

Javascript hobby pr...
 
Notifications
Clear all

Javascript hobby project collaboration

8 Posts
4 Users
0 Reactions
5,616 Views
Jonas
Posts: 207
Reputable Member
Topic starter
 

Must say i have a hard time understand how recursion works with setTimeout and could need some direction and help.
I wonder if anyone would like to participate and make my sequenser "a fully functional" and online educational software for sequensing and editing.
My aim is to make the thing so easy to use, that someone with zero experience of music software and sequensing can start to record and sequense.
Right now i am utterly stuck on the playup using recursions, although it sounds ok it plays double messages all the way.

And when i try to fix it according to logic, it will not simply play at all.
Warning my code is although nice contained in understandable named functions and variables, riddled with global variables.
Fast and sloppy.
And my biggest hangup, i want things to work as soon as i write them simply hate debugging.

https://jonasth.github.io/

There really isn't much of midisequenser done in javascript online, at some point i would like to make a single synth/sampler in javascript i have been playing with Nyqvist sampling theorem some decades ago and was probably one of the first to create a stretch algorithm for samples that do not produce the Donald duck effect available in samplers from that time.

 
Posted : 23/04/2021 4:02 pm
Eddie Lotter
Posts: 295
Reputable Member
 

There really isn't much of midisequenser done in javascript online

Google disagrees with you. :p

 
Posted : 24/04/2021 5:35 am
Geoff
Posts: 1043
Noble Member
 

I'm not sure why you're using recursion, but recursion is where specific part of a program (i.e. a function or subroutine) calls itself maybe repeatedly, as in the original function A in turn calls A (which I'll refer to as A1) and A1 then calls A again (now A2) and this could happen any number of levels. Normally, as the logic of the process resolves, the levels of recursion will unwind so that at the end of the process no recursive calls are still active and the program is tidy.

Your mention of global variables may be the problem, recursion really need a language that allows the function (or whatever) to create local variables each time it is called, and these variable are unique to that iteration of the function. C for example does that normally. It _IS_ possible to use something like BASIC which cannot naturally do recursion by implementing a 'stack', using an array, but this makes things more complicated. Look at versions of the 'QuickSort' routine, I have seen versions in BASIC using an array, and versions using C which benefit from recursion.

Certainly you should NOT be using global variable within any recursive routine, as they will get messed up. Using a stack/array could keep the data protected. The problem with this solution is that you need to define the size of the array correctly at the start, depending on the number of recursions expected and the size of the data. For QuickSort there is a formula, although the stack can still overflow with a very peculiar data-set. Not sure how you'd set the size in the situation you're needing.

Geoff

 
Posted : 24/04/2021 7:45 am
Jonas
Posts: 207
Reputable Member
Topic starter
 

Eddie Lotter you did not provide any link?
There is one midisequenser online and it is rather good. "acceptable"
https://www.g200kg.com/websequencer/
According to me this is the only one of those i've seen worthy the name midisequenser.
The rest are just some sort of quantised sampleplay backs where you register notes to play.
Not much of realtime sequensing there.

JT

 
Posted : 24/04/2021 8:47 am
Jonas
Posts: 207
Reputable Member
Topic starter
 

Hello Geoff, i use setTimout to schedule events in the future, but setTimout isn't exactly precise so playuptime of note may differ quite alot. That is why i compare playup time with the realtime clock as note is played, and then i can set next note to play a little earlier to chew off the latency that builds up.
Imagine a little pacman chewing up the latency by move forward in time "closer to next note":D

But although i am far from an expert i can say that most probably there is a bug in javascript using setTimout to playup recursively until last note or stop.
Or i have totally missed the point of recursions. It is weird i get the latency removed when messages played twice just saying.
But can't remove it following plain logic.
https://jonasth.github.io/

The reason for using recursion is that any type of loop would not wait until note played to play next.
I do not know what kind of option there is to recursion in this case, after note "played" next note scheduled. I do not know if you familiar with setTimeout it is just a scheduled timepoint in the future to do something like a function call or execute code.

No i do not think global variables has anything to do with my recursion problems, it is just me picking up some of the complains on my coding "style?" from comp.lang.javascript LoL
There is really no problem with having some global variables, with the memory banks of today. It is naming and knowing what you are doing that is important.
And either i do not know what recursion doing, or someone did a bobo implementing it, i start to lean at the later.
JT

 
Posted : 24/04/2021 10:04 am
Jonas
Posts: 207
Reputable Member
Topic starter
 

The errors of setTimeout is gone and so is gone and so is setTimeout replaced with setInterval.
setTimeout had been much nicer on the processor though.
https://jonasth.github.io/

 
Posted : 30/05/2021 9:38 am
Benjamin
Posts: 2
New Member
 

Hey there,

you might want to check out this project: https://github.com/mudcube/MIDI.js/

.setTimeout isn't the best approach if you need exact timing. Using setInterval/requestAnimationFrame and sequencing notes through the WebAudio API ahead of time will give you exact timing. Something like this:

[code type=markup]
const notes = [....all your notes... ]
const audioCtx = new AudioContext()
const lookAheadTime = 0.1

const tick = () => {
notes.forEach(note=> {

let delay = audioCtx.currentTime - note.timestamp // Duration until the note should be played
if (delay < lookAheadTime && noteHasntBeenPlayedYet(note)) {
//Schedule your note in 'delay' seconds using the audioCtx
}
}

window.requestAnimationFrame(tick)
}
[/code]

So each time tick() is called, you look ahead 0.1 seconds and see if any note will start in the next 0.1 seconds. If it does you schedule the note in the audioCtx and remember that you've played that note already, so you don't schedule it again in the next iteration. For an interactive sequencer where you can jump back and forth in time you'll obviously need additional logic. But for playing audio this is the best approach to get good timing.

Using requestAnimationFrame instead of setTimeout/setInterval allows you to create smoother animations/visualisations.

 
Posted : 09/06/2021 2:15 pm
Jonas
Posts: 207
Reputable Member
Topic starter
 

I am pretty happy with my solution, i think it is pretty accurate.
https://www.facebook.com/jonas.thornvall/videos/3952413871495073

 
Posted : 14/06/2021 10:46 pm
Share: