Language Constructs
Apart from the sequencing language, Mégra has some "traditional" programming language constructs that might help when interfacing with the "outside world" or in other situations. Most a borrowed from other languages.
Some of these are not stable yet and might change as demands are refined ...
Arithmetics
Mégra has some basic arithmetic support ...
Syntax
- Multiplication:
(mul <arg0> ... <argN>)
- Division:
(div <args>)
- Addition:
(add <arg0> ... <argN>)
- Subtraction:
(sub <args>)
- Modulo:
(mod <args>)
- Power:
(pow <args>)
- Max on n:
(max <args>)
- returns arg with the maximum value - Min on n:
(min <args>)
- returns arg with the minimum value
Examples:
(add 1 2 3) ;; 6
(pow 2 2) ;; 4
(max 2 4 6) ;; 6
The arithmetics are (kinda) lazily evaluated, so you can modify global behaviours.
(let tonic 100)
(sx 'ba #t
(nuc 'root (saw tonic))
(nuc 'fifth (saw (mul tonic 1.5))))
By changing tonic
you can now change the chord while it's running ...
callback
- Define a Callback
Same as fun
, but for MIDI- and OSC callbacks (see articles about MIDI and OSC to see how to define callbacks).
concat
- Concatenate Symbols or Strings
Syntax
(concat <string_or_sym_1> ... <string_or_sym_N>)
The first argument determines the return type (if it's a symbol, then concat
returns a symbol, if it's a string, then concat
returns a string).
Example
(concat 'foo "bar" 'baz) ;; returns symbol
(concat "foo" "bar" 'baz) ;; returns string
fun
- Define Functions
Syntax
(fun <function-name> (<arg0> .. <argN)
<function-body>
)
Example
(fun square (a)
(mul a a))
(print (square 2))
You can also use this to create sound events with certain parameters:
(fun doublesaw (freq)
(mosc :osc1 'saw :osc2 'saw :freq1 freq :freq2 (add freq 2)))
(sx 'foo #t
(loop 'bar (doublesaw 100) (doublesaw 110) (doublesaw 90) (~)))
Furthermore, you can use this feature to create more abstract generator functions:
(fun x3 (a)
(vec a a a))
(sx 'ba #t
(cyc 'foo (x3 (saw 200))))
Or even entire generators:
(fun x3 (name a)
(cyc name a a a))
(sx 'ba #t
(x3 'boo (saw 200))
(x3 'doo (saw 300)))
If you want to define a function without parameters, the intuitive way to do this would be just leaving the parenthesis
empty, but in lisp-fashion you can also pass a #f
flag:
;; either
(fun noparam ()
(once (saw 100)))
;; or
(fun noparam #f
(once (saw 100)))
You can use the @rest
and @all
placeholders if you want to pass on arguments to another function:
;; pass on all arguments from 'foo' to 'saw'
(fun foo () (once (saw @all)))
;; arguments are passed on
(foo 300 :rev 0.2)
;; a chord function for 'cyc' and 'loop'
(fun chord ()
(vec (vec @all))) ;; pass on all args
(sx 'baa #t
(loop 'fa (chord (saw 100) (saw 350))))
;; pass on rest, freq is a mandatory positional arg
(fun bar (freq)
(once (saw freq @rest)))
(bar 300) ;; frequency is mandatory
(bar 400 :rev 0.2) ;; the rest is optional
insert
- Insert Into a Hash Map (also see map
)
Syntax
(insert <map_name> <key> <value>)
Map must exist!
Example
(let foo (map (pair "some" "thing")))
(insert foo "another" "thing")
(print foo)
let
- Define Global Variables
Syntax
(let <name> <value>)
Note that name
can be a symbol or just a random identifier ..
Example
(let freq 100)
(sx 'ba #t
(nuc 'fu (saw freq)))
map
- Define a Hash Map (Unstable!)
Syntax
(map (pair <key1> <value1) ... (pair <keyN> <valueN>))
Example
(let foo (map (pair "some" "thing") (pair "another" "thing")))
(print foo)
match
- Conditional Branching (Unstable!)
A vague mashup of Common Lisp's cond
and Rust's match
... not sure where it's going, yet ...
Example
Match the incoming argument precisely:
(fun decide (a)
(match a
0 (print "ping")
1 (print "pong")))
(decide 1)
;; (decide 0)
You can also specify conditions (all branches that match will be executed):
(fun decide (a)
(match a
(> 10) (print "ping") ;; larger than 10
(< 12) (print "pong") ;; smaller than 12
))
(decide 13) ;; pin
;; (decide 11)
;; (decide 9)
Available conditions:
(< x)
lesser x(<= x)
lesser or equal x(> x)
greater x(>= x)
greater or equal x(istype x)
argument is of type x- use
'num
to match numerical types - use
'str
to match string type - use
'vec
to match vector type - use
'sym
to match symbol type - use
'map
to match map type
(fun va (x)
(match x
(istype 'str) (once (sine 600))))
(va 10) ;; nothing
(va "10") ;; beep
There's currently no default or fallback condition that is executed if no other matches.
pair
- a Pair of Things
(only used for hash map definition so far, see there ...)
print
- Print Debug Output
Example
(print "hi")
(print (nuc 'fa (saw 100)))
(print (mul 2 5))
progn
- Execute Several Statements at Once
Very much borrowed from Common Lisp ...
Syntax
(progn
<statement0>
...
<statementN>)
Example
;; start two contexts at the same time ...
(progn
(sx 'baz #t (nuc 'foo (saw 200)))
(sx 'bam #t (nuc 'bar (saw 320))))
push
- Push an Element to a Vector (also see vec
)
Syntax
(push <vec_name> <value>)
Vector must exist!
Example
(let hi (vec "h" "e" "l" "l" "o"))
(push hi "jane")
(print hi)
vec
- Define a Vector
Syntax
(vec <val1> ... <valN>)
Example
(let hi (vec "h" "e" "l" "l" "o"))
(print hi)