Table of Contents
the beatmaker
,
light beat.
heavy beat:
cha-cha beat?
rest*comment*
variable_name=beats;
for examplefoo=,:,:..,:
[variable_name]
to reference it in a beat
development intro and goals
I started improving my earlier beatmaker design to include rests and allow for variable reference and quickly ended up doing another post's worth of work. So here it is in another post.
my main goals were to add a rest beat, and to add variables nd loops to enable more complex rhythms.
you can also check this project out on github
notes
adding a rest
This is actually what started everything. Unfortunately I can't just "play" a silent note. Tone.js doesn't allow notes of 0Hz, 0 velocity, or 0 duration. Gain is an envelope applied to the whole instrument and so would be annoying to trigger.
Instead we use a different part of the Tone.js toolkit to manually schedule notes rather than automatically, thus we can simply delay the note after the rest. Works great, but I had to change my implementation to a case statement from a lookup table.
OH WAIT! what if its a trailing rest? now what note's gonna get extended? (trailing rests are still "played" since they should delay when the next loop of the beat starts) well thankfully, Tone.js lets us push back the end of the loop. But now we need to know when we're a trailing rest. So now we have a big switch block thats peeking at the next letter in the code to see if we're at the end. Well, this is nearly like the parsers i made in college, so lets just make one since we've done so much of it already, that way we can have variables and stuff too.
designing the parse
I ended up going with a simple recursive descent parser since its what I'm familiar with and this project has set on the shelf long enough. There weren't any notable challenges in its creation. except for the fact that currently self reference causes infinite recursion. To fix it I decided to crawl each assignment and expand any lookups to their value such that, internally, there are no lookups inside an assignment. I wouldn't describe this as necessarily the most elegant option but it lets me get this project out the door quickly and out of my head, while still allowing a pleasing amount of flexibility.