use std::cmp::min; use std::time::Duration; use pitch_calc::{Letter, LetterOctave}; use rand::{prelude::*, Rng}; use rodio::{source::SineWave, OutputStream, Sink, Source}; fn main() { let (_stream, stream_handle) = OutputStream::try_default().unwrap(); let sink = Sink::try_new(&stream_handle).unwrap(); let bpm = 131.2; let seconds_per_beat = (1.0 / bpm) * 60.0; let mut rng = rand::thread_rng(); // fill one measure let measure = { let mut measure = vec![]; let mut sixteenth_notes_remaining = 4 * 4; while sixteenth_notes_remaining > 0 { let note = [2, 3] .iter() .flat_map(|&octave| { use Letter::*; [C, D, E, F, G, A, B] .iter() .map(move |&letter| LetterOctave(letter, octave)) }) .choose(&mut rng) .expect("how is there not a note"); let max_length = min(4, sixteenth_notes_remaining); let length = rng.gen_range(1..=max_length); sixteenth_notes_remaining -= length; measure.push((note, length)); } measure }; loop { for (note, length) in &measure { let freq = note.hz(); let wave = SineWave::new(freq as u32); let length = (*length as f32) / 4.0 * seconds_per_beat; let source = wave .take_duration(Duration::from_secs_f32(length)) .amplify(0.10); sink.append(source); // The sound plays in a separate thread. This call will block the current thread until the sink // has finished playing all its queued sounds. sink.sleep_until_end(); } } }