Skip to content

Commit 8ddf419

Browse files
authored
Merge pull request #61 from firefly-zero/modulators
More modulators, new modulation API
2 parents 04faa8d + 44c58d4 commit 8ddf419

4 files changed

Lines changed: 223 additions & 37 deletions

File tree

src/audio/modulators.mbt

Lines changed: 101 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
///|
22
pub trait Modulator {
3-
fn modulate(Self, node_id : UInt, param : UInt) -> Unit
3+
fn modulate(Self, node_id : UInt, param : UInt, low : Float, high : Float) -> Unit
44
}
55

66
///|
@@ -12,8 +12,6 @@ pub trait Modulator {
1212
/// and the value between `start_at` and `end_at` changes linearly from `start` to `end`.
1313
#valtype
1414
pub(all) struct LinearModulator {
15-
start : Float
16-
end : Float
1715
start_at : Time
1816
end_at : Time
1917
}
@@ -24,12 +22,14 @@ pub impl Modulator for LinearModulator with fn modulate(
2422
self : LinearModulator,
2523
node_id : UInt,
2624
param : UInt,
25+
low : Float,
26+
high : Float,
2727
) -> Unit {
2828
@ffi.audio_mod_linear(
2929
node_id,
3030
param,
31-
self.start,
32-
self.end,
31+
low,
32+
high,
3333
self.start_at.0,
3434
self.end_at.0,
3535
)
@@ -44,8 +44,6 @@ pub impl Modulator for LinearModulator with fn modulate(
4444
/// Equivalent to [`LinearModulator`] with `start_at` being equal to `end_at`.
4545
#valtype
4646
pub(all) struct HoldModulator {
47-
before : Float
48-
after : Float
4947
time : Time
5048
}
5149

@@ -55,8 +53,58 @@ pub impl Modulator for HoldModulator with fn modulate(
5553
self : HoldModulator,
5654
node_id : UInt,
5755
param : UInt,
56+
low : Float,
57+
high : Float,
5858
) -> Unit {
59-
@ffi.audio_mod_hold(node_id, param, self.before, self.after, self.time.0)
59+
@ffi.audio_mod_hold(node_id, param, low, high, self.time.0)
60+
}
61+
62+
///|
63+
/// ADSR envelope.
64+
///
65+
/// It looks like this: `🭋🭍🬹🬿`
66+
///
67+
/// 1. Until `attack`, the value goes from 0 to 1;
68+
/// 2. Until `decay`, it goes from 1 to `sustain_level`;
69+
/// 3. Until `sustain`, it holds `sustain_level`;
70+
/// 4. Until `release`, it goes from `sustain_level` to 0;
71+
/// 5. After `release`, it holds 0.
72+
///
73+
/// Most commonly used with `Gain`.
74+
#valtype
75+
pub(all) struct AdsrModulator {
76+
/// When the value reaches 1.
77+
attack : Time
78+
/// When the value reaches `sustain_level`.
79+
decay : Time
80+
/// Until when the value holds `sustain_level`.
81+
sustain : Time
82+
/// The value generated from `decay` until `sustain`.
83+
sustain_level : Float
84+
/// When the value drops to 0.
85+
release : Time
86+
}
87+
88+
///|
89+
#inline
90+
pub impl Modulator for AdsrModulator with fn modulate(
91+
self : AdsrModulator,
92+
node_id : UInt,
93+
param : UInt,
94+
low : Float,
95+
high : Float,
96+
) -> Unit {
97+
@ffi.audio_mod_adsr(
98+
node_id,
99+
param,
100+
low,
101+
high,
102+
self.attack.0,
103+
self.decay.0,
104+
self.sustain.0,
105+
self.sustain_level,
106+
self.release.0,
107+
)
60108
}
61109

62110
///|
@@ -68,8 +116,6 @@ pub impl Modulator for HoldModulator with fn modulate(
68116
#valtype
69117
pub(all) struct SineModulator {
70118
freq : Hz
71-
low : Float
72-
high : Float
73119
}
74120

75121
///|
@@ -78,6 +124,50 @@ pub impl Modulator for SineModulator with fn modulate(
78124
self : SineModulator,
79125
node_id : UInt,
80126
param : UInt,
127+
low : Float,
128+
high : Float,
129+
) -> Unit {
130+
@ffi.audio_mod_sine(node_id, param, self.freq, low, high)
131+
}
132+
133+
///|
134+
/// Square wave low-frequency oscillator.
135+
///
136+
/// It looks like this: `🭿🭾🭿🭾🭿🭾🭿🭾`.
137+
#valtype
138+
pub(all) struct SquareModulator {
139+
period : Time
140+
}
141+
142+
///|
143+
#inline
144+
pub impl Modulator for SquareModulator with fn modulate(
145+
self : SquareModulator,
146+
node_id : UInt,
147+
param : UInt,
148+
low : Float,
149+
high : Float,
150+
) -> Unit {
151+
@ffi.audio_mod_square(node_id, param, low, high, self.period.0)
152+
}
153+
154+
///|
155+
/// Sawtooth wave low-frequency oscillator.
156+
///
157+
/// It looks like this: `╱│╱│╱│╱│`.
158+
#valtype
159+
pub(all) struct SawtoothModulator {
160+
period : Time
161+
}
162+
163+
///|
164+
#inline
165+
pub impl Modulator for SawtoothModulator with fn modulate(
166+
self : SawtoothModulator,
167+
node_id : UInt,
168+
param : UInt,
169+
low : Float,
170+
high : Float,
81171
) -> Unit {
82-
@ffi.audio_mod_sine(node_id, param, self.freq, self.low, self.high)
172+
@ffi.audio_mod_sawtooth(node_id, param, low, high, self.period.0)
83173
}

src/audio/nodes.mbt

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -177,60 +177,105 @@ pub impl Node for Clip with fn id(self) -> UInt {
177177

178178
///|
179179
/// Modulate the gain level.
180-
pub fn[Mod : Modulator] Gain::modulate(self : Gain, mod : Mod) -> Unit {
181-
mod.modulate(self.id(), 0)
180+
pub fn[Mod : Modulator] Gain::modulate(
181+
self : Gain,
182+
low : Float,
183+
high : Float,
184+
mod : Mod,
185+
) -> Unit {
186+
mod.modulate(self.id(), 0, low, high)
182187
}
183188

184189
///|
185190
/// Modulate the pan value (from 0. to 1.: 0. is only left, 1. is only right).
186-
pub fn[Mod : Modulator] Pan::modulate(self : Pan, mod : Mod) -> Unit {
187-
mod.modulate(self.id(), 0)
191+
pub fn[Mod : Modulator] Pan::modulate(
192+
self : Pan,
193+
low : Float,
194+
high : Float,
195+
mod : Mod,
196+
) -> Unit {
197+
mod.modulate(self.id(), 0, low, high)
188198
}
189199

190200
///|
191201
/// Modulate the muted state.
192202
///
193203
/// Below 0.5 is muted, above is unmuted.
194-
pub fn[Mod : Modulator] Mute::modulate(self : Mute, mod : Mod) -> Unit {
195-
mod.modulate(self.id(), 0)
204+
pub fn[Mod : Modulator] Mute::modulate(
205+
self : Mute,
206+
low : Float,
207+
high : Float,
208+
mod : Mod,
209+
) -> Unit {
210+
mod.modulate(self.id(), 0, low, high)
196211
}
197212

198213
///|
199214
/// Modulate the paused state.
200215
///
201216
/// Below 0.5 is paused, above is playing.
202-
pub fn[Mod : Modulator] Pause::modulate(self : Pause, mod : Mod) -> Unit {
203-
mod.modulate(self.id(), 0)
217+
pub fn[Mod : Modulator] Pause::modulate(
218+
self : Pause,
219+
low : Float,
220+
high : Float,
221+
mod : Mod,
222+
) -> Unit {
223+
mod.modulate(self.id(), 0, low, high)
204224
}
205225

206226
///|
207227
/// Modulate the cut-off frequency.
208-
pub fn[Mod : Modulator] LowPass::modulate(self : LowPass, mod : Mod) -> Unit {
209-
mod.modulate(self.id(), 0)
228+
pub fn[Mod : Modulator] LowPass::modulate(
229+
self : LowPass,
230+
low : Float,
231+
high : Float,
232+
mod : Mod,
233+
) -> Unit {
234+
mod.modulate(self.id(), 0, low, high)
210235
}
211236

212237
///|
213238
/// Modulate the cut-off frequency.
214-
pub fn[Mod : Modulator] HighPass::modulate(self : HighPass, mod : Mod) -> Unit {
215-
mod.modulate(self.id(), 0)
239+
pub fn[Mod : Modulator] HighPass::modulate(
240+
self : HighPass,
241+
low : Float,
242+
high : Float,
243+
mod : Mod,
244+
) -> Unit {
245+
mod.modulate(self.id(), 0, low, high)
216246
}
217247

218248
///|
219249
/// Modulate the low cut amplitude and adjust the high amplitude to keep the gap.
220250
///
221251
/// In other words, the difference between low and high cut points will stay the same.
222-
pub fn[Mod : Modulator] Clip::modulate_both(self : Clip, mod : Mod) -> Unit {
223-
mod.modulate(self.id(), 0)
252+
pub fn[Mod : Modulator] Clip::modulate_both(
253+
self : Clip,
254+
low : Float,
255+
high : Float,
256+
mod : Mod,
257+
) -> Unit {
258+
mod.modulate(self.id(), 0, low, high)
224259
}
225260

226261
///|
227262
/// Modulate the low cut amplitude.
228-
pub fn[Mod : Modulator] Clip::modulate_low(self : Clip, mod : Mod) -> Unit {
229-
mod.modulate(self.id(), 1)
263+
pub fn[Mod : Modulator] Clip::modulate_low(
264+
self : Clip,
265+
low : Float,
266+
high : Float,
267+
mod : Mod,
268+
) -> Unit {
269+
mod.modulate(self.id(), 1, low, high)
230270
}
231271

232272
///|
233273
/// Modulate the high cut amplitude.
234-
pub fn[Mod : Modulator] Clip::modulate_high(self : Clip, mod : Mod) -> Unit {
235-
mod.modulate(self.id(), 2)
274+
pub fn[Mod : Modulator] Clip::modulate_high(
275+
self : Clip,
276+
low : Float,
277+
high : Float,
278+
mod : Mod,
279+
) -> Unit {
280+
mod.modulate(self.id(), 2, low, high)
236281
}

src/audio/source_nodes.mbt

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,44 @@ pub impl SourceNode for File with fn id(self) -> UInt {
8888

8989
///|
9090
/// Modulate oscillation frequency.
91-
pub fn[Mod : Modulator] Sine::modulate(self : Sine, mod : Mod) -> Unit {
92-
mod.modulate(self.id(), 0)
91+
pub fn[Mod : Modulator] Sine::modulate(
92+
self : Sine,
93+
low : Float,
94+
high : Float,
95+
mod : Mod,
96+
) -> Unit {
97+
mod.modulate(self.id(), 0, low, high)
9398
}
9499

95100
///|
96101
/// Modulate oscillation frequency.
97-
pub fn[Mod : Modulator] Square::modulate(self : Square, mod : Mod) -> Unit {
98-
mod.modulate(self.id(), 0)
102+
pub fn[Mod : Modulator] Square::modulate(
103+
self : Square,
104+
low : Float,
105+
high : Float,
106+
mod : Mod,
107+
) -> Unit {
108+
mod.modulate(self.id(), 0, low, high)
99109
}
100110

101111
///|
102112
/// Modulate oscillation frequency.
103-
pub fn[Mod : Modulator] Sawtooth::modulate(self : Sawtooth, mod : Mod) -> Unit {
104-
mod.modulate(self.id(), 0)
113+
pub fn[Mod : Modulator] Sawtooth::modulate(
114+
self : Sawtooth,
115+
low : Float,
116+
high : Float,
117+
mod : Mod,
118+
) -> Unit {
119+
mod.modulate(self.id(), 0, low, high)
105120
}
106121

107122
///|
108123
/// Modulate oscillation frequency.
109-
pub fn[Mod : Modulator] Triangle::modulate(self : Triangle, mod : Mod) -> Unit {
110-
mod.modulate(self.id(), 0)
124+
pub fn[Mod : Modulator] Triangle::modulate(
125+
self : Triangle,
126+
low : Float,
127+
high : Float,
128+
mod : Mod,
129+
) -> Unit {
130+
mod.modulate(self.id(), 0, low, high)
111131
}

src/internal/ffi/audio.mbt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,19 @@ pub fn audio_mod_hold(
144144
time : UInt,
145145
) = "audio" "mod_hold"
146146

147+
///|
148+
pub fn audio_mod_adsr(
149+
node_id : UInt,
150+
param : UInt,
151+
low : Float,
152+
high : Float,
153+
attack : UInt,
154+
decay : UInt,
155+
sustain : UInt,
156+
sustain_level : Float,
157+
release : UInt,
158+
) = "audio" "mod_adsr"
159+
147160
///|
148161
/// Sine wave low-frequency oscillator.
149162
///
@@ -157,3 +170,21 @@ pub fn audio_mod_sine(
157170
low : Float,
158171
high : Float,
159172
) = "audio" "mod_sine"
173+
174+
///|
175+
pub fn audio_mod_square(
176+
node_id : UInt,
177+
param : UInt,
178+
low : Float,
179+
high : Float,
180+
period : UInt,
181+
) = "audio" "mod_square"
182+
183+
///|
184+
pub fn audio_mod_sawtooth(
185+
node_id : UInt,
186+
param : UInt,
187+
low : Float,
188+
high : Float,
189+
period : UInt,
190+
) = "audio" "mod_sawtooth"

0 commit comments

Comments
 (0)