#![warn(missing_docs)] //! This file implements the interface to turn a parsed representation //! of a sheet into pulses. use super::*; #[allow(unused_imports)] use crate::instruments::{self, Instrument as IInstrument}; #[derive(Debug, Clone, Copy)] /// The environment when generating waves from a sheet. struct SheetEnv { volume: Volume, bpm: BPM, instrument: Instrument, duration: Beats, octave: usize, rate: Samples, } impl SheetEnv { fn set_volume(&mut self, volume: Volume) { self.volume = volume; } fn set_bpm(&mut self, bpm: BPM) { self.bpm = bpm; } fn set_instrument(&mut self, instrument: Instrument) { self.instrument = instrument; } fn set_duration(&mut self, duration: Beats) { self.duration = duration; } fn set_octave(&mut self, octave: usize) { self.octave = octave; } } impl Default for SheetEnv { fn default() -> Self { let volume = Volume::default(); let bpm = BPM::default(); let instrument = Instrument::default(); let duration = Beats::default(); let octave = 4usize; let rate = Samples::default(); Self { volume, bpm, instrument, duration, octave, rate, } } } impl From<(&SheetDuration, Beats)> for Beats { fn from((duration, env_duration): (&SheetDuration, Beats)) -> Self { let duration_base: Beats = if let Some(base) = duration.beats { base } else { env_duration }; let mut final_duration = duration_base; for i in (0..duration.dots).map(|n| n + 1) { let power = 2usize.pow(i as u32) as f64; final_duration = (*final_duration + *duration_base / power).into(); } final_duration } } impl From<(&SheetUnit, &mut SheetEnv)> for Wave { fn from((unit, env): (&SheetUnit, &mut SheetEnv)) -> Self { let mut result = Vec::new(); // Unfortunately our trait is wrongly designed and that is not // dynamically dispatchable, so we need separate variables for // each instrument. let mut piano = instruments::PianoFromC::default(); let mut violin = instruments::Violin::default(); let mut sinus = instruments::Sinus::default(); let mut tangent = instruments::Tangent::default(); match unit { SheetUnit::Tone(chord, duration) => { let mut local_waves = Vec::new(); for tone in chord.0.iter() { let octave = if let Some(abs_or_rel) = tone.octave { match abs_or_rel { SheetOctave::Absolute(absolute_octave) => absolute_octave, SheetOctave::Relative(relative_octave) => { let result: isize = relative_octave + env.octave as isize; assert!(!result.is_negative()); result as usize } } } else { env.octave }; env.set_octave(octave); let semitone: Semitones = (octave, tone.semitone).into(); let final_duration: Beats = (duration, env.duration).into(); env.set_duration(final_duration); let wave = match env.instrument { Instrument::Piano => { piano.play(semitone, env.rate, env.bpm, final_duration, env.volume) } Instrument::Violin => { violin.play(semitone, env.rate, env.bpm, final_duration, env.volume) } Instrument::Sinus => { sinus.play(semitone, env.rate, env.bpm, final_duration, env.volume) } Instrument::Tangent => { tangent.play(semitone, env.rate, env.bpm, final_duration, env.volume) } }; local_waves.push(wave); } let local_result = mix_waves_exact(local_waves); result.append(&mut local_result.to_vec()); } SheetUnit::Silence(duration) => { let duration_per_beat: Seconds = env.bpm.into(); let final_duration: Beats = (duration, env.duration).into(); env.set_duration(final_duration); let duration: Seconds = (*final_duration * *duration_per_beat).into(); let nb_samples = (*duration * *env.rate).floor() as usize; result.append(&mut vec![0f64.into(); nb_samples]); } SheetUnit::Instruction(instruction) => match instruction { Instruction::VolumeTo(volume) => { env.set_volume(*volume); } Instruction::BPMTo(bpm) => { env.set_bpm(*bpm); } Instruction::InstrumentTo(instrument) => { env.set_instrument(*instrument); } }, } Wave::new(result) } } impl From<(&mut SheetGroup, &mut SheetEnv)> for Wave { fn from((group, env): (&mut SheetGroup, &mut SheetEnv)) -> Self { group.do_cram(&mut env.duration); // if group.nodes.len() == 19 { // println!("group={group:?}"); // } // After we crammed the expressions, we are sure that all // tones have the correct durations, so we can safely ignore // all cram expressions afterwards. let mut stack = vec![0usize]; let mut seen = vec![false; group.nodes.len()]; let mut stack_args: Vec = vec![]; while let Some(top) = stack.pop() { match &group.nodes[top] { SheetGroupNode::Intermediate(repetition, _) if *repetition != 0 => { if !seen[top] { stack.push(top); stack.append( &mut group.edges[top] .iter() .copied() .rev() .filter(|child| match group.nodes[*child] { SheetGroupNode::Intermediate(child_repetition, _) if child_repetition != 0 => { true } SheetGroupNode::Unit(_) => true, _ => false, }) .collect(), ); } else { match repetition { 0 => { unreachable!() } // 1 => { // for _ in 0..group.edges[top] // .iter() // .filter(|child| match group.nodes[**child] { // SheetGroupNode::Intermediate(child_repetition, _) // if child_repetition != 0 => // { // true // } // SheetGroupNode::Unit(_) => true, // _ => false, // }) // .count() // { // result.append(&mut stack_args.pop().unwrap().to_vec()); // } // } _ => { let mut local_stack_args = vec![]; let mut local_results = vec![]; let mut final_local_result = vec![]; for _ in 0..group.edges[top] .iter() .filter(|child| match group.nodes[**child] { SheetGroupNode::Intermediate(child_repetition, _) if child_repetition != 0 => { true } SheetGroupNode::Unit(_) => true, _ => false, }) .count() { local_stack_args.push(stack_args.pop().unwrap()); } for local_wave in local_stack_args.into_iter().rev() { local_results.append(&mut local_wave.to_vec()); } for _ in 0..(repetition - 1) { final_local_result.append(&mut local_results.clone()); } final_local_result.append(&mut local_results); stack_args.push(Wave::new(final_local_result)); } } } } SheetGroupNode::Unit(unit) => { stack_args.push((unit, &mut *env).into()); } _ => { continue; } } seen[top] = true; } let result = stack_args .iter() .flat_map(|vec| vec.iter()) .copied() .collect(); Wave::new(result) } } // Note: The rest are but ordinary house-keeping codes to glue // everything together. impl From<&mut SheetBlock> for Wave { fn from(block: &mut SheetBlock) -> Self { let mut result = Vec::new(); let mut env = SheetEnv::default(); for group in block.groups.iter_mut() { let wave: Wave = (group, &mut env).into(); result.append(&mut wave.to_vec()); } Self::new(result) } } impl From<&mut Sheet> for Wave { fn from(sheet: &mut Sheet) -> Self { mix_waves_exact(sheet.blocks.iter_mut().map(Into::::into).collect()) } } #[cfg(test)] mod tests { // use super::*; }