The segment-rate and segment-shape machine shared by the TVA, TVF and pitch envelopes.
More...
|
| | EnvelopeMachine (const TableSet &tables) |
| | Creates the machine over a loaded table set, which must outlive it.
|
| int | rate_scale (int base_rate, int modifier) const noexcept |
| | Converts a base rate byte and a 0x40-neutral modifier into an 8.8 rate multiplier.
|
| int | level_scale (int level, int modifier) const noexcept |
| | Converts a level byte and a 0x40-neutral modifier into an 8.8 multiplier.
|
| double | segment_milliseconds (int rate_byte, int rate_multiplier, int velocity_multiplier=unity_multiplier, int bias=0) const noexcept |
| | The duration of one envelope segment in milliseconds, or zero for an instant segment.
|
| double | segment_curve (double position, double start, double target, bool linear) const noexcept |
| | Interpolates one segment's value at a normalised position, 0 to 1.
|
| std::int64_t | hold_samples (const PartialParameters &partial, int velocity) const noexcept |
| | How long a partial's envelope machine stays held at its note-on state, in samples.
|
The segment-rate and segment-shape machine shared by the TVA, TVF and pitch envelopes.
An envelope is a chain of segments, each with a target level and a rate byte. The rate byte selects a base duration from g_rate_curve, which two 8.8 multipliers then scale: one from key-follow and one from velocity. A segment completes when a 16-bit phase accumulator wraps, which makes the duration 0x10000 / (rate * speed) * 10 ms at the 100 Hz control tick.
Everything here is integer arithmetic with deliberate 16-bit truncation. The control path of the original is exclusively 16-bit fixed point, and several of these expressions depend on wrapping or on truncation toward zero.
| std::int64_t ts::EnvelopeMachine::hold_samples |
( |
const PartialParameters & | partial, |
|
|
int | velocity ) const |
|
nodiscardnoexcept |
How long a partial's envelope machine stays held at its note-on state, in samples.
Zero for a normal partial; a sample count for a delayed start; hold_forever for a one-shot.
Partial block byte 0x00 arms a one-shot clock at note-on. While it runs, none of the voice's envelopes or LFOs advance — every control value stays where the note-on compute left it, which for an ordinary attack envelope is silence. When it fires, the machine simply starts. It fires once; it is a delayed start, not a tremolo. 0xff is the one-shot form: held for the voice's whole life, so the sample plays at its note-on control levels (the .o variation tones), and note-off takes the fast fade instead of the release.