TuningFork.Pattern (TuningFork v0.1.11)

Copy Markdown View Source

Patterns of events over cycles, queried by span.

iex> pattern = TuningFork.Pattern.fastcat([:bd, :sn])
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.5, :bd}, {0.5, 1.0, :sn}]

Summary

Types

One event: whole is where it sits as written, nil for a continuous value; part is the portion of it a query covers and is never nil; value is what it is.

A stretch of time, in cycles. The end is exclusive.

t()

Functions

Add other to every value, keeping this pattern's timing.

Apply fun to about nine events in ten.

Apply fun to about one event in ten.

Apply fun to the whole pattern.

Combine pattern with other, keeping pattern's wholes: each event of pattern is cut into parts wherever other's events fall inside it, and fun joins the two values. A continuous other is read once per event, at its start. An event other has nothing for is left out.

Spread the values sounding together in one whole out into a run of equal events, one after another. mode is :up, :down, :updown or :downup.

arp/2 with fun ordering the values: it is given the list sounding at once and returns the run.

{count, pattern} pairs played in turn, each for count cycles. parts must not be empty.

The bits of number, most significant first, as a cycle of true and false.

binary/1 padded to width bits.

The on-off pattern euclid/3 is built from, as a list of booleans.

true or false, evenly.

A continuous true about amount of the time, false otherwise, from rand/1.

A continuous pattern of one of choices, chosen anew at every instant from rand/1. choices must not be empty.

One of choices per cycle, held for the whole of it. choices must not be empty.

Cut the cycle into n parts and apply fun to a different one each cycle, first to last. fun is applied to the whole pattern and the result narrowed to the part.

chunk/3 walking backwards through the parts.

Hold every event for amount of its own length: below 1.0 shorter, above 1.0 overlapping. Continuous events are left alone. A pattern of amounts applies each over its own span, as patterned/3.

Squeeze one cycle of pattern into the from..to portion of every cycle. from and to are within 0.0 to 1.0; anything else gives silence/0.

Count the pattern as factor times fewer steps. The other way from expand/2.

A cosine from 1.0 to 0.0 and back, once a cycle.

Drop events at random, keeping about 1 - amount of them. The same event in the same cycle is dropped or kept the same way every run; seed chooses a different set of drops.

Divide every value by other. Division by zero leaves the value as it was. See add/2.

Everything but the first count steps, stretched to fill the cycle.

count copies stacked, each time cycles later than the last. fun is given each shifted copy and its number, 0 upwards, and returns the pattern to stack.

hits beats spread as evenly as possible over steps, each carrying pattern. Rests are silence/0. A negative hits sounds on the rests instead.

euclid/3 with the hits rotated rotation steps to the left.

hits beats over steps, each held until the next one rather than lasting one step.

hits beats over steps, rotated by rotation. The same as euclid/4.

euclid/4 with each argument a pattern, read once a cycle.

Apply fun to pattern on every nth cycle, counting from cycle zero. fun takes a pattern and returns one; on other cycles the pattern plays as written.

Count the pattern as factor times as many steps, without changing what it plays.

Play the pattern factor times over, counted as factor times as many steps: fast/2 and expand/2 together.

Squeeze pattern into 1 / factor of the time, so it repeats factor times a cycle.

chunk/3 fitting all n parts into one cycle rather than taking n cycles over them.

Squeeze one cycle of pattern into the first 1 / factor of every cycle, leaving the rest silent. A factor of zero or less gives silence/0; a factor of 1 or less leaves the pattern as it is.

All of them inside one cycle, in order.

Keep only the events test returns true for.

The onsets of cycle cycle as {from, to, value} tuples, relative to the cycle start, rounded to six places and sorted.

Apply fun on the first cycle of each group of n. The same as every/3.

Take by steps more each time round, up to the whole pattern. shrink/2 reversed.

Slow the pattern down by n, apply fun, then speed it back up, so fun works on 1 / n of a cycle at a time.

Swap true and false in every value, leaving any other value alone.

A continuous whole number from 0 to n - 1, from rand/1.

A ramp from 1.0 down to 0.0 across each cycle.

Shift the pattern on by 1 / n of a cycle more each cycle, coming back round after n.

iter/2 the other way round, shifting back rather than on.

Apply fun on the last cycle of each group of n, counting from cycle zero.

Lay every fun in the list over the pattern at once.

Play only the first amount of each cycle, over and over to fill it.

Multiply every value by other. See add/2.

The pattern unchanged; fun is ignored.

A pattern from a query function.

Lay a changed copy over the original, amount cycles later.

