# `TuningFork.Pattern.Control`
[🔗](https://github.com/jaman/tuning_fork/blob/v0.1.11/tuning_fork/lib/tuning_fork/pattern/control.ex#L1)

Patterns of control maps, built as a chain of setters that `TuningFork.Kit` turns into voices.

    import TuningFork.Pattern.Control

    n("<0 4 0 9 7>*16") |> scale("g:minor") |> transpose(-12) |> octave(3) |> shape(:saw)

# `acid`

```elixir
@spec acid(TuningFork.Pattern.t(), number()) :: TuningFork.Pattern.t()
```

Set `cutoff`, `resonance`, `lpenv`, `lpsustain` and `lpdecay` together from one knob,
`amount` from 0.0 to 1.0. Any of them set later in the chain wins.

    n("<0 4 0 9 7>*16") |> scale("g:minor") |> transpose(-12) |> shape(:saw) |> acid(0.55)

# `adsr`

```elixir
@spec adsr(
  TuningFork.Pattern.t(),
  number() | nil,
  number() | nil,
  number() | nil,
  number() | nil
) ::
  TuningFork.Pattern.t()
```

Attack, decay, sustain and release in one go. Any of them may be `nil` to leave that part of
the envelope as it was.

    n("0 4") |> adsr(0.01, 0.1, 0.4, 0.2)

# `anchor`

```elixir
@spec anchor(TuningFork.Pattern.t(), String.t() | integer() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

The note a voicing is placed against, as `TuningFork.Pattern.Voicing.render/2`'s `:anchor`.

# `attack`

```elixir
@spec attack(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long the note takes to reach full level, in seconds.

# `bank`

```elixir
@spec bank(TuningFork.Pattern.t(), String.t() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Which bank the sounds come from: `s("bd") |> bank("crate")` plays the recording registered
as `crate_bd` once `TuningFork.Sample.Bank` has it, as Strudel does, and until then the
kit's own drum, adjusted for a name in `TuningFork.Kit.banks/0`.

# `bpf`

```elixir
@spec bpf(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

A bandpass at this frequency, in hertz. `cutoff/2` and `ftype/2` in one.

# `bpq`

```elixir
@spec bpq(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How narrow the bandpass is. See `bpf/2`.

# `chord`

```elixir
@spec chord(TuningFork.Pattern.t() | String.t() | term()) :: TuningFork.Pattern.t()
```

A pattern of chord symbols, each as `%{chord: symbol}`, for `voicing/1`.

    chord("<Bbm9 Fm9>/4") |> voicing()

# `coarse`

```elixir
@spec coarse(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Hold every sample for `every` samples. 1 changes nothing.

# `compressor`

```elixir
@spec compressor(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How hard the bus is compressed, 0.0 for not at all and 1.0 for flat.

# `crush`

```elixir
@spec crush(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Round every sample to `bits` bits: 16 is untouched, 1 is a square.

# `cutoff`

```elixir
@spec cutoff(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Where the filter turns over, in hertz. Lower is darker.

# `decay`

```elixir
@spec decay(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long it takes to fall from full level to `sustain/2`, in seconds.

# `delay`

```elixir
@spec delay(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How much of the note comes back as an echo, 0.0 to 1.0. `delaytime/2` is how far behind, in
cycles, and `delayfeedback/2` how much of each repeat survives into the next. The echoes are
the note played again, quieter; `echoes/1` makes them.

    s("bd rim") |> delay(0.5) |> delaytime(0.125) |> delayfeedback(0.6)

# `delayfeedback`

```elixir
@spec delayfeedback(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How much of each echo survives into the next, 0.0 to 1.0. See `delay/2`.

# `delaytime`

```elixir
@spec delaytime(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How far behind the echoes fall, in cycles. Default an eighth. See `delay/2`.

# `dict`

```elixir
@spec dict(TuningFork.Pattern.t(), atom() | String.t() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Which voicing dictionary `voicing/1` reads: one of `TuningFork.Pattern.Voicing.dictionaries/0`.

# `distort`

```elixir
@spec distort(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How hard to drive into a soft clipper, 0.0 for clean.

# `drawing`

```elixir
@spec drawing(TuningFork.Pattern.t()) :: :pianoroll | :scope | nil
```

What a pattern has asked to be drawn as, or `nil` for nothing.

    iex> TuningFork.Pattern.Control.drawing(TuningFork.Pattern.Control.s("bd"))
    nil
    iex> TuningFork.Pattern.Control.drawing(TuningFork.Pattern.Control.scope(TuningFork.Pattern.Control.s("bd")))
    :scope

# `early`

```elixir
@spec early(
  TuningFork.Pattern.t() | String.t(),
  number() | TuningFork.Pattern.t() | String.t()
) ::
  TuningFork.Pattern.t()
```

Move `pattern` earlier by `amount` cycles; a pattern of amounts applies each over its own span.

# `echoes`

```elixir
@spec echoes(TuningFork.Pattern.t()) :: TuningFork.Pattern.t()
```

Turn every event carrying a `:delay` above zero into itself plus four echoes: the same event
`:delaytime` cycles later each time (default 0.125, capped at 0.5), with `:gain` scaled by
`:delay` and then by `:delayfeedback` per repeat (default 0.5, capped at 0.95), and `:delay`
removed. Any other event is passed straight through.

# `echoes_of`

```elixir
@spec echoes_of(TuningFork.Pattern.event()) :: [TuningFork.Pattern.event()]
```

The four echoes an event carrying a `:delay` above zero makes, as `echoes/1` places them,
and `[]` for any other event.

# `fm`

```elixir
@spec fm(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Frequency modulation depth, 0.0 upwards. `fmh/2` sets the modulator's ratio to the note.

    note("c3") |> fm(3) |> fmh(2)

# `fmattack`

```elixir
@spec fmattack(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How much of the note the FM modulation takes to arrive, 0.0 to 1.0 of its length. Left out,
the modulation is there from the first sample.

# `fmh`

```elixir
@spec fmh(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How high the modulator sits against the note, 1.0 being in unison. See `fm/2`.

# `ftype`

```elixir
@spec ftype(TuningFork.Pattern.t(), atom() | String.t() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Which kind of filter `cutoff/2` makes: `:lowpass` (the default), `:highpass` or `:bandpass`,
as an atom or string.

# `gain`

```elixir
@spec gain(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How loud, 0.0 to 1.0.

# `highpass`

```elixir
@spec highpass(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Highpass filter amount, 0.0 to 1.0. Higher is thinner.

# `hpf`

```elixir
@spec hpf(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

The same as `highpass/2`.

# `hpq`

```elixir
@spec hpq(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How much the highpass peaks at its corner. Applies to `ftype(:highpass)` with `cutoff/2`,
not to `highpass/2`.

# `jux`

```elixir
@spec jux(TuningFork.Pattern.t(), (TuningFork.Pattern.t() -&gt; TuningFork.Pattern.t())) ::
  TuningFork.Pattern.t()
```

Stack the pattern panned hard left with `fun` of it panned hard right.

    s("bd*4") |> jux(&rev/1)

# `jux_by`

```elixir
@spec jux_by(TuningFork.Pattern.t(), number(), (TuningFork.Pattern.t() -&gt;
                                            TuningFork.Pattern.t())) ::
  TuningFork.Pattern.t()
```

`jux/2` with the pattern panned to `-amount` and `fun` of it to `amount`: 1.0 is hard left
and right, 0.0 leaves both in the middle.

# `late`

```elixir
@spec late(
  TuningFork.Pattern.t() | String.t(),
  number() | TuningFork.Pattern.t() | String.t()
) ::
  TuningFork.Pattern.t()
```

Move `pattern` later by `amount` cycles; a pattern of amounts applies each over its own span.

# `lpattack`

```elixir
@spec lpattack(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long the filter sweep takes to open, in seconds. Default 0.002.

# `lpdecay`

```elixir
@spec lpdecay(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long the filter sweep takes to fall back, in seconds. Default 0.2.

# `lpenv`

```elixir
@spec lpenv(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Octaves the filter sweeps above `cutoff/2` over the note, falling away over `lpdecay/2`.

# `lpf`

```elixir
@spec lpf(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

The same as `cutoff/2`.

# `lpq`

```elixir
@spec lpq(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

The same as `resonance/2`.

# `lprelease`

```elixir
@spec lprelease(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long the filter sweep takes to release. See `lpenv/2`.

# `lpsustain`

```elixir
@spec lpsustain(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Where the filter sweep settles, 0.0 to 1.0 of the way up. Default 0.0.

# `mask`

```elixir
@spec mask(TuningFork.Pattern.t(), TuningFork.Pattern.t() | String.t()) ::
  TuningFork.Pattern.t()
```

Keep only the events of `pattern` that fall where `source` is true.

    s("bd*8") |> mask("1 0 1 1")

# `mini`

```elixir
@spec mini(String.t()) :: TuningFork.Pattern.t()
```

A pattern from mini-notation: `mini("bd*2 [~ sn]")`.

# `mode`

```elixir
@spec mode(TuningFork.Pattern.t(), atom() | String.t() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How a voicing sits against its anchor: `:below`, `:above`, `:root` or `:duck`, or a string
such as `"root:g2"` naming the anchor too.

# `n`

```elixir
@spec n(TuningFork.Pattern.t() | String.t() | term()) :: TuningFork.Pattern.t()
```

A pattern of scale degrees, 0 being the root of the `scale/2` (`"c:major"` without one).
`source` is as for `s/1`; each value becomes `%{degree: value}`.

    iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.Control.n("0 4"))
    [{0.0, 0.5, %{degree: 0}}, {0.5, 1.0, %{degree: 4}}]

# `n`

```elixir
@spec n(TuningFork.Pattern.t(), TuningFork.Pattern.t() | String.t() | term()) ::
  TuningFork.Pattern.t()
```

Set the degree on an existing pattern's events, as `set/3` does.

# `note`

```elixir
@spec note(TuningFork.Pattern.t() | String.t() | term()) :: TuningFork.Pattern.t()
```

A pattern of notes, by name or by MIDI number. `source` is as for `s/1`; each value becomes
`%{note: value}`.

    iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.Control.note("c3 g3"))
    [{0.0, 0.5, %{note: "c3"}}, {0.5, 1.0, %{note: "g3"}}]

# `note`

```elixir
@spec note(TuningFork.Pattern.t(), TuningFork.Pattern.t() | String.t() | term()) ::
  TuningFork.Pattern.t()
```

Set the note on an existing pattern's events, as `set/3` does.

# `octave`

```elixir
@spec octave(TuningFork.Pattern.t(), integer() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Which octave the scale sits in. Without one it is 3.

# `offset`

```elixir
@spec offset(TuningFork.Pattern.t(), integer() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How many voicings along the dictionary's list `voicing/1` moves.

# `orbit`

```elixir
@spec orbit(TuningFork.Pattern.t(), non_neg_integer() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Which bus this goes to, counting from zero. `room/2`, `postgain/2`, `xfade/2` and
`compressor/2` apply per bus.

# `pan`

```elixir
@spec pan(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Where in the stereo field, -1.0 left to 1.0 right.

# `phaser`

```elixir
@spec phaser(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Phaser rate: how many times a second the notches sweep. `phaserdepth/2` says how far.

# `phaserdepth`

```elixir
@spec phaserdepth(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How far the phaser's notches travel, 0.0 to 1.0. Default 0.5. See `phaser/2`.

# `pianoroll`

```elixir
@spec pianoroll(TuningFork.Pattern.t()) :: TuningFork.Pattern.t()
```

Mark this row to be drawn as a pianoroll. A row not marked is not drawn.

    n("<0 4 0 9 7>*16") |> scale("g:minor") |> acid(0.55) |> pianoroll()

# `postgain`

```elixir
@spec postgain(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How loud the bus is after everything else, 0.0 upwards.

# `release`

```elixir
@spec release(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long the note takes to fall silent after it ends, in seconds.

# `resonance`

```elixir
@spec resonance(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How much the filter peaks at its cutoff: 0.707 is flat, 8 is a howl.

# `room`

```elixir
@spec room(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How much reverb the bus is heard through, 0.0 to 1.0. The reverb is shared by every event on
the bus, and the loudest `room` asked for is the one applied. `roomsize/2` says how big it is.

# `roomsize`

```elixir
@spec roomsize(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How long the room rings, in seconds to silence; 2 unless set. See `room/2`.

# `s`

```elixir
@spec s(TuningFork.Pattern.t() | String.t() | term()) :: TuningFork.Pattern.t()
```

A pattern of sounds. `source` is mini-notation, a pattern, or a bare value; each value
becomes `%{sound: value}` unless it is already a map.

    iex> TuningFork.Pattern.first_cycle(TuningFork.Pattern.Control.s("bd sn"))
    [{0.0, 0.5, %{sound: "bd"}}, {0.5, 1.0, %{sound: "sn"}}]

# `s`

```elixir
@spec s(TuningFork.Pattern.t(), TuningFork.Pattern.t() | String.t() | term()) ::
  TuningFork.Pattern.t()
```

Set the sound on an existing pattern's events, as `set/3` does: `n("0 1") |> s("hh")`.

# `scale`

```elixir
@spec scale(TuningFork.Pattern.t(), String.t() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Which scale `n/1`'s degrees are in, as `"root:name"`; `TuningFork.Scale` lists the roots and
names. Like every setter here, `scale` may be a plain value or a pattern; see `set/3`.

# `scope`

```elixir
@spec scope(TuningFork.Pattern.t()) :: TuningFork.Pattern.t()
```

Mark this row to be drawn as an oscilloscope of the whole mix.

    s("bd!4") |> scope()

# `set`

```elixir
@spec set(TuningFork.Pattern.t(), TuningFork.Pattern.t() | String.t()) ::
  TuningFork.Pattern.t()
```

Merge the controls of `other` onto every event of `pattern`, keeping `pattern`'s wholes: an
event is cut into parts where `other` changes inside it, each part carrying `other`'s map
merged over the event's. Where `other` has nothing, the event is left alone.

    n("0 4") |> set(chord("Bbm9")) |> voicing()

# `set`

```elixir
@spec set(TuningFork.Pattern.t(), atom(), term()) :: TuningFork.Pattern.t()
```

Set control `key` on every event of a pattern.

`value` is a plain term, a pattern, or a mini-notation string. A pattern keeps the event's
whole and cuts it into parts where the pattern changes inside it, as `Pattern.app_left/3`;
where it has nothing the event is left out. An event whose value is not yet a map becomes
`%{key => value, sound: old_value}`.

# `shape`

```elixir
@spec shape(
  TuningFork.Pattern.t(),
  atom() | number() | String.t() | TuningFork.Pattern.t()
) ::
  TuningFork.Pattern.t()
```

The waveform: `:sine`, `:saw`, `:square`, `:triangle` or `:noise`. A number is Strudel's
`shape`, a waveshaper from 0.0 to below 1.0, and goes on `:waveshape` instead.

# `size`

```elixir
@spec size(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

`roomsize/2` under Strudel's shorter name.

# `speed`

```elixir
@spec speed(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How fast a sample or oscillator runs, 1.0 being as written: 2.0 is an octave up and half as
long. A negative value is taken as its absolute value.

# `struct`

```elixir
@spec struct(TuningFork.Pattern.t(), TuningFork.Pattern.t() | String.t()) ::
  TuningFork.Pattern.t()
```

Keep the values of `pattern` but the structure of `source`: an event for every true step of
`source`, carrying the value `pattern` holds at that moment. `x`, `t`, `1` are true; `~`,
`f`, `0` are not.

    s("bd") |> struct("x ~ x ~")

# `sustain`

```elixir
@spec sustain(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

The level the note holds at after its decay, 0.0 to 1.0.

# `transpose`

```elixir
@spec transpose(TuningFork.Pattern.t(), integer() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Move every note by `semitones`, up or down.

# `velocity`

```elixir
@spec velocity(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

How hard the note is struck, 0.0 to 1.0. Multiplies `gain/2`.

# `vib`

```elixir
@spec vib(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Vibrato rate, in hertz. `vibmod/2` says how far.

# `vibmod`

```elixir
@spec vibmod(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Vibrato depth, in semitones. Default half a semitone. See `vib/2`.

# `voicing`

```elixir
@spec voicing(TuningFork.Pattern.t() | String.t()) :: TuningFork.Pattern.t()
```

Turn a pattern of chord symbols into their notes, one event per note with the symbol's
timing and its other controls, as `TuningFork.Pattern.Voicing.render/2` voices them under
the event's `:dict`, `:anchor`, `:mode`, `:offset` and `:degree`. A string is `chord/1`
first. A symbol the dictionary does not know is silent.

    chord("<C^7 Dm7 G7>") |> voicing() |> shape(:saw)

# `vowel`

```elixir
@spec vowel(TuningFork.Pattern.t(), String.t() | atom() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Filter the sound into a vowel: `"a"`, `"e"`, `"i"`, `"o"` or `"u"`, as a string or atom.

# `xfade`

```elixir
@spec xfade(TuningFork.Pattern.t(), number() | TuningFork.Pattern.t()) ::
  TuningFork.Pattern.t()
```

Fade between this bus and the rest: 0.0 none of it, 0.5 equal, 1.0 all of it.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
