Diminished Forth definition and interpreter
This is the tiny language floatbeat uses to define sounds, designed for fun and fast live coding of music.
It's a stack based language similar to Forth. The main differences are It also has some tweaks intended to make it faster (both to write, and to execute)
A word is a contiguous sequence of (unicode.IsDigit or .) or (unicode.IsLetter or _) or a single other non-whitespace rune.
Whitespace is only needed in order to separate adjacent sequences of digits or letters.
2DUP --> [2] [DUP]
2.4* --> [2.4] [*]
a__b!=5 --> [a__b] [!] [=] [5]
Words are case insensitive.
The entire program is run every time the machine needs a new sample. If your sample rate is 44.1kHz, the program will run 44100 times every second.
The iteration number is available in the built-in word T.
Built-in words S and BPM convert T to common time durations, to build sequences.
Use KEEP to define a value to be used later: 75 KEEP my_var Retrieve with my_var?
KEEPd values are evaluated at runtime but are fixed once set.
(KEEP is less confusing than CONSTANT, as values may vary from one iteration to the next)
KEEPd values can be accessed in later iterations using OLD.
You can build filters using DELTA and PREWARP.
The word . pops the value off the top of the stack and adds it to an output stack ready to be returned.
TRUE===1FALSE===0+-*/=><NOTORAND:;define a wordIFTHENELSE: can't be nested, define words if you want to do thisDROP( x -- )DUP( x -- x x )DDUP( x y -- x y x y ) : standard Forth uses2DUPfor thisOVER( x y -- x y x )NIP( x y -- y )TUCK( x y -- y x y )SWAP( x y -- y x )ROT( x y z -- y z x )DMOD( number, modulus -- remainder, floor ) : standard Forth has/MODCONSTANT!@?
-
.: remove the item on top of stack (TOS) and add it to the output stack (clipped to -1..+1) -
&===DUP .i.e. add the item on TOS to the output stack without removing it from the stack -
~===SWAP -i.e. reverse subtract -
\===SWAP /i.e. reverse divide -
HIDE( x y z -- z x y ) ===ROT ROT -
FIDDLE( x y z -- y x z ) ===ROT SWAP -
NOOP: noop -
T: iteration number -
ON( schedule_t, duration, base_t -- 0 or age, 1 ) : Is the note of lengthdurationscheduled forschedule_tcurrently in progress at timebase_t, and if so, how old is it?example
1S 0.5S T ON IF 440HZ SIN. THENplays an A for 0.5 sec, 1 sec after the start. -
FROM...CHOOSE: treat TOS as a pointer and execute the word with that index betweenFROMandCHOOSE. So2 FROM a b c d CHOOSEwould execute onlycbecausechas index 2 in the set.example
T 1S 4 DMOD FROM play_c play_d play_e play_f CHOOSEwill executeplay_cin the first second,play_din the second, and so on. Because of theDMOD, the age of each note will be on TOS for the play routines. -
KEEP x===CONSTANT x ! -
OLD( definition_name time -- value ) : get the value saved underdefinition_namein the iteration the specified time agoexample
my_var 0.3s OLD -
DELTA( definition_name -- delta ) : get the difference between the current value ofdefinition_nameand its value in a previous iteration. Useful for implementing filters. -
PREWARP( freq -- prewarp_freq ) : Evaluate tan( πfreq/ samplerate ) , useful for implementing filters. -
::...;: import pre-set definition packagesexample
:: scale divisions;will import thescalepackage (defines the equal tempered scale) and thedivisionspackage
-
#,SHARP,♯( freq -- freq ) : Sharpen a frequency by 1 semitone (equal tempered) -
FLAT,♭( freq -- freq ) : Flatten a frequency by 1 semitone (equal tempered)
These all take a phase angle, which you can get by multiplying T by a frequency value.
The built-in word HZ is available to get the right angle: 440 HZ T*sin
(Note: x HZ * !== x S *, because the way HZ is defined includes a factor of 2&pi.)
(Note 2: Previous versions of d4 had simpler syntax, but this has had to change to enable FM synthesis to work properly.)
-
SIN( angle -- signal ) : Sine wave oscillator -
SAW( angle -- signal ) : Sawtooth oscillator -
PULSE( width angle -- signal ) : Pulse wave oscillator -
SQ( angle -- signal ) : Square wave oscillator -
TR( angle -- signal ) : Triangle wave oscillator -
NOISE( -- signal ) : White noise source -
CLIP( n ) : When outputting to a buffer (sound hardware...), scale the results down by this factor.example
A SIN. C SIN. 2 CLIPwill scale down the 2 notes so they fit into -1...+1