Apply fun to about three quarters of the events.

Whether this event begins here rather than continuing one already sounding: true when part starts where whole starts, false when whole is nil.

inside/3 with 1 / n: speed up by n, apply fun, slow back down.

Play the pattern at target steps a cycle, whatever it was written as. A pattern of zero steps gives silence/0.

Play the pattern forwards on even cycles and backwards on odd ones.

Apply fun with each value of amounts over the span that value holds.

Smooth continuous noise from 0.0 to 1.0, interpolated between one whole cycle's value and the next. seed chooses a different sequence.

One pattern per cycle from patterns, chosen by which: a pattern of whole numbers counting from zero, sampled at the start of each cycle and wrapped round the length of the list. A cycle where which has no number is silent. patterns must not be empty.

Repeat each event n times inside its own span.

Play every pattern at once, each stretched so they all run at steps steps a cycle.

value, once per cycle, filling the cycle.

The events of pattern between the two cycle positions.

A continuous value from 0.0 to 1.0, hashed from the position and seed. The same position always gives the same value.

Stretch a 0.0-to-1.0 pattern onto low..high.

Apply fun to about a quarter of the events.

Play each cycle backwards.

Play the stretch of cycles cycles starting at cycle from, over and over.

The numbers 0 to n - 1, one a cycle divided evenly.

A ramp from 0.0 to 1.0 across each cycle.

Chop pattern into n equal events a cycle, each holding the value sounding at its start, discrete or continuous. Where pattern has no value at a start, that event is left out.

Move the whole of pattern later by amount cycles. A negative amount moves it earlier.

Take by steps fewer each time round, until there is nothing left, the takes laid end to end with stepcat/1.

A continuous pattern: fun is given a cycle position and returns the value there. A query gets one event with whole: nil, sampled at the middle of the span.

A pattern with nothing in it.

A sine from 0.0 to 1.0 and back, once a cycle.

Stretch pattern over factor cycles. The inverse of fast/2. factor may be a pattern or mini-notation.

One pattern per cycle, in turn: the first on cycle 0, the second on cycle 1, and so on, wrapping round. Each keeps its own speed.

Apply fun to about half the cycles, whole ones at a time.

Apply fun to about amount of the cycles, whole ones at a time. The same cycle is chosen the same way every run; seed chooses a different set.

Apply fun to about half the events. sometimes_by/4 with 0.5.

Apply fun to about amount of the events. The same event in the same cycle is chosen the same way every run; seed chooses a different set.

0.0 for the first half of each cycle and 1.0 for the second.

Squeeze one cycle of pattern into each event of structure. Continuous events and events straddling a cycle line give nothing.

Replace every event with a pattern of its own, squeezed into the event's whole. fun is given the value and returns the pattern. Continuous events and events straddling a cycle line give nothing.

Everything at once.

One pattern from each group in turn, stepcat/1ed into one pattern.

Lay patterns end to end in one cycle, each given room in proportion to its steps/1. The result is counted as the sum of their steps.

How many steps this pattern is counted as having. Read by stepcat/1, pace/2 and the other stepwise functions; it does not change what the pattern plays.

count copies of the pattern, each time later than the one before.

Take other away from every value. See add/2.

Lay fun of the pattern over the original, in place.

swing_by/3 with an amount of a third.

Push the second half of each of n subdivisions of the cycle late by amount of a subdivision.

The first count steps of the pattern, stretched to fill the cycle.

A cycle divided between {weight, pattern} pairs in proportion to their weights. A total weight of zero or less gives silence/0.

Each pattern in many in turn stepcat/1ed after pattern, one per cycle. many must not be empty.

A triangle from 0.0 up to 1.0 and back down, once a cycle.

Keep only the events degrade/3 with the same seed drops, about half.

Keep only the events degrade_by/3 with the same amount and seed drops.

The value pattern holds at position, or nil where it holds none.

A continuous pattern of one of choices, given as {weight, value} pairs, chosen anew at every instant in proportion to weight. choices must not be empty.

One of choices, given as {weight, value} pairs, per cycle, held for the whole of it. choices must not be empty.

Apply fun on the cycles test returns true for. test is given the cycle number, an integer counting up from zero.

The same pattern, counted as having steps steps. What it plays does not change.

Replace every value with fun of it, leaving the timing alone.

Take one step from each pattern in turn, round and round.

Play the slice of each cycle between from and to, stretched to fill it.

Types

event()

@type event() :: %{whole: span() | nil, part: span(), value: term()}

One event: whole is where it sits as written, nil for a continuous value; part is the portion of it a query covers and is never nil; value is what it is.

