summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Lee <jacob@unabridgedsoftware.com>2021-12-04 10:55:23 -0500
committerJacob Lee <jacob@unabridgedsoftware.com>2021-12-04 10:55:23 -0500
commite91c02971c08a180a3b1dc3dee9a0b035a79fa95 (patch)
tree1c1788be9942b72b89a401d7702a1e82badb0a18
parentb73dde8aa4a5701eb05a5232d907f008dc8f6b00 (diff)
Add oscillator back and allow toggling between instrument and waveform in Godot interface. Still need to work on how we're playing the instrument.
-rw-r--r--klangfarb/Main.tscn1
-rw-r--r--klangfarb/main.gd43
-rw-r--r--klangfarbrs/src/instrument.rs5
-rw-r--r--klangfarbrs/src/lib.rs85
4 files changed, 79 insertions, 55 deletions
diff --git a/klangfarb/Main.tscn b/klangfarb/Main.tscn
index 7b547cd..4d3e135 100644
--- a/klangfarb/Main.tscn
+++ b/klangfarb/Main.tscn
@@ -8,5 +8,6 @@
stream = SubResource( 1 )
volume_db = -13.216
script = ExtResource( 2 )
+play_instrument = true
continuous = false
fm_index = 100.0
diff --git a/klangfarb/main.gd b/klangfarb/main.gd
index 590d45b..433342e 100644
--- a/klangfarb/main.gd
+++ b/klangfarb/main.gd
@@ -4,6 +4,8 @@ extends AudioStreamPlayer
export(String, "sine", "square", "triangle", "sawtooth", "white_noise", "brown_noise") var waveform = "sine"
# controllable frequency interface
export(float, 20, 8000, 5) var freq = 440.0
+# toggle between playing a waveform or an instrument
+export(bool) var play_instrument = false
# bending the waveform
export(bool) var apply_bend = false
export(Vector2) var phasor_bend = Vector2(0.5, 0.5)
@@ -41,34 +43,35 @@ func _fill_buffer() -> void:
# playback stream buffer
playback.push_buffer(synth.frames(to_fill))
-#func _check_waveform():
- #if waveform == "square":
- #synth.square()
- #elif waveform == "sine":
- #synth.sine()
- #elif waveform == "triangle":
- #synth.triangle()
- #elif waveform == "sawtooth":
- #synth.sawtooth()
- #elif waveform == "white_noise":
- #synth.white_noise()
- #elif waveform == "brown_noise":
- #synth.brown_noise()
+func _check_waveform():
+ if waveform == "square":
+ synth.square()
+ elif waveform == "sine":
+ synth.sine()
+ elif waveform == "triangle":
+ synth.triangle()
+ elif waveform == "sawtooth":
+ synth.sawtooth()
+ elif waveform == "white_noise":
+ synth.white_noise()
+ elif waveform == "brown_noise":
+ synth.brown_noise()
func _process(_delta):
if self.is_playing():
-# synth.apply_bend(apply_bend)
-# synth.frequency(freq)
-# synth.phasor_bend(phasor_bend)
+ synth.apply_bend(apply_bend)
+ synth.frequency(freq)
+ synth.phasor_bend(phasor_bend)
synth.frequency_modulation(frequency_modulation)
-# synth.fm_frequency(fm_multiplier * freq)
+ synth.fm_frequency(fm_multiplier * freq)
synth.fm_depth(fm_index)
synth.continuous(continuous)
synth.set_attack(attack)
synth.set_decay(decay)
synth.set_sustain(sustain)
synth.set_release(release)
- # _check_waveform()
+ synth.play_instrument(play_instrument)
+ _check_waveform()
_fill_buffer()
func _ready() -> void:
@@ -79,7 +82,7 @@ func _ready() -> void:
# get our AudioStreamPlayback object
playback = self.get_stream_playback()
# prefill the stream's sample buffer (which feeds DAC)
- #_check_waveform()
+ _check_waveform()
_fill_buffer()
func _input(event):
@@ -89,7 +92,7 @@ func _input(event):
synth.trigger()
elif event is InputEventMouseMotion:
freq = event.position.x
- # synth.frequency(freq)
+ synth.frequency(freq)
# phasor_bend.x = event.position.x / 1024
# phasor_bend.y = event.position.y / 600
fm_multiplier = 600 / (event.position.y + 1)
diff --git a/klangfarbrs/src/instrument.rs b/klangfarbrs/src/instrument.rs
index bf08fe4..6fc797b 100644
--- a/klangfarbrs/src/instrument.rs
+++ b/klangfarbrs/src/instrument.rs
@@ -2,6 +2,7 @@ use super::{ Partial, Sample, Hz, SamplesPerSecond };
pub struct Instrument {
pub partials: Vec<Partial>,
+ pub complete: bool,
}
impl Instrument {
@@ -9,7 +10,8 @@ impl Instrument {
Self {
partials: partial_multipliers.iter()
.map(|&p| Partial::new(1.0, 1.0, p, 0.0, sample_rate, 2000, base_freq))
- .collect()
+ .collect(),
+ complete: false,
}
}
@@ -32,6 +34,7 @@ impl Iterator for Instrument {
.map(|i| i.unwrap()).collect();
if filtered.is_empty() {
+ self.complete = true;
None
} else {
Some(filtered.iter().sum())
diff --git a/klangfarbrs/src/lib.rs b/klangfarbrs/src/lib.rs
index b0b9dc1..e60e7b3 100644
--- a/klangfarbrs/src/lib.rs
+++ b/klangfarbrs/src/lib.rs
@@ -41,11 +41,13 @@ type Millisecond = u32;
#[derive(NativeClass)]
#[inherit(Node)]
pub struct MonoSynth {
+ pub osc: Osc,
pub instrument: Instrument,
pub sample_rate: SamplesPerSecond,
pub frequency: Hz,
pub apply_bend: bool,
pub phasor_bend: Vector2,
+ pub play_instrument: bool,
pub continuous: bool,
pub duration: Millisecond,
// ADSR amplifier
@@ -75,15 +77,17 @@ impl MonoSynth {
/// wave.square() # changes to a square wave
/// ```
pub fn new(_owner: &Node) -> Self {
- let freq = 440.0;
+ let freq = 220.0;
let sprt = 48000.0;
Self {
- instrument: Instrument::new(freq, vec![1.0, 0.909], sprt),
+ osc: Osc::new(freq, sprt),
+ instrument: Instrument::new(freq, vec![0.56, 0.92, 1.19, 1.7, 2.0, 2.74, 3.0, 3.76, 4.07], sprt),
sample_rate: sprt,
frequency: freq,
apply_bend: false,
phasor_bend: Vector2::new(0.0, 0.0),
+ play_instrument: false,
continuous: true,
duration: 0,
envelope: Envelope::new(30, 500, 0.5, 1000, sprt),
@@ -104,41 +108,41 @@ impl MonoSynth {
godot_print!("DAS IST KLANGFARBRS.")
}
- // #[export]
- // fn sine(&mut self, _owner: &Node) {
- // self.osc.waveform = Waveform::Sine
- // }
+ #[export]
+ fn sine(&mut self, _owner: &Node) {
+ self.osc.waveform = Waveform::Sine
+ }
- // #[export]
- // fn square(&mut self, _owner: &Node) {
- // self.osc.waveform = Waveform::Square
- // }
+ #[export]
+ fn square(&mut self, _owner: &Node) {
+ self.osc.waveform = Waveform::Square
+ }
- // #[export]
- // fn triangle(&mut self, _owner: &Node) {
- // self.osc.waveform = Waveform::Triangle
- // }
+ #[export]
+ fn triangle(&mut self, _owner: &Node) {
+ self.osc.waveform = Waveform::Triangle
+ }
- // #[export]
- // fn sawtooth(&mut self, _owner: &Node) {
- // self.osc.waveform = Waveform::Sawtooth
- // }
+ #[export]
+ fn sawtooth(&mut self, _owner: &Node) {
+ self.osc.waveform = Waveform::Sawtooth
+ }
- // #[export]
- // fn white_noise(&mut self, _owner: &Node) {
- // self.osc.waveform = Waveform::WhiteNoise
- // }
+ #[export]
+ fn white_noise(&mut self, _owner: &Node) {
+ self.osc.waveform = Waveform::WhiteNoise
+ }
- // #[export]
- // fn brown_noise(&mut self, _owner: &Node) {
- // self.osc.waveform = Waveform::BrownNoise
- // }
+ #[export]
+ fn brown_noise(&mut self, _owner: &Node) {
+ self.osc.waveform = Waveform::BrownNoise
+ }
- // #[export]
- // fn frequency(&mut self, _owner: &Node, frequency: Hz) {
- // self.frequency = frequency;
- // self.osc.set_frequency(frequency)
- // }
+ #[export]
+ fn frequency(&mut self, _owner: &Node, frequency: Hz) {
+ self.frequency = frequency;
+ self.osc.set_frequency(frequency)
+ }
#[export]
fn continuous(&mut self, _owner: &Node, state: bool) {
@@ -146,6 +150,11 @@ impl MonoSynth {
}
#[export]
+ fn play_instrument(&mut self, _owner: &Node, state: bool) {
+ self.play_instrument = state;
+ }
+
+ #[export]
fn phasor_bend(&mut self, _owner: &Node, phasor_bend: Vector2) {
self.phasor_bend = phasor_bend
}
@@ -206,7 +215,7 @@ impl MonoSynth {
#[export]
fn trigger(&mut self, _owner: &Node,
) {
- ()
+ self.envelope = Envelope::new(self.attack, self.decay, self.sustain, self.release, self.sample_rate);
}
#[export]
@@ -221,8 +230,11 @@ impl MonoSynth {
// self.osc.set_frequency(self.osc.get_frequency() + modulation_value);
// }
- let mut sample = self.instrument.sample();
- // self.osc.last_value = sample;
+ let mut sample = match self.play_instrument {
+ true => self.instrument.sample(),
+ false => self.osc.sample(),
+ };
+ self.osc.last_value = sample;
// TODO:
// if self.apply_bend {
@@ -238,6 +250,11 @@ impl MonoSynth {
}
}
+ // TODO: For now this enables the instrument to be played multiple times. Would like to find a cleaner way to do this.
+ if self.instrument.complete {
+ self.instrument = Instrument::new(self.frequency, vec![0.56, 0.92, 1.19, 1.7, 2.0, 2.74, 3.0, 3.76, 4.07], self.sample_rate)
+ }
+
frames.push(Vector2::new(sample, sample));
}