Initial commit
This commit is contained in:
212
src/plaits.rs
Normal file
212
src/plaits.rs
Normal file
@@ -0,0 +1,212 @@
|
||||
//! Unified wrapper for Mutable Instruments Plaits synthesis engines.
|
||||
//!
|
||||
//! This module provides a single enum that wraps all 13 synthesis engines from
|
||||
//! the `mi_plaits_dsp` crate (a Rust port of the Mutable Instruments Plaits
|
||||
//! Eurorack module). Each engine produces sound through a different synthesis
|
||||
//! technique.
|
||||
//!
|
||||
//! # Engine Categories
|
||||
//!
|
||||
//! ## Pitched Engines
|
||||
//! - [`Modal`](PlaitsEngine::Modal) - Physical modeling of resonant structures
|
||||
//! - [`Va`](PlaitsEngine::Va) - Virtual analog (classic subtractive synthesis)
|
||||
//! - [`Ws`](PlaitsEngine::Ws) - Waveshaping synthesis
|
||||
//! - [`Fm`](PlaitsEngine::Fm) - 2-operator FM synthesis
|
||||
//! - [`Grain`](PlaitsEngine::Grain) - Granular synthesis
|
||||
//! - [`Additive`](PlaitsEngine::Additive) - Additive synthesis with harmonic control
|
||||
//! - [`Wavetable`](PlaitsEngine::Wavetable) - Wavetable oscillator
|
||||
//! - [`Chord`](PlaitsEngine::Chord) - Polyphonic chord generator
|
||||
//! - [`Swarm`](PlaitsEngine::Swarm) - Swarm of detuned oscillators
|
||||
//! - [`Noise`](PlaitsEngine::Noise) - Filtered noise with resonance
|
||||
//!
|
||||
//! ## Percussion Engines
|
||||
//! - [`Bass`](PlaitsEngine::Bass) - Analog kick drum model
|
||||
//! - [`Snare`](PlaitsEngine::Snare) - Analog snare drum model
|
||||
//! - [`Hat`](PlaitsEngine::Hat) - Hi-hat synthesis
|
||||
//!
|
||||
//! # Control Parameters
|
||||
//!
|
||||
//! All engines share a common control interface via [`EngineParameters`]:
|
||||
//! - `note` - MIDI note number (pitch)
|
||||
//! - `harmonics` - Timbre brightness/harmonics control
|
||||
//! - `timbre` - Primary timbre parameter
|
||||
//! - `morph` - Secondary timbre/morph parameter
|
||||
//! - `accent` - Velocity/accent amount
|
||||
//! - `trigger` - Gate/trigger state
|
||||
|
||||
use crate::types::{Source, BLOCK_SIZE};
|
||||
use mi_plaits_dsp::engine::additive_engine::AdditiveEngine;
|
||||
use mi_plaits_dsp::engine::bass_drum_engine::BassDrumEngine;
|
||||
use mi_plaits_dsp::engine::chord_engine::ChordEngine;
|
||||
use mi_plaits_dsp::engine::fm_engine::FmEngine;
|
||||
use mi_plaits_dsp::engine::grain_engine::GrainEngine;
|
||||
use mi_plaits_dsp::engine::hihat_engine::HihatEngine;
|
||||
use mi_plaits_dsp::engine::modal_engine::ModalEngine;
|
||||
use mi_plaits_dsp::engine::noise_engine::NoiseEngine;
|
||||
use mi_plaits_dsp::engine::snare_drum_engine::SnareDrumEngine;
|
||||
use mi_plaits_dsp::engine::swarm_engine::SwarmEngine;
|
||||
use mi_plaits_dsp::engine::virtual_analog_engine::VirtualAnalogEngine;
|
||||
use mi_plaits_dsp::engine::waveshaping_engine::WaveshapingEngine;
|
||||
use mi_plaits_dsp::engine::wavetable_engine::WavetableEngine;
|
||||
use mi_plaits_dsp::engine::{Engine, EngineParameters};
|
||||
|
||||
/// Wrapper enum containing all Plaits synthesis engines.
|
||||
///
|
||||
/// Only one engine is active at a time. The engine is lazily initialized
|
||||
/// when first needed and can be switched by creating a new instance with
|
||||
/// [`PlaitsEngine::new`].
|
||||
pub enum PlaitsEngine {
|
||||
/// Physical modeling of resonant structures (strings, plates, tubes).
|
||||
Modal(ModalEngine),
|
||||
/// Classic virtual analog with saw, pulse, and sub oscillator.
|
||||
Va(VirtualAnalogEngine),
|
||||
/// Waveshaping synthesis for harsh, aggressive timbres.
|
||||
Ws(WaveshapingEngine),
|
||||
/// Two-operator FM synthesis.
|
||||
Fm(FmEngine),
|
||||
/// Granular synthesis with pitch-shifting grains.
|
||||
Grain(GrainEngine),
|
||||
/// Additive synthesis with individual harmonic control.
|
||||
Additive(AdditiveEngine),
|
||||
/// Wavetable oscillator with smooth morphing.
|
||||
Wavetable(WavetableEngine<'static>),
|
||||
/// Polyphonic chord generator (boxed due to size).
|
||||
Chord(Box<ChordEngine<'static>>),
|
||||
/// Swarm of detuned sawtooth oscillators.
|
||||
Swarm(SwarmEngine),
|
||||
/// Filtered noise with variable resonance.
|
||||
Noise(NoiseEngine),
|
||||
/// Analog bass drum synthesis.
|
||||
Bass(BassDrumEngine),
|
||||
/// Analog snare drum synthesis.
|
||||
Snare(SnareDrumEngine),
|
||||
/// Metallic hi-hat synthesis.
|
||||
Hat(HihatEngine),
|
||||
}
|
||||
|
||||
impl PlaitsEngine {
|
||||
/// Creates and initializes a new engine based on the given source type.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if `source` is not a Plaits source variant (e.g., `Source::Tri`).
|
||||
pub fn new(source: Source, sample_rate: f32) -> Self {
|
||||
match source {
|
||||
Source::PlModal => {
|
||||
let mut e = ModalEngine::new(BLOCK_SIZE);
|
||||
e.init(sample_rate);
|
||||
Self::Modal(e)
|
||||
}
|
||||
Source::PlVa => {
|
||||
let mut e = VirtualAnalogEngine::new(BLOCK_SIZE);
|
||||
e.init(sample_rate);
|
||||
Self::Va(e)
|
||||
}
|
||||
Source::PlWs => {
|
||||
let mut e = WaveshapingEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Ws(e)
|
||||
}
|
||||
Source::PlFm => {
|
||||
let mut e = FmEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Fm(e)
|
||||
}
|
||||
Source::PlGrain => {
|
||||
let mut e = GrainEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Grain(e)
|
||||
}
|
||||
Source::PlAdd => {
|
||||
let mut e = AdditiveEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Additive(e)
|
||||
}
|
||||
Source::PlWt => {
|
||||
let mut e = WavetableEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Wavetable(e)
|
||||
}
|
||||
Source::PlChord => {
|
||||
let mut e = ChordEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Chord(Box::new(e))
|
||||
}
|
||||
Source::PlSwarm => {
|
||||
let mut e = SwarmEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Swarm(e)
|
||||
}
|
||||
Source::PlNoise => {
|
||||
let mut e = NoiseEngine::new(BLOCK_SIZE);
|
||||
e.init(sample_rate);
|
||||
Self::Noise(e)
|
||||
}
|
||||
Source::PlBass => {
|
||||
let mut e = BassDrumEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Bass(e)
|
||||
}
|
||||
Source::PlSnare => {
|
||||
let mut e = SnareDrumEngine::new();
|
||||
e.init(sample_rate);
|
||||
Self::Snare(e)
|
||||
}
|
||||
Source::PlHat => {
|
||||
let mut e = HihatEngine::new(BLOCK_SIZE);
|
||||
e.init(sample_rate);
|
||||
Self::Hat(e)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders a block of audio samples.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `params` - Engine parameters (pitch, timbre, morph, etc.)
|
||||
/// - `out` - Output buffer for main signal (length must be `BLOCK_SIZE`)
|
||||
/// - `aux` - Output buffer for auxiliary signal (length must be `BLOCK_SIZE`)
|
||||
/// - `already_enveloped` - Set to true by percussion engines that apply their own envelope
|
||||
pub fn render(
|
||||
&mut self,
|
||||
params: &EngineParameters,
|
||||
out: &mut [f32],
|
||||
aux: &mut [f32],
|
||||
already_enveloped: &mut bool,
|
||||
) {
|
||||
match self {
|
||||
Self::Modal(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Va(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Ws(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Fm(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Grain(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Additive(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Wavetable(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Chord(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Swarm(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Noise(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Bass(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Snare(e) => e.render(params, out, aux, already_enveloped),
|
||||
Self::Hat(e) => e.render(params, out, aux, already_enveloped),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [`Source`] variant corresponding to the current engine.
|
||||
pub fn source(&self) -> Source {
|
||||
match self {
|
||||
Self::Modal(_) => Source::PlModal,
|
||||
Self::Va(_) => Source::PlVa,
|
||||
Self::Ws(_) => Source::PlWs,
|
||||
Self::Fm(_) => Source::PlFm,
|
||||
Self::Grain(_) => Source::PlGrain,
|
||||
Self::Additive(_) => Source::PlAdd,
|
||||
Self::Wavetable(_) => Source::PlWt,
|
||||
Self::Chord(_) => Source::PlChord,
|
||||
Self::Swarm(_) => Source::PlSwarm,
|
||||
Self::Noise(_) => Source::PlNoise,
|
||||
Self::Bass(_) => Source::PlBass,
|
||||
Self::Snare(_) => Source::PlSnare,
|
||||
Self::Hat(_) => Source::PlHat,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user