span()

@type span() :: {float(), float()}

A stretch of time, in cycles. The end is exclusive.

t()

@type t() :: %TuningFork.Pattern{query: (span() -> [event()]), steps: number()}

Functions

add(pattern, other)

@spec add(t(), t() | number() | map()) :: t()

Add other to every value, keeping this pattern's timing.

other is a number, a map, or another pattern sampled at each event's start; where a pattern has no value there the event is left alone. Two maps are added key by key where they share a key and the rest kept; a map and a number add the number to every numeric value.

iex> pattern = TuningFork.Pattern.add(TuningFork.Pattern.fastcat([0, 2]), 12)
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.5, 12}, {0.5, 1.0, 14}]

almost_always(pattern, fun, seed \\ 0)

@spec almost_always(t(), (t() -> t()), integer()) :: t()

Apply fun to about nine events in ten.

almost_never(pattern, fun, seed \\ 0)

@spec almost_never(t(), (t() -> t()), integer()) :: t()

Apply fun to about one event in ten.

always(pattern, fun)

@spec always(t(), (t() -> t())) :: t()

Apply fun to the whole pattern.

app_left(pattern, other, fun)

@spec app_left(t(), t(), (term(), term() -> term())) :: t()

Combine pattern with other, keeping pattern's wholes: each event of pattern is cut into parts wherever other's events fall inside it, and fun joins the two values. A continuous other is read once per event, at its start. An event other has nothing for is left out.

iex> left = TuningFork.Pattern.fastcat([:a, :b])
iex> right = TuningFork.Pattern.fastcat([1, 2, 3])
iex> TuningFork.Pattern.app_left(left, right, fn a, b -> {a, b} end) |> TuningFork.Pattern.first_cycle()
[{0.0, 0.5, {:a, 1}}, {0.5, 1.0, {:b, 2}}]

arp(pattern, mode \\ :up)

@spec arp(t(), :up | :down | :updown | :downup) :: t()

Spread the values sounding together in one whole out into a run of equal events, one after another. mode is :up, :down, :updown or :downup.

arp_with(pattern, fun)

@spec arp_with(t(), ([term()] -> [term()])) :: t()

arp/2 with fun ordering the values: it is given the list sounding at once and returns the run.

arrange(parts)

@spec arrange([{pos_integer(), t()}]) :: t()

{count, pattern} pairs played in turn, each for count cycles. parts must not be empty.

arrange([{2, a}, {1, b}])

binary(number)

@spec binary(non_neg_integer()) :: t()

The bits of number, most significant first, as a cycle of true and false.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.binary(5))
[{0.0, 0.25, false}, {0.25, 0.5, true}, {0.5, 0.75, false}, {0.75, 1.0, true}]

binary(number, width)

@spec binary(non_neg_integer(), pos_integer()) :: t()

binary/1 padded to width bits.

bjorklund(hits, steps)

@spec bjorklund(non_neg_integer(), pos_integer()) :: [boolean()]

The on-off pattern euclid/3 is built from, as a list of booleans.

iex> TuningFork.Pattern.bjorklund(3, 8)
[true, false, false, true, false, false, true, false]

brand(seed \\ 0)

@spec brand(integer()) :: t()

true or false, evenly.

brand_by(amount, seed \\ 0)

@spec brand_by(number(), integer()) :: t()

A continuous true about amount of the time, false otherwise, from rand/1.

choose(choices, seed \\ 0)

@spec choose([term()], integer()) :: t()

A continuous pattern of one of choices, chosen anew at every instant from rand/1. choices must not be empty.

choose_cycles(choices, seed \\ 0)

@spec choose_cycles([term()], integer()) :: t()

One of choices per cycle, held for the whole of it. choices must not be empty.

chunk(pattern, n, fun)

@spec chunk(t(), pos_integer(), (t() -> t())) :: t()

Cut the cycle into n parts and apply fun to a different one each cycle, first to last. fun is applied to the whole pattern and the result narrowed to the part.

chunk(pattern, 4, &fast(&1, 2))

chunk_back(pattern, n, fun)

@spec chunk_back(t(), pos_integer(), (t() -> t())) :: t()

chunk/3 walking backwards through the parts.

clip(pattern, amounts)

@spec clip(t(), number() | t()) :: t()

Hold every event for amount of its own length: below 1.0 shorter, above 1.0 overlapping. Continuous events are left alone. A pattern of amounts applies each over its own span, as patterned/3.

compress(pattern, from, to)

@spec compress(t(), number(), number()) :: t()

