use crate::dsl::{SeqNote, Value};
pub struct Phrase {
steps_per_beat: u32,
cursor_beat: f32,
velocity: f32,
pub(super) notes: Vec<SeqNote>,
}
impl Phrase {
pub(super) fn new(steps_per_beat: u32) -> Self {
Phrase {
steps_per_beat: steps_per_beat.max(1),
cursor_beat: 0.0,
velocity: 1.0,
notes: Vec::new(),
}
}
fn step_of(&self, beat: f32) -> u32 {
(beat.max(0.0) * self.steps_per_beat as f32).round() as u32
}
fn len_of(&self, dur_beats: f32) -> u32 {
((dur_beats.max(0.0) * self.steps_per_beat as f32).round() as u32).max(1)
}
pub fn at(&mut self, beat: f32) -> &mut Self {
self.cursor_beat = beat;
self
}
pub fn vel(&mut self, velocity: f32) -> &mut Self {
self.velocity = velocity.clamp(0.0, 1.0);
self
}
pub fn note(&mut self, pitch: &str, dur_beats: f32) -> &mut Self {
self.push(pitch, dur_beats);
self
}
pub fn chord(&mut self, pitches: &[&str], dur_beats: f32) -> &mut Self {
for p in pitches {
self.push(p, dur_beats);
}
self
}
pub fn play(&mut self, pitch: &str, dur_beats: f32) -> &mut Self {
self.push(pitch, dur_beats);
self.cursor_beat += dur_beats;
self
}
pub fn rest(&mut self, dur_beats: f32) -> &mut Self {
self.cursor_beat += dur_beats;
self
}
fn push(&mut self, pitch: &str, dur_beats: f32) {
self.notes.push(SeqNote {
step: self.step_of(self.cursor_beat),
len: self.len_of(dur_beats),
pitch: Value::Note(pitch.to_string()),
gain: self.velocity,
});
}
pub fn hit(&mut self, gm_note: u8) -> &mut Self {
self.notes.push(SeqNote {
step: self.step_of(self.cursor_beat),
len: 1,
pitch: Value::Note(format!("midi:{gm_note}")),
gain: self.velocity,
});
self
}
pub fn kick(&mut self) -> &mut Self {
self.hit(36)
}
pub fn snare(&mut self) -> &mut Self {
self.hit(38)
}
pub fn hat(&mut self) -> &mut Self {
self.hit(42)
}
pub fn open_hat(&mut self) -> &mut Self {
self.hit(46)
}
pub fn clap(&mut self) -> &mut Self {
self.hit(39)
}
pub fn crash(&mut self) -> &mut Self {
self.hit(49)
}
pub fn ride(&mut self) -> &mut Self {
self.hit(51)
}
pub fn tom(&mut self) -> &mut Self {
self.hit(45)
}
}