# `TuningFork.Part`
[🔗](https://github.com/jaman/tuning_fork/blob/v0.1.11/tuning_fork/lib/tuning_fork/part.ex#L1)

One line of music, written by moving a cursor measured in beats.

    import TuningFork.Part

    bass =
      part(bpm: 112, synth: soft_bass)
      |> play(:d2, 1.5)
      |> play(:a2, 0.5)

# `instrument`

```elixir
@type instrument() :: (atom() | number() | nil -&gt; TuningFork.Voice.t())
```

A voice for each note: called with the note, or `nil` for a hit with no pitch.

# `step_entry`

```elixir
@type step_entry() ::
  atom()
  | number()
  | TuningFork.Voice.t()
  | nil
  | {atom() | number() | TuningFork.Voice.t(), keyword()}
```

# `t`

```elixir
@type t() :: %TuningFork.Part{
  bpm: float(),
  cursor: float(),
  fx: keyword(),
  gain: float(),
  notes: [{float(), TuningFork.Voice.t()}],
  pan: float(),
  rand: TuningFork.Rand.t(),
  synth: TuningFork.Voice.t() | instrument() | nil
}
```

# `at`

```elixir
@spec at(t(), number()) :: t()
```

Put the cursor at an exact beat, forwards or back.

# `beats`

```elixir
@spec beats(t()) :: float()
```

How far the part runs, in beats.

The later of the cursor and the end of its last-ringing note.

# `between`

```elixir
@spec between(t(), number(), number()) :: {float(), t()}
```

A number from `low` up to but not including `high`, and the part with its generator advanced.

# `chord`

```elixir
@spec chord(t(), [atom() | number()], number(), keyword()) :: t()
```

Play every note of a chord at once, then move the cursor on by `step` beats.

`notes` is a list of note names or frequencies. `opts` are `play/4`'s and apply to every
note of the chord.

# `cursor`

```elixir
@spec cursor(t()) :: float()
```

Where the cursor is, in beats.

# `gain`

```elixir
@spec gain(t(), number()) :: t()
```

Change the part's level for everything after this point.

# `maybe`

```elixir
@spec maybe(t(), float(), (t() -&gt; t()), number()) :: t()
```

Call `fun` with the part with the given probability, and move on by `step` beats either
way.

`probability` runs 0.0 to 1.0 and is drawn from the part's own generator, which advances
whether or not `fun` is called.

# `notes`

```elixir
@spec notes(t()) :: [{float(), TuningFork.Voice.t()}]
```

The part's notes, as `{beat, voice}`, in the order they were played.

# `pan`

```elixir
@spec pan(t(), number()) :: t()
```

Move the part in the stereo field for everything after this point.

Clamped to `-1.0` to `1.0`.

# `part`

```elixir
@spec part(keyword()) :: t()
```

An empty part with its cursor at beat zero. Every part starts from its own beat zero; one
that comes in later begins with `rest/2`.

## Options

  * `:synth` — the voice its notes are played with, or a `t:instrument/0` asked for one per
    note; default `nil`, in which case `TuningFork.Voice.new/1` is used per note
  * `:bpm` — its tempo, default 120
  * `:gain` — a level over everything in it, default 1.0
  * `:pan` — where it sits, `-1.0` hard left to `1.0` hard right, default 0.0 centred
  * `:fx` — effects applied to this part alone, as `[echo: [...], reverb: [...]]`, default
    none
  * `:seed` — seeds the part's own random generator, default 1

# `pattern`

```elixir
@spec pattern(t(), [atom() | number()], number() | [number()], keyword()) :: t()
```

Play a run of notes, each `step` beats apart.

`step` may be a list, whose entries are used in turn and repeat: `[0.5, 0.5, 1.0]` is two
short and one long, over and over. `opts` are `play/4`'s and apply to every note.

# `pick`

```elixir
@spec pick(t(), [term()], non_neg_integer()) :: {[term()], t()}
```

`count` independent choices from `list`, and the part with its generator advanced. The
result may repeat an element.

# `play`

```elixir
@spec play(t(), atom() | number() | TuningFork.Voice.t(), number(), keyword()) :: t()
```

Play a note at the cursor and move the cursor on by `step` beats.

`note` may be a note name, a frequency in Hz, or a whole `TuningFork.Voice`, which is
played as it stands without being pitched. `step` is how long until the next note, in beats,
independent of how long this note sounds.

## Options

  * `:release` — how long the note sounds, in beats. Longer than `step` overlaps the next
  * `:gain` — this note's level, multiplied by the part's
  * `:pan` — how far this note sits from where the part does, `-1.0` to `1.0`, added to the
    part's and clamped to that range
  * `:bend` — semitones to arrive at by the end of the note; `2` bends up a tone
  * `:curves` — modulation in full, as `TuningFork.Voice` takes it. A `:freq` curve given
    here supersedes `:bend`
  * `:synth` — a voice, or a `t:instrument/0`, for this note only, overriding the part's

Any option value of the form `{:between, low, high}` is drawn from the part's own generator
for each note.

    |> play(:e4, 0.5, release: 3.0)
    |> play(:e4, 1.0, bend: 2)
    |> play(:e4, 1.0, curves: %{gain: Curve.linear(0.2, 1.0)})

# `play_any`

```elixir
@spec play_any(t(), [atom() | number() | TuningFork.Voice.t()], number(), keyword()) ::
  t()
```

Play one of `notes`, chosen by the part's own generator, and move on by `step` beats.

The same seed picks the same notes in the same order. `opts` are `play/4`'s.

# `repeat`

```elixir
@spec repeat(t(), pos_integer() | String.t(), (t() -&gt; t())) :: t()
```

Apply `fun` to the part `times` over, from wherever the cursor is.

`times` may instead be a string of `x` and `.`, one per pass: `fun` is applied on an `x`,
and on a `.` the cursor moves on by as much as `fun` would have moved it, playing nothing.

    |> repeat(4, &steps(&1, "x...x..."))
    |> repeat("..xx", &steps(&1, "x...x..."))

# `repeat_indexed`

```elixir
@spec repeat_indexed(t(), pos_integer(), (t(), non_neg_integer() -&gt; t())) :: t()
```

Apply `fun` to the part `times` over, told which pass it is, counting from zero.

# `rest`

```elixir
@spec rest(t(), number()) :: t()
```

Move the cursor on by `beats` without playing anything.

# `steps`

```elixir
@spec steps(t(), String.t() | [step_entry()], number(), keyword()) :: t()
```

Play a pattern of evenly spaced steps, each `step` beats apart.

A string plays the part's own synth on `x` or `X`, plays at a ninth of full level on a digit
`1` to `9` (multiplied into any `:gain` given), and rests on any other character. Spaces
are ignored. `step` defaults to 0.25.

    |> steps("x..x..x.")
    |> steps("x2x2x9x2", 0.25)

A list places a different entry on each step. An entry is anything `play/4` accepts, `nil`
for a rest, or `{note, opts}` for one step carrying its own options merged over `opts`:

    |> steps([{:a3, release: 4.0}, nil, :c4, nil, :e4, nil, nil, nil])

# `synth`

```elixir
@spec synth(t(), TuningFork.Voice.t() | instrument()) :: t()
```

Change the voice, or `t:instrument/0`, used for everything after this point.

# `under`

```elixir
@spec under(t(), atom() | number() | TuningFork.Voice.t(), keyword()) :: t()
```

Play a note without moving the cursor, for stacking a chord. Takes `play/4`'s options.

---

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