Walks a pattern in time, rendering the events that come due to PCM block by block.
player = TuningFork.Pattern.Player.new(pattern, 44_100, cps: 0.5)
{pcm, player} = TuningFork.Pattern.Player.advance(player, 512, 2)
Summary
Functions
The next frames frames, and the player advanced past them.
What each bus is set to, keyed by orbit: a map of room, roomsize, postgain, xfade
and compressor. An orbit the pattern has never mentioned has no entry.
Run at a different speed from the next block on. The position carries on.
Where the player has reached, in cycles.
Scale everything the player puts out, sounding notes included, by gain; 0.0 is silence.
Stop everything sounding. The position carries on.
A player at cycle zero of pattern, running at rate samples per second.
Whether a pattern is waiting for the next cycle line to come in.
How many notes are sounding and not fading out. Never more than the :voices cap.
Render cycles of a pattern to signed 16-bit little-endian PCM, without a sound device.
Bus zero's {room, roomsize}.
How many notes are sounding right now, the ones fading out included.
Swap the pattern without stopping. The position carries on.
Types
@type route() :: {non_neg_integer(), float()}
Where a voice goes: its orbit, and how much of it is sent to that orbit's room.
@type t() :: %TuningFork.Pattern.Player{ buses: %{required(non_neg_integer()) => map()}, cps: float(), cycle: float(), gain: float(), next: {TuningFork.Pattern.t(), :cycle} | nil, parallel: term(), pattern: TuningFork.Pattern.t(), pending: [TuningFork.Pattern.event()], rate: pos_integer(), reverbs: %{required(non_neg_integer()) => TuningFork.Reverb.t()}, sounding: [ {non_neg_integer(), TuningFork.Voice.Live.t(), :playing | :fading, route()} ], voice: (term(), float() -> TuningFork.Voice.t() | nil), voices: pos_integer() }
Functions
@spec advance(t(), pos_integer(), pos_integer()) :: {binary(), t()}
The next frames frames, and the player advanced past them.
The result is always exactly frames frames for channels channels. Events beginning inside
the block start at their own sample rather than at the block boundary.
@spec buses(t()) :: %{required(non_neg_integer()) => map()}
What each bus is set to, keyed by orbit: a map of room, roomsize, postgain, xfade
and compressor. An orbit the pattern has never mentioned has no entry.
Run at a different speed from the next block on. The position carries on.
Where the player has reached, in cycles.
Scale everything the player puts out, sounding notes included, by gain; 0.0 is silence.
Stop everything sounding. The position carries on.
@spec new(TuningFork.Pattern.t(), pos_integer(), keyword()) :: t()
A player at cycle zero of pattern, running at rate samples per second.
Options
:cps— cycles per second, default 0.5:voice— a function from a value and a length in seconds to aTuningFork.Voiceornil. DefaultTuningFork.Kit.voice/2:voices— most notes sounding at once, default 32. Past that the oldest are faded out over 10 ms:parallel— render the sounding voices on every core (Task.async_stream); the same output, sooner, at the cost of a task per voice per block. For one player on a machine of its own; not for many players sharing a server. Defaultfalse
Whether a pattern is waiting for the next cycle line to come in.
@spec playing(t()) :: non_neg_integer()
How many notes are sounding and not fading out. Never more than the :voices cap.
@spec render(TuningFork.Pattern.t(), pos_integer(), keyword()) :: binary()
Render cycles of a pattern to signed 16-bit little-endian PCM, without a sound device.
pcm = Player.render(pattern, 44_100, cycles: 4, cps: 0.5)The result is exactly cycles cycles long; whatever is still ringing at the end is folded
back over the beginning.
Options
:cycles— how many to render, default 4:cps— cycles per second, default 0.5:channels— 2 for stereo, the default:tail— seconds rendered past the last cycle and folded back over the start, default 1.0:voice,:voices— asnew/3takes them
Bus zero's {room, roomsize}.
@spec sounding(t()) :: non_neg_integer()
How many notes are sounding right now, the ones fading out included.
@spec update(t(), TuningFork.Pattern.t(), keyword()) :: t()
Swap the pattern without stopping. The position carries on.
at: :cycle, the default, holds it until the next cycle line. at: :now takes effect on the
next block. Notes already sounding finish as the pattern read when they started.