song-idea-generator/libsig/src/tempo.rs

51 lines
1.5 KiB
Rust

use serde::{Serialize, Deserialize};
use derive_more::Display;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
#[derive(Debug, PartialEq, Copy, Clone, Display, Serialize, Deserialize)]
#[display(fmt="{} bpm, with {} swing", bpm, swing)]
pub struct Tempo {
bpm: u16,
swing: Swing,
}
impl Distribution<Tempo> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Tempo {
// These parameters are static and known-good
let raw_bpm_distr: f32 = rand_distr::SkewNormal::new(25.0, 75.0, 5.0).unwrap().sample(rng);
let bpm: u16 =
if raw_bpm_distr < 33. { 33 } else if raw_bpm_distr > 300.0 { 300 } else { raw_bpm_distr as u16 };
let swing: Swing = Standard::sample(&self, rng);
Tempo {
bpm, swing
}
}
}
#[derive(Debug, PartialEq, Copy, Clone, Display, Serialize, Deserialize)]
pub enum Swing {
#[display(fmt = "no")]
None,
#[display(fmt = "light")]
Light,
#[display(fmt = "heavy")]
Heavy
}
impl Distribution<Swing> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Swing {
let index: u8 = rng.gen_range(0..6);
match index {
0 | 1 | 2=> Swing::None,
3 | 4 => Swing::Light,
5 => Swing::Heavy,
_ => unreachable!(),
}
}
}
#[test]
fn fmt_tempo_struct() {
assert_eq!(&format!("{}", Tempo { bpm: 80, swing: Swing::Light}), "80 bpm, with light swing");
}