Squeeze one cycle of pattern into the from..to portion of every cycle. from and to are within 0.0 to 1.0; anything else gives silence/0.

iex> TuningFork.Pattern.first_cycle(
...>   TuningFork.Pattern.compress(TuningFork.Pattern.pure(:x), 0.25, 0.75)
...> )
[{0.25, 0.75, :x}]

contract(pattern, factor)

@spec contract(t(), number()) :: t()

Count the pattern as factor times fewer steps. The other way from expand/2.

cosine()

@spec cosine() :: t()

A cosine from 1.0 to 0.0 and back, once a cycle.

degrade(pattern, amount, seed \\ 0)

@spec degrade(t(), number(), integer()) :: t()

Drop events at random, keeping about 1 - amount of them. The same event in the same cycle is dropped or kept the same way every run; seed chooses a different set of drops.

degrade_by(pattern, amount, seed \\ 0)

@spec degrade_by(t(), number(), integer()) :: t()

The same as degrade/3.

divide(pattern, other)

@spec divide(t(), t() | number() | map()) :: t()

Divide every value by other. Division by zero leaves the value as it was. See add/2.

drop(pattern, count)

@spec drop(t(), number()) :: t()

Everything but the first count steps, stretched to fill the cycle.

A negative count drops from the end instead.

iex> pattern = TuningFork.Pattern.drop(TuningFork.Pattern.fastcat([:a, :b, :c, :d]), 2)
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.5, :c}, {0.5, 1.0, :d}]

echo_with(pattern, count, time, fun)

@spec echo_with(t(), pos_integer(), number(), (t(), non_neg_integer() -> t())) :: t()

count copies stacked, each time cycles later than the last. fun is given each shifted copy and its number, 0 upwards, and returns the pattern to stack.

euclid(pattern, hits, steps)

@spec euclid(t(), integer(), pos_integer()) :: t()

hits beats spread as evenly as possible over steps, each carrying pattern. Rests are silence/0. A negative hits sounds on the rests instead.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.euclid(TuningFork.Pattern.pure(:bd), 3, 8))
[{0.0, 0.125, :bd}, {0.375, 0.5, :bd}, {0.75, 0.875, :bd}]

euclid(pattern, hits, steps, rotation)

@spec euclid(t(), integer(), pos_integer(), integer()) :: t()

euclid/3 with the hits rotated rotation steps to the left.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.euclid(TuningFork.Pattern.pure(:bd), 3, 8, 2))
[{0.125, 0.25, :bd}, {0.5, 0.625, :bd}, {0.75, 0.875, :bd}]

euclid_legato(pattern, hits, steps)

@spec euclid_legato(t(), pos_integer(), pos_integer()) :: t()

hits beats over steps, each held until the next one rather than lasting one step.

euclid_rot(pattern, hits, steps, rotation)

@spec euclid_rot(t(), pos_integer(), pos_integer(), integer()) :: t()

hits beats over steps, rotated by rotation. The same as euclid/4.

euclid_with(pattern, hits, steps, rotation)

@spec euclid_with(t(), t(), t(), t()) :: t()

euclid/4 with each argument a pattern, read once a cycle.

euclid_with(pure(:bd), mini("<3 5>"), pure(8), pure(0))

every(n, fun, pattern)

@spec every(pos_integer(), (t() -> t()), t()) :: t()

Apply fun to pattern on every nth cycle, counting from cycle zero. fun takes a pattern and returns one; on other cycles the pattern plays as written.

every(4, &rev/1, pattern)

expand(pattern, factor)

@spec expand(t(), number()) :: t()

Count the pattern as factor times as many steps, without changing what it plays.

extend(pattern, factor)

@spec extend(t(), number()) :: t()

Play the pattern factor times over, counted as factor times as many steps: fast/2 and expand/2 together.

fast(pattern, factors)

@spec fast(t(), number()) :: t()

Squeeze pattern into 1 / factor of the time, so it repeats factor times a cycle.

A factor of zero or less gives silence/0. The step count is carried through unchanged.

fast_chunk(pattern, n, fun)

@spec fast_chunk(t(), pos_integer(), (t() -> t())) :: t()

chunk/3 fitting all n parts into one cycle rather than taking n cycles over them.

fast_gap(pattern, factor)

@spec fast_gap(t(), number()) :: t()

Squeeze one cycle of pattern into the first 1 / factor of every cycle, leaving the rest silent. A factor of zero or less gives silence/0; a factor of 1 or less leaves the pattern as it is.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.fast_gap(TuningFork.Pattern.pure(:x), 4))
[{0.0, 0.25, :x}]

