diff --git a/REUSE.toml b/REUSE.toml index 5a07fdd..d292269 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -10,6 +10,6 @@ SPDX-FileCopyrightText = "2025 Kalle Fagerberg" SPDX-License-Identifier = "MIT" [[annotations]] -path = ["**/moon.mod", "example/moon.work", "**/moon.pkg.json", "**/moon.pkg"] +path = ["**/moon.mod", "**/moon.work", "**/moon.pkg.json", "**/moon.pkg"] SPDX-FileCopyrightText = "2025 Kalle Fagerberg" SPDX-License-Identifier = "CC0-1.0" diff --git a/example/audio/main.mbt b/example/audio/main.mbt index f010c7b..4f083cc 100644 --- a/example/audio/main.mbt +++ b/example/audio/main.mbt @@ -7,7 +7,8 @@ fn main { /// boot is only called once, after all the memory is initialized. pub fn boot() -> Unit { @audio.out.add_file(b"pickupCoin") |> ignore - @audio.out.add_gain(0.5).next().add_sine(@audio.A4, 1) |> ignore + let gain = @audio.out.add_gain(0.5) + gain.add_sine(@audio.A4, 1) |> ignore } ///| diff --git a/example/audio/moon.work b/example/audio/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/audio/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/example/font/moon.work b/example/font/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/font/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/example/image/moon.work b/example/image/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/image/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/example/input/moon.work b/example/input/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/input/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/example/moon.work b/example/moon.work deleted file mode 100644 index 431a1f5..0000000 --- a/example/moon.work +++ /dev/null @@ -1,3 +0,0 @@ -members = [ - "..", -] diff --git a/example/random/moon.work b/example/random/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/random/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/example/scores/moon.work b/example/scores/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/scores/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/example/shapes/moon.work b/example/shapes/moon.work new file mode 100644 index 0000000..5edbb9a --- /dev/null +++ b/example/shapes/moon.work @@ -0,0 +1,4 @@ +members = [ + ".", + "../..", +] diff --git a/src/audio/node.mbt b/src/audio/node.mbt index 6430c46..e7eef22 100644 --- a/src/audio/node.mbt +++ b/src/audio/node.mbt @@ -1,497 +1,209 @@ ///| -#valtype -struct Node { - id : UInt -} derive(Eq, Compare, Hash) - -///| -pub trait Marker { - fn next(Self) -> Node -} - -///| -/// The output audio node. Mixes all inputs and plays them on the device's speaker. -pub let out : Node = Node::{ id: 0 } - -///| -/// A marker for a specific node type. See `Node::add_sine`. -pub struct Sine(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Sine with fn next(self : Sine) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_mix`. -struct Mix(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Mix with fn next(self : Mix) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_all_for_one`. -struct AllForOne(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for AllForOne with fn next(self : AllForOne) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_gain`. -struct Gain(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Gain with fn next(self : Gain) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_loop`. -struct Loop(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Loop with fn next(self : Loop) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_concat`. -struct Concat(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Concat with fn next(self : Concat) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_pan`. -struct Pan(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Pan with fn next(self : Pan) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_mute`. -struct Mute(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Mute with fn next(self : Mute) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_pause`. -struct Pause(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Pause with fn next(self : Pause) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_track_position`. -struct TrackPosition(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for TrackPosition with fn next(self : TrackPosition) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_low_pass`. -struct LowPass(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for LowPass with fn next(self : LowPass) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_high_pass`. -struct HighPass(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for HighPass with fn next(self : HighPass) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_take_left`. -struct TakeLeft(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for TakeLeft with fn next(self : TakeLeft) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_take_right`. -struct TakeRight(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for TakeRight with fn next(self : TakeRight) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_swap`. -struct Swap(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Swap with fn next(self : Swap) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_clip`. -struct Clip(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Clip with fn next(self : Clip) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_square`. -struct Square(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Square with fn next(self : Square) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_sawtooth`. -struct Sawtooth(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Sawtooth with fn next(self : Sawtooth) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_triangle`. -struct Triangle(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Triangle with fn next(self : Triangle) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_noise`. -struct Noise(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Noise with fn next(self : Noise) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_empty`. -struct Empty(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Empty with fn next(self : Empty) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_zero`. -struct Zero(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for Zero with fn next(self : Zero) -> Node { - self.0 -} - -///| -/// A marker for a specific node type. See `Node::add_file`. -struct File(Node) - -///| -/// Get the next node for applying more effects. -#inline -pub impl Marker for File with fn next(self : File) -> Node { - self.0 +pub trait SourceNode { + fn id(Self) -> UInt + fn reset(Self) -> Unit = _ +} + +///| +pub trait Node { + fn id(Self) -> UInt + fn add_sine(Self, freq : Hz, phase : Float) -> Sine = _ + fn add_square(Self, freq : Hz, phase : Float) -> Square = _ + fn add_sawtooth(Self, freq : Hz, phase : Float) -> Sawtooth = _ + fn add_triangle(Self, freq : Hz, phase : Float) -> Triangle = _ + fn add_noise(Self, seed : Int) -> Noise = _ + fn add_empty(Self) -> Empty = _ + fn add_zero(Self) -> Zero = _ + fn add_file(Self, path : @firefly.Utf8View) -> File = _ + fn add_mix(Self) -> Mix = _ + fn add_all_for_one(Self) -> AllForOne = _ + fn add_gain(Self, level : Float) -> Gain = _ + fn add_loop(Self) -> Loop = _ + fn add_concat(Self) -> Concat = _ + fn add_pan(Self, level : Float) -> Pan = _ + fn add_mute(Self) -> Mute = _ + fn add_pause(Self) -> Pause = _ + fn add_track_position(Self) -> TrackPosition = _ + fn add_low_pass(Self, freq : Hz, q : Float) -> LowPass = _ + fn add_high_pass(Self, freq : Hz, q : Float) -> HighPass = _ + fn add_take_left(Self) -> TakeLeft = _ + fn add_take_right(Self) -> TakeRight = _ + fn add_swap(Self) -> Swap = _ + fn add_clip(Self, low : Float, high : Float) -> Clip = _ + fn reset(Self) -> Unit = _ + fn reset_all(Self) -> Unit = _ + fn clear(Self) -> Unit = _ } ///| /// Add sine wave oscillator source (`∿`). -pub fn Node::add_sine(self : Node, freq : Hz, phase : Float) -> Sine { - Sine(Node::{ id: @ffi.audio_add_sine(self.id, freq, phase) }) +impl Node with fn add_sine(self, freq : Hz, phase : Float) -> Sine { + Sine::{ id: @ffi.audio_add_sine(self.id(), freq, phase) } } ///| /// Add square wave oscillator source (`⎍`). -pub fn Node::add_square(self : Node, freq : Hz, phase : Float) -> Square { - Square(Node::{ id: @ffi.audio_add_square(self.id, freq, phase) }) +impl Node with fn add_square(self, freq : Hz, phase : Float) -> Square { + Square::{ id: @ffi.audio_add_square(self.id(), freq, phase) } } ///| /// Add sawtooth wave oscillator source (`╱│`). -pub fn Node::add_sawtooth(self : Node, freq : Hz, phase : Float) -> Sawtooth { - Sawtooth(Node::{ id: @ffi.audio_add_sawtooth(self.id, freq, phase) }) +impl Node with fn add_sawtooth(self, freq : Hz, phase : Float) -> Sawtooth { + Sawtooth::{ id: @ffi.audio_add_sawtooth(self.id(), freq, phase) } } ///| /// Add triangle wave oscillator source (`╱╲`). -pub fn Node::add_triangle(self : Node, freq : Hz, phase : Float) -> Triangle { - Triangle(Node::{ id: @ffi.audio_add_triangle(self.id, freq, phase) }) +impl Node with fn add_triangle(self, freq : Hz, phase : Float) -> Triangle { + Triangle::{ id: @ffi.audio_add_triangle(self.id(), freq, phase) } } ///| /// Add white noise source (amplitude on each tick is random). -pub fn Node::add_noise(self : Node, seed : Int) -> Noise { - Noise(Node::{ id: @ffi.audio_add_noise(self.id, seed) }) +impl Node with fn add_noise(self, seed : Int) -> Noise { + Noise::{ id: @ffi.audio_add_noise(self.id(), seed) } } ///| /// Add always stopped source. -pub fn Node::add_empty(self : Node) -> Empty { - Empty(Node::{ id: @ffi.audio_add_empty(self.id) }) +impl Node with fn add_empty(self) -> Empty { + Empty::{ id: @ffi.audio_add_empty(self.id()) } } ///| /// Add silent source producing zeros. -pub fn Node::add_zero(self : Node) -> Zero { - Zero(Node::{ id: @ffi.audio_add_zero(self.id) }) +impl Node with fn add_zero(self) -> Zero { + Zero::{ id: @ffi.audio_add_zero(self.id()) } } ///| /// Add source playing audio from a file. -pub fn Node::add_file(self : Node, path : @firefly.Utf8View) -> File { - let file = File(Node::{ +impl Node with fn add_file(self, path : @firefly.Utf8View) -> File { + let file = File::{ id: @ffi.audio_add_file( - self.id, + self.id(), @memory.bytesview_addr(path), @memory.bytesview_size(path), ), - }) + } @memory.keep(path) file } ///| /// Add node simply mixing all inputs. -pub fn Node::add_mix(self : Node) -> Mix { - Mix(Node::{ id: @ffi.audio_add_mix(self.id) }) +impl Node with fn add_mix(self) -> Mix { + Mix::{ id: @ffi.audio_add_mix(self.id()) } } ///| /// Add mixer node that stops if any of the sources stops. -pub fn Node::add_all_for_one(self : Node) -> AllForOne { - AllForOne(Node::{ id: @ffi.audio_add_all_for_one(self.id) }) +impl Node with fn add_all_for_one(self) -> AllForOne { + AllForOne::{ id: @ffi.audio_add_all_for_one(self.id()) } } ///| /// Add gain control node. -pub fn Node::add_gain(self : Node, level : Float) -> Gain { - Gain(Node::{ id: @ffi.audio_add_gain(self.id, level) }) +impl Node with fn add_gain(self, level : Float) -> Gain { + Gain::{ id: @ffi.audio_add_gain(self.id(), level) } } ///| /// Add a loop node that resets the input if it stops. -pub fn Node::add_loop(self : Node) -> Loop { - Loop(Node::{ id: @ffi.audio_add_loop(self.id) }) +impl Node with fn add_loop(self) -> Loop { + Loop::{ id: @ffi.audio_add_loop(self.id()) } } ///| /// Add a node that plays the inputs one after the other, in the order as they added. -pub fn Node::add_concat(self : Node) -> Concat { - Concat(Node::{ id: @ffi.audio_add_concat(self.id) }) +impl Node with fn add_concat(self) -> Concat { + Concat::{ id: @ffi.audio_add_concat(self.id()) } } ///| /// Add node panning the audio to the left (0.), right (1.), or something in between. -pub fn Node::add_pan(self : Node, level : Float) -> Pan { - Pan(Node::{ id: @ffi.audio_add_pan(self.id, level) }) +impl Node with fn add_pan(self, level : Float) -> Pan { + Pan::{ id: @ffi.audio_add_pan(self.id(), level) } } ///| /// Add node that can be muted using modulation. -pub fn Node::add_mute(self : Node) -> Mute { - Mute(Node::{ id: @ffi.audio_add_mute(self.id) }) +impl Node with fn add_mute(self) -> Mute { + Mute::{ id: @ffi.audio_add_mute(self.id()) } } ///| /// Add node that can be paused using modulation. -pub fn Node::add_pause(self : Node) -> Pause { - Pause(Node::{ id: @ffi.audio_add_pause(self.id) }) +impl Node with fn add_pause(self) -> Pause { + Pause::{ id: @ffi.audio_add_pause(self.id()) } } ///| /// Add node tracking the elapsed playback time. -pub fn Node::add_track_position(self : Node) -> TrackPosition { - TrackPosition(Node::{ id: @ffi.audio_add_track_position(self.id) }) +impl Node with fn add_track_position(self) -> TrackPosition { + TrackPosition::{ id: @ffi.audio_add_track_position(self.id()) } } ///| /// Add lowpass filter node. -pub fn Node::add_low_pass(self : Node, freq : Hz, q : Float) -> LowPass { - LowPass(Node::{ id: @ffi.audio_add_low_pass(self.id, freq, q) }) +impl Node with fn add_low_pass(self, freq : Hz, q : Float) -> LowPass { + LowPass::{ id: @ffi.audio_add_low_pass(self.id(), freq, q) } } ///| /// Add highpass filter node. -pub fn Node::add_high_pass(self : Node, freq : Hz, q : Float) -> HighPass { - HighPass(Node::{ id: @ffi.audio_add_high_pass(self.id, freq, q) }) +impl Node with fn add_high_pass(self, freq : Hz, q : Float) -> HighPass { + HighPass::{ id: @ffi.audio_add_high_pass(self.id(), freq, q) } } ///| /// Add node converting stereo to mono by taking the left channel. -pub fn Node::add_take_left(self : Node) -> TakeLeft { - TakeLeft(Node::{ id: @ffi.audio_add_take_left(self.id) }) +impl Node with fn add_take_left(self) -> TakeLeft { + TakeLeft::{ id: @ffi.audio_add_take_left(self.id()) } } ///| /// Add node converting stereo to mono by taking the right channel. -pub fn Node::add_take_right(self : Node) -> TakeRight { - TakeRight(Node::{ id: @ffi.audio_add_take_right(self.id) }) +impl Node with fn add_take_right(self) -> TakeRight { + TakeRight::{ id: @ffi.audio_add_take_right(self.id()) } } ///| /// Add node swapping left and right channels of the stereo input. -pub fn Node::add_swap(self : Node) -> Swap { - Swap(Node::{ id: @ffi.audio_add_swap(self.id) }) +impl Node with fn add_swap(self) -> Swap { + Swap::{ id: @ffi.audio_add_swap(self.id()) } } ///| /// Add node clamping the input amplitude. Can be used for hard distortion. -pub fn Node::add_clip(self : Node, low : Float, high : Float) -> Clip { - Clip(Node::{ id: @ffi.audio_add_clip(self.id, low, high) }) +impl Node with fn add_clip(self, low : Float, high : Float) -> Clip { + Clip::{ id: @ffi.audio_add_clip(self.id(), low, high) } } ///| -/// Modulate oscillation frequency. -pub fn[Mod : Modulator] Sine::modulate(self : Sine, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) +/// Reset the node state to how it was when it was just added. +impl SourceNode with fn reset(self) { + @ffi.audio_reset(self.id()) } ///| -/// Modulate oscillation frequency. -pub fn[Mod : Modulator] Square::modulate(self : Square, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) +/// Reset the node state to how it was when it was just added. +impl Node with fn reset(self) { + @ffi.audio_reset(self.id()) } ///| -/// Modulate oscillation frequency. -pub fn[Mod : Modulator] Sawtooth::modulate(self : Sawtooth, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) +/// Reset the node and all child nodes to the state to how it was when they were just added. +impl Node with fn reset_all(self) { + @ffi.audio_reset_all(self.id()) } ///| -/// Modulate oscillation frequency. -pub fn[Mod : Modulator] Triangle::modulate(self : Triangle, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) -} - -///| -/// Modulate the gain level. -pub fn[Mod : Modulator] Gain::modulate(self : Gain, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) -} - -///| -/// 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.0.id, 0) -} - -///| -/// Modulate the muted state. +/// Remove all child nodes. /// -/// Below 0.5 is muted, above is unmuted. -pub fn[Mod : Modulator] Mute::modulate(self : Mute, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) -} - -///| -/// 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.0.id, 0) -} - -///| -/// Modulate the cut-off frequency. -pub fn[Mod : Modulator] LowPass::modulate(self : LowPass, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) -} - -///| -/// Modulate the cut-off frequency. -pub fn[Mod : Modulator] HighPass::modulate(self : HighPass, mod : Mod) -> Unit { - mod.modulate(self.0.id, 0) -} - -///| -/// 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.0.id, 0) -} - -///| -/// Modulate the low cut amplitude. -pub fn[Mod : Modulator] Clip::modulate_low(self : Clip, mod : Mod) -> Unit { - mod.modulate(self.0.id, 1) -} - -///| -/// Modulate the high cut amplitude. -pub fn[Mod : Modulator] Clip::modulate_high(self : Clip, mod : Mod) -> Unit { - mod.modulate(self.0.id, 2) +/// After it is called, you should make sure to discard all references to the +/// old child nodes. +impl Node with fn clear(self) { + @ffi.audio_clear(self.id()) } diff --git a/src/audio/nodes.mbt b/src/audio/nodes.mbt new file mode 100644 index 0000000..887dc1a --- /dev/null +++ b/src/audio/nodes.mbt @@ -0,0 +1,236 @@ +///| +struct Out {} + +///| +pub impl Node for Out with fn id(_self) -> UInt { + return 0 +} + +///| +/// The output audio node. Mixes all inputs and plays them on the device's speaker. +pub let out : Out = Out::{ } + +///| +/// A marker for a specific node type. See `Node::add_mix`. +struct Mix { + id : UInt +} + +///| +pub impl Node for Mix with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_all_for_one`. +struct AllForOne { + id : UInt +} + +///| +pub impl Node for AllForOne with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_gain`. +struct Gain { + id : UInt +} + +///| +pub impl Node for Gain with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_loop`. +struct Loop { + id : UInt +} + +///| +pub impl Node for Loop with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_concat`. +struct Concat { + id : UInt +} + +///| +pub impl Node for Concat with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_pan`. +struct Pan { + id : UInt +} + +///| +pub impl Node for Pan with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_mute`. +struct Mute { + id : UInt +} + +///| +pub impl Node for Mute with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_pause`. +struct Pause { + id : UInt +} + +///| +pub impl Node for Pause with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_track_position`. +struct TrackPosition { + id : UInt +} + +///| +pub impl Node for TrackPosition with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_low_pass`. +struct LowPass { + id : UInt +} + +///| +pub impl Node for LowPass with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_high_pass`. +struct HighPass { + id : UInt +} + +///| +pub impl Node for HighPass with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_take_left`. +struct TakeLeft { + id : UInt +} + +///| +pub impl Node for TakeLeft with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_take_right`. +struct TakeRight { + id : UInt +} + +///| +pub impl Node for TakeRight with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_swap`. +struct Swap { + id : UInt +} + +///| +pub impl Node for Swap with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_clip`. +struct Clip { + id : UInt +} + +///| +pub impl Node for Clip with fn id(self) -> UInt { + return self.id +} + +///| +/// Modulate the gain level. +pub fn[Mod : Modulator] Gain::modulate(self : Gain, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} + +///| +/// 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) +} + +///| +/// 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) +} + +///| +/// 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) +} + +///| +/// Modulate the cut-off frequency. +pub fn[Mod : Modulator] LowPass::modulate(self : LowPass, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} + +///| +/// Modulate the cut-off frequency. +pub fn[Mod : Modulator] HighPass::modulate(self : HighPass, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} + +///| +/// 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) +} + +///| +/// Modulate the low cut amplitude. +pub fn[Mod : Modulator] Clip::modulate_low(self : Clip, mod : Mod) -> Unit { + mod.modulate(self.id(), 1) +} + +///| +/// Modulate the high cut amplitude. +pub fn[Mod : Modulator] Clip::modulate_high(self : Clip, mod : Mod) -> Unit { + mod.modulate(self.id(), 2) +} diff --git a/src/audio/source_nodes.mbt b/src/audio/source_nodes.mbt new file mode 100644 index 0000000..a33f894 --- /dev/null +++ b/src/audio/source_nodes.mbt @@ -0,0 +1,111 @@ +///| +/// A marker for a specific node type. See `Node::add_sine`. +pub struct Sine { + id : UInt +} + +///| +pub impl SourceNode for Sine with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_square`. +struct Square { + id : UInt +} + +///| +pub impl SourceNode for Square with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_sawtooth`. +struct Sawtooth { + id : UInt +} + +///| +pub impl SourceNode for Sawtooth with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_triangle`. +struct Triangle { + id : UInt +} + +///| +pub impl SourceNode for Triangle with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_noise`. +struct Noise { + id : UInt +} + +///| +pub impl SourceNode for Noise with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_empty`. +struct Empty { + id : UInt +} + +///| +pub impl SourceNode for Empty with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_zero`. +struct Zero { + id : UInt +} + +///| +pub impl SourceNode for Zero with fn id(self) -> UInt { + return self.id +} + +///| +/// A marker for a specific node type. See `Node::add_file`. +struct File { + id : UInt +} + +///| +pub impl SourceNode for File with fn id(self) -> UInt { + return self.id +} + +///| +/// Modulate oscillation frequency. +pub fn[Mod : Modulator] Sine::modulate(self : Sine, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} + +///| +/// Modulate oscillation frequency. +pub fn[Mod : Modulator] Square::modulate(self : Square, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} + +///| +/// Modulate oscillation frequency. +pub fn[Mod : Modulator] Sawtooth::modulate(self : Sawtooth, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} + +///| +/// Modulate oscillation frequency. +pub fn[Mod : Modulator] Triangle::modulate(self : Triangle, mod : Mod) -> Unit { + mod.modulate(self.id(), 0) +} diff --git a/src/internal/ffi/audio.mbt b/src/internal/ffi/audio.mbt index 99f199c..bf0260b 100644 --- a/src/internal/ffi/audio.mbt +++ b/src/internal/ffi/audio.mbt @@ -111,7 +111,7 @@ pub fn audio_reset_all(node_id : UInt) -> Unit = "audio" "reset_all" /// /// After it is called, you should make sure to discard all references to the /// old child nodes. -pub fn audio_clear_node(node_id : UInt) -> Unit = "audio" "clear_node" +pub fn audio_clear(node_id : UInt) -> Unit = "audio" "clear" ///| /// Linear (ramp up or down) envelope.