goofi v3.0.0

Osc

An oscillator in [-1, 1], one channel per channel of `pitch`.

Osc rs
out
Type name
audio:Osc
Plane
audio
Tags
generator
Language
rust
Tier
native
Bundle
audio
Source
node-bundles/audio/Osc.rs
Availability
available

Slots

SlotDirectionType
outoutputAUDIO

Parameters

osc

NameTypeDefaultRangeDoc
pitchfloat0.75-10 … 10volts per octave, 0 at C4 (0.75 is A4); an audio reference is one voice per channel
waveformstringsinesine | triangle | sawtooth | squarethe shape one cycle traces, from the roundest to the brightest

Source

The current source of this node, as it stands in the goofi repository at node-bundles/audio/Osc.rs.

node-bundles/audio/Osc.rs
use goofi_audio_sdk::goofi_core::SlotType;
use goofi_audio_sdk::{hz_of, AudioNode, Block, Manifest, OutputDecl, ParamDecl, ParamSpec, Lanes, Tag, BLOCK};

goofi_audio_sdk::params! {
    PITCH = ParamDecl {
        group: "osc",
        name: "pitch",
        spec: ParamSpec::Float { default: 0.75, min: -10.0, max: 10.0 },
        expression: None,
        doc: Some("volts per octave, 0 at C4 (0.75 is A4); an audio reference is one voice per channel"),
        section: 0,
        show: None,
    },
    WAVEFORM = ParamDecl {
        group: "osc",
        name: "waveform",
        spec: ParamSpec::Str {
            default: "sine",
            options: &["sine", "triangle", "sawtooth", "square"],
            refresh: false,
        },
        expression: None,
        doc: Some("the shape one cycle traces, from the roundest to the brightest"),
        section: 0,
        show: None,
    },
}

static OUTS: &[OutputDecl] = &[OutputDecl { name: "out", kind: SlotType::Audio }];

static MANIFEST: Manifest = Manifest {
    tags: &[Tag::Generator],
    doc: "An oscillator in [-1, 1], one channel per channel of `pitch`.",
    inputs: &[],
    outputs: OUTS,
    params: PARAMS,
};

#[derive(Default)]
struct Osc {
    phase: Lanes<f32>,
    step: f32,
}

impl AudioNode for Osc {
    fn prepare(&mut self, rate: f64) {
        self.step = 1.0 / rate as f32;
    }

    fn process(&mut self, b: &mut Block<'_>) {
        let pitch = &b.params[P::PITCH];
        let waveform = b.params[P::WAVEFORM].chan(0)[0] as u8;
        let out = &mut b.outs[0];
        let width = out.channels() as usize;
        let phases = self.phase.fit(width);
        for (c, phase) in phases.iter_mut().enumerate() {
            let p = pitch.chan(c);
            let samples = out.chan_mut(c);
            for i in 0..BLOCK {
                samples[i] = match waveform {
                    1 => 1.0 - 4.0 * (*phase - 0.5).abs(),
                    2 => 2.0 * *phase - 1.0,
                    3 => if *phase < 0.5 { 1.0 } else { -1.0 },
                    _ => (std::f32::consts::TAU * *phase).sin(),
                };
                *phase = (*phase + hz_of(p[i]) * self.step).fract();
            }
        }
    }
}

goofi_audio_sdk::export!(Osc, MANIFEST);

← All nodes