bevy_fundsp 0.2.0

A Bevy plugin that integrates FunDSP into Bevy.
Documentation
#![allow(clippy::precedence)]

use bevy::prelude::*;
use bevy_fundsp::{dsp_source, prelude::*};
use bevy_oddio::{frames::Stereo, output::AudioSink, Audio, AudioPlugin};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(AudioPlugin)
        .add_plugin(DspPlugin::default())
        .add_dsp_source(sine_wave, SourceType::Dynamic)
        .add_startup_system_to_stage(StartupStage::PostStartup, play_sine)
        .add_system(change_pitch)
        .run();
}

const FREQUENCY_ID: i64 = 0;

fn sine_wave() -> impl AudioUnit32 {
    tag(FREQUENCY_ID, 440.0) >> sine() >> split::<U2>() * 0.2
}

#[derive(Resource)]
struct SineSink(Handle<AudioSink<DspSource>>);

fn play_sine(
    mut assets: ResMut<Assets<DspSource>>,
    dsp_manager: Res<DspManager>,
    mut audio: ResMut<Audio<Stereo, DspSource>>,
    mut commands: Commands,
) {
    let source = dsp_manager
        .get_graph(sine_wave)
        .unwrap_or_else(|| panic!("DSP source not found!"));
    let sink = audio.play_dsp(assets.as_mut(), source);
    commands.insert_resource(SineSink(sink));
}

fn change_pitch(
    sink: Res<SineSink>,
    mut assets: ResMut<Assets<AudioSink<DspSource>>>,
    time: Res<Time>,
) {
    if let Some(sink) = assets.get_mut(&sink.0) {
        let exp = time.elapsed_seconds_wrapped_f64().sin();
        let pitch_hz = 2.0.pow(exp) * 440.0;

        sink.control::<dsp_source::Iter, _>()
            .set(FREQUENCY_ID, pitch_hz);
    }
}