feat(crucible): name slices only by a sure note, spelled for the song key
A slice gets a note name only when at least 60 % of up to twelve reads across its body sit on one note; growls, pitch drops and noise get no name rather than a wrong one. An optional song key spells names with flats in flat keys (Eb2, not D#2).
This commit is contained in:
1 parent
adfb2c0287
commit
d6939a753a
8 files changed
+143
-19
No files matched your search
@@ -218,10 +218,18 @@ pub fn hz_to_midi(hz: f32) -> f32 {
|
||||
}
|
||||
/// Scientific note name: MIDI 60 = C4, 43.65 Hz = F1. FL Studio labels MIDI 60 as C5.
|
||||
pub fn note_name(note: u8) -> String {
|
||||
const NAMES: [&str; 12] = [
|
||||
note_name_spelled(note, false)
|
||||
}
|
||||
/// Note name with sharps, or with flats (Db, Eb, Gb, Ab, Bb) for keys written in flats.
|
||||
pub fn note_name_spelled(note: u8, flats: bool) -> String {
|
||||
const SHARPS: [&str; 12] = [
|
||||
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
|
||||
];
|
||||
format!("{}{}", NAMES[note as usize % 12], note as i32 / 12 - 1)
|
||||
const FLATS: [&str; 12] = [
|
||||
"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B",
|
||||
];
|
||||
let names = if flats { FLATS } else { SHARPS };
|
||||
format!("{}{}", names[note as usize % 12], note as i32 / 12 - 1)
|
||||
}
|
||||
/// Reads a scientific note name such as "F1" or "c#2", the inverse of [`note_name`].
|
||||
pub fn parse_note(text: &str) -> Option<u8> {
|
||||
@@ -231,7 +239,14 @@ pub fn parse_note(text: &str) -> Option<u8> {
|
||||
let text = text.trim();
|
||||
let split = text.find(|c: char| c.is_ascii_digit() || c == '-')?;
|
||||
let (pitch, octave) = text.split_at(split);
|
||||
let class = NAMES.iter().position(|n| n.eq_ignore_ascii_case(pitch))? as i32;
|
||||
const FLATS: [&str; 12] = [
|
||||
"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B",
|
||||
];
|
||||
let class = NAMES
|
||||
.iter()
|
||||
.position(|n| n.eq_ignore_ascii_case(pitch))
|
||||
.or_else(|| FLATS.iter().position(|n| n.eq_ignore_ascii_case(pitch)))?
|
||||
as i32;
|
||||
let octave: i32 = octave.parse().ok()?;
|
||||
u8::try_from((octave + 1) * 12 + class)
|
||||
.ok()
|
||||
|
||||
@@ -374,5 +374,7 @@ fn note_names_parse_back() {
|
||||
assert_eq!(common_dsp::parse_note(&common_dsp::note_name(n)), Some(n));
|
||||
}
|
||||
assert_eq!(common_dsp::parse_note(" f1 "), Some(29));
|
||||
assert_eq!(common_dsp::note_name_spelled(30, true), "Gb1");
|
||||
assert_eq!(common_dsp::parse_note("Gb1"), Some(30));
|
||||
assert_eq!(common_dsp::parse_note("H2"), None);
|
||||
}
|
||||
Reference in new issue
Block a user