# RSCuteDSP

A Rust port of the Signalsmith DSP C++ library, providing various DSP (Digital Signal Processing) algorithms for audio and signal processing. This library implements the same high-quality algorithms as the original C++ library, optimized for Rust performance and ergonomics.

[![Crates.io](https://img.shields.io/crates/v/cute-dsp)](https://crates.io/crates/cute-dsp)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- **FFT**: Fast Fourier Transform implementation optimized for sizes that are products of 2^a * 3^b, with both complex and real-valued implementations
- **Filters**: Biquad filters with various configurations (lowpass, highpass, bandpass, etc.) and design methods (Butterworth, cookbook)
- **Delay Lines**: Efficient delay line implementation with multiple interpolation methods (nearest, linear, cubic)
- **Curves**: Cubic curve interpolation with control over slope and curvature
- **Windows**: Window functions for spectral processing (Hann, Hamming, Kaiser, Blackman-Harris, etc.)
- **Envelopes**: LFOs and envelope generators with precise control and minimal aliasing
- **Spectral Processing**: Tools for spectral manipulation, phase vocoding, and frequency-domain operations
- **Time Stretching**: High-quality time stretching and pitch shifting using phase vocoder techniques
- **STFT**: Short-time Fourier transform implementation with overlap-add processing
- **Mixing Utilities**: Multi-channel mixing matrices and stereo-to-multi-channel conversion
- **Linear Algebra**: Expression template system for efficient vector operations
- **no_std Support**: Can be used in environments without the standard library, with optional `alloc` feature
- **Spacing (Room Reverb)**: Simulate room acoustics with customizable geometry, early reflections, and multi-channel output

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
cute-dsp = "0.0.2"
```

## WebAssembly Support

This library supports compilation to WebAssembly for use in web browsers and Node.js, with full DSP functionality exposed.

To build for WASM (no-modules target for broad compatibility):

1. Install `wasm-pack`:
   ```bash
   cargo install wasm-pack
   ```

2. Build the WASM package:
   ```bash
   wasm-pack build --target no-modules --out-dir pkg --features wasm
   ```

3. Use in HTML/JavaScript (no-modules target):
   ```html
   <!DOCTYPE html>
   <html>
   <head>
       <meta charset="utf-8">
       <title>CuteDSP WASM Demo</title>
   </head>
   <body>
       <script src="pkg/cute_dsp.js"></script>
       <script>
       async function run() {
           // Initialize WASM
           await wasm_bindgen();

           // Create FFT instance
           const fft = new wasm_bindgen.WasmFFT(1024);

           // Create input arrays
           const realIn = new Float32Array(1024);
           const imagIn = new Float32Array(1024);
           const realOut = new Float32Array(1024);
           const imagOut = new Float32Array(1024);

           // Fill input with a sine wave
           for (let i = 0; i < 1024; i++) {
               realIn[i] = Math.sin(2 * Math.PI * i / 1024);
               imagIn[i] = 0;
           }

           // Perform FFT
           fft.fft_forward(realIn, imagIn, realOut, imagOut);

           // Create and use a biquad filter
           const filter = new wasm_bindgen.WasmBiquad();
           filter.lowpass(0.1, 0.7); // Normalized frequency, Q factor

           const audioIn = new Float32Array(1024);
           const audioOut = new Float32Array(1024);
           // Fill audioIn with audio data...

           filter.process(audioIn, audioOut);

           // Create a delay line
           const delay = new wasm_bindgen.WasmDelay(44100); // Max delay samples
           const delayedSample = delay.process(0.5, 22050.0); // Input sample, delay in samples

           // Create an LFO
           const lfo = new wasm_bindgen.WasmLFO();
           lfo.set_params(0.0, 1.0, 5.0, 0.0, 0.0); // low, high, rate, rate_variation, depth_variation
           const lfoSample = lfo.process();

           // Create window functions
           const kaiser = new wasm_bindgen.WasmKaiser(0.1); // Beta parameter
           const windowData = new Float32Array(512);
           kaiser.fill(windowData);

           // Hann and Hamming windows
           wasm_bindgen.WasmHann.fill(windowData);
           wasm_bindgen.WasmHamming.fill(windowData);

           // Create a delay line
           const delay = new wasm_bindgen.WasmDelay(44100); // Max delay samples
           const delayedSample = delay.process(0.5, 22050.0); // Input sample, delay in samples

           // Create an LFO
           const lfo = new wasm_bindgen.WasmLFO();
           lfo.set_params(0.0, 1.0, 5.0, 0.0, 0.0); // low, high, rate, rate_variation, depth_variation
           const lfoSample = lfo.process();

           // Create window functions
           const kaiser = new wasm_bindgen.WasmKaiser(0.1); // Beta parameter
           const windowData = new Float32Array(512);
           kaiser.fill(windowData);

           // Hann and Hamming windows
           wasm_bindgen.WasmHann.fill(windowData);
           wasm_bindgen.WasmHamming.fill(windowData);

           // Create STFT
           const stft = new wasm_bindgen.WasmSTFT(false); // false for non-modified
           stft.configure(1, 1, 512); // input channels, output channels, block size

           // Linear curve mapping
           const curve = wasm_bindgen.WasmLinearCurve.from_points(0.0, 1.0, 0.0, 100.0);
           const mappedValue = curve.evaluate(0.5);

           // Sample rate conversion filters
           const srcFilter = new Float32Array(256);
           wasm_bindgen.WasmSampleRateConverter.fill_kaiser_sinc_filter(srcFilter, 0.45, 0.55);

           // Spectral utilities
           const complex = wasm_bindgen.WasmSpectralUtils.mag_phase_to_complex(1.0, 0.5);
           const magPhase = wasm_bindgen.WasmSpectralUtils.complex_to_mag_phase(1.0, 0.0);
           const dbValue = wasm_bindgen.WasmSpectralUtils.linear_to_db(10.0);

           // Multi-channel mixing
           const hadamard = new wasm_bindgen.WasmHadamardMixer(4); // 4-channel mixer
           const channels = new Float32Array([1.0, 0.5, 0.3, 0.1]);
           hadamard.mix_in_place(channels);

           console.log('DSP operations completed!');
       }

       run();
       </script>
   </body>
   </html>
   ```

   Or try the included real-time demo: `wasm_demo.html`

## Usage Examples

### FFT Example

```rust
use cute_dsp::fft::{SimpleFFT, SimpleRealFFT};
use num_complex::Complex;

fn fft_example() {
    // Create a new FFT instance for size 1024
    let fft = SimpleFFT::<f32>::new(1024);

    // Input and output buffers
    let mut time_domain = vec![Complex::new(0.0, 0.0); 1024];
    let mut freq_domain = vec![Complex::new(0.0, 0.0); 1024];

    // Fill input with a sine wave
    for i in 0..1024 {
        time_domain[i] = Complex::new((i as f32 * 0.1).sin(), 0.0);
    }

    // Perform forward FFT
    fft.fft(&time_domain, &mut freq_domain);

    // Process in frequency domain if needed

    // Perform inverse FFT
    fft.ifft(&freq_domain, &mut time_domain);
}
```

### Biquad Filter Example

```rust
use cute_dsp::filters::{Biquad, BiquadDesign, FilterType};

fn filter_example() {
    // Create a new biquad filter
    let mut filter = Biquad::<f32>::new(true);

    // Configure as a lowpass filter at 1000 Hz with Q=0.7 (assuming 44.1 kHz sample rate)
    filter.lowpass(1000.0 / 44100.0, 0.7, BiquadDesign::Cookbook);

    // Process a buffer of audio
    let mut audio_buffer = vec![0.0; 1024];
    // Fill buffer with audio data...

    // Apply the filter
    filter.process_buffer(&mut audio_buffer);
}
```

### Delay Line Example

```rust
use cute_dsp::delay::{Delay, InterpolatorCubic};

fn delay_example() {
    // Create a delay line with cubic interpolation and 1 second capacity at 44.1 kHz
    let mut delay = Delay::new(InterpolatorCubic::<f32>::new(), 44100);

    // Process audio
    let mut output = 0.0;
    for _ in 0..1000 {
        let input = 0.5; // Replace with your input sample

        // Read from the delay line (500 ms delay)
        output = delay.read(22050.0);

        // Write to the delay line
        delay.write(input);

        // Use output...
    }
}
```

### Time Stretching and Pitch Shifting Example

```rust
use cute_dsp::stretch::SignalsmithStretch;

fn time_stretch_example() {
    // Create a new stretch processor
    let mut stretcher = SignalsmithStretch::<f32>::new();

    // Configure for 2x time stretching with pitch shift up 3 semitones
    stretcher.configure(1, 1024, 256, false); // 1 channel, 1024 block size, 256 interval
    stretcher.set_transpose_semitones(3.0, 0.5); // Pitch up 3 semitones
    stretcher.set_formant_semitones(1.0, false); // Formant shift

    // Input and output buffers
    let input_len = 1024;
    let output_len = 2048; // 2x longer output
    let input = vec![vec![0.0; input_len]]; // Fill with audio data
    let mut output = vec![vec![0.0; output_len]];

    // Process the audio
    stretcher.process(&input, input_len, &mut output, output_len);
}
```

### Multichannel Mixing Example

```rust
use cute_dsp::mix::{Hadamard, StereoMultiMixer};

fn mixing_example() {
    // Create a Hadamard matrix for 4-channel mixing
    let hadamard = Hadamard::<f32>::new(4);

    // Mix 4 channels in-place
    let mut data = vec![1.0, 2.0, 3.0, 4.0];
    hadamard.in_place(&mut data);
    // data now contains orthogonal mix of input channels

    // Create a stereo-to-multichannel mixer (must be even number of channels)
    let mixer = StereoMultiMixer::<f32>::new(6);

    // Convert stereo to 6 channels
    let stereo_input = [0.5, 0.8];
    let mut multi_output = vec![0.0; 6];
    mixer.stereo_to_multi(&stereo_input, &mut multi_output);

    // Convert back to stereo
    let mut stereo_output = [0.0, 0.0];
    mixer.multi_to_stereo(&multi_output, &mut stereo_output);

    // Apply energy-preserving crossfade
    let mut to_coeff = 0.0;
    let mut from_coeff = 0.0;
    cute_dsp::mix::cheap_energy_crossfade(0.3, &mut to_coeff, &mut from_coeff);
    // Use coefficients for crossfading between signals
}
```

### Spacing (Room Reverb) Example

```rust
use cute_dsp::spacing::{Spacing, Position};

fn spacing_example() {
    // Create a new Spacing effect with a given sample rate
    let mut spacing = Spacing::<f32>::new(48000.0);
    // Add source and receiver positions (in meters)
    let src = spacing.add_source(Position { x: 0.0, y: 0.0, z: 0.0 });
    let recv = spacing.add_receiver(Position { x: 3.43, y: 0.0, z: 0.0 });
    // Add a direct path
    spacing.add_path(src, recv, 1.0, 0.0);
    // Prepare input and output buffers
    let mut input = vec![0.0; 500];
    input[0] = 1.0; // Impulse
    let mut outputs = vec![vec![0.0; 500]];
    // Process the input through the effect
    spacing.process(&[&input], &mut outputs);
    // outputs[0] now contains the processed signal
}
```

## Advanced Usage

For more advanced usage examples, see the examples directory:

- [FFT Example](examples/fft_example.rs) - Fast Fourier Transform
- [Filter Example](examples/filter_example.rs) - Biquad filters
- [Delay Example](examples/delay_example.rs) - Delay lines
- [STFT Example](examples/stft_example.rs) - Short-time Fourier transform
- [Stretch Example](examples/stretch_example.rs) - Time stretching and pitch shifting
- [Curves Example](examples/curves_example.rs) - Curve interpolation
- [Envelopes Example](examples/envelopes_example.rs) - LFOs and envelope generators
- [Linear Example](examples/linear_example.rs) - Linear operations
- [Mix Example](examples/mix_example.rs) - Audio mixing utilities
- [Performance Example](examples/perf_example.rs) - Performance optimizations
- [Rates Example](examples/rates_example.rs) - Sample rate conversion
- [Spectral Example](examples/spectral_example.rs) - Spectral processing
- [Windows Example](examples/windows_example.rs) - Window functions

## Module Overview

### FFT (`fft` module)
Provides Fast Fourier Transform implementations optimized for different use cases:
- `SimpleFFT`: General purpose complex-to-complex FFT
- `SimpleRealFFT`: Optimized for real-valued inputs
- Support for non-power-of-2 sizes (factorizable into 2^a × 3^b)

### Filters (`filters` module)
Digital filter implementations:
- `Biquad`: Second-order filter section with various design methods
- Various filter types: lowpass, highpass, bandpass, notch, peaking, etc.
- Support for filter cascading and multi-channel processing

### Delay (`delay` module)
Delay line utilities:
- Various interpolation methods (nearest, linear, cubic)
- Single and multi-channel delay lines
- Buffer abstractions for efficient memory usage

### Spectral Processing (`spectral` module)
Frequency-domain processing tools:
- Magnitude/phase conversion utilities
- Phase vocoder techniques for pitch and time manipulation
- Frequency-domain filtering and manipulation

### STFT (`stft` module)
Short-time Fourier transform processing:
- Overlap-add processing framework
- Window function application
- Spectral processing utilities

### Stretch (`stretch` module)
Time stretching and pitch shifting:
- High-quality phase vocoder implementation using `SignalsmithStretch`
- Independent control of time and pitch
- Formant preservation and frequency mapping
- Real-time processing capabilities

### Mix (`mix` module)
Multichannel mixing utilities:
- Orthogonal matrices (Hadamard, Householder) for efficient mixing
- Stereo to multichannel conversion
- Energy-preserving crossfading

### Windows (`windows` module)
Window functions for spectral processing:
- Common window types (Hann, Hamming, Kaiser, etc.)
- Window design utilities
- Overlap handling and perfect reconstruction

### Envelopes (`envelopes` module)
Low-frequency oscillators and envelope generators:
- Precise control with minimal aliasing
- Multiple waveform types
- Configurable frequency and amplitude

### Linear (`linear` module)
Linear algebra utilities:
- Expression template system for efficient vector operations
- Optimized mathematical operations

### Curves (`curves` module)
Curve interpolation:
- Cubic curve interpolation with control over slope and curvature
- Smooth parameter transitions

### Rates (`rates` module)
Sample rate conversion:
- High-quality resampling algorithms
- Configurable quality settings

### Spacing (`spacing` module)
Provides a customizable room reverb effect:
- Multi-tap delay network simulating early reflections
- 3D source and receiver positioning
- Adjustable room size, damping, diffusion, bass, decay, and cross-mix
- Suitable for spatial audio and immersive effects

## Feature Flags

- `std` (default): Use the Rust standard library
- `alloc`: Enable allocation without std (for no_std environments)

## Performance

This library is designed with performance in mind and offers several optimizations:

- **SIMD Opportunities**: Code structure allows for SIMD optimizations where applicable
- **Cache-Friendly Algorithms**: Algorithms are designed to minimize cache misses
- **Minimal Allocations**: Operations avoid allocations during processing
- **Trade-offs**: Where appropriate, there are options to trade between quality and performance

For maximum performance:
- Use the largest practical buffer sizes for batch processing
- Reuse processor instances rather than creating new ones
- Consider using the `f32` type for most audio applications unless higher precision is needed
- Review the examples in `examples/perf_example.rs` for performance-critical applications

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Acknowledgments

- Original C++ library: [Signalsmith Audio DSP Library](https://github.com/signalsmith-audio/dsp)
- Signalsmith Audio's excellent [technical blog](https://signalsmith-audio.co.uk/writing/) with in-depth explanations of DSP concepts
- The comprehensive [design documentation](https://signalsmith-audio.co.uk/code/stretch/) for the time stretching algorithm
