BytorioGet started

Source reference

examples/resources/synthesis/odin/main.odin

package main

import audio "sdk:audio"
import byt "sdk:bytorio"
import data "sdk:data"

tone: audio.Instrument
tone_pitch: f32 = 440
tone_cutoff: f32 = 1200
tone_wave: f32 = 0.25

init :: proc() {
    pcm := data.pcm(64, 1)
    defer data.free_pcm(&pcm)
    for &value, i in pcm.samples {
        phase := f32(i % 32) / 32
        value = phase * 2 - 1 if i < 32 else (1 if i % 32 < 16 else -1)
    }
    wave := audio.wavetable({32, 2}, pcm)
    notes := []audio.Node {
        {kind = .Wavetable, source = wave},
        {kind = .Wavetable, source = wave, frequency_hz = 110},
        {kind = .LFO, frequency_hz = 5},
        {kind = .ADSR, attack_frames = 16, decay_frames = 32, sustain = 0.5, release_frames = 64},
        {
            kind            = .Wavetable,
            source          = wave,
            wave            = 0.25,
            frequency_input = 1,
            fm_depth_hz     = 80,
            phase_input     = 2,
            pm_depth_cycles = 0.03,
        },
        {kind = .Mix, input = 0, other = 4, gain = 0.4, secondary_gain = 0.6},
        {kind = .Gain, input = 5, gain = 0, gain_input = 3, depth = 0.2},
        {kind = .Filter, input = 6, cutoff_hz = 1200, resonance = 0.2},
        {
            kind             = .Delay,
            input            = 7,
            max_delay_frames = 128,
            delay_frames     = 64,
            feedback         = 0.25,
            wet              = 0.35,
        },
        {kind = .Pan, input = 8, pan = -0.2},
        {kind = .Output, input = 9},
    }
    instrument := audio.instrument(notes)
    tone = instrument
    noise := audio.instrument([]audio.Node {
        {kind = .Noise, seed = 1234567},
        {kind = .ADSR, attack_frames = 4, decay_frames = 8, sustain = 0.25, release_frames = 32},
        {kind = .Gain, input = 0, gain = 0, gain_input = 1, depth = 0.08},
        {kind = .Filter, input = 2, cutoff_hz = 5000, resonance = 0.1, filter_mode = .Highpass},
        {kind = .Output, input = 3},
    })
    bus := audio.bus({gain = 0.8})
    audio.effects(bus, []audio.Node {
        {kind = .Input},
        {
            kind             = .Delay,
            input            = 0,
            max_delay_frames = 256,
            delay_frames     = 96,
            feedback         = 0.3,
            wet              = 0.25,
        },
        {kind = .Filter, input = 1, cutoff_hz = 6000},
        {kind = .Output, input = 2},
    })
    v := audio.voice(0)
    audio.note_on(v, instrument, 440, {bus = bus, velocity = 0.8})
    audio.note_on(audio.voice(1), noise, 440, {bus = bus, at = 64})
    audio.node_control(v, instrument, 4, .Wave, 1, 128, 64)
    audio.node_control(v, instrument, 7, .Cutoff, 2400, 256, 128)
    audio.effect_control(bus, 1, .Feedback, 0.1, 320, 32)
    patch := data.pcm(8, 1)
    defer data.free_pcm(&patch)
    for &value in patch.samples { value = 0.25 }
    audio.edit_wavetable(wave, 4, patch, 512)
    audio.note_off(audio.voice(1), 640)
    audio.note_off(v, 1024)
    // A sustained third note proves independent state and producer-stall survival.
    audio.note_on(audio.voice(2), instrument, 220, {at = 1200, velocity = 0.3})
    audio.node_control(audio.voice(2), instrument, 8, .Wet, 0.8, 1600, 128)
    sample_pcm := data.pcm(8, 1)
    defer data.free_pcm(&sample_pcm)
    copy(sample_pcm.samples, []f32{0, 0.25, 0.5, 0.75, 1, 0.75, 0.5, 0.25})
    sample := audio.sample({8, 1, 24000}, sample_pcm)
    sample_instrument := audio.instrument([]audio.Node {
        {kind = .Sample, source = sample, loop = true, loop_end = 8},
        {kind = .Gain, input = 0, gain = 0.05},
        {kind = .Pan, input = 1, pan = 0.4},
        {kind = .Output, input = 2},
    })
    audio.note_on(audio.voice(3), sample_instrument, 440, {at = 96})
    sample_patch := data.pcm(1, 1)
    defer data.free_pcm(&sample_patch)
    sample_patch.samples[0] = -0.5
    audio.edit_sample(sample, 0, sample_patch, 800)
    audio.note_off(audio.voice(3), 1800)
    cancelled_pcm := data.pcm(2, 1)
    defer data.free_pcm(&cancelled_pcm)
    for &value in cancelled_pcm.samples { value = 0.5 }
    cancelled := audio.sample({2, 1, 48000}, cancelled_pcm)
    audio.edit_sample(cancelled, 0, cancelled_pcm)
    audio.play_sample(audio.voice(4), cancelled, {at = 2000})
    audio.destroy(cancelled)
    for &value in pcm.samples { value = 0 }
}
update :: proc(dt: f64) {
    if byt.pressed(.Left) { tone_pitch = max(110, tone_pitch / 2) }
    if byt.pressed(.Right) { tone_pitch = min(1760, tone_pitch * 2) }
    if byt.pressed(.Up) { tone_cutoff = min(12000, tone_cutoff + 400) }
    if byt.pressed(.Down) { tone_cutoff = max(200, tone_cutoff - 400) }
    if byt.pressed(.Action) { tone_wave = 1 - tone_wave }
    v := audio.voice(2)
    if byt.pressed(.Left) || byt.pressed(.Right) {
        audio.node_control(v, tone, 0, .Frequency, tone_pitch, audio.ASAP, 64)
        audio.node_control(v, tone, 4, .Frequency, tone_pitch, audio.ASAP, 64)
    }
    if byt.pressed(.Up) ||
       byt.pressed(.Down) { audio.node_control(v, tone, 7, .Cutoff, tone_cutoff, audio.ASAP, 64) }
    if byt.pressed(.Action) { audio.node_control(v, tone, 4, .Wave, tone_wave, audio.ASAP, 64) }
    status := audio.status()
    _, count := audio.completions()
    byt.debug_position(f64(status.completed), f64(count))
}
draw :: proc() {
    byt.clear(byt.rgb(20, 28, 44))
    byt.text("SYNTH: FM / ENVELOPE / FILTER / DELAY", 12, 20, byt.rgb(240, 240, 240))
    byt.rect(24, 48, 272, 40, byt.rgb(70, 180, 150))
    byt.rect(24, 92, int(tone_pitch / 8), 6, byt.rgb(240, 200, 80))
    byt.text("LEFT/RIGHT PITCH  UP/DOWN FILTER", 12, 110, byt.rgb(240, 240, 240))
    byt.text("SPACE: MORPH WAVE", 12, 126, byt.rgb(240, 240, 240))
}