fastcat(items)

@spec fastcat([t() | term()]) :: t()

All of them inside one cycle, in order.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.fastcat([:bd, :sn, :hh]))
[{0.0, 0.333333, :bd}, {0.333333, 0.666667, :sn}, {0.666667, 1.0, :hh}]

A bare value in items is taken as pure/1 of it. The result is counted as length(items) steps.

filter_events(pattern, test)

@spec filter_events(t(), (event() -> boolean())) :: t()

Keep only the events test returns true for.

first_cycle(pattern, cycle \\ 0)

@spec first_cycle(t(), non_neg_integer()) :: [{float(), float(), term()}]

The onsets of cycle cycle as {from, to, value} tuples, relative to the cycle start, rounded to six places and sorted.

first_of(pattern, n, fun)

@spec first_of(t(), pos_integer(), (t() -> t())) :: t()

Apply fun on the first cycle of each group of n. The same as every/3.

grow(pattern, by \\ 1)

@spec grow(t(), pos_integer()) :: t()

Take by steps more each time round, up to the whole pattern. shrink/2 reversed.

inside(pattern, n, fun)

@spec inside(t(), number(), (t() -> t())) :: t()

Slow the pattern down by n, apply fun, then speed it back up, so fun works on 1 / n of a cycle at a time.

inside(pattern, 2, &rev/1)

invert(pattern)

@spec invert(t()) :: t()

Swap true and false in every value, leaving any other value alone.

iex> TuningFork.Pattern.invert(TuningFork.Pattern.binary(5))
...> |> TuningFork.Pattern.first_cycle()
...> |> Enum.map(&elem(&1, 2))
[true, false, true, false]

irand(n, seed \\ 0)

@spec irand(pos_integer(), integer()) :: t()

A continuous whole number from 0 to n - 1, from rand/1.

iex> pattern = TuningFork.Pattern.segment(TuningFork.Pattern.irand(8), 4)
iex> TuningFork.Pattern.first_cycle(pattern) |> Enum.all?(fn {_f, _t, v} -> v in 0..7 end)
true

isaw()

@spec isaw() :: t()

A ramp from 1.0 down to 0.0 across each cycle.

iter(pattern, n)

@spec iter(t(), pos_integer()) :: t()

Shift the pattern on by 1 / n of a cycle more each cycle, coming back round after n.

iex> pattern = TuningFork.Pattern.iter(TuningFork.Pattern.fastcat([:a, :b, :c, :d]), 4)
iex> TuningFork.Pattern.first_cycle(pattern, 1)
[{0.0, 0.25, :b}, {0.25, 0.5, :c}, {0.5, 0.75, :d}, {0.75, 1.0, :a}]

iter_back(pattern, n)

@spec iter_back(t(), pos_integer()) :: t()

iter/2 the other way round, shifting back rather than on.

last_of(pattern, n, fun)

@spec last_of(t(), pos_integer(), (t() -> t())) :: t()

Apply fun on the last cycle of each group of n, counting from cycle zero.

layer(pattern, funs)

@spec layer(t(), [(t() -> t())]) :: t()

Lay every fun in the list over the pattern at once.

layer(pattern, [&rev/1, &fast(&1, 2)])

linger(pattern, amount)

@spec linger(t(), number()) :: t()

Play only the first amount of each cycle, over and over to fill it.

iex> pattern = TuningFork.Pattern.linger(TuningFork.Pattern.fastcat([:a, :b, :c, :d]), 0.5)
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.25, :a}, {0.25, 0.5, :b}, {0.5, 0.75, :a}, {0.75, 1.0, :b}]

mul(pattern, other)

@spec mul(t(), t() | number() | map()) :: t()

Multiply every value by other. See add/2.

never(pattern, fun)

@spec never(t(), (t() -> t())) :: t()

The pattern unchanged; fun is ignored.

new(query, steps \\ 1)

@spec new((span() -> [event()]), number()) :: t()

A pattern from a query function.

query takes a span/0 and returns the events in it. steps is how many steps the pattern is counted as having — see steps/1.

off(pattern, amount, fun)

@spec off(t(), number(), (t() -> t())) :: t()

Lay a changed copy over the original, amount cycles later.

off(pattern, 0.125, &with_value(&1, fn note -> %{note | gain: 0.4} end))

often(pattern, fun, seed \\ 0)

@spec often(t(), (t() -> t()), integer()) :: t()

Apply fun to about three quarters of the events.

onset?(map)

@spec onset?(event()) :: boolean()

