Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
Loading...
Searching...
No Matches
ts::DecodedWave Struct Reference

A wave decoded from the ROM, with everything playback needs. More...

#include <tabulasonora/sampler.hpp>

Public Member Functions

int loop_period () const noexcept
 The forward loop's period in samples.
bool is_looping () const noexcept
 Whether a forward loop is actually in effect.

Public Attributes

std::vector< float > samples
 The decoded samples.
std::vector< std::int32_t > steps
 The shifted per-sample deltas, needed to rebuild a ping-pong traversal.
std::int32_t seed = 0
 The predictor's value entering the data start — the integral of the preamble deltas from the 32-sample exponent-block boundary below it, where the engine's decoder zeroes.
int loop_start = 0
 Index of the loop point.
int data_end = 0
 Number of decodable samples.
SamplerMode mode = SamplerMode::one_shot
 Which sampler variant applies.
std::vector< float > loop_buffer
 The buffer a forward loop reads from; empty for the other modes.
bool reversed = false
 Whether samples has been turned round because the wave plays backwards.

Detailed Description

A wave decoded from the ROM, with everything playback needs.

Member Function Documentation

◆ loop_period()

int ts::DecodedWave::loop_period ( ) const
inlinenodiscardnoexcept

The forward loop's period in samples.

Inclusive of the data end: one pass plays loop_start..data_end. Dropping that last sample is inaudible on a long loop but detunes a short single-cycle one outright — a 63 against 64 sample period is 27 cents sharp.

◆ is_looping()

bool ts::DecodedWave::is_looping ( ) const
inlinenodiscardnoexcept

Whether a forward loop is actually in effect.

Member Data Documentation

◆ samples

std::vector<float> ts::DecodedWave::samples

The decoded samples.

◆ steps

std::vector<std::int32_t> ts::DecodedWave::steps

The shifted per-sample deltas, needed to rebuild a ping-pong traversal.

◆ seed

std::int32_t ts::DecodedWave::seed = 0

The predictor's value entering the data start — the integral of the preamble deltas from the 32-sample exponent-block boundary below it, where the engine's decoder zeroes.

Every decoded sample already includes it; it is kept so the ping-pong rebuild can integrate from the same origin. An unaligned wave rides this as a constant DC — the verification article's "module has DC", measured live at exactly −0.041015625 on Crash Cym.1 and −0.139 on the sine-kick zone.

◆ loop_start

int ts::DecodedWave::loop_start = 0

Index of the loop point.

◆ data_end

int ts::DecodedWave::data_end = 0

Number of decodable samples.

◆ mode

SamplerMode ts::DecodedWave::mode = SamplerMode::one_shot

Which sampler variant applies.

◆ loop_buffer

std::vector<float> ts::DecodedWave::loop_buffer

The buffer a forward loop reads from; empty for the other modes.

The 4-tap window reaches two samples past the read index, so the buffer must carry the samples the loop wraps to rather than whatever follows it. It is the wave plus a few wrapped samples — a fixed size, independent of how long a note holds — so it is built once with the wave and shared by every voice that plays it.

◆ reversed

bool ts::DecodedWave::reversed = false

Whether samples has been turned round because the wave plays backwards.

Playback does not consult this: the samples are already in the order they are read, so a reverse wave is an ordinary one-shot from here on. It is recorded because a buffer that no longer matches the order steps is in would otherwise be silently confusing — the steps stay forward, and nothing that reads them applies to a reverse wave.


The documentation for this struct was generated from the following file: