Skip to content

Commit

Permalink
Ramp node.
Browse files Browse the repository at this point in the history
  • Loading branch information
SamiPerttu committed Sep 5, 2024
1 parent 3ae8d08 commit 0222d25
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Feedback biquads and dirty biquads by Jatin Chowdhury.
- Sine oscillator has now generic inner state. To migrate, use
`Sine<f32>` if speed is important or `Sine<f64>` if steady maintenance of phase is important.
- Non-bandlimited ramp node with opcodes `ramp`, `ramp_hz`, `ramp_phase` and `ramp_hz_phase`.

### Version 0.18.2

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,10 @@ The type parameters in the table refer to the hacker preludes.
| `pluck(f, gain, damping)` | 1 (excitation) | 1 | [Karplus-Strong](https://en.wikipedia.org/wiki/Karplus%E2%80%93Strong_string_synthesis) plucked string oscillator with frequency `f` Hz, `gain` per second (`gain` <= 1) and high frequency `damping` in 0...1. |
| `product(x, y)` | `x + y` | `x = y` | Multiply nodes `x` and `y`. Same as `x * y`. |
| `pulse()` | 2 (frequency, duty cycle) | 1 | Bandlimited pulse wave with duty cycle in 0...1. |
| `ramp()` | 1 (frequency) | 1 | Non-bandlimited ramp (sawtooth) wave in 0...1. |
| `ramp_hz(f)` | 0 | 1 | Non-bandlimited ramp (sawtooth) wave in 0...1 with frequency `f` Hz. |
| `ramp_phase(phase)` | 1 (frequency) | 1 | Non-bandlimited ramp (sawtooth) wave in 0...1 with initial `phase` in 0...1. |
| `ramp_hz_phase(f, phase)` | 0 | 1 | Non-bandlimited ramp (sawtooth) wave in 0...1 with frequency `f` Hz and initial `phase` in 0...1. |
| `resample(node)` | 1 (speed) | `node` | Resample generator `node` using cubic interpolation at speed obtained from the input, where 1 is the original speed. |
| `resonator()` | 3 (audio, frequency, Q) | 1 | Constant-gain bandpass resonator (2nd order). |
| `resonator_hz(f, q)` | 1 | 1 | Constant-gain bandpass resonator (2nd order) with center frequency `f` Hz and Q `q`. |
Expand Down
26 changes: 26 additions & 0 deletions src/hacker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,32 @@ pub fn sine_phase(phase: f32) -> An<Sine<f64>> {
An(Sine::with_phase(phase))
}

/// Ramp generator with output in 0...1. Not bandlimited.
/// - Input 0: repetition frequency (Hz)
/// - Output 0: ramp phase in 0...1
pub fn ramp() -> An<Ramp<f64>> {
An(Ramp::new())
}

/// Ramp generator with output in 0...1 at fixed frequency `f` Hz.
/// - Output 0: ramp phase in 0...1
pub fn ramp_hz(f: f32) -> An<Pipe<Constant<U1>, Ramp<f64>>> {
constant(f) >> ramp()
}

/// Ramp generator with output in 0...1, starting from initial phase `phase` in 0...1.
/// - Input 0: repetition frequency (Hz)
/// - Output 0: ramp phase in 0...1
pub fn ramp_phase(phase: f32) -> An<Ramp<f64>> {
An(Ramp::with_phase(phase))
}

/// Ramp generator with output in 0...1 at fixed frequency `f` Hz.
/// - Output 0: ramp phase in 0...1
pub fn ramp_hz_phase(f: f32, phase: f32) -> An<Pipe<Constant<U1>, Ramp<f64>>> {
constant(f) >> ramp_phase(phase)
}

/// Rossler dynamical system oscillator.
/// - Input 0: frequency. The Rossler oscillator exhibits peaks at multiples of this frequency.
/// - Output 0: system output
Expand Down
26 changes: 26 additions & 0 deletions src/hacker32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,32 @@ pub fn sine_phase(phase: f32) -> An<Sine<f32>> {
An(Sine::with_phase(phase))
}

/// Ramp generator with output in 0...1. Not bandlimited.
/// - Input 0: repetition frequency (Hz)
/// - Output 0: ramp phase in 0...1
pub fn ramp() -> An<Ramp<f32>> {
An(Ramp::new())
}

/// Ramp generator with output in 0...1 at fixed frequency `f` Hz.
/// - Output 0: ramp phase in 0...1
pub fn ramp_hz(f: f32) -> An<Pipe<Constant<U1>, Ramp<f32>>> {
constant(f) >> ramp()
}

/// Ramp generator with output in 0...1, starting from initial phase `phase` in 0...1.
/// - Input 0: repetition frequency (Hz)
/// - Output 0: ramp phase in 0...1
pub fn ramp_phase(phase: f32) -> An<Ramp<f32>> {
An(Ramp::with_phase(phase))
}

/// Ramp generator with output in 0...1 at fixed frequency `f` Hz.
/// - Output 0: ramp phase in 0...1
pub fn ramp_hz_phase(f: f32, phase: f32) -> An<Pipe<Constant<U1>, Ramp<f32>>> {
constant(f) >> ramp_phase(phase)
}

/// Rossler dynamical system oscillator.
/// - Input 0: frequency. The Rossler oscillator exhibits peaks at multiples of this frequency.
/// - Output 0: system output
Expand Down
77 changes: 72 additions & 5 deletions src/oscillator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl<F: Real> AudioNode for Sine<F> {
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
super::signal::Routing::Generator(0.0).route(input, self.outputs())
super::signal::Routing::Arbitrary(0.0).route(input, self.outputs())
}
}