Whether this event begins here rather than continuing one already sounding: true when part starts where whole starts, false when whole is nil.

outside(pattern, n, fun)

@spec outside(t(), number(), (t() -> t())) :: t()

inside/3 with 1 / n: speed up by n, apply fun, slow back down.

pace(pattern, target)

@spec pace(t(), number()) :: t()

Play the pattern at target steps a cycle, whatever it was written as. A pattern of zero steps gives silence/0.

iex> pattern = TuningFork.Pattern.pace(TuningFork.Pattern.fastcat([:a, :b, :c, :d]), 2)
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.5, :a}, {0.5, 1.0, :b}]

palindrome(pattern)

@spec palindrome(t()) :: t()

Play the pattern forwards on even cycles and backwards on odd ones.

iex> pattern = TuningFork.Pattern.palindrome(TuningFork.Pattern.fastcat([:a, :b]))
iex> {TuningFork.Pattern.first_cycle(pattern), TuningFork.Pattern.first_cycle(pattern, 1)}
{[{0.0, 0.5, :a}, {0.5, 1.0, :b}], [{0.0, 0.5, :b}, {0.5, 1.0, :a}]}

patterned(pattern, amounts, fun)

@spec patterned(t(), t(), (t(), term() -> t())) :: t()

Apply fun with each value of amounts over the span that value holds.

patterned(pattern, mini("<1 2>"), &fast/2)

fun takes the pattern and one value; fast/2, slow/2, ply/2 and clip/2 go through this when given a pattern instead of a number.

perlin(seed \\ 0)

@spec perlin(integer()) :: t()

Smooth continuous noise from 0.0 to 1.0, interpolated between one whole cycle's value and the next. seed chooses a different sequence.

pick(which, patterns)

@spec pick(t(), [t()]) :: t()

One pattern per cycle from patterns, chosen by which: a pattern of whole numbers counting from zero, sampled at the start of each cycle and wrapped round the length of the list. A cycle where which has no number is silent. patterns must not be empty.

ply(pattern, counts)

@spec ply(t(), pos_integer()) :: t()

Repeat each event n times inside its own span.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.ply(TuningFork.Pattern.fastcat([:a, :b]), 2))
[{0.0, 0.25, :a}, {0.25, 0.5, :a}, {0.5, 0.75, :b}, {0.75, 1.0, :b}]

polymeter(parts, steps)

@spec polymeter([{pos_integer(), t()}], pos_integer()) :: t()

Play every pattern at once, each stretched so they all run at steps steps a cycle.

parts are {how many steps this pattern has, pattern} pairs and must not be empty.

iex> a = TuningFork.Pattern.fastcat([:a, :b, :c])
iex> b = TuningFork.Pattern.fastcat([:x, :y, :z, :w])
iex> TuningFork.Pattern.polymeter([{3, a}, {4, b}], 4)
...> |> TuningFork.Pattern.first_cycle()
...> |> length()
8

pure(value)

@spec pure(term()) :: t()

value, once per cycle, filling the cycle.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.pure(:bd))
[{0.0, 1.0, :bd}]

query(pattern, arg)

@spec query(t(), span()) :: [event()]

The events of pattern between the two cycle positions.

The span end is exclusive. A zero-width span samples continuous patterns and reports nothing discrete. An event the span cuts across is returned with its whole intact and its part shortened to the span; a part narrower than a rounding error is left out.

rand(seed \\ 0)

@spec rand(integer()) :: t()

A continuous value from 0.0 to 1.0, hashed from the position and seed. The same position always gives the same value.

range(pattern, low, high)

@spec range(t(), number(), number()) :: t()

Stretch a 0.0-to-1.0 pattern onto low..high.

range(sine(), 200, 2_000)

rarely(pattern, fun, seed \\ 0)

@spec rarely(t(), (t() -> t()), integer()) :: t()

Apply fun to about a quarter of the events.

rev(pattern)

@spec rev(t()) :: t()

Play each cycle backwards.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.rev(TuningFork.Pattern.fastcat([:a, :b])))
[{0.0, 0.5, :b}, {0.5, 1.0, :a}]

ribbon(pattern, from, cycles)

@spec ribbon(t(), number(), pos_integer()) :: t()

Play the stretch of cycles cycles starting at cycle from, over and over.

run(n)

@spec run(pos_integer()) :: t()

The numbers 0 to n - 1, one a cycle divided evenly.

iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.run(4))
[{0.0, 0.25, 0}, {0.25, 0.5, 1}, {0.5, 0.75, 2}, {0.75, 1.0, 3}]

