Functional JavaScript API
While the mini notation is powerful on its own, there is much more to discover. Internally, the mini notation will expand to use the actual functional JavaScript API.
For example, this Pattern in Mini Notation:
is equivalent to this Pattern without Mini Notation:
Similarly, there is an equivalent function for every aspect of the mini notation.
Which representation to use is a matter of context. As a rule of thumb, you can think of the JavaScript API to fit better for the larger context, while mini notation is more practical for individiual rhythms.
Limits of Mini Notation
While the Mini Notation is a powerful way to write rhythms shortly, it also has its limits. Take this example:
stack( note("c2 eb2(3,8)").s('sawtooth').cutoff(800), s("bd,~ sd,hh*4") )
Here, we are using mini notation for the individual rhythms, while using the function stack
to mix them.
While stack is also available as ,
in mini notation, we cannot use it here, because we have different types of sounds.
Notes
Notes are automatically available as variables:
An important difference to the mini notation: For sharp notes, the letter βsβ is used instead of β#β, because JavaScript does not support β#β in a variable name.
The above is the same as:
Using strings, you can also use β#β.
Alternative Syntax
In the above example, we are nesting a function inside a function, which makes reading the parens a little more difficult. To avoid getting to many nested parens, there is an alternative syntax to add a type to a pattern:
You can use this with any function that declares a type (like n
, s
, note
, freq
etc), just make sure to leave the parens empty!
Pattern Factories
The following functions will return a pattern.
cat
The given items are concatenated, where each one takes one cycle. Synonym: slowcat
- items (any): The items to concatenate
cat(e5, b4, [d5, c5]).note() // "<e5 b4 [d5 c5]>".note()
seq
Like cat, but the items are crammed into one cycle. Synonyms: fastcat, sequence
seq(e5, b4, [d5, c5]).note() // "e5 b4 [d5 c5]".note()
stack
The given items are played at the same time at the same length.
stack(g3, b3, [e4, d4]).note() // "g3,b3,[e4,d4]".note()
timeCat
Like Pattern.seq, but each step has a length, relative to the whole.
timeCat([3,e3],[1, g3]).note() // "e3@3 g3".note()
Combining Patterns
You can freely mix JS patterns, mini patterns and values! For example, this pattern:
cat( stack(g3,b3,e4), stack(a3,c3,e4), stack(b3,d3,fs4), stack(b3,e4,g4) ).note()
β¦is equivalent to:
cat( "g3,b3,e4", "a3,c3,e4", "b3,d3,f#4", "b3,e4,g4" ).note()
β¦ as well as:
While mini notation is almost always shorter, it only has a handful of modifiers: * / ! @. When using JS patterns, there is a lot more you can do.
Time Modifiers
The following functions modify a pattern temporal structure in some way.
Pattern.slow
Slow down a pattern over the given number of cycles. Like the "/" operator in mini notation.
- factor (number|Pattern): slow down factor
s("<bd sd> hh").slow(2) // s("[<bd sd> hh]/2")
Pattern.fast
Speed up a pattern by the given factor. Used by "*" in mini notation.
- factor (number|Pattern): speed up factor
s("<bd sd> hh").fast(2) // s("[<bd sd> hh]*2")
Pattern.early
Nudge a pattern to start earlier in time. Equivalent of Tidal's <~ operator
- cycles (number|Pattern): number of cycles to nudge left
"bd ~".stack("hh ~".early(.1)).s()
Pattern.late
Nudge a pattern to start later in time. Equivalent of Tidal's ~> operator
- cycles (number|Pattern): number of cycles to nudge right
"bd ~".stack("hh ~".late(.1)).s()
Pattern.legato
Multiplies the hap duration with the given factor.
note("c3 eb3 g3 c4").legato("<.25 .5 1 2>")
Pattern.struct
Applies the given structure to the pattern:
note("c3,eb3,g3") .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~") .slow(4)
Pattern.euclid
Changes the structure of the pattern to form an euclidean rhythm. Euclidian rhythms are rhythms obtained using the greatest common divisor of two numbers. They were described in 2004 by Godfried Toussaint, a canadian computer scientist. Euclidian rhythms are really useful for computer/algorithmic music because they can describe a large number of rhythms with a couple of numbers.
- pulses (number): the number of onsets / beats
- steps (number): the number of steps to fill
// The Cuban tresillo pattern. note("c3").euclid(3,8)
Pattern.euclidLegato
Similar to euclid
, but each pulse is held until the next pulse,
so there will be no gaps.
n("g2").decay(.1).sustain(.3).euclidLegato(3,8)
Pattern.rev
Reverse all haps in a pattern
note("c3 d3 e3 g3").rev()
Pattern.iter
Divides a pattern into a given number of subdivisions, plays the subdivisions in order, but increments the starting subdivision each cycle. The pattern wraps to the first subdivision after the last subdivision is played.
note("0 1 2 3".scale('A minor')).iter(4)
Pattern.iterBack
Like iter
, but plays the subdivisions in reverse order. Known as iter' in tidalcycles
note("0 1 2 3".scale('A minor')).iterBack(4)
Conditional Modifiers
Pattern.every
An alias for firstOf
- n (number): how many cycles
- func (function): function to apply
note("c3 d3 e3 g3").every(4, x=>x.rev())
Pattern.when
Applies the given function whenever the given pattern is in a true state.
- binary_pat (Pattern):
- func (function):
"c3 eb3 g3".when("<0 1>/2", x=>x.sub(5)).note()
Accumulation Modifiers
Pattern.stack
Stacks the given pattern(s) to the current pattern.
s("hh*2").stack( n("c2(3,8)") )
Pattern.superimpose
Superimposes the result of the given function(s) on top of the original pattern:
"<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" .superimpose(x=>x.add(2)) .scale('C minor').note()
Pattern.layer
Layers the result of the given function(s). Like Pattern.superimpose, but without the original pattern:
"<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" .layer(x=>x.add("0,2")) .scale('C minor').note()
Pattern.off
Superimposes the function result on top of the original pattern, delayed by the given time.
- time (Pattern|number): offset time
- func (function): function to apply
"c3 eb3 g3".off(1/8, x=>x.add(7)).note()
Pattern.echo
Superimpose and offset multiple times, gradually decreasing the velocity
- times (number): how many times to repeat
- time (number): cycle offset between iterations
- feedback (number): velocity multiplicator for each iteration
s("bd sd").echo(3, 1/6, .8)
Pattern.echoWith
Superimpose and offset multiple times, applying the given function each time.
- times (number): how many times to repeat
- time (number): cycle offset between iterations
- func (function): function to apply, given the pattern and the iteration index
"<0 [2 4]>" .echoWith(4, 1/8, (p,n) => p.add(n*2)) .scale('C minor').note().legato(.2)
Concat Modifiers
Pattern.seq
Appends the given pattern(s) to the current pattern. Synonyms: .sequence .fastcat
s("hh*2").seq( n("c2(3,8)") )
Pattern.cat
Appends the given pattern(s) to the next cycle. Synonym: .slowcat
s("hh*2").cat( n("c2(3,8)") )
Value Modifiers
Pattern.add
Assumes a pattern of numbers. Adds the given number to each item in the pattern.
// Here, the triad 0, 2, 4 is shifted by different amounts "0 2 4".add("<0 3 4 0>").scale('C major').note() // Without add, the equivalent would be: // "<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major').note()
// You can also use add with notes: "c3 e3 g3".add("<0 5 7 0>").note() // Behind the scenes, the notes are converted to midi numbers: // "48 52 55".add("<0 5 7 0>").note()
Pattern.sub
Like add, but the given numbers are subtracted.
"0 2 4".sub("<0 1 2 3>").scale('C4 minor').note() // See add for more information.
Pattern.mul
Multiplies each number by the given factor.
"1 1.5 [1.66, <2 2.33>]".mul(150).freq()
Pattern.div
Divides each number by the given factor.
Pattern.round
Assumes a numerical pattern. Returns a new pattern with all values rounded to the nearest integer.
"0.5 1.5 2.5".round().scale('C major').note()
Pattern.apply
Like layer, but with a single function:
"<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4")).note()
Pattern.range
Assumes a numerical pattern, containing unipolar values in the range 0 .. 1. Returns a new pattern with values scaled to the given min/max range. Most useful in combination with continuous patterns.
s("bd sd,hh*4").cutoff(sine.range(500,2000).slow(4))
Pattern.chunk
Divides a pattern into a given number of parts, then cycles through those parts in turn, applying the given function to each part in turn (one part per cycle).
"0 1 2 3".chunk(4, x=>x.add(7)).scale('A minor').note()
Pattern.chunkBack
Like chunk
, but cycles through the parts in reverse order. Known as chunk' in tidalcycles
"0 1 2 3".chunkBack(4, x=>x.add(7)).scale('A minor').note()