Skip to content
neo451 edited this page Jun 19, 2024 · 24 revisions

Welcome to the modal! This page documents some design process, syntax difference with tidal/strudel and (maybe) new features.

Overall structure

modal aimed to be both a lua library that looks alot like strudel:

d1(every("<3 4>", "x -> x |+ 7", note"[0 3 7]")
note"0 7":every(4, "|+ note 1"):d1()

and thanks to the amazing and powerful lpeg library, modal also support the maxi notation, discussed here: https://github.com/tidalcycles/strudel/discussions/96

this is under active construction

d1 $ every <3 4> (|+ note 7) note [0 4 7] -- TODO

Syntax

Literals

-- lua: strings mostly gets converted to pattern
d1(s"bd")
d2(note"0 .. 7":s"piano")
-- modal: no quotes needed!
d1 $ s bd
d2 $ note [0 .. 7] |> s piano 

Mini-notation

Structures

-- () is just like lisp lists
> (fast 2 bd)

-- [(,) (|)] is fastcat / timecat / stack / randcat
> [bd sd]
> [bd sd, ~ cp]
> [bd|sd|cp]

-- <(|)> is slowcat / arrange
> <bd sd>
> <bd|sd|cp>

-- {(,)}%x is polymeter
> {bd sd cp, hh}%5

-- should be able to combine these dynamically
> [bd <sd cp>]
> [(fast 2 bd) sd] -- not that useful? 

Modifiers

-- these work outside structures
> bd*2 
> bd/2
> bd?0.7
> bd(3,8)
> bd:2

-- these work inside all structures
> [bd!3 sd]
> <bd@3 sd>
> <0 .. 3> -- eq to <0 1 2 3> actually more sensible than tidal/strudel?

ideas

  1. dot method? > lpf sine.range(200, 2000)
  2. literal lists that translates to lua table > layer '((fast 2) rev) $ s [bd sd] or more tidal like > layer (fast 2, rev) $ s [bd sd]

Functions

In lua, most library functions support both strudel style method calling and tidal style function calling:

euclid(3, 8, 1, s"bd")

s"bd":euclid(3, 8, 1)

Partial application

In modal, method calling does not make sense, also, currying the method calls make no sense as well.

In both case, the tidal style functions are smartly curried like in haskell, meaning you can do partial application easily like in Tidal

off(0.25, euclid(3,8,1), s"bd")
off 0.25 (euclid 3 8 1) s bd

you can also pattern curried functions in higher order functions like every

> every 4 [(+ 1), (fast 2)] 1 -- > compile lua: every(4, stack { function(x) return x + 1 end, function(x) return fast(2, x) end }, 1)

Composing

-- OO-style method chaining
id = function(a)
   return a:fast(2):slow(2)
end

-- functional style piping
id = pipe(fast(2), slow(2))

TODO

id = fast 2 . slow 2

Embedding patterns

declare reusable patterns and sample names is especially easy in this environment

a = 1  -- only with global vars
reify"^a 2 3" --> [1 2 3]
ff = "bd!4"
reify"^ff, ~ sd ~ sd" --> [bd [bd sd] bd [bd sd]]
bd = 808bd
reify"^bd sd"
a = 1
[^a 2 3]
ff = [bd!4]
[^ff, ~ sd ~ sd]
bd = 808bd
[^bd sd]

TODOs

  1. pattern of functions(tranformations)
every 4 [(fast 2) rev] $ note 1

this is not possibe for current haskell implementation where every's second param is just a function, but might be possible just by fully patternify??? this might just be like a good syntax arround spread?

  1. lib pats && auto sample name swap
-- M.fonf = reify("bd sd bd sd") -- libaray patterns
> bd = 808bd
> fonf = 808bd sd 808 bd
Clone this wiki locally