saw()

@spec saw() :: t()

A ramp from 0.0 to 1.0 across each cycle.

segment(pattern, n)

@spec segment(t(), pos_integer()) :: t()

Chop pattern into n equal events a cycle, each holding the value sounding at its start, discrete or continuous. Where pattern has no value at a start, that event is left out.

segment(sine(), 8)

shift(pattern, amount)

@spec shift(t(), number()) :: t()

Move the whole of pattern later by amount cycles. A negative amount moves it earlier.

shrink(pattern, by \\ 1)

@spec shrink(t(), pos_integer()) :: t()

Take by steps fewer each time round, until there is nothing left, the takes laid end to end with stepcat/1.

signal(fun)

@spec signal((float() -> term())) :: t()

A continuous pattern: fun is given a cycle position and returns the value there. A query gets one event with whole: nil, sampled at the middle of the span.

silence()

@spec silence() :: t()

A pattern with nothing in it.

sine()

@spec sine() :: t()

A sine from 0.0 to 1.0 and back, once a cycle.

slow(pattern, factors)

@spec slow(t(), number() | t() | String.t()) :: t()

Stretch pattern over factor cycles. The inverse of fast/2. factor may be a pattern or mini-notation.

slowcat(patterns)

@spec slowcat([t()]) :: t()

One pattern per cycle, in turn: the first on cycle 0, the second on cycle 1, and so on, wrapping round. Each keeps its own speed.

some_cycles(pattern, fun, seed \\ 0)

@spec some_cycles(t(), (t() -> t()), integer()) :: t()

Apply fun to about half the cycles, whole ones at a time.

some_cycles_by(pattern, amount, fun, seed \\ 0)

@spec some_cycles_by(t(), number(), (t() -> t()), integer()) :: t()

Apply fun to about amount of the cycles, whole ones at a time. The same cycle is chosen the same way every run; seed chooses a different set.

sometimes(pattern, fun, seed \\ 0)

@spec sometimes(t(), (t() -> t()), integer()) :: t()

Apply fun to about half the events. sometimes_by/4 with 0.5.

sometimes_by(pattern, amount, fun, seed \\ 0)

@spec sometimes_by(t(), number(), (t() -> t()), integer()) :: t()

Apply fun to about amount of the events. The same event in the same cycle is chosen the same way every run; seed chooses a different set.

sometimes_by(pattern, 0.3, &fast(&1, 2))

square()

@spec square() :: t()

0.0 for the first half of each cycle and 1.0 for the second.

squeeze(structure, pattern)

@spec squeeze(t(), t()) :: t()

Squeeze one cycle of pattern into each event of structure. Continuous events and events straddling a cycle line give nothing.

squeeze_values(pattern, fun)

@spec squeeze_values(t(), (term() -> t())) :: t()

Replace every event with a pattern of its own, squeezed into the event's whole. fun is given the value and returns the pattern. Continuous events and events straddling a cycle line give nothing.

stack(patterns)

@spec stack([t()]) :: t()

Everything at once.

iex> TuningFork.Pattern.first_cycle(
...>   TuningFork.Pattern.stack([TuningFork.Pattern.pure(:bd), TuningFork.Pattern.pure(:hh)])
...> )
[{0.0, 1.0, :bd}, {0.0, 1.0, :hh}]

stepalt(groups)

@spec stepalt([[t()]]) :: t()

One pattern from each group in turn, stepcat/1ed into one pattern.

groups are lists of patterns. On the first pass the first of each group is taken, on the next the second, and so on, until every group has come back round to its first.

iex> a = [TuningFork.Pattern.pure(:a), TuningFork.Pattern.pure(:b)]
iex> TuningFork.Pattern.stepalt([a, [TuningFork.Pattern.pure(:x)]])
...> |> TuningFork.Pattern.first_cycle()
...> |> Enum.map(&elem(&1, 2))
[:a, :x, :b, :x]

stepcat(patterns)

@spec stepcat([t()]) :: t()

Lay patterns end to end in one cycle, each given room in proportion to its steps/1. The result is counted as the sum of their steps.

iex> a = TuningFork.Pattern.fastcat([:a, :b, :c])
iex> b = TuningFork.Pattern.fastcat([:d, :e])
iex> TuningFork.Pattern.stepcat([a, b]) |> TuningFork.Pattern.first_cycle()
[{0.0, 0.2, :a}, {0.2, 0.4, :b}, {0.4, 0.6, :c}, {0.6, 0.8, :d}, {0.8, 1.0, :e}]

steps(pattern)

@spec steps(t()) :: number()

