#![allow(unused_imports, dead_code)]
use fluffl::{
audio::*,
console::*,
io::*,
math::FP64,
prelude::*,
text_writer::*,
window::{event_util::*, *},
*,
};
use std::collections::*;
fn sinf32(t: f32) -> f32 {
(2.0 * std::f32::consts::PI * t).sin() * 0.2
}
pub struct SoundWave {
frequency: f32,
wave: fn(f32) -> f32,
interval: (f32, f32),
attack_time: f32,
release_time: f32,
}
impl SoundWave {
pub fn new(wave: fn(f32) -> f32, frequency: f32, interval: (f32, f32)) -> Self {
let smoothing_length = (interval.0 - interval.1).abs();
Self {
frequency,
wave,
interval,
attack_time: smoothing_length * 0.05,
release_time: smoothing_length * 0.02,
}
}
pub fn evaluate(&self, time: f32) -> f32 {
let to_seconds = 1.0 / 1000.0;
let interval_lo = self.interval.0 * to_seconds;
let interval_hi = self.interval.1 * to_seconds;
let attack_dt = self.attack_time * to_seconds;
let release_dt = self.release_time * to_seconds;
let frequency = self.frequency;
let wave = self.wave;
let linear_t = |x: f32, e0: f32, e1: f32| -> f32 { ((x - e0) / (e1 - e0)).clamp(0.0, 1.0) };
let attack_t = linear_t(time, interval_lo, interval_lo + attack_dt);
let release_t = linear_t(time, interval_lo - release_dt, interval_hi);
let attack_coef = 1.0 - (1.0 - attack_t).powf(2.0);
let release_coef = 1.0 - (release_t * release_t);
attack_coef * wave(frequency * time) * release_coef
}
}
pub struct AudioState {
pub channels: u32,
pub frequency: u32,
pub t: f64,
pub amplitude: f32,
pub sound_waves: VecDeque<SoundWave>,
}
impl AudioState {
pub fn new<CB>(mut init: CB) -> Self
where
CB: FnMut(&mut Self),
{
let mut state = Self {
channels: 0,
frequency: 0,
t: 0.0,
amplitude: 1.0,
sound_waves: vec![].into_iter().collect(),
};
init(&mut state);
state
}
}
#[allow(clippy::identity_op)]
fn synth_callback_cb(state: &mut AudioState, output: &mut [f32]) {
let conversion_factor_sec = 1.0 / state.frequency as f64;
let conversion_factor_ms = 1000.0 * conversion_factor_sec;
for samp_idx in 0..output.len() / 2 {
let mut dst = 0.0;
let time_in_ms = (state.t * conversion_factor_ms) as f32;
let time_in_seconds = state.t * conversion_factor_sec;
let is_in_bounds = |wave: &&SoundWave| {
time_in_ms > (wave.interval.0 + -1.0) && time_in_ms < (wave.interval.1 + 1.0)
};
for wave in state.sound_waves.iter().filter(is_in_bounds) {
dst += wave.evaluate(time_in_seconds as f32);
}
output[2 * samp_idx + 0] = dst;
output[2 * samp_idx + 1] = dst;
state.t += 1.0;
}
}
type ShortState = AudioState;
type ShortDeviceCB = fn(&mut ShortState, &mut [f32]);
type ShortDeviceContext = FlufflAudioDeviceContext<ShortDeviceCB, ShortState>;
#[fluffl(Debug)]
pub async fn main() {
unimplemented!("example is in construction");
}