Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 101 additions & 11 deletions src/audio/modulators.mbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
///|
pub trait Modulator {
fn modulate(Self, node_id : UInt, param : UInt) -> Unit
fn modulate(Self, node_id : UInt, param : UInt, low : Float, high : Float) -> Unit
}

///|
Expand All @@ -12,8 +12,6 @@ pub trait Modulator {
/// and the value between `start_at` and `end_at` changes linearly from `start` to `end`.
#valtype
pub(all) struct LinearModulator {
start : Float
end : Float
start_at : Time
end_at : Time
}
Expand All @@ -24,12 +22,14 @@ pub impl Modulator for LinearModulator with fn modulate(
self : LinearModulator,
node_id : UInt,
param : UInt,
low : Float,
high : Float,
) -> Unit {
@ffi.audio_mod_linear(
node_id,
param,
self.start,
self.end,
low,
high,
self.start_at.0,
self.end_at.0,
)
Expand All @@ -44,8 +44,6 @@ pub impl Modulator for LinearModulator with fn modulate(
/// Equivalent to [`LinearModulator`] with `start_at` being equal to `end_at`.
#valtype
pub(all) struct HoldModulator {
before : Float
after : Float
time : Time
}

Expand All @@ -55,8 +53,58 @@ pub impl Modulator for HoldModulator with fn modulate(
self : HoldModulator,
node_id : UInt,
param : UInt,
low : Float,
high : Float,
) -> Unit {
@ffi.audio_mod_hold(node_id, param, self.before, self.after, self.time.0)
@ffi.audio_mod_hold(node_id, param, low, high, self.time.0)
}

///|
/// ADSR envelope.
///
/// It looks like this: `馃瓔馃瓖馃馃`
///
/// 1. Until `attack`, the value goes from 0 to 1;
/// 2. Until `decay`, it goes from 1 to `sustain_level`;
/// 3. Until `sustain`, it holds `sustain_level`;
/// 4. Until `release`, it goes from `sustain_level` to 0;
/// 5. After `release`, it holds 0.
///
/// Most commonly used with `Gain`.
#valtype
pub(all) struct AdsrModulator {
/// When the value reaches 1.
attack : Time
/// When the value reaches `sustain_level`.
decay : Time
/// Until when the value holds `sustain_level`.
sustain : Time
/// The value generated from `decay` until `sustain`.
sustain_level : Float
/// When the value drops to 0.
release : Time
}

///|
#inline
pub impl Modulator for AdsrModulator with fn modulate(
self : AdsrModulator,
node_id : UInt,
param : UInt,
low : Float,
high : Float,
) -> Unit {
@ffi.audio_mod_adsr(
node_id,
param,
low,
high,
self.attack.0,
self.decay.0,
self.sustain.0,
self.sustain_level,
self.release.0,
)
}

///|
Expand All @@ -68,8 +116,6 @@ pub impl Modulator for HoldModulator with fn modulate(
#valtype
pub(all) struct SineModulator {
freq : Hz
low : Float
high : Float
}

///|
Expand All @@ -78,6 +124,50 @@ pub impl Modulator for SineModulator with fn modulate(
self : SineModulator,
node_id : UInt,
param : UInt,
low : Float,
high : Float,
) -> Unit {
@ffi.audio_mod_sine(node_id, param, self.freq, low, high)
}

///|
/// Square wave low-frequency oscillator.
///
/// It looks like this: `馃馃馃馃馃馃馃馃`.
#valtype
pub(all) struct SquareModulator {
period : Time
}

///|
#inline
pub impl Modulator for SquareModulator with fn modulate(
self : SquareModulator,
node_id : UInt,
param : UInt,
low : Float,
high : Float,
) -> Unit {
@ffi.audio_mod_square(node_id, param, low, high, self.period.0)
}

///|
/// Sawtooth wave low-frequency oscillator.
///
/// It looks like this: `鈺扁攤鈺扁攤鈺扁攤鈺扁攤`.
#valtype
pub(all) struct SawtoothModulator {
period : Time
}

///|
#inline
pub impl Modulator for SawtoothModulator with fn modulate(
self : SawtoothModulator,
node_id : UInt,
param : UInt,
low : Float,
high : Float,
) -> Unit {
@ffi.audio_mod_sine(node_id, param, self.freq, self.low, self.high)
@ffi.audio_mod_sawtooth(node_id, param, low, high, self.period.0)
}
81 changes: 63 additions & 18 deletions src/audio/nodes.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -177,60 +177,105 @@ pub impl Node for Clip with fn id(self) -> UInt {

///|
/// Modulate the gain level.
pub fn[Mod : Modulator] Gain::modulate(self : Gain, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Gain::modulate(
self : Gain,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the pan value (from 0. to 1.: 0. is only left, 1. is only right).
pub fn[Mod : Modulator] Pan::modulate(self : Pan, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Pan::modulate(
self : Pan,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the muted state.
///
/// Below 0.5 is muted, above is unmuted.
pub fn[Mod : Modulator] Mute::modulate(self : Mute, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Mute::modulate(
self : Mute,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the paused state.
///
/// Below 0.5 is paused, above is playing.
pub fn[Mod : Modulator] Pause::modulate(self : Pause, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Pause::modulate(
self : Pause,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the cut-off frequency.
pub fn[Mod : Modulator] LowPass::modulate(self : LowPass, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] LowPass::modulate(
self : LowPass,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the cut-off frequency.
pub fn[Mod : Modulator] HighPass::modulate(self : HighPass, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] HighPass::modulate(
self : HighPass,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the low cut amplitude and adjust the high amplitude to keep the gap.
///
/// In other words, the difference between low and high cut points will stay the same.
pub fn[Mod : Modulator] Clip::modulate_both(self : Clip, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Clip::modulate_both(
self : Clip,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate the low cut amplitude.
pub fn[Mod : Modulator] Clip::modulate_low(self : Clip, mod : Mod) -> Unit {
mod.modulate(self.id(), 1)
pub fn[Mod : Modulator] Clip::modulate_low(
self : Clip,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 1, low, high)
}

///|
/// Modulate the high cut amplitude.
pub fn[Mod : Modulator] Clip::modulate_high(self : Clip, mod : Mod) -> Unit {
mod.modulate(self.id(), 2)
pub fn[Mod : Modulator] Clip::modulate_high(
self : Clip,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 2, low, high)
}
36 changes: 28 additions & 8 deletions src/audio/source_nodes.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,44 @@ pub impl SourceNode for File with fn id(self) -> UInt {

///|
/// Modulate oscillation frequency.
pub fn[Mod : Modulator] Sine::modulate(self : Sine, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Sine::modulate(
self : Sine,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate oscillation frequency.
pub fn[Mod : Modulator] Square::modulate(self : Square, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Square::modulate(
self : Square,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate oscillation frequency.
pub fn[Mod : Modulator] Sawtooth::modulate(self : Sawtooth, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Sawtooth::modulate(
self : Sawtooth,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}

///|
/// Modulate oscillation frequency.
pub fn[Mod : Modulator] Triangle::modulate(self : Triangle, mod : Mod) -> Unit {
mod.modulate(self.id(), 0)
pub fn[Mod : Modulator] Triangle::modulate(
self : Triangle,
low : Float,
high : Float,
mod : Mod,
) -> Unit {
mod.modulate(self.id(), 0, low, high)
}
31 changes: 31 additions & 0 deletions src/internal/ffi/audio.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,19 @@ pub fn audio_mod_hold(
time : UInt,
) = "audio" "mod_hold"

///|
pub fn audio_mod_adsr(
node_id : UInt,
param : UInt,
low : Float,
high : Float,
attack : UInt,
decay : UInt,
sustain : UInt,
sustain_level : Float,
release : UInt,
) = "audio" "mod_adsr"

///|
/// Sine wave low-frequency oscillator.
///
Expand All @@ -157,3 +170,21 @@ pub fn audio_mod_sine(
low : Float,
high : Float,
) = "audio" "mod_sine"

///|
pub fn audio_mod_square(
node_id : UInt,
param : UInt,
low : Float,
high : Float,
period : UInt,
) = "audio" "mod_square"

///|
pub fn audio_mod_sawtooth(
node_id : UInt,
param : UInt,
low : Float,
high : Float,
period : UInt,
) = "audio" "mod_sawtooth"
Loading