Sign in

    dowdiness/moondsp/dsp does not have a README file

    ArithSym

    pub(open) trait ArithSym {
    fn constant(Double) -> Self
    fn mul(Self, Self) -> Self
    fn mix(Self, Self) -> Self
    fn clip(Self, Double) -> Self
    }

    Core algebra for the Finally Tagless DSP representation. Downstream packages implement this trait to provide different interpretations (evaluation, code generation, pretty printing, etc.).

    ChannelSpec

    pub trait ChannelSpec {
    fn channel_count(Self) -> Int
    }

    DelaySym

    pub(open) trait DelaySym : DspSym {
    fn delay(Self, Int, Int, Double) -> Self
    }

    DspSym

    pub(open) trait DspSym : ArithSym {
    fn oscillator(Self, Waveform) -> Self
    fn noise(UInt) -> Self
    fn adsr(Double, Double, Double, Double) -> Self
    fn gain(Self, Double) -> Self
    fn output(Self) -> Self
    }

    FilterSym

    pub(open) trait FilterSym : DspSym {
    fn biquad(Self, BiquadMode, Double, Double) -> Self
    }

    StereoDelaySym

    pub(open) trait StereoDelaySym : StereoSym + DelaySym {
    fn stereo_delay(Self, Int, Int, Double) -> Self
    }

    StereoFilterSym

    pub(open) trait StereoFilterSym : StereoSym + FilterSym {
    fn stereo_biquad(Self, BiquadMode, Double, Double) -> Self
    }

    StereoSym

    pub(open) trait StereoSym : DspSym {
    fn pan(Self, Double) -> Self
    fn stereo_gain(Self, Double) -> Self
    fn stereo_clip(Self, Double) -> Self
    fn stereo_mixdown(Self) -> Self
    fn stereo_output(Self) -> Self
    }

    Adsr

    pub struct Adsr {
    // private fields
    }

    Stateful ADSR envelope generator.

    Adsr::Adsr

    #alias(new)
    fn Adsr::Adsr(attack_ms~ : Double, decay_ms~ : Double, sustain~ : Double, release_ms~ : Double) -> Adsr

    Create a new ADSR envelope with normalized parameters.

    Adsr::gate_off

    fn Adsr::gate_off(self : Adsr) -> Unit

    Release the current note from the envelope's present level.

    Adsr::gate_on

    fn Adsr::gate_on(self : Adsr) -> Unit

    Start a new note and enter the attack stage from silence.

    Adsr::level

    fn Adsr::level(self : Adsr) -> Double

    Return the current envelope level.

    Adsr::process

    fn Adsr::process(self : Adsr, context : DspContext, output : AudioBuffer) -> Unit

    Fill a buffer with successive envelope values.

    Adsr::reset

    fn Adsr::reset(self : Adsr) -> Unit

    Reset the envelope to idle silence.

    Adsr::set_parameters

    fn Adsr::set_parameters(self : Adsr, attack_ms~ : Double, decay_ms~ : Double, sustain~ : Double, release_ms~ : Double) -> Unit

    Update envelope parameters without restarting its stage or level.

    Adsr::stage

    fn Adsr::stage(self : Adsr) -> EnvStage

    Return the current envelope stage.

    Adsr::tick

    fn Adsr::tick(self : Adsr, context : DspContext) -> Double

    Advance the envelope by one sample using the given DSP context.

    AudioBuffer

    pub struct AudioBuffer {
    // private fields
    }

    Thin wrapper around FixedArray[Double] for DSP block processing.

    AudioBuffer::AudioBuffer

    #alias(new)
    fn AudioBuffer::AudioBuffer(data : FixedArray[Double]) -> AudioBuffer

    Wrap a FixedArray[Double] by copying its contents.

    The buffer's underlying storage is distinct from the source array; neither side observes mutations made through the other. Mutating the source has no effect on the buffer, and writes through the buffer (via set / fill) do not propagate back to the source. Non-finite source samples (NaN, +Inf, -Inf) are normalized to 0.0 in the copied storage; finite samples pass through unchanged. Use this when ingesting external data of unclear lifetime. For explicit zero-copy adoption, see AudioBuffer::adopt.

    AudioBuffer::adopt

    fn AudioBuffer::adopt(data : FixedArray[Double]) -> AudioBuffer

    Wrap a FixedArray[Double] without copying.

    The buffer and the source array share storage in both directions: writes through the buffer (set / fill) mutate the source, and mutations through the source handle appear through the buffer. Two specific bypasses follow from this: (a) the buffer's initial contents are whatever the source array holds at adoption time, not run through the normal non-finite-to-0.0 normalization path; and (b) any later mutation through the retained source handle skips AudioBuffer validation entirely. Writes through buf.set(...) or buf.fill(...) on an adopted buffer still go through those methods and normalize non-finite values to 0.0. Use this only for FFI-bridged buffers (e.g., TypedArray or SharedArrayBuffer wrappers) where the copy cost is genuinely prohibitive and the caller can reason about the source lifetime. Otherwise use AudioBuffer::new.

    AudioBuffer::all

    #alias(every)
    fn AudioBuffer::all(self : AudioBuffer, predicate : (Double) -> Bool raise?) -> Bool raise?

    Test whether predicate holds for every sample in the buffer.

    AudioBuffer::any

    #alias(exists)
    fn AudioBuffer::any(self : AudioBuffer, predicate : (Double) -> Bool raise?) -> Bool raise?

    Test whether predicate holds for at least one sample in the buffer.

    AudioBuffer::fill

    fn AudioBuffer::fill(self : AudioBuffer, value : Double) -> Unit

    Fill the buffer with a single sample value.

    Non-finite values (NaN, +Inf, -Inf) are normalized to 0.0.

    AudioBuffer::filled

    fn AudioBuffer::filled(size : Int, init? : Double) -> AudioBuffer

    Construct an audio buffer pre-filled with init (default 0.0).

    The buffer's storage is freshly allocated and not shared with any caller-visible array. Routed through adopt to avoid the unnecessary copy AudioBuffer::new would now perform on the freshly-allocated FixedArray. The initializer is normalized once before allocation: non-finite values become 0.0, while finite values pass through unchanged.

    AudioBuffer::get

    fn AudioBuffer::get(self : AudioBuffer, index : Int) -> Double

    Read one sample from the buffer.

    AudioBuffer::length

    fn AudioBuffer::length(self : AudioBuffer) -> Int

    Get the number of samples stored in the buffer.

    AudioBuffer::set

    fn AudioBuffer::set(self : AudioBuffer, index : Int, value : Double) -> Unit

    Write one sample into the buffer.

    Non-finite values (NaN, +Inf, -Inf) are normalized to 0.0.

    Biquad

    pub struct Biquad {
    // private fields
    }

    Stateful biquad filter using Direct Form II Transposed processing.

    Biquad::Biquad

    #alias(new)
    fn Biquad::Biquad() -> Biquad

    Create a new biquad filter with zeroed state and no active coefficients.

    Biquad::process

    fn Biquad::process(self : Biquad, context : DspContext, buffer : AudioBuffer) -> Unit

    Filter one block of samples in place.

    Biquad::reset

    fn Biquad::reset(self : Biquad) -> Unit

    Clear the filter delay state without changing the current coefficients.

    Biquad::tick

    fn Biquad::tick(self : Biquad, input : Double) -> Double

    Filter one input sample and advance the internal delay state.

    Biquad::update

    fn Biquad::update(self : Biquad, context : DspContext, mode : BiquadMode, cutoff : Double, q : Double) -> Bool

    Recalculate filter coefficients for the given mode, cutoff, and resonance.

    Returns false and disables processing when the parameters are invalid.

    BiquadMode

    pub(all) enum BiquadMode {
    LowPass
    HighPass
    BandPass
    } derive(Eq)

    Supported biquad response shapes for the Phase 1 filter primitive.

    Clip

    pub struct Clip {
    }

    Stateless hard-clipping processor for explicit range limiting.

    Clip::Clip

    #alias(new)
    fn Clip::Clip() -> Clip

    Create a clip processor.

    Clip::process

    fn Clip::process(self : Clip, context~ : DspContext, buffer~ : AudioBuffer, threshold~ : Double) -> Unit

    Apply hard clipping in place using a symmetric threshold.

    DelayLine

    pub struct DelayLine {
    // private fields
    }

    Stateful integer-sample delay line backed by a circular buffer.

    DelayLine::DelayLine

    #alias(new)
    fn DelayLine::DelayLine(max_delay_samples : Int, delay_samples? : Int, feedback? : Double) -> DelayLine

    Create a delay line with preallocated storage and a normalized delay length.

    DelayLine::delay_samples

    fn DelayLine::delay_samples(self : DelayLine) -> Int

    Return the active delay length in samples.

    DelayLine::feedback

    fn DelayLine::feedback(self : DelayLine) -> Double

    Return the active feedback amount.

    DelayLine::max_delay_samples

    fn DelayLine::max_delay_samples(self : DelayLine) -> Int

    Return the maximum representable delay length in samples.

    DelayLine::process

    fn DelayLine::process(self : DelayLine, context : DspContext, buffer : AudioBuffer) -> Unit

    Process one block of samples in place.

    DelayLine::reset

    fn DelayLine::reset(self : DelayLine) -> Unit

    Clear the circular buffer state without changing the configured delay.

    DelayLine::set_delay_samples

    fn DelayLine::set_delay_samples(self : DelayLine, delay_samples : Int) -> Unit

    Update the active delay length, clamping to the allocated storage range.

    DelayLine::set_feedback

    fn DelayLine::set_feedback(self : DelayLine, feedback : Double) -> Unit

    Update the feedback amount, clamping to the stable supported range.

    DelayLine::tick

    fn DelayLine::tick(self : DelayLine, input : Double) -> Double

    Process one input sample and return the delayed output sample.

    DemoSource

    pub struct DemoSource {
    // private fields
    }

    Encapsulates the mutable oscillator + noise state used by the browser demo tick functions. Each WASM entry point (root, browser/, browser_test/) creates its own instance so module-level mutable globals stay per-package.

    DemoSource::DemoSource

    #alias(new)
    fn DemoSource::DemoSource() -> DemoSource

    DemoSource::reset

    fn DemoSource::reset(self : DemoSource) -> Unit

    Reset oscillator and noise state to the start of the waveform.

    DemoSource::tick_source

    fn DemoSource::tick_source(self : DemoSource, source_id~ : Int, freq_hz~ : Double, sample_rate~ : Double) -> Double

    Generate one sample from the selected source.

    Source ids:
    • 0: sine (default)
    • 1: saw
    • 2: square
    • 3: triangle
    • 4: noise

    DspContext

    pub struct DspContext {
    // private fields
    }

    Shared execution context for block-based DSP processing.

    DspContext::DspContext

    #alias(new)
    fn DspContext::DspContext(sample_rate~ : Double, block_size~ : Int) -> DspContext

    Create a DSP context with normalized runtime parameters.

    DspContext::block_size

    fn DspContext::block_size(self : DspContext) -> Int

    Return the configured block size for this processing context.

    DspContext::make_buffer

    fn DspContext::make_buffer(self : DspContext, init? : Double) -> AudioBuffer

    Create an owned audio buffer sized to this context's block size.

    DspContext::sample_rate

    fn DspContext::sample_rate(self : DspContext) -> Double

    Return the configured sample rate for this processing context.

    EnvStage

    pub enum EnvStage {
    Idle
    Attack
    Decay
    Sustain
    Release
    } derive(Eq)

    Public ADSR stage names for diagnostics and tests.

    Gain

    pub struct Gain {
    }

    Stateless in-place gain processor for Phase 1 block processing.

    Gain::Gain

    #alias(new)
    fn Gain::Gain() -> Gain

    Create a gain processor.

    Gain::process

    fn Gain::process(self : Gain, context~ : DspContext, buffer~ : AudioBuffer, amount~ : Double) -> Unit

    Apply a scalar gain to a block of audio samples in place.

    Mix

    pub struct Mix {
    }

    Stateless in-place mixer for combining audio buffers.

    Mix::Mix

    #alias(new)
    fn Mix::Mix() -> Mix

    Create a mix processor.

    Mix::process

    fn Mix::process(self : Mix, context : DspContext, output : AudioBuffer, input : AudioBuffer) -> Unit

    Add one input buffer into the output buffer without implicit clipping.

    Mono

    pub struct Mono {
    }

    impl ChannelSpec for Mono

    Mono::Mono

    #alias(new)
    fn Mono::Mono() -> Mono

    Noise

    pub struct Noise {
    // private fields
    }

    Deterministic white-noise source with explicit RNG state.

    Noise::Noise

    #alias(new)
    fn Noise::Noise(seed : UInt) -> Noise

    Create a new white-noise generator from an explicit seed.

    Noise::process

    fn Noise::process(self : Noise, context : DspContext, output : AudioBuffer) -> Unit

    Fill an output buffer with white-noise samples.

    Noise::reset

    fn Noise::reset(self : Noise, seed : UInt) -> Unit

    Reset the generator to a new explicit seed.

    Noise::seed

    fn Noise::seed(self : Noise) -> UInt

    Expose the current RNG state for testing and diagnostics.

    Noise::tick

    fn Noise::tick(self : Noise) -> Double

    Generate one white-noise sample in the range [-1.0, 1.0].

    Oscillator

    pub struct Oscillator {
    // private fields
    }

    Stateful oscillator for the first reusable Phase 1 DSP primitive.

    Oscillator::Oscillator

    #alias(new)
    fn Oscillator::Oscillator() -> Oscillator

    Create a new oscillator at phase zero.

    Oscillator::phase

    fn Oscillator::phase(self : Oscillator) -> Double

    Expose the current phase for testing and diagnostics.

    Oscillator::process

    fn Oscillator::process(self : Oscillator, context~ : DspContext, output~ : AudioBuffer, freq_hz~ : Double) -> Unit

    Fill an output buffer with oscillator samples.

    Oscillator::process_waveform

    fn Oscillator::process_waveform(self : Oscillator, context~ : DspContext, output~ : AudioBuffer, waveform~ : Waveform, freq_hz~ : Double) -> Unit

    Fill an output buffer with samples for the selected waveform.

    Oscillator::reset

    fn Oscillator::reset(self : Oscillator) -> Unit

    Reset the oscillator to the start of the waveform.

    Oscillator::tick

    fn Oscillator::tick(self : Oscillator, freq_hz~ : Double, sample_rate~ : Double) -> Double

    Generate one sine sample and advance the oscillator state.

    Oscillator::tick_waveform

    fn Oscillator::tick_waveform(self : Oscillator, waveform~ : Waveform, freq_hz~ : Double, sample_rate~ : Double) -> Double

    Generate one sample for the selected waveform and advance the oscillator state.

    Pan

    pub struct Pan {
    }

    Stateless equal-power pan processor for mono-to-stereo routing.

    Pan::Pan

    #alias(new)
    fn Pan::Pan() -> Pan

    Create a pan processor.

    Pan::process

    fn Pan::process(self : Pan, context~ : DspContext, input~ : AudioBuffer, left_output~ : AudioBuffer, right_output~ : AudioBuffer, position~ : Double) -> Unit

    Pan a mono input buffer into explicit left and right output buffers.

    Finite positions are clamped to [-1.0, 1.0], where -1.0 is hard left, 0.0 is center, and 1.0 is hard right. Invalid positions or contexts write silence to both outputs.

    ParamSmoother

    pub struct ParamSmoother {
    // private fields
    }

    Stateful one-pole smoother for click-free control changes.

    ParamSmoother::ParamSmoother

    #alias(new)
    fn ParamSmoother::ParamSmoother(initial : Double, smoothing_ms : Double, sample_rate : Double) -> ParamSmoother

    Create a parameter smoother from an initial value, smoothing time, and explicit sample rate.

    ParamSmoother::current

    fn ParamSmoother::current(self : ParamSmoother) -> Double

    Return the current smoothed value.

    ParamSmoother::from_context

    fn ParamSmoother::from_context(initial : Double, smoothing_ms : Double, context : DspContext) -> ParamSmoother

    Create a parameter smoother using the sample rate stored in a DSP context.

    ParamSmoother::reset

    fn ParamSmoother::reset(self : ParamSmoother, value : Double) -> Unit

    Immediately snap both the current and target value to a new point.

    ParamSmoother::set_smoothing_time

    fn ParamSmoother::set_smoothing_time(self : ParamSmoother, smoothing_ms : Double, sample_rate : Double) -> Unit

    Update the smoothing time using an explicit sample rate.

    ParamSmoother::set_smoothing_time_from_context

    fn ParamSmoother::set_smoothing_time_from_context(self : ParamSmoother, smoothing_ms : Double, context : DspContext) -> Unit

    Update the smoothing time using the sample rate stored in a DSP context.

    ParamSmoother::set_target

    fn ParamSmoother::set_target(self : ParamSmoother, value : Double) -> Unit

    Set a new target value. Invalid inputs are ignored to keep the state deterministic inside the audio path.

    ParamSmoother::target

    fn ParamSmoother::target(self : ParamSmoother) -> Double

    Return the current target value.

    ParamSmoother::tick

    fn ParamSmoother::tick(self : ParamSmoother) -> Double

    Advance the smoother by one sample.

    Stereo

    pub struct Stereo {
    }

    Stereo::Stereo

    #alias(new)
    fn Stereo::Stereo() -> Stereo

    StereoReverb

    pub struct StereoReverb {
    // private fields
    }

    Wet-only stereo room reverb with fixed delay lengths and preallocated state.

    The network is eight parallel damped feedback combs followed by four serial allpasses per channel. Delay lengths use the published Freeverb tunings, scaled once for the requested sample rate. decay_seconds is the low- frequency T60; damping is a normalized high-frequency loss coefficient.

    StereoReverb::StereoReverb

    fn StereoReverb::StereoReverb(sample_rate : Double, decay_seconds? : Double, damping? : Double) -> StereoReverb

    StereoReverb::process

    fn StereoReverb::process(self : StereoReverb, context : DspContext, left_input : AudioBuffer, right_input : AudioBuffer, left_output : AudioBuffer, right_output : AudioBuffer) -> Unit

    Render wet stereo only. Inputs and outputs may be reused across calls; no allocation occurs in this audio-rate path.

    StereoReverb::reset

    fn StereoReverb::reset(self : StereoReverb) -> Unit

    Clear the complete late-field state. Ordinary zero-input processing should be used to preserve and drain a tail; reset is for an explicit hard stop.

    Waveform

    pub(all) enum Waveform {
    Sine
    Saw
    Square
    Triangle
    } derive(Eq)

    Supported oscillator waveforms for the Phase 1 source primitive.

    effective_sample_count

    fn effective_sample_count(context : DspContext, buffer : AudioBuffer) -> Int

    Compute the effective number of samples to process, bounded by both the context block size and the buffer length.

    exit_deliverable

    fn[T : FilterSym + DspSym + ArithSym] exit_deliverable() -> T

    The Phase 2 exit deliverable: sine(2).range(200,400).sine().lpf(800,1).out() An LFO at 2 Hz modulates the frequency of a carrier oscillator between 200-400 Hz, then filtered through a low-pass biquad at 800 Hz.

    is_finite

    fn is_finite(value : Double) -> Bool

    Check whether a floating-point value is finite (not NaN, not Inf).

    is_finite_positive

    fn is_finite_positive(value : Double) -> Bool

    Check whether a floating-point value is finite and strictly positive.

    lin_map

    fn[T : ArithSym] lin_map(input : T, in_lo : Double, in_hi : Double, out_lo : Double, out_hi : Double) -> T

    Maps [in_lo, in_hi] -> [out_lo, out_hi]. Only requires ArithSym. Precondition: in_lo != in_hi (division by zero otherwise).

    max_feedback_amount

    fn max_feedback_amount() -> Double

    mono_shape

    fn mono_shape() -> Int

    Bridge to existing MONO_SIGNAL_SHAPE constant (value 0).

    pan_left_gain

    fn pan_left_gain(position : Double) -> Double

    Equal-power left-channel gain for a pan position in [-1.0, 1.0]. -1.0 = hard left (gain 1.0), 0.0 = center (~0.707), 1.0 = hard right (gain 0.0). Non-finite positions return 0.0.

    pan_right_gain

    fn pan_right_gain(position : Double) -> Double

    Equal-power right-channel gain for a pan position in [-1.0, 1.0]. -1.0 = hard left (gain 0.0), 0.0 = center (~0.707), 1.0 = hard right (gain 1.0). Non-finite positions return 0.0.

    range

    fn[T : ArithSym] range(input : T, lo : Double, hi : Double) -> T

    Maps [-1, 1] -> [lo, hi]. Only requires ArithSym.

    sanitize_buffer

    fn sanitize_buffer(buffer : AudioBuffer, sample_count : Int) -> Int

    Replace non-finite samples (NaN, Inf) with 0.0 in-place. Returns the number of samples replaced. This is the output firewall — the last line of defense before samples leave the DSP engine.

    stereo_shape

    fn stereo_shape() -> Int

    Bridge to existing STEREO_SIGNAL_SHAPE constant (value 1).