RhythmScript is a minimal scripting language for creating arbitrary rhythms.
Please refer to the example at the bottom of the page.
Writing a rhythm should be as easy as typing on a keyboard. Metric modulation is a common enough concept in experimental music that it should be built-in and easy to use. It's just tempo ratios and regrouping, which are very easy to implement.
The tempo is set with the -tempo keyword, followed by a number (with or without a decimal point).
The tempo is in beats per minute.
The -subdiv keyword sets the subdivision of the beat. For example, -subdiv2 means that
the beat is divided into 2 equal parts, -subdiv3 means that the beat is divided into 3 equal parts,
and so on.
The -superdiv keyword does the opposite: it sets the new beat to take the same amount of time as n
of the old beats.
Subdivision and superdivision applied directly to the CURRENT internal pulse. It is NOT relative to the most recent
-tempocommand.
The -321go and -readysetgo keywords are DDR-inspired game exclusive. They are visual
cues for the player to start playing the rhythm.
In the JavaScript implementation, these keywords just send messages to the canvas. In the Unity implementation, they will trigger a countdown animation and any other necessary visual effects.
Any non-whitespace, non-keyword character is interpreted as a literal. Each character in a literal plays for the duration of the current tempo.
Remember that whitespace is ignored, so udlr udlr is the same as udlrudlr. This is just
used for organizing the script into readable chunks.
Ultimately, the meaning of the characters is up to the game or program that is interpreting the RhythmScript. In our DDR-inspired game, the characters correspond to the arrow keys on the keyboard.
| Standard Character | Meaning |
|---|---|
| u | Up |
| d | Down |
| l | Left |
| r | Right |
| x | Rest/No input |
Additionally, there are characters that represent directions NOT to press. Imagine them as the bombs in Fruit Ninja.
| Anti-Character | Meaning |
|---|---|
| U | No Up |
| D | No Down |
| L | No Left |
| R | No Right |
NOTE: As of 2024-02-15, anti-characters are not implemented yet.
The + operator indicates that the surrounding literal characters should be played at the same time.
For example, udlr+udlr means to play udl in sequence, r+u simultaneously,
and then dlr in sequence.
Under the hood, the + operator ticks the clock backwards by 1 beat at the current tempo. This
technically means you can have several + operators in a row to travel back in time by several
beats. This is recommended for polyrhythms and other complexly-layered rhythms.
Blocks are defined with curly braces {}. The contents of the block are repeated a certain number of
times, which is specified by a number after the block. For example, {udlr}.4 means to play
udlr 4 times.
You can also nest blocks within other blocks.
Because whitespace is ignored, blocks can be written on multiple lines and indented for readability.
For the specific implementation of RhythmScript within our DDR-inspired game, we have a -free
keyword that starts a freestyle section. This means that the player can hit any button at any time, and the game
will not penalize them. The -unfree keyword ends the freestyle section.
In a more general implementation, there would be no need for these keywords.
The -print keyword is followed by a string, which is printed to the console. This is useful for
debugging. Leading and trailing whitespace is ignored, but spaces within the string are preserved.
Because there is no built-in synchronization with the music, you should organize your RhythmScript to ensure you know where in the piece of music you are.
To do this, the parser ignores the following things:
// on a line/* and */
-print statements
-tmpo128 // tempo = 128
-subdiv2 // get 8th notes
-print Starting intro
-321go
udlrudlr udlrxxxx
u+r
u+r
u+r
u+r // 8 combos of 2 arrows at once
d+l
d+l
d+l
d+l
{
// literal
ududlrlr
xxxxx // rest
// nested loop: do this 8 times
{
uxxuxxux // tresillo
}.8
}.2
// (do the above block within curly braces 2 times)
// go twice as fast
-subdiv2
lrlrlrlrlrlrlrlr
udududududududud
-free
// start freestyle section (not necessary to hit these beats)
-print Intro done; starting A section
// reset the tempo to any value @ any time
-tempo90
// metric modulation: q's -> 8ths -> dotted q's
-subdiv2
-superdiv3
{
udlrudl // group length/"measure" length is arbitrary
rludrlu // here's 7 dotted q's grouped
}.8
-unfree // no longer freestyle section
{lrrlrrlr}.8 // do this 8 times