How many steps this pattern is counted as having. Read by stepcat/1, pace/2 and the other stepwise functions; it does not change what the pattern plays.

iex> TuningFork.Pattern.steps(TuningFork.Pattern.fastcat([:a, :b, :c]))
3
iex> TuningFork.Pattern.steps(TuningFork.Pattern.pure(:a))
1

stut(pattern, count, time)

@spec stut(t(), pos_integer(), number()) :: t()

count copies of the pattern, each time later than the one before.

sub(pattern, other)

@spec sub(t(), t() | number() | map()) :: t()

Take other away from every value. See add/2.

superimpose(pattern, fun)

@spec superimpose(t(), (t() -> t())) :: t()

Lay fun of the pattern over the original, in place.

swing(pattern, n)

@spec swing(t(), pos_integer()) :: t()

swing_by/3 with an amount of a third.

swing_by(pattern, amount, n)

@spec swing_by(t(), number(), pos_integer()) :: t()

Push the second half of each of n subdivisions of the cycle late by amount of a subdivision.

swing_by(pattern, 1/3, 4)

take(pattern, count)

@spec take(t(), number()) :: t()

The first count steps of the pattern, stretched to fill the cycle.

A negative count takes from the end instead.

iex> pattern = TuningFork.Pattern.take(TuningFork.Pattern.fastcat([:a, :b, :c, :d]), 2)
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.5, :a}, {0.5, 1.0, :b}]

timecat(pairs)

@spec timecat([{number(), t()}]) :: t()

A cycle divided between {weight, pattern} pairs in proportion to their weights. A total weight of zero or less gives silence/0.

iex> TuningFork.Pattern.first_cycle(
...>   TuningFork.Pattern.timecat([{3, TuningFork.Pattern.pure(:a)}, {1, TuningFork.Pattern.pure(:b)}])
...> )
[{0.0, 0.75, :a}, {0.75, 1.0, :b}]

tour(pattern, many)

@spec tour(t(), [t()]) :: t()

Each pattern in many in turn stepcat/1ed after pattern, one per cycle. many must not be empty.

tri()

@spec tri() :: t()

A triangle from 0.0 up to 1.0 and back down, once a cycle.

undegrade(pattern, seed \\ 0)

@spec undegrade(t(), integer()) :: t()

Keep only the events degrade/3 with the same seed drops, about half.

undegrade_by(pattern, amount, seed \\ 0)

@spec undegrade_by(t(), number(), integer()) :: t()

Keep only the events degrade_by/3 with the same amount and seed drops.

value_at(pattern, position)

@spec value_at(t(), number()) :: term()

The value pattern holds at position, or nil where it holds none.

wchoose(choices, seed \\ 0)

@spec wchoose([{number(), term()}], integer()) :: t()

A continuous pattern of one of choices, given as {weight, value} pairs, chosen anew at every instant in proportion to weight. choices must not be empty.

wchoose_cycles(choices, seed \\ 0)

@spec wchoose_cycles([{number(), term()}], integer()) :: t()

One of choices, given as {weight, value} pairs, per cycle, held for the whole of it. choices must not be empty.

when_cycle(test, fun, pattern)

@spec when_cycle((integer() -> boolean()), (t() -> t()), t()) :: t()

Apply fun on the cycles test returns true for. test is given the cycle number, an integer counting up from zero.

with_steps(pattern, steps)

@spec with_steps(t(), number()) :: t()

The same pattern, counted as having steps steps. What it plays does not change.

with_value(pattern, fun)

@spec with_value(t(), (term() -> term())) :: t()

Replace every value with fun of it, leaving the timing alone.

zip(patterns)

@spec zip([t()]) :: t()

Take one step from each pattern in turn, round and round.

iex> a = TuningFork.Pattern.fastcat([:a, :b])
iex> b = TuningFork.Pattern.fastcat([1, 2])
iex> TuningFork.Pattern.zip([a, b]) |> TuningFork.Pattern.first_cycle()
[{0.0, 0.25, :a}, {0.25, 0.5, 1}, {0.5, 0.75, :b}, {0.75, 1.0, 2}]

zoom(pattern, from, to)

@spec zoom(t(), number(), number()) :: t()

Play the slice of each cycle between from and to, stretched to fill it.

iex> pattern = TuningFork.Pattern.zoom(TuningFork.Pattern.fastcat([:a, :b, :c, :d]), 0.25, 0.75)
iex> TuningFork.Pattern.first_cycle(pattern)
[{0.0, 0.5, :b}, {0.5, 1.0, :c}]