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()