pub struct PlaybackWindow { /* private fields */ }Expand description
The span of song time one callback renders.
This is the sync guarantee. Clip playback and pattern playback in
mixer.rs take the same value and ask it the same question, so a clip
note and a pattern step on the same beat cannot land on different samples:
there is only one expression that turns a tick into a sample offset, and
only one that decides where the window starts and ends.
Windows are half-open and contiguous. The next window begins exactly where this one ended, rather than at the transport’s new position, because those are not always the same number: a block is almost never a whole number of ticks, and a transport that carries the remainder can advance 179 ticks where the block measured 178. Starting the next window at the position would leave a one-tick hole in song time, and an onset that fell in it would never play. Starting it where the last one ended cannot.
Implementations§
Source§impl PlaybackWindow
impl PlaybackWindow
Sourcepub const MAX_TICK_GAP: i64 = 1
pub const MAX_TICK_GAP: i64 = 1
The largest gap between one window’s end and the next block’s position that still counts as continuous playback.
One tick, and it is not a fudge factor: the block length in ticks is truncated and the transport’s advance is not, so consecutive positions can run at most one tick ahead of the measured window. Anything larger is the playhead being moved, which is a discontinuity — pending notes get flushed and nothing is replayed.
Sourcepub fn for_block(
position: i64,
frames: u32,
ticks_per_sample: f64,
loop_region: Option<(i64, i64)>,
previous: Option<Self>,
) -> Self
pub fn for_block( position: i64, frames: u32, ticks_per_sample: f64, loop_region: Option<(i64, i64)>, previous: Option<Self>, ) -> Self
The window for one callback.
loop_region is the loop’s (start, end) when the transport is
looping, and None when it is not — one argument rather than a flag
and two numbers, because “looping over nowhere” is not a state that
should be spellable.
previous is the window the last callback used, if playback has been
running. Two things come from the loop region:
- A wrap — the transport moving backwards — starts the window at the loop point, so the ticks between it and the position the callback arrived at are played rather than skipped. That is what clip playback has always done.
- The window never extends past the loop end. Without that, the last callback of a loop would reach across the loop point and play the first notes on the other side of it, and then the wrap would play them again: one doubled downbeat per time round.
Sourcepub fn narrowed(&self, from: i64, to: i64) -> Self
pub fn narrowed(&self, from: i64, to: i64) -> Self
A window over part of this one, for splitting a callback at a pattern switch. Sample offsets are unchanged: they are measured from the original start of the block, not from the piece.
pub const fn from(&self) -> i64
pub const fn to(&self) -> i64
Sourcepub const fn is_continuous(&self) -> bool
pub const fn is_continuous(&self) -> bool
Whether this window carries on from the previous one. false after a
jump, a loop wrap, or the first block of playback — every case where
notes still sounding have to be turned off.
pub const fn is_empty(&self) -> bool
pub const fn contains(&self, tick: i64) -> bool
Sourcepub fn sample_offset(&self, tick: i64) -> u32
pub fn sample_offset(&self, tick: i64) -> u32
Where in the callback’s buffer an event at tick belongs.
The one expression that turns song time into a sample. A tick before the window lands on the first sample rather than underflowing, and one past the end lands on the last: a note played at the wrong end of a buffer is 1.5 ms out, and a note not played at all is a hole in the part.
Trait Implementations§
Source§impl Clone for PlaybackWindow
impl Clone for PlaybackWindow
Source§fn clone(&self) -> PlaybackWindow
fn clone(&self) -> PlaybackWindow
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more