Rust API
Structs
AlienConfig
Reverse playback of recent stereo audio in repeated loops with fades.
Alien comes after resynthesis. Its input history and loop phase advance also when Alien is disabled. Thus, when you enable Alien, it can play audio that it recorded during bypass. A change of the loop length keeps the history and clamps the current phase into the new loop. The boundary fades are 200 frames long at all sample rates.
enabled: boolSelects reversed playback instead of the direct input. The default is false. The recording and the phase continue to advance in both states.
loop_frames: u32The loop length in frames, 1..=96000. The default is 95,999. This value is a frame count at the two rates. Thus, its duration in seconds changes with the sample rate. A short loop can be fully inside the fades.
pub fn validate(self) -> Result<(), Error>Validates all fields, also when Alien is disabled.
loop_frames must be in its documented inclusive range. Validation does not clamp values. It does not change the processor state.
Errors
Returns the first Error::InvalidConfig with its dotted field path and the problem.
CorrectionConfig
The controls for pitch-class correction, with target selection in the period domain.
Correction is enabled by default, with all chromatic notes and a retune time of zero. Target selection and the smoothing of the correction ratio occur at each update of the pitch tracking. When a period is tracked, this update usually occurs every five frames. If the active note table is empty or correction is disabled, the ratio moves toward 1.0 at the same rate.
Correction MIDI replaces the active note table. It does not change this configuration. A change to notes or to enabled loads the configured mask again. Reset releases the correction keys 0..=126. It keeps key 127 and the active note table. Key 127 has no effect on the note table.
At construction, the chromatic table uses 44.1 kHz periods, also for a 48 kHz processor. Each of these events loads the periods for the prepared rate:
- An initial mask that is not chromatic.
- A later change to the mask or to
enabled. - A correction MIDI event.
enabled: boolEnables the selection of correction targets. The default is true.
If you disable correction, the ratio moves toward 1.0 with retune_ms at the next tracking updates. The ratio does not change to 1.0 immediately.
notes: NoteMaskThe configured target pitch classes. The default is NoteMask::CHROMATIC.
All boolean masks are valid. MIDI can replace the active table. This replacement stays until this mask or enabled changes.
retune_ms: f32The half-life of the smoothing in milliseconds, 0..=400. The default is 0.
If the value is zero, the ratio changes to the target at the next tracking update. A value that is not zero is a half-life. It is not a fixed time to get exactly to the target.
pub fn validate(self) -> Result<(), Error>Validates all fields, also if correction is disabled.
All values of enabled and notes are valid. retune_ms must be finite and in its documented inclusive range. Validation does not clamp values. It does not change the state of the processor.
Errors
Returns Error::InvalidConfig, with the dotted path of the field and the problem, if retune_ms is not valid.
Feedback
A snapshot of the pitch analysis and the output level that you can copy.
Get it with Processor::feedback or Processor::take_feedback. The pitch fields describe the tracked input and the correction target. The peak measures the final clipped stereo output. Default gives a snapshot with all zeros and no target. It does not read the nominal latency of a prepared processor.
resample_ratio: f32The pitch-correction ratio from the last processed frame, where 1 is unity.
It does not include the configured pitch shift or the ratios of individual voices. It is zero before processing, after a reset or after a change of stereo output.
period_samples: f32The reported input pitch period in samples, with fractional samples.
It is zero if the input is unvoiced or outside the reporting bounds of PitchConfig.
frequency_hz: f32The reported input pitch frequency in hertz.
The value comes from the sample rate and the current tracked period. It is zero if the estimate is not reported.
target_midi_note: Option<f32>The correction target or the input pitch, as a MIDI note number.
The value is the selected correction pitch class if all of these conditions are true:
- Correction is enabled.
- The active note table is not empty.
- A tracking update selected a target after the last table change, reset or tracking restart.
The pitch class is in the octave nearest to the reported input. In other cases, the value is the input pitch as a fractional MIDI note. It is not the final pitch of shifted output or harmony output.
The value is None if voiced is false, and only then. This occurs if the input is unvoiced or if its frequency is outside the current reporting bounds. A target table that has no selected target does not give None.
voiced: boolThis field is true if the current pitch estimate is positive and inside the current reporting bounds.
This is not an amplitude gate or a confidence score. A tracking result can stay between detector updates.
peak_level: f32The largest absolute clipped stereo sample, divided by 32768.
The peak window starts at construction, at a reset, at a change of stereo output or at a call to Processor::take_feedback. The value is in 0..=32767/32768. The mono downmix occurs after this measurement. Processor::feedback does not clear the value.
processed_frames: u64The number of frames processed since construction or the last reset, with drain frames included.
The count saturates at u64::MAX. Drain completion resets it in the last drain call.
latency_frames: usizeThe nominal resynthesis latency, as Processor::latency_frames gives.
FormantConfig
The controls for vocal-tract changes and synthesized aspiration during resynthesis.
This stage is disabled by default. If it is enabled, it does these steps:
- It estimates an LPC model.
- It removes the spectral envelope of the input.
- It applies a changed model to the resampled audio.
If width and stretch are 1, the model dimensions do not change. But the fixed-point analysis and synthesis path does not give a bit-identical copy of the input. Aspiration occurs only if the formant path is enabled.
enabled: boolEnables formant analysis and synthesis. The default is false.
width: f32The vocal-tract width factor, 0.5..=2. The default is 1.
The square of the width scales the estimated tract areas. The width also scales the amplitude of the synthesized output.
stretch: f32The vocal-tract length factor, 0.5..=2. The default is 1.
It controls the interpolation of the area model and thus the filter order.
aspiration_mix: f32The aspiration level, 0..=1, without a unit. The default is 0.
If the value is 0.01 or less, the stage makes no noise. Active aspiration follows the signal amplitude. It uses the random stream of the processor, together with other stages. During each drain call, the processor sets the aspiration to zero. The configuration that the host sees does not change.
aspiration_cutoff_hz: f32The high-pass cutoff for aspiration in hertz, 500..=10000. The default is 4000.
The stage limits the cutoff to 0.48 × sample rate and truncates it to whole hertz. A change to this value updates the coefficients. The filter history does not change.
pub fn validate(self) -> Result<(), Error>Validates all fields, also if the formant stage is disabled.
Each floating-point control must be finite and in its documented inclusive range. Validation does not clamp values. It does not change the state of the processor.
Errors
Returns the first Error::InvalidConfig, with the dotted path of the field and the problem.
HarmonyConfig
The configuration of four harmony voices that follow intervals, chords or MIDI.
Positive intervals make the pitch higher. The defaults are:
- MIDI channels 0..=3 as the source.
- The key of C and the major scale.
- Unison intervals.
- A tonic major chord in root position.
- A register of 50%.
- A closed voicing and zero portamento.
- Four voices for the interval sources.
These settings configure all sources. Only the fields for the selected source change the target notes. Validation always checks all fields.
Harmony makes its voices from the tracked input. MIDI controls the pitch and the gain. It is not an independent oscillator. The gain in decibels is linear in the velocity: velocities 1..=127 give approximately -23.72 to +12 dB. A velocity of zero releases the note.
The gain attack, the gain release and the period portamento advance at the controller cadence. This cadence is usually every 101 frames. A MIDI event can make the next control step occur sooner. The envelopes and the portamento advance only while the input is voiced.
source: HarmonySourceThe pitch source. The default is HarmonySource::MidiChannels.
key: PitchClassThe pitch class of the tonic. The default is C. Smart intervals, named chords and degree chords use it. It does not transpose direct MIDI notes.
scale: HarmonyScaleThe scale for smart intervals and degree chords. The default is major.
chromatic_intervals: [i8; 4]Four fixed semitone offsets, each in -24..=24. The default is all zeros. HarmonySource::FixedInterval uses them. A value of 12 makes the pitch one octave higher.
diatonic_intervals: [i8; 4]Four offsets in scale steps, each in -14..=14. The default is all zeros. HarmonySource::SmartInterval uses them. Seven steps make the pitch one octave higher.
chord: ChordNameThe named chord for HarmonySource::ChordByName. The default is major.
degree: ChordDegreeThe chord on a scale degree for HarmonySource::ChordByDegree. The default is I.
inversion: InversionThe inversion for named chords and degree chords. The default is root position.
register_percent: f32The chord register from low to high, 0..=100%.
The default is 50%. All chord sources use it, which includes MIDI chords. The value is truncated to a whole percentage before it selects the octave shift.
voicing_spread_percent: f32The chord voicing from close to open, 0..=100%.
The default is 0%. All chord sources use it. The value is truncated to a whole percentage. The result selects discrete octave positions, not continuous detuning.
portamento_ms: f32The half-life of the target-period smoothing in milliseconds, 0..=10000. The default is 0. The smoothing applies at each control step. The coefficient assumes 100 frames for each step. At the usual cadence of 101 frames, the half-life is approximately 1% longer. If the value is zero, the voice uses the target period immediately. The gain envelopes still apply. A note on a free voice can start without a glide. In the interval sources, if the input moves more than one semitone bin, each voice starts at its new target without a glide.
voices: u8The number of voices that sound in the interval sources, 0..=4.
The default is 4. HarmonySource::FixedInterval and HarmonySource::SmartInterval use the first voices voices. The other voices release with the usual gain envelope. The chord and MIDI sources ignore this field. In JavaScript, the field is optional and a missing value gives the default.
pub fn validate(self) -> Result<(), Error>Validates all fields, which includes the fields that the selected source does not use.
Each element of the two interval arrays must be in its documented inclusive range. The floating-point controls must be finite and in their documented inclusive ranges. Validation does not clamp values. It does not change the processor state.
Errors
Returns the first Error::InvalidConfig with its dotted field path and the problem. For an array control, the error identifies the array field, not the index of an element.
NoteMask
The permitted correction pitch classes, in the order C, C♯, D, D♯, E, F, F♯, G, G♯, A, A♯, B.
A true flag enables that pitch class in all octaves.
The default is CHROMATIC. All combinations of flags are valid. This includes NONE. If the mask is empty, the correction ratio moves toward unity with the configured retune half-life. An empty mask does not clear the histories.
0: [bool; 12]pub const CHROMATIC: SelfThe mask that permits all pitch classes.
pub const NONE: SelfThe mask with no active target notes.
Correction updates move toward unity with the configured retune half-life. The current correction does not always stop immediately.
pub const fn new(notes: [bool; 12]) -> SelfReturns a mask from twelve flags, where index 0 is C.
pub fn from_key_scale(key: PitchClass, scale: CorrectionScale) -> SelfReturns the pitch classes of scale, with key as the tonic.
Major uses the semitone offsets 0, 2, 4, 5, 7, 9, 11. Natural minor uses 0, 2, 3, 5, 7, 8, 10. Chromatic permits all classes for all keys. This function only makes a value. To apply the value, use the correction configuration.
PitchConfig
The acquisition sensitivity and the bounds for pitch reports to the host.
threshold: f32The normalized cycle-difference threshold for acquisition, 0.002..=0.2.
The default is 0.1. Larger values accept less exact cycle agreement. This value controls acquisition. It is not an output gain or an amplitude gate.
min_frequency_hz: f32The lower bound of the feedback in hertz (inclusive), 40..=2000.
The default is 40. It must be strictly less than max_frequency_hz. These bounds do not change the tracking, the correction or the resampling. A feedback query applies the current bounds to the kept analysis. It does not process another sample.
max_frequency_hz: f32The upper bound of the feedback in hertz (inclusive), 40..=2000.
The default is 1100. It must be strictly greater than min_frequency_hz. Results outside the bounds are reported as unvoiced, with zero frequency and zero period.
pub fn validate(self) -> Result<(), Error>Checks the threshold, then each frequency range, then the order of the frequencies.
Errors
Returns Error::InvalidConfig for a value that is not finite or is out of range. If the bounds are equal or reversed, the error has the field resynthesis.pitch.min_frequency_hz and the problem ConfigProblem::Unordered. The other value of that problem is resynthesis.pitch.max_frequency_hz.
PrepareConfig
The fixed limits of a processor: the sample rate and the maximum number of frames for each call.
The default is 44.1 kHz, with a limit of 1,024 frames for each block.
max_block_frames: NonZeroUsizeThe maximum number of frames in one process call or drain call.
The default is 1,024. The limit must not be zero, but a block can be empty. The limit does not change the delay-line capacities of the algorithm. It also does not require full blocks.
pub fn new(sample_rate: SampleRate, max_block_frames: usize) -> Result<Self, Error>Returns new processor limits and does not allocate audio storage.
max_block_frames counts mono input samples or stereo output frames. It does not count the total samples in the two output channels. It is a limit for each call, and smaller blocks and empty blocks are also valid. The value does not have to be a power of two. Processor::new allocates the processor.
Errors
Returns Error::InvalidConfig with the field prepare.max_block_frames if the maximum is zero. The field type is NonZeroUsize. Thus, this invariant also holds if you edit the field after construction.
Processor
A prepared vocal processor with state, mono input and stereo synthesis.
Construction fixes the sample rate and the block limit, and allocates all histories. Use the process method that matches the buffer layout of the host. Each input frame produces one output frame. ResynthesisConfig::stereo_output selects the voice panning separately.
The audio, configuration, reset and drain calls need exclusive access to this instance. Each processor owns its histories and numeric state, and there is no global audio state. These prepared operations do not allocate, do not lock and do no I/O. Public operations that can fail validate before they change state or output. Refer to the crate documentation for the signal chain and the lifecycle.
pub fn new(preparation: PrepareConfig, config: ProcessorConfig) -> Result<Self, Error>Validates the settings, allocates histories and makes a new processor.
Each processor is independent. preparation fixes the rate and the block limit for each call. After construction, the audio, control, feedback, reset and drain calls do not allocate, do not lock and do no I/O. Audio histories, pitch reports and meters start clear. The random stream starts from the low 32 bits of random_seed.
Punch uses its default cached drive until the first window of 100 frames with Punch enabled. The initial note table of correction has the rate behavior that CorrectionConfig describes.
Errors
Returns Error::InvalidConfig if a stage field or the output gain is not valid. This check occurs before the allocation of the histories. The types of preparation already make sure that the block limit is not zero and that the sample rate is supported.
pub fn process(
&mut self,
input: &[i16],
output: &mut [[i16; 2]],
events: &[TimedEvent],
) -> Result<(), Error>Processes mono PCM into [left, right] stereo frames.
The output must have the same number of frames as the input. Both must fit in PrepareConfig::max_block_frames. If the call succeeds, it writes all output frames. The layout is stereo also when voice panning is off. For interleaved PCM, as_chunks_mut::<2>() can show a buffer of even length as pairs.
Each event applies before its frame. Offsets must be in the block and must not decrease. Events with equal offsets execute in slice order. An empty block accepts no events. A successful call cancels a drain, also if the call is empty.
Errors
The call checks Error::BufferLength first and Error::BlockTooLarge second. Then it checks Error::InvalidEvent for the first invalid event. The validation of the full event slice finishes before the state or the output changes.
pub fn process_planar(
&mut self,
input: &[i16],
left: &mut [i16],
right: &mut [i16],
events: &[TimedEvent],
) -> Result<(), Error>Processes mono PCM into separate left and right output slices.
The three slices must have equal frame counts. The audio, the event order, the behavior for empty blocks and the drain cancellation are the same as for process. If the call succeeds, it writes all output samples.
Errors
The call checks Error::BufferLength for the left channel, then for the right channel. Next, it checks Error::BlockTooLarge, then Error::InvalidEvent. If an error occurs, the two output buffers and all processor state do not change.
pub fn process_mono_in_place(
&mut self,
audio: &mut [i16],
events: &[TimedEvent],
) -> Result<(), Error>Replaces mono PCM with the stereo result after the downmix.
The method reads each input sample before it writes over that location. The downmix uses (i32::from(left) + i32::from(right)) >> 1, which rounds toward negative infinity. Panning and stereo effects run before this downmix. Peak feedback measures the stereo samples. Events and drain cancellation are the same as for process.
Errors
Returns Error::BlockTooLarge for a slice that is too large. Returns Error::InvalidEvent for the first invalid event. All checks finish before the audio slice or the processor state changes.
pub fn begin_drain(&mut self) -> usizeStarts a tail with the current tail_frames budget and returns that budget.
Call this method one time after the last input block. Another call starts the full budget again, but does not clear histories. A successful process call, a successful configuration call or a reset cancels the drain.
The drain uses silent input and mutes aspiration temporarily. Each drain call returns a frame count and fills the unused output with zeros. The call that uses all of the budget does a reset, also if it returns frames. An empty buffer uses no budget. The budget can include silence. The reset at the end of the budget stops the fixed-point output that is left in the histories that it clears.
pub fn drain(&mut self, output: &mut [[i16; 2]]) -> Result<usize, Error>Renders the next stereo tail frames and returns their count.
Call begin_drain first. Before a drain starts or after it finishes, this method returns zero and clears the output. The method always fills unused frames with zeros. An empty buffer does not advance the drain.
Errors
If the output is larger than the prepared block limit, the method returns Error::BlockTooLarge and does not change state or output.
pub fn drain_planar(
&mut self,
left: &mut [i16],
right: &mut [i16],
) -> Result<usize, Error>Renders the tail into separate output channels of equal size.
The return values, the zeros in unused samples, empty buffers and completion are the same as for drain. A final call can return frames and also do the reset in that call.
Errors
The method checks Error::BufferLength before Error::BlockTooLarge. If either error occurs, the two channels and the drain state do not change.
pub fn drain_mono(&mut self, output: &mut [i16]) -> Result<usize, Error>Renders the tail as mono PCM and returns the number of rendered frames.
The downmix is the same as in process_mono_in_place. The method fills unused samples with zeros. If the drain is not active or is complete, the method returns zero. An empty output uses no budget. At completion, the method does a reset, as begin_drain describes.
Errors
If the output is larger than the prepared block limit, the method returns Error::BlockTooLarge before it changes output or state.
pub fn tail_frames(&self) -> usizeReturns the finite tail budget for the current configuration.
This value is a configured limit. It is not the number of drain frames that are left, and it is not a measured decay time. It can include silence. It can also stop filter output that continues for a long time.
pub fn prepare_config(&self) -> PrepareConfigReturns the fixed sample rate and block limit.
pub fn config(&self) -> ProcessorConfigReturns a copy of the current settings and does not change state.
If you edit the copy, nothing changes until set_config or a configuration event applies it. The temporary aspiration mute of a drain does not change the settings that this method returns.
pub fn latency_frames(&self) -> usizeReturns the nominal resynthesis latency: 1,593 frames at both rates.
The dry path has a delay of 1,543 frames. Resampled voices, choir delays and effects have their own timing. Thus, this value does not align all paths.
pub fn feedback(&self) -> FeedbackReturns the pitch, stereo peak and frame count, and does not clear them.
To start a new peak window, use take_feedback.
pub fn take_feedback(&mut self) -> FeedbackReturns the current feedback and clears only the peak window.
pub fn telemetry(&self) -> TelemetryReturns the state of the voices, the levels and the effects, and does not clear the peak windows.
The telemetry is for meters and displays. It does not change the audio. To start new peak windows, use take_telemetry. The peak windows of the telemetry are independent of the peak window of Feedback.
pub fn take_telemetry(&mut self) -> TelemetryReturns the current telemetry and clears only its three peak windows.
The peak window of Feedback and all audio histories do not change.
pub fn formant_envelope(
&self,
max_frequency_hz: f32,
input: &mut [f32],
output: &mut [f32],
) -> Result<bool, Error>Writes the formant envelopes of the model that the audio used for the last frame.
input gets the vocal-tract envelope that the LPC analysis found. output gets the envelope after the width and stretch controls. Point k of n is at the frequency max_frequency_hz * k / (n - 1). The values are linear magnitudes. They have no absolute level, because the analysis normalizes the signal energy. Scale them for a display.
max_frequency_hz must be finite, more than zero and not more than half of the sample rate. The two slices must have the same length.
Returns Ok(true) if the envelopes are valid. Returns Ok(false) and fills the two slices with zeros in these cases:
FormantConfig::enabledisfalse.- The current model has no synthesis filter. This occurs before the first analysis and after an analysis that fails.
The method does not allocate memory and does not change the audio.
Errors
The method checks Error::BufferLength first, then Error::InvalidFrequency. On error, the two slices do not change.
pub fn set_config(&mut self, config: ProcessorConfig) -> Result<(), Error>Validates all configuration fields and applies them.
The validation also examines the fields of disabled stages. A stage that does not change keeps its state. A change of stereo_output resets the resynthesis audio state, Alien, the reverb delays, the peak and the reported ratio. It also releases the harmony MIDI notes. It keeps Punch, Warm, the correction keys, the random stream, the reverb low-pass memories and the frame count. A change of random_seed starts the random stream again.
Each successful call cancels a drain, also for an identical configuration. A change of reverb mode keeps the delay contents. If you disable Punch, Warm or reverb, the history of that stage stops. Alien continues to record. A change in either half of the u64 seed starts the stream again, but the new sequence uses only the low 32 bits.
Errors
Returns Error::InvalidConfig if a field is not valid. The method returns this error before it changes any state, also an active drain.
pub fn reset(&mut self)Clears the audio histories, held notes, pitch feedback, peak and frame count.
This method cancels an active drain. It also clears the correction ratio, the Punch envelopes, the Warm filters, the Alien recording and the reverb delays. It releases the harmony MIDI notes and, in MIDI-chord mode, the chord voices. It keeps these items:
- the configuration
- the random stream and the arctangent lookup position of Punch
- the reverb low-pass memories and the reverb write position
- correction key 127 and the active correction note table
- the last usable period of the pitch tracker, which fills unvoiced gaps
- the harmony gain envelopes and the last voice ratios of the harmony controller
- the prepared chord targets of the named and degree chord sources
- the choir drift
- the control-step counter of Choir and Harmony
- the phase of the harmonic modulation.
When the method clears the held keys, it does not load the configured scale again. For a fully new state, make a new processor.
ProcessorConfig
The settings for the complete signal chain, in the order of the stages.
The default enables chromatic pitch correction, one choir voice and unity output gain. Punch, Warm, formants, Alien and reverb are disabled. This configuration does active pitch processing. It is not a bypass with zero latency.
Change a copy, then apply it with Processor::set_config or ControlEvent::Configure. The validation examines all fields before a change has an effect. This includes the fields of disabled stages.
punch: PunchConfigThe input dynamics and saturation stage, which applies first.
It is disabled by default.
resynthesis: ResynthesisConfigThe stage for pitch tracking, correction, voice resynthesis and formant control.
The default is ResynthesisConfig::default.
output_gain: f32The linear gain after all effects, 0..=64.
The default is 1 (unity). Zero mutes the output, but the internal processing continues. The gain is quantized in steps of 1/256 before the fixed-point multiplication and the final PCM clipping. Thus, a positive value below 1/256 also mutes the output.
pub fn validate(self) -> Result<(), Error>Checks all stages and the final gain, and does not change state.
The validation uses the signal order: Punch, Warm, resynthesis, Alien, reverb, then output gain. It includes disabled stages and the controls of voice modes that are not active.
Errors
Returns the first Error::InvalidConfig. The error names the field and its range, finiteness or order problem. The function does not clamp or normalize values.
PunchConfig
The input gain and the transient enhancement with arctangent saturation.
Punch comes before Warm and before pitch detection. It finds the peak of each window of 100 processed frames. Two envelope followers set the drive from these peaks. When Punch is disabled, it does not process audio, and its envelope and window state do not change.
A gain change updates the cached drive at the next boundary of the peak window. A reset calculates that drive again immediately from the configured gain.
enabled: boolEnables this input stage. The default is false.
gain_db: f32The input gain in decibels, -96..=12.
The default is 0 dB. The saturation drive from this gain changes at the next 100-frame peak boundary.
impact: f32The transient emphasis without a unit, 0..=1.
The default is 0.5. It sets the release half-life of the adaptive follower: 5000 ms at 0, 250 ms at 0.5 and 1 ms at 1. The attack uses attack_ms.
ceiling_db: f32The output ceiling of the saturation in dBFS, -96..=0.
The default is -3 dBFS. Later stages and the final gain can make the final output higher than this level.
attack_ms: f32The attack half-life of the peak follower in milliseconds, 0.01..=5000.
The default is 10 ms. The coefficients include the effect of the 100-frame update interval.
pub fn validate(self) -> Result<(), Error>Validates all fields, also when Punch is disabled.
The floating-point controls must be finite and in their documented inclusive ranges. Validation does not clamp values. It does not change the processor state.
Errors
Returns the first Error::InvalidConfig with its dotted field path and the problem.
ResynthesisConfig
The controls for pitch correction, pitch shift, voice arrangement and formants.
The defaults render one choir voice with these settings:
- Chromatic correction.
- A pitch shift of 1.0.
- Disabled formants.
- No harmonic modulation.
- No dry mix.
- No stereo pan.
Validation applies to all controls, also when their stage or voice mode is not active.
The dry path takes the audio after Punch and Warm and delays it by 1,543 frames. The wet voice readers have more delay, which changes with the pitch. After this stage, the two paths go through Alien, reverb and the final output gain.
pitch: PitchConfigThe acquisition sensitivity and the reporting bounds. The default is PitchConfig::default.
correction: CorrectionConfigThe target notes and the retune time. The default is enabled chromatic correction with a retune time of zero.
pitch_ratio: f32The pitch multiplier, 0.25..=4. The default is 1.
A value of 0.5 lowers the pitch by one octave. A value of 2 raises the pitch by one octave. This value multiplies the correction ratio and the ratio of each voice. A value above 1 also enables the anti-alias low-pass filters.
formant: FormantConfigThe vocal-tract changes and aspiration. They are disabled by default.
mode: MultiVoiceModeThe voice arrangement. The default is MultiVoiceMode::Choir.
Harmony renders the lead voice and a maximum of four harmony voices.
choir_voices: u8The total number of choir voices, with the lead voice, 1..=16. The default is 1.
The other voices read the delayed lead history with random pitch drift. The code adds the voices and does not divide the sum by the number of voices. Thus, more voices can increase the output level and the clipping. Harmony does not use this value.
choir_detune: f32The drift control for secondary voices, 10..=100, without a unit. The default is 50.
The unit is not cents. The lead voice has no random choir drift. Thus, a choir with one voice does not get this detune.
choir_delay: f32The scale of the choir delay table, 20..=200, without a unit. The default is 60.
A value of 200 uses the full fixed table of frame offsets. The unit is not milliseconds. The table offset of the lead voice is zero at all settings.
choir_spread_percent: f32The stereo width of the choir, 0..=100%. The default is 100%.
The code uses this value only if stereo_output enables the voice pan and the choir has more than one voice.
stereo_output: boolEnables a stereo pan for each voice. The default is false.
This value is independent of the buffer layout of the process method. A change to this value resets some audio histories and the feedback. Processor::set_config gives the details.
harmony: HarmonyConfigThe controls for the four harmony voices. The default is MIDI-channel allocation.
Validation applies to these controls, and they can receive MIDI, also while Choir is selected.
harmony_gain: f32The pan gain of the harmony voices, 0..=1. The default is 0.5.
The code applies this gain only if stereo_output is true. The harmony path without pan does not use this control. It does not scale the lead voice.
harmonic_modulation: f32The modulation depth, 0..=24, without a unit. The default is 0 (off).
The code multiplies the control by two and truncates it to an integer. Then it uses the result for a cosine modulation after the wet voices are mixed. The value is not an interval in semitones.
dry_mix: f32The dry fraction at the resynthesis stage, 0..=1. The default is 0.
The code truncates this value to Q8. The wet weight is 1.0 minus the Q8 dry weight. The dry path starts after Punch and Warm and has a delay of 1,543 frames. Alien, reverb and the output gain still occur after this stage.
random_seed: u64The seed for choir drift and aspiration, which use the same stream. The default is 0x1234_abcd.
Only the low 32 bits select the sequence. If a configuration change gives a different 64-bit value, the processor starts the stream again from the low 32 bits. This is also true for a change to only the high bits. Reset keeps the current position in the stream. The enabled stages set the number of random values that the code reads.
pub fn validate(self) -> Result<(), Error>Validates all fields, also the settings for stages that are disabled or not active.
Each floating-point control must be finite and in its documented inclusive range. choir_voices must be in 1..=16. Validation does not clamp values. It does not change the state of the processor.
Errors
Returns the first Error::InvalidConfig, with the dotted path of the field and the problem. For an array control in harmony, the error identifies the array field, not the index of an element.
ReverbConfig
The reverb after Alien, with controls for the network, the wet mix and the decay.
The reverb is disabled by default. In bypass, the stage returns the input and does not advance the delay network or the damping filters. If the stage is enabled and the mix is zero, the network still operates. A reset clears the delay buffer but keeps the memories of the damping filters. The mix, diffusion and decay controls are quantized to Q14. The function of each control changes with the network.
enabled: boolEnables the selected network. The default is false. In bypass, the histories do not change.
mode: ReverbModeThe topology of the delay network. The default is ReverbMode::Echo.
mix: f32The wet fraction, 0..=1.
The default is 0.5. The dry weight is 1 - mix. Schroeder and Binaural use a mono dry signal. The other modes keep the stereo dry input. If the network is enabled, a zero mix still advances it.
diffusion: f32The diffusion control without a unit, 0..=1.
The default is 0.5. MediumHall and LargeHall scale their allpass coefficients with it. Binaural uses it as the gain of its early taps. In Echo, it sets the distance of the feedback tap. Schroeder and SmallRoom do not use it.
decay: f32The feedback control without a unit, 0..=1.
The default is 0.6. The prepared coefficient is approximately decay / 1.05. It is less than unity also at the maximum. This value is not a decay time in seconds. Some paths also use fixed feedback coefficients. Binaural does not use this control.
brightness_hz: f32The low-pass cutoff in hertz for networks with damped paths, 80..=20000.
The default is 4000 Hz. The preparation also limits it to 0.49 × sample rate. A change of the cutoff keeps the sample histories of the filters.
pub fn validate(self) -> Result<(), Error>Validates all fields, also when the stage is disabled or the selected mode does not use a field.
The floating-point controls must be finite and in their documented inclusive ranges. Validation does not clamp values. It does not change the processor state.
Errors
Returns the first Error::InvalidConfig with its dotted field path and the problem.
Telemetry
A snapshot of the voices, the levels and the effect state that you can copy.
Get it with Processor::telemetry or Processor::take_telemetry. The telemetry is for meters and displays. No audio calculation reads it. Default gives a snapshot with all zeros.
The three peak fields measure a window. The window starts at construction, at a reset, at a change of stereo output or at a call to Processor::take_telemetry. This window is independent of the peak window of Feedback.
processed_frames: u64The number of frames processed since construction or the last reset, as Feedback::processed_frames gives.
input_peak: f32The largest absolute input sample in the window, divided by 32768.
The measurement is before Punch and Warm. The value is in 0..=1.
output_peak: [f32; 2]The largest absolute clipped sample of the left and the right output in the window, divided by 32768.
The measurement is after the output gain. Each value is in 0..=32767/32768.
reverb_wet_peak: f32The largest absolute wet contribution of the reverb in the window, where 1 is full scale.
The contribution is the wet signal times the mix, before the output gain. It is the larger of the two channels. While the reverb is disabled, the window gets no new values.
clarity: f32How periodic the tracked input is, in 0..=1.
The value is 1 for a signal that repeats exactly at the tracked period. It is 0 for a signal with no relation between cycles and during pitch acquisition. Use it as a confidence score for Feedback::voiced. The tracker updates the related sums on each frame.
tracking: boolThis field is true if the pitch tracker follows a period. It is false during pitch acquisition.
voice_count: u8The number of valid entries in voice_ratios and voice_gains.
The value is 5 in Harmony mode. In Choir mode, it is ResynthesisConfig::choir_voices, in 1..=16.
voice_ratios: [f32; 16]The pitch ratio of each voice on the last frame, where 1 is the input pitch.
Entry zero is the lead voice. In Harmony mode, entries 1 to 4 are the harmony voices. In Choir mode, the entries after the lead are the secondary voices. Each ratio includes the correction, the configured pitch shift and the ratio of the voice. The entries after voice_count are zero.
voice_gains: [f32; 16]The linear gain of each voice, in the order of voice_ratios.
The lead and the choir voices have a gain of 1. The gain of a harmony voice includes the MIDI velocity gain, in 0..=3.98095703125. MIDI velocity 127 gives the maximum, approximately +12 dB. The gain is zero for a voice that does not sound. It does not include the configured harmony level or the pan. The harmony controller updates it every 101 frames.
punch_gain: f32The current drive of Punch, divided by its base drive.
The value is the ratio of the two input envelopes times the configured input gain. It is more than 1 at an attack. Punch updates it every 100 frames. The value is 1 while Punch is disabled.
warm_gain: f32The linear gain that Warm applies before its saturation curve and removes after it.
The value is the inverse of the input peak envelope. For input below -30 dB, it is the gain of +30 dB. Warm updates it every 100 frames. The value is 1 while Warm is disabled.
alien_loop_frames: u32The length of the Alien loop in frames, as AlienConfig::loop_frames gives.
alien_phase_frames: u32The current frame in the Alien loop. It is less than alien_loop_frames.
The reverse reader is two times this number of frames behind the recording position. The value advances also while Alien is disabled.
formant_generation: u32The wrapping count of formant analyses since construction.
The count increases every 441 frames while the formant stage is enabled. Compare two values to find if Processor::formant_envelope can give a new result.
TimedEvent
A control that applies immediately before the zero-based input frame offset.
Offsets must be less than the current block length. They must not decrease in the event slice. Events with equal offsets execute in slice order. Thus, a later change at the same frame sees the earlier changes. An empty block accepts no events.
Offsets are local to this call, not a total count of processed frames. This timing tells when the state changes. Smoothing, the analysis interval and the signal latency also control when the audible result occurs.
The processor validates each event before it starts to process the block. If one event is not valid, the processor rejects the full block. This includes the valid events that are earlier in the slice.
offset: usizeThe frame offset in the block.
event: ControlEventThe control change.
WarmConfig
Asymmetric input saturation, followed by a 50 Hz high-pass filter.
Warm operates after Punch and before pitch detection. Its adaptive normalization updates every 100 enabled frames. When Warm is disabled, the envelope and filter histories do not change. When Warm is enabled again, they continue from their last state, unless the processor was reset.
enabled: boolEnables the saturation stage. The default is false.
drive_db: f32The drive in decibels, 0..=6. The default is 3 dB. The output gain changes by -0.35 dB for each dB of drive. At 0 dB, the envelope normalization and the output high-pass filter still operate.
pub fn validate(self) -> Result<(), Error>Validates all fields, also when Warm is disabled.
drive_db must be finite and in its documented inclusive range. Validation does not clamp values. It does not change the processor state.
Errors
Returns the first Error::InvalidConfig with its dotted field path and the problem.
Enums
ChordDegree
A diatonic chord with its root on a degree of the selected HarmonyScale.
Triads use the root, third and fifth scale degrees. Seventh chords also use the seventh. Degrees above the seventh go into higher octaves. The degree names do not set a major or minor quality. The selected scale supplies the tones. The default is the tonic triad, I.
I = 0A triad on the first degree.
Ii = 1A triad on the second degree.
IiSeventh = 2A seventh chord on the second degree.
Iii = 3A triad on the third degree.
IiiSeventh = 4A seventh chord on the third degree.
Iv = 5A triad on the fourth degree.
IvSeventh = 6A seventh chord on the fourth degree.
V = 7A triad on the fifth degree.
VSeventh = 8A seventh chord on the fifth degree.
Vi = 9A triad on the sixth degree.
ViSeventh = 10A seventh chord on the sixth degree.
Vii = 11A triad on the seventh degree.
ViiSeventh = 12A seventh chord on the seventh degree.
ChordName
A named chord for HarmonySource::ChordByName.
Each variant lists the semitones above the root. These values do not include the inversion, the key transposition, the register or the voicing spread. Triads use three voices.
Major = 0Major triad: 0, 4, 7. This is the default chord.
MajorSixth = 1Major sixth: 0, 4, 7, 9.
MajorSeventh = 2Major seventh: 0, 4, 7, 11.
MajorSeventhSuspendedFourth = 3Major seventh with suspended fourth: 0, 5, 7, 11.
Minor = 4Minor triad: 0, 3, 7.
MinorSixth = 5Minor sixth: 0, 3, 7, 9.
MinorSeventh = 6Minor seventh: 0, 3, 7, 10.
MinorSeventhFlatFifth = 7Minor seventh with flat fifth: 0, 3, 6, 10.
Diminished = 8Diminished triad: 0, 3, 6.
DiminishedSeventh = 9Diminished seventh: 0, 3, 6, 9.
DominantSeventh = 10Dominant seventh: 0, 4, 7, 10.
DominantSeventhFlatFifth = 11Dominant seventh with flat fifth: 0, 4, 6, 10.
Augmented = 12Augmented triad: 0, 4, 8.
AugmentedSeventh = 13Augmented seventh: 0, 4, 8, 10.
SuspendedFourth = 14Suspended fourth: 0, 5, 7.
SuspendedSecond = 15Suspended second: 0, 2, 7.
SuspendedSeventh = 16Suspended seventh: 0, 5, 7, 10.
ConfigProblem
The problem with a configuration field.
OutOfRangeThe value is outside min..=max.
NotFiniteThe value is NaN or infinite.
UnorderedThe value must be below the value of the field other.
ControlEvent
A configuration or MIDI control that applies before a frame in the block.
Give controls to a process call as TimedEvent values. The call borrows the slice only for that call. There is no heap allocation and no deferred queue. A stage event replaces all settings of that stage. To change one field, start from the current configuration of the processor. Configuration changes have the same effects on state as Processor::set_config.
Configure(ProcessorConfig)This event replaces the full configuration.
Resynthesis(ResynthesisConfig)This event replaces the resynthesis configuration.
Punch(PunchConfig)This event replaces the Punch configuration.
Warm(WarmConfig)This event replaces the Warm configuration.
Alien(AlienConfig)This event replaces the Alien configuration.
Reverb(ReverbConfig)This event replaces the reverb configuration.
OutputGain(f32)This event sets the final linear gain, 0..=64.
The quantization and the mute behavior are the same as for ProcessorConfig::output_gain. The value must be finite.
Midi(MidiEvent)This event sends a note control to the harmony source that HarmonyConfig selects.
MIDI-channel mode uses channels 0..=3. Omni mode and MIDI-chord mode combine channels.
CorrectionMidi(MidiEvent)This event changes the correction keyboard independently of harmony MIDI.
The held notes 0..=126 become pitch classes. Channels and nonzero velocities do not change the selected classes. Key 127 is stored, but the classes do not include it. Each event replaces the active correction table. If a later change sets new configured notes, or enables or disables correction, the configured mask loads again.
ResetThis event resets immediately before the event frame, with the semantics of Processor::reset.
Later events in the same block still run. The processor continues to render from this frame.
pub fn validate(self) -> Result<(), Error>Checks the configuration or MIDI ranges of the event, and does not apply the event.
Errors
Returns Error::InvalidConfig for an invalid configuration or gain. Returns Error::InvalidMidi for invalid MIDI fields. Reset is always valid. The process call that contains the event checks the offset and the order.
CorrectionScale
A scale for NoteMask::from_key_scale.
MajorThe major scale.
MinorThe natural minor scale.
ChromaticThe chromatic scale with all notes.
Error
The reason for a rejected call.
A call that returns this error validates before it acts. If it returns Err, the state and the output do not change.
UnsupportedSampleRateThe numeric rate has no SampleRate variant that matches it.
InvalidFrequencyA frequency is not finite or is outside the interval 0 < hz <= max_hz.
InvalidConfigA configuration field is not valid.
field is the dotted path of the field from the root configuration, for example "resynthesis.choir_detune", "reverb.mix" or "prepare.max_block_frames".
BufferLengthA buffer length is not equal to the input length or to the length of the other output channel.
BlockTooLargeA block has more frames than the prepared maximum of the processor.
InvalidEventThe timed event at index is not valid.
InvalidMidiThe MIDI bytes or the MIDI fields are not valid.
The causes are:
- a status byte below 0x80
- a data byte above 127
- a typed event with a channel, note or velocity out of range.
EventProblem
The reason for the rejection of a timed event during the block preflight.
The preflight examines the full block. For each event, it checks the offset bounds first, then the order, then the payload. The Error::InvalidEvent that contains this value identifies the first event in slice order that fails.
OffsetOutsideBlockThe zero-based offset is equal to or more than the block frame count.
Each event in an empty block has this problem.
OffsetDecreasingThe offset is less than the offset of the previous event.
Equal offsets are valid.
ConfigThe event has a configuration field that is not valid.
MidiThe event has a MIDI message that is not valid.
HarmonyScale
The scale that smart intervals and chords by degree use.
Major = 0Major (ionian): semitone offsets 0, 2, 4, 5, 7, 9, 11. This is the default scale.
MajorWithoutSeventh = 1Major with the sixth again in the seventh slot of the table: 0, 2, 4, 5, 7, 9, 9. The degree table still has seven entries.
MajorFlatSeventh = 2Major with a flat seventh (mixolydian): 0, 2, 4, 5, 7, 9, 10.
Minor = 3Natural minor (aeolian): 0, 2, 3, 5, 7, 8, 10.
HarmonicMinor = 4Harmonic minor: 0, 2, 3, 5, 7, 8, 11.
MinorNaturalSixth = 5Minor with a natural sixth (dorian): 0, 2, 3, 5, 7, 9, 10.
MinorMajorSeventh = 6Minor with a major seventh: 0, 2, 3, 5, 7, 9, 11. This table keeps the natural sixth of the ascending melodic minor scale.
HarmonySource
The source of target periods for the four harmony voices.
The default is MidiChannels. The static interval and chord sources use the related HarmonyConfig fields. The MIDI sources use ControlEvent::Midi. The configuration of the sources that are not selected is still validated and kept.
FixedIntervalEach voice is a fixed number of semitones from the singer. This source uses chromatic_intervals.
SmartIntervalEach voice follows an interval in scale steps from the singer. This source uses diatonic_intervals, key and scale.
ChordByDegreeThe voices sing a chord on a scale degree. This source uses degree, key, scale and inversion.
ChordByNameThe voices sing a named chord. This source uses chord, key and inversion.
ChordViaMidiThe voices sing the active MIDI notes as a chord. The register and the spread select new octaves and a new order for these notes. The key and the inversion do not apply. This source combines all channels. It uses the same rules to allocate and steal voices as MidiOmni.
MidiOmniA note from any channel goes to the first free voice. If all four voices are busy, the note steals the voice with the oldest assignment. The stolen note stays pending until it resumes or until its Note Off. If a Note Off releases a voice, that voice resumes the pending note with the newest assignment. Only a pending note with a positive assignment order can resume. A repeated Note On for an active pitch updates its gain and its assignment order. Note Off matches the pitch on all channels.
MidiChannelsVoice n follows MIDI channel n for the zero-based channels 0..=3.
Other valid MIDI channels do not control voices. Each channel has one current note. Note Off releases that note only if the pitch is the same. This is the default.
Inversion
The chord inversion raises the lowest chord tones by one octave.
The inversion applies before the register and the spread. It applies only to named chords and degree chords. Root position is the default. The first inversion moves one tone and the second inversion moves two tones. The voicing of MIDI chords uses the played notes, not this control.
Root = 0The root position.
First = 1The first inversion.
Second = 2The second inversion.
MidiEvent
The supported MIDI note controls, with zero-based channel numbers.
Use ControlEvent::Midi for harmony. Use ControlEvent::CorrectionMidi for the independent correction keyboard. The typed representation can contain u8 values that are not valid. validate and the event preflight of the processor check the MIDI ranges. Note numbers use A4 = 69 at 440 Hz.
NoteOnA note starts.
NoteOffA note stops.
AllNotesOffAll notes stop (controller 123).
For harmony, it clears the active MIDI assignments and the stolen notes that are still held, on all channels. In MIDI-chord mode, it also releases the chord voices. The gain envelopes do not change, so the released voices decay. The prepared targets of the named and degree chord sources do not change. For the correction keyboard, it clears keys 0..=126 and keeps key 127.
pub fn from_bytes(bytes: [u8; 3]) -> Result<Option<Self>, Error>Decodes one complete MIDI message of three bytes.
This function accepts Note On, Note Off and controller 123 (All Notes Off). A Note On with velocity zero becomes Note Off. The function ignores the release velocity of Note Off and the value of controller 123. All Notes Off does not keep the source channel. Thus, for harmony, it acts on all channels. Refer to AllNotesOff for the envelope and chord state that it keeps.
For other messages with valid ranges of status and data bytes, the function returns Ok(None). This function is not a parser for a MIDI stream. It does not assemble running status, messages of variable length or system-exclusive data.
Errors
Returns Error::InvalidMidi if the status is below 0x80 or a data byte is more than 127. This also applies to an unsupported message.
MultiVoiceMode
The method that resynthesis uses to render its voices.
ChoirVoices at the pitch of the lead voice, with random drift, delays and an optional stereo pan.
HarmonyVoices that follow musical intervals, chords or MIDI notes.
PitchClass
One of the twelve notes in an octave.
C = 0The note C.
CSharp = 1The note C sharp.
D = 2The note D.
DSharp = 3The note D sharp.
E = 4The note E.
F = 5The note F.
FSharp = 6The note F sharp.
G = 7The note G.
GSharp = 8The note G sharp.
A = 9The note A.
ASharp = 10The note A sharp.
B = 11The note B.
pub const ALL: [Self; 12]All pitch classes, from C upward.
Index n is n semitones above C.
pub const fn semitone(self) -> u8Returns the number of semitones above C, 0..=11.
ReverbMode
The echo or reverberation network. The default is Echo.
All modes share one delay buffer. A mode change uses the same buffer contents and damping filter memories. Thus a transition can play audio from the previous network. The stereo layout of the buffer does not make all modes give different left and right signals. Schroeder gives the same value on the two channels.
EchoA single feedback echo.
SchroederFour parallel comb filters that feed two allpass filters (mono).
SmallRoomA stereo small room.
BinauralA short binaural room.
MediumHallA medium hall.
LargeHallA large hall.
SampleRate
The sample rate of the input and the output.
The default is 44.1 kHz. The prepared delay and filter layouts support only the listed rates. To convert an integer device rate, use SampleRate::try_from. The rate of a processor is fixed at construction. To change the rate, you must make a new processor.
Hz4410044.1 kHz.
Hz4800048 kHz.
pub const fn as_u32(self) -> u32Returns the rate in hertz.
pub fn hz(self) -> f32Returns the rate in hertz, as f32.
Constants
HARMONY_VOICES
pub const HARMONY_VOICES: usize = 4;The number of harmony voices in addition to the lead voice: four. The interval arrays and the voice allocation for MIDI channels use the same count.