//! This file implements an interface for instruments. //! //! An instrument is a type that can produce a `Wave` when given a //! note in semitone, a sample rate, and a duration in beats. use super::*; use std::{ f64::consts::PI, fmt::{self, Display, Formatter}, }; /// The interface of an instrument. pub trait Instrument { /// Produce pulses for a given note, sample rate, and duration. /// /// This will be separately modified to account for the effect of /// attack-decay-sustain-release. See /// [Wikipedia](). fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into; } // Some instruments #[derive(Default)] pub struct Sinus {} impl Display for Sinus { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "the pure sine instrument") } } impl Instrument for Sinus { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; let mut current_adsr = 0f64; for i in 0..nb_samples { current_adsr = adsr(i, nb_samples, current_adsr); let y: f64 = (*volume * f64::sin(theta)) * current_adsr; let y = if y >= 1f64 { 1f64 } else if y <= -1f64 { -1f64 } else { y }; result.push(y.into()); theta += step; } Wave::new(result) } } // Other instruments: tangent, and variations of piano. // Tangent #[derive(Default)] pub struct Tangent {} impl Display for Tangent { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "the pure tangent instrument") } } impl Instrument for Tangent { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; let mut current_adsr = 0f64; for i in 0..nb_samples { current_adsr = adsr(i, nb_samples, current_adsr); let y: f64 = (*volume * f64::tan(theta)) * current_adsr; let y = if y >= 1f64 { 1f64 } else if y <= -1f64 { -1f64 } else { y }; result.push(y.into()); theta += step; } Wave::new(result) } } // Piano Without overtones #[derive(Default)] pub struct PianoWOver {} impl Display for PianoWOver { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "the piano instrument without overtones") } } impl Instrument for PianoWOver { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; let mut current_adsr = 0f64; for i in 0..nb_samples { let mut y = f64::sin(theta); // let mut y = 0.6f64 * f64::sin(theta) + 0.4f64 * f64::sin(2f64 * theta); y *= f64::exp((-0.0035f64) * theta); y += y * y * y; y *= 1f64 + 16f64 * i as f64 * f64::exp((-6f64) * i as f64); y *= *volume; current_adsr = adsr(i, nb_samples, current_adsr); y *= current_adsr; result.push(y.into()); theta += step; } Wave::new(result) } } #[derive(Default)] pub struct PianoVideo {} impl Display for PianoVideo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "the piano instrument that I obtained from a video") } } impl Instrument for PianoVideo { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; let mut current_adsr = 0f64; for i in 0..nb_samples { let mut y = 0.6f64 * f64::sin(theta) + 0.4f64 * f64::sin(2f64 * theta); y *= f64::exp((-0.0015f64) * theta); y += y * y * y; y *= 1f64 + 16f64 * i as f64 * f64::exp((-6f64) * i as f64); y *= *volume; current_adsr = adsr(i, nb_samples, current_adsr); y *= current_adsr; result.push(y.into()); theta += step; } Wave::new(result) } } #[derive(Default)] pub struct PianoStackoverflow {} impl Display for PianoStackoverflow { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, "the piano instrument that I obtained from a stackoverflow answer." ) } } impl Instrument for PianoStackoverflow { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); // dbg!(note); // dbg!(note_h); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; let mut current_adsr = 0f64; for i in 0..nb_samples { let mut y = f64::sin(theta) + (1f64 / 2f64) * f64::sin(2f64 * theta) + (1f64 / 4f64) * f64::sin(3f64 * theta) + (1f64 / 8f64) * f64::sin(4f64 * theta) + (1f64 / 16f64) * f64::sin(5f64 * theta) + (1f64 / 32f64) * f64::sin(6f64 * theta); y *= f64::exp((-0.0015f64) * theta); y += y * y * y; y *= 1f64 + 16f64 * i as f64 * f64::exp((-6f64) * i as f64); y *= *volume; current_adsr = adsr(i, nb_samples, current_adsr); y *= current_adsr; result.push(y.into()); theta += step; } Wave::new(result) } } fn adsr(step: usize, total: usize, current: f64) -> f64 { if step < 4320 { if current <= 1f64 { current + 0.0002314814814814815f64 } else { 1f64 } } else if total - step < 4320 { if current >= 0f64 { current - 0.0002314814814814815f64 } else { 0f64 } } else { current } } #[derive(Default)] pub struct PianoFromC {} impl Display for PianoFromC { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "the piano instrument from the last project in C.") } } impl Instrument for PianoFromC { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let (note_octave, note_rem): (usize, usize) = note.octave(); let exp_coeff = match note_octave { n if n <= 3 => 0.0015f64, 4 => 0.0015f64, 5 => 0.001f64, 6 => { if note_rem < 9 { 0.0005f64 } else { 0.0003f64 } } 7 => { if note_rem < 5 { 0.0003f64 } else { 0.00009f64 } } _ => 0.00009f64, }; let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; let mut adsr_factor = 1f64; for i in 0..nb_samples { let mut y = 0.65f64 * f64::sin(theta) + 0.475f64 * f64::sin(2f64 * theta) + 0.05f64 * f64::sin(3f64 * theta); y *= f64::exp((-exp_coeff) * theta); y += y * y * y; y *= 1f64 + 16f64 * i as f64 * f64::exp((-6f64) * i as f64); adsr_factor = adsr(i, nb_samples, adsr_factor); y *= adsr_factor; y *= *volume; result.push(y.into()); theta += step; } Wave::new(result) } } #[derive(Default)] pub struct Violin {} impl Display for Violin { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "an attempt at the violin instrument") } } impl Instrument for Violin { fn play(&mut self, note: T, rate: U, bpm: S, duration: V, volume: R) -> Wave where T: Into, S: Into, U: Into, V: Into, R: Into, { let note = note.into(); let rate = rate.into(); let duration = duration.into(); let volume = volume.into(); let bpm = bpm.into(); let duration_per_beat: Seconds = bpm.into(); let duration: Seconds = (*duration * *duration_per_beat).into(); let nb_samples = (*duration * *rate).floor() as usize; let note_h: Hertz = note.into(); let step = *note_h * 2f64 * PI / *rate; let mut theta = 0f64; let mut result: Vec = vec![]; for i in 0..nb_samples { let mut y = f64::sin(theta) + f64::sin(2f64 * theta) + (3f64 / 4f64) * f64::sin(3f64 * theta) + (1f64 / 8f64) * f64::sin(4f64 * theta) + (1f64 / 16f64) * f64::sin(5f64 * theta) + (1f64 / 32f64) * f64::sin(6f64 * theta) + (1f64 / 64f64) * f64::sin(7f64 * theta) + (10f64 / 128f64) * f64::sin(8f64 * theta) + (1f64 / 256f64) * f64::sin(9f64 * theta) + (1f64 / 512f64) * f64::sin(10f64 * theta) + (1f64 / 1024f64) * f64::sin(11f64 * theta) + (1f64 / 2048f64) * f64::sin(12f64 * theta); y *= f64::exp((-0.00051f64) * theta); // y += y * y * y; y *= 1f64 + 16f64 * i as f64 * f64::exp((-6f64) * i as f64); y *= *volume; result.push(y.into()); theta += step; } Wave::new(result) } }