TuningFork.Sample (TuningFork v0.1.11)

Copy Markdown View Source

Recorded audio, to be played as a TuningFork.Voice.

kick = Sample.load!("kick.wav")
part(bpm: 96, synth: Voice.new(sample: kick)) |> steps("x..x..x.")

Summary

Functions

The value at a fractional frame position in the recording, from -1.0 to 1.0.

How long the recording lasts at its own speed, in seconds.

How long the recording lasts when played at freq, in seconds.

How many frames long the recording is.

A sample from PCM already in memory.

Read a recording from disk: a WAV or a FLAC as they are, anything else through TuningFork.Sample.Decode.

position brought back inside the loop when the recording has one and the position has passed its end; unchanged otherwise.

How far to move through the recording per output frame to sound at freq through a device running at rate.

A new sample with the recording reversed, keeping its rate and root.

A new sample cut out of this one: length seconds starting from seconds in.

Types

t()

@type t() :: %TuningFork.Sample{
  id: term(),
  loop: {non_neg_integer(), pos_integer()} | nil,
  name: String.t(),
  pcm: binary(),
  rate: pos_integer(),
  root: float() | nil
}

Functions

at(sample, position)

@spec at(t(), float()) :: float()

The value at a fractional frame position in the recording, from -1.0 to 1.0.

Cubic Hermite interpolation through the two frames either side and their neighbours. A position before the start or past the end is 0.0 rather than a wrap, unless the recording has a loop, which looped/2 brings it back inside.

duration(sample)

@spec duration(t()) :: float()

How long the recording lasts at its own speed, in seconds.

duration(sample, freq)

@spec duration(t(), float() | nil) :: float()

How long the recording lasts when played at freq, in seconds.

Longer when pitched down and shorter when pitched up. A sample with no :root, or a freq of nil, gives duration/1.

frames(sample)

@spec frames(t()) :: non_neg_integer()

How many frames long the recording is.

from_pcm(pcm, opts \\ [])

@spec from_pcm(binary(), keyword()) :: t()

A sample from PCM already in memory.

Stereo input is folded to mono, since a voice is synthesised in mono and panned afterwards. More than two channels raises ArgumentError.

Options

  • :rate — samples per second of the PCM given, default 44100
  • :channels — 1 or 2, default 1
  • :root — the pitch the recording already is, as a note name or a frequency in Hz
  • :loop{from, to} frames a voice goes round between once it reaches to, so a note can outlast the recording; default nil
  • :gain — a factor the recording is scaled by as it is loaded, default 1.0
  • :name — what to call it, default "sample"

load!(path, opts \\ [])

@spec load!(Path.t(), keyword()) :: t()

Read a recording from disk: a WAV or a FLAC as they are, anything else through TuningFork.Sample.Decode.

Which it is comes from the file's own header, not its name. Raises if the file cannot be read or will not decode.

Options

  • :root — the pitch the recording already is, as a note name or a frequency in Hz. Leave it out for percussion, which has no pitch to move from
  • :name — what to call it, default the file's basename

:rate and :channels come from the file and are not taken here.

looped(sample, position)

@spec looped(t(), float()) :: float()

position brought back inside the loop when the recording has one and the position has passed its end; unchanged otherwise.

ratio(sample, freq, rate)

@spec ratio(t(), float() | nil, pos_integer()) :: float()

How far to move through the recording per output frame to sound at freq through a device running at rate.

Two ratios in one: freq against the sample's :root, and the sample's own rate against rate. A sample with no :root, or a freq of nil, is read at its own pitch and still corrected for rate.

reverse(sample)

@spec reverse(t()) :: t()

A new sample with the recording reversed, keeping its rate and root.

slice(sample, from, length)

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

A new sample cut out of this one: length seconds starting from seconds in.

A range running past the end is truncated to what is there. The result keeps the rate and root of the original and gets its own :id, so caches tell it apart from what it came from.