Expand Down Expand Up @@ -190,7 +190,7 @@ impl<N: Size<f32>> AudioNode for Dsf<N> {
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
super::signal::Routing::Generator(0.0).route(input, self.outputs())
super::signal::Routing::Arbitrary(0.0).route(input, self.outputs())
}
}

Expand Down Expand Up @@ -293,7 +293,7 @@ impl AudioNode for Pluck {
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
super::signal::Routing::Generator(0.0).route(input, self.outputs())
super::signal::Routing::Arbitrary(0.0).route(input, self.outputs())
}

fn allocate(&mut self) {
Expand Down Expand Up @@ -358,7 +358,7 @@ impl AudioNode for Rossler {
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
super::signal::Routing::Generator(0.0).route(input, self.outputs())
super::signal::Routing::Arbitrary(0.0).route(input, self.outputs())
}
}

Expand Down Expand Up @@ -417,6 +417,73 @@ impl AudioNode for Lorenz {
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
super::signal::Routing::Generator(0.0).route(input, self.outputs())
super::signal::Routing::Arbitrary(0.0).route(input, self.outputs())
}
}

/// Ascending ramp generator with output in 0...1. Not bandlimited.
/// - Input 0: repetition frequency in Hz.
/// - Output 0: current phase in 0...1.
#[derive(Default, Clone)]
pub struct Ramp<F: Float> {
phase: F,
sample_duration: F,
hash: u64,
initial_phase: Option<F>,
}

impl<F: Float> Ramp<F> {
/// Create ramp generator.
pub fn new() -> Self {
let mut ramp = Self::default();
ramp.reset();
ramp.set_sample_rate(DEFAULT_SR);
ramp
}
/// Create ramp generator with initial phase in 0...1.
pub fn with_phase(initial_phase: f32) -> Self {
let mut ramp = Self {
phase: F::zero(),
sample_duration: F::zero(),
hash: 0,
initial_phase: Some(F::from_f32(initial_phase)),
};
ramp.reset();
ramp.set_sample_rate(DEFAULT_SR);
ramp
}
}

impl<F: Float> AudioNode for Ramp<F> {
const ID: u64 = 21;
type Inputs = typenum::U1;
type Outputs = typenum::U1;

fn reset(&mut self) {
self.phase = match self.initial_phase {
Some(phase) => phase,
None => convert(rnd1(self.hash)),
};
}

fn set_sample_rate(&mut self, sample_rate: f64) {
self.sample_duration = convert(1.0 / sample_rate);
}

#[inline]
fn tick(&mut self, input: &Frame<f32, Self::Inputs>) -> Frame<f32, Self::Outputs> {
let phase = self.phase.to_f32();
self.phase += F::from_f32(input[0]) * self.sample_duration;
self.phase -= self.phase.floor();
[phase].into()
}

fn set_hash(&mut self, hash: u64) {
self.hash = hash;
self.reset();
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
super::signal::Routing::Arbitrary(0.0).route(input, self.outputs())
}
}
26 changes: 26 additions & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,32 @@ pub fn sine_phase<F: Real>(phase: f32) -> An<Sine<F>> {
An(Sine::with_phase(phase))
}

/// Ramp generator with output in 0...1. Not bandlimited.
/// - Input 0: repetition frequency (Hz)
/// - Output 0: ramp phase in 0...1
pub fn ramp<F: Float>() -> An<Ramp<F>> {
An(Ramp::new())
}

/// Ramp generator with output in 0...1 at fixed frequency `f` Hz.
/// - Output 0: ramp phase in 0...1
pub fn ramp_hz<F: Float>(f: f32) -> An<Pipe<Constant<U1>, Ramp<F>>> {
constant(f) >> ramp()
}

/// Ramp generator with output in 0...1, starting from initial phase `phase` in 0...1.
/// - Input 0: repetition frequency (Hz)
/// - Output 0: ramp phase in 0...1
pub fn ramp_phase<F: Float>(phase: f32) -> An<Ramp<F>> {
An(Ramp::with_phase(phase))
}

/// Ramp generator with output in 0...1 at fixed frequency `f` Hz.
/// - Output 0: ramp phase in 0...1
pub fn ramp_hz_phase<F: Float>(f: f32, phase: f32) -> An<Pipe<Constant<U1>, Ramp<F>>> {
constant(f) >> ramp_phase(phase)
}

/// Rossler dynamical system oscillator.
/// - Input 0: frequency. The Rossler oscillator exhibits peaks at multiples of this frequency.
/// - Output 0: system output
Expand Down
4 changes: 2 additions & 2 deletions src/wavetable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ where
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
Routing::Generator(0.0).route(input, self.outputs())
Routing::Arbitrary(0.0).route(input, self.outputs())
}
}

Expand Down Expand Up @@ -423,7 +423,7 @@ impl AudioNode for PhaseSynth {
}

fn route(&mut self, input: &SignalFrame, _frequency: f64) -> SignalFrame {
Routing::Generator(0.0).route(input, self.outputs())
Routing::Arbitrary(0.0).route(input, self.outputs())
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/test_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ fn test_basic() {
noise() >> fresonator_hz(Atan(0.5), 500.0, 50.0)
| noise() >> fhighpass_hz(Softsign(0.2), 2000.0, 2.0),
);
check_wave(dc(440.0) >> ramp() | dc(-220.0) >> ramp_phase(0.0));

check_wave_big(Box::new(dc((110.0, 0.5)) >> pulse() * 0.2 >> delay(0.1)));
check_wave_big(Box::new(envelope(|t| exp(-t * 10.0))));
Expand Down

0 comments on commit 0222d25

Please sign in to comment.