feat(domain): add Song, Section, LyricLine, ChordPosition types
This commit is contained in:
88
crates/domain/src/song.rs
Normal file
88
crates/domain/src/song.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::Chord;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ChordPosition {
|
||||
pub offset: usize,
|
||||
pub chord: Chord,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LyricLine {
|
||||
pub text: String,
|
||||
pub chords: Vec<ChordPosition>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum SectionKind {
|
||||
Verse, Chorus, Bridge, PreChorus,
|
||||
Intro, Outro, Break, Tab,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl SectionKind {
|
||||
pub fn from_label(s: &str) -> Self {
|
||||
match s.to_lowercase().replace(['-', '_', ' '], "").as_str() {
|
||||
"verse" => Self::Verse,
|
||||
"chorus" => Self::Chorus,
|
||||
"bridge" => Self::Bridge,
|
||||
"prechorus" => Self::PreChorus,
|
||||
"intro" => Self::Intro,
|
||||
"outro" => Self::Outro,
|
||||
"break" => Self::Break,
|
||||
"tab" => Self::Tab,
|
||||
_ => Self::Other(s.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Section {
|
||||
pub kind: SectionKind,
|
||||
pub label: Option<String>,
|
||||
pub lines: Vec<LyricLine>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SongMeta {
|
||||
pub title: String,
|
||||
pub artist: String,
|
||||
pub capo: Option<u8>,
|
||||
pub original_key: Option<String>,
|
||||
pub tuning: Option<String>,
|
||||
pub tempo: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Song {
|
||||
pub meta: SongMeta,
|
||||
pub sections: Vec<Section>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Chord, Note};
|
||||
|
||||
#[test]
|
||||
fn lyric_line_chord_positions() {
|
||||
let line = LyricLine {
|
||||
text: "A drop in the ocean".into(),
|
||||
chords: vec![
|
||||
ChordPosition { offset: 0, chord: Chord { root: Note::E, descriptor: Some("m".into()) } },
|
||||
ChordPosition { offset: 8, chord: Chord { root: Note::C, descriptor: None } },
|
||||
],
|
||||
};
|
||||
assert_eq!(line.chords[0].offset, 0);
|
||||
assert_eq!(line.chords[1].offset, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn section_kind_from_label() {
|
||||
assert_eq!(SectionKind::from_label("Chorus"), SectionKind::Chorus);
|
||||
assert_eq!(SectionKind::from_label("Pre-Chorus"), SectionKind::PreChorus);
|
||||
assert_eq!(SectionKind::from_label("Tab"), SectionKind::Tab);
|
||||
assert_eq!(SectionKind::from_label("Riff"), SectionKind::Other("Riff".into()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user