Files
pocket-chords/crates/domain/src/song.rs

89 lines
2.4 KiB
Rust

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()));
}
}