use std::sync::Arc; use cpal::{ traits::{DeviceTrait, HostTrait, StreamTrait}, SampleRate, Stream, }; use fundsp::prelude::*; use oddio::{Frames, FramesSignal, Gain, Handle, Mixer, MonoToStereo, Stop}; use super::sound_effects::{SoundEffect, SoundType}; pub type SoundSamples = Arc>; pub type SoundEffectHandle = Handle>>>>; pub struct SoundOutput { mixer_handle: Handle>, sample_rate: SampleRate, _stream: Stream, } impl Default for SoundOutput { fn default() -> Self { Self::new() } } impl SoundOutput { pub fn new() -> Self { let host = cpal::default_host(); let device = host .default_output_device() .expect("no output device available"); let sample_rate = device.default_output_config().unwrap().sample_rate(); let config = cpal::StreamConfig { channels: 2, sample_rate, buffer_size: cpal::BufferSize::Default, }; let (mixer_handle, mixer) = oddio::split(oddio::Mixer::new()); let stream = device .build_output_stream( &config, move |out_flat: &mut [f32], _: &cpal::OutputCallbackInfo| { let out_stereo: &mut [[f32; 2]] = oddio::frame_stereo(out_flat); oddio::run(&mixer, sample_rate.0, out_stereo); }, move |err| { eprintln!("{}", err); }, ) .unwrap(); stream.play().unwrap(); Self { mixer_handle, sample_rate, _stream: stream, } } pub fn render_sound_effect(&self, effect: &SoundEffect) -> SoundSamples { let effect_buffer: Vec = effect .sounds .iter() .flat_map(|sound| match sound.sound_type { SoundType::Silence => (0 ..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) .map(|_| 0f32) .collect::>(), SoundType::Tone(freq) => { let mut c = square_hz(freq as f32); c.reset(Some(self.sample_rate.0 as f64)); (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) .map(|_| c.get_mono()) .collect::>() } SoundType::Sweep(start_freq, end_freq) => { let mut c = lfo(|t| { lerp( start_freq as f32, end_freq as f32, t * sound.duration.as_secs_f32(), ) }) >> square(); c.reset(Some(self.sample_rate.0 as f64)); (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) .map(|_| c.get_mono()) .collect::>() } SoundType::Noise(min, max) => { let mut c = (((white() + dc(1.0)) * dc(max as f32 / 2.0)) + dc(min as f32)) >> square(); (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize) .map(|_| c.get_mono()) .collect::>() } }) .collect(); oddio::Frames::from_iter(self.sample_rate.0, effect_buffer.iter().copied()) } pub fn play_sound(&mut self, samples: SoundSamples) -> SoundEffectHandle { self.mixer_handle .control::, _>() .play(oddio::MonoToStereo::new(oddio::Gain::new( oddio::FramesSignal::from(samples), 0.50, ))) } }