use rodio;
use rodio::buffer::SamplesBuffer;
use rodio::source;
use rodio::OutputStream;
use rodio::OutputStreamHandle;
use rodio::Sink;
use rodio::Source;
use std::f32::consts::PI;
use std::time::Duration;
use rand::random;
pub enum Wave {
Sine,
Square,
Saw,
Noise,
}
pub struct Audact {
_output_stream: OutputStream,
output_stream_handle: OutputStreamHandle,
channels: Vec<Channel>,
steps: i32,
sample_rate: u32,
total_samples_needed: f32,
}
struct Channel {
sink: Sink,
source: Vec<f32>,
processing: Processing,
}
#[derive(Builder, Clone, Copy)]
#[builder(default)]
pub struct Processing {
gain: f32,
filter: (f32, f32),
attack: Duration,
reverb: (Duration, f32),
}
impl Default for Processing {
fn default() -> Self {
Processing {
gain: 1f32,
filter: (0f32, 5000f32),
attack: Duration::from_millis(0u64),
reverb: (Duration::from_millis(0), 0f32),
}
}
}
impl Audact {
pub fn new(steps: i32, bpm: i32, per_bar: f32) -> Audact {
let (_output_stream, output_stream_handle) = OutputStream::try_default().unwrap();
let sample_rate = 44100f32;
let bpm_duration =
Duration::from_millis((((60f32 / bpm as f32) * 1000f32) / per_bar) as u64);
let subsecs = bpm_duration.subsec_nanos() as f32 / 100_000_000f32;
let samples_needed =
sample_rate * ((bpm_duration.as_secs() as f32 + subsecs) / 4f32) * 0.8f32;
let total_samples_needed = samples_needed * steps as f32;
Audact {
_output_stream,
output_stream_handle,
channels: Vec::new(),
steps,
sample_rate: sample_rate as u32,
total_samples_needed,
}
}
fn sine_wave(t: f32) -> f32 {
t.sin()
}
fn square_wave(t: f32) -> f32 {
t.sin().round()
}
fn saw_wave(t: f32) -> f32 {
t - t.floor()
}
fn noise_wave(_: f32) -> f32 {
(random::<f32>() * 2f32) - 1f32
}
fn smooth_source(source: &mut Vec<f32>) {
fn smooth(source: &mut Vec<f32>) {
let mut prev_sample = 0f32;
for s in source.iter_mut() {
if *s == 0f32 {
*s = prev_sample * 0.99;
}
prev_sample = *s;
}
}
for _ in 0..2 {
let mut pad = vec![0f32; 1024usize];
source.append(&mut pad);
smooth(source);
source.reverse();
}
}
pub fn channel(&mut self, wave: Wave, volume: f32, processing: Processing, seq: Vec<f32>) {
let sink = Sink::try_new(&self.output_stream_handle).unwrap();
sink.pause();
sink.set_volume(volume);
let sample_rate = self.sample_rate as f32;
let steps = self.steps as f32;
let total_samples_needed = self.total_samples_needed;
let mut source: Vec<f32> = (0u64..self.total_samples_needed as u64)
.map(move |t| {
let s_t = total_samples_needed / t as f32;
let freq = seq[(steps / s_t).floor() as usize];
if freq == 0f32 {
return 0f32;
}
let freq = t as f32 * freq * PI / sample_rate;
match wave {
Wave::Sine => Audact::sine_wave(freq),
Wave::Square => Audact::square_wave(freq),
Wave::Saw => Audact::saw_wave(freq),
Wave::Noise => Audact::noise_wave(freq),
}
})
.collect();
Audact::smooth_source(&mut source);
let channel = Channel {
sink,
source,
processing,
};
self.channels.push(channel);
}
pub fn start(&mut self, bars: i32) {
let tmp_voice_channels = &self.channels;
let sample_rate = self.sample_rate;
for _ in 0..bars {
for chan in tmp_voice_channels {
let samples = chan.source.clone();
let sample_buffer = vec![SamplesBuffer::new(2, sample_rate, samples)];
let source = source::from_iter(sample_buffer)
.buffered()
.fade_in(chan.processing.attack)
.low_pass(chan.processing.filter.1 as u32)
.reverb(chan.processing.reverb.0, chan.processing.reverb.1)
.amplify(chan.processing.gain);
chan.sink.append(source);
}
}
for chan in tmp_voice_channels {
chan.sink.play();
}
for chan in tmp_voice_channels {
chan.sink.sleep_until_end();
}
}
}