51 lines
1.5 KiB
Rust
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");
|
|
} |