use serde::{Deserialize, Serialize};
const RECOMMENDED_NOTE_TICK: u16 = 192;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Note {
pub id: u16,
pub sound_id: u16,
pub time: u32,
pub track: u16,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bpm {
pub value: f64,
pub time: u32,
}
impl Default for Bpm {
fn default() -> Self {
Self {
value: 120.0,
time: 0,
}
}
}
impl Bpm {
pub fn new(value: f64, time: u32) -> Self {
Self { value, time }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BeatPerBar {
pub value: u8,
pub time: u32,
}
impl Default for BeatPerBar {
fn default() -> Self {
Self { value: 4, time: 0 }
}
}
impl BeatPerBar {
pub fn new(value: u8, time: u32) -> Self {
Self { value, time }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Instrument {
SomeElse,
Kick,
Snare,
HiHat,
Tom,
CrashCym,
RideCym,
Clap,
Pno,
AGui,
EGui,
BGui,
EBGui,
Kbd,
Syn,
Vox,
}
impl Default for Instrument {
fn default() -> Self {
Self::SomeElse
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrackTag {
pub id: u16,
pub name: String,
pub instrument: Instrument,
}
impl Default for TrackTag {
fn default() -> Self {
Self {
id: 0,
name: String::new(),
instrument: Instrument::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SoundMap {
pub audio_format: String,
pub audio_bits: u8,
pub audio_sample_rate: u32,
pub notes: Vec<Note>,
pub track_tags: Vec<TrackTag>,
pub bpm: Vec<Bpm>,
pub beat_per_bar: Vec<BeatPerBar>,
pub note_tick: u16,
}
impl Default for SoundMap {
fn default() -> Self {
Self {
audio_format: "wav".to_string(),
audio_bits: 24,
audio_sample_rate: 48000,
notes: Vec::new(),
track_tags: Vec::new(),
bpm: vec![Bpm::default()],
beat_per_bar: vec![BeatPerBar::default()],
note_tick: RECOMMENDED_NOTE_TICK,
}
}
}
impl SoundMap {
pub fn new() -> Self {
Self::default()
}
pub fn with_audio_format(mut self, audio_format: &str) -> Self {
self.audio_format = audio_format.to_string();
self
}
pub fn with_audio_bits(mut self, audio_bits: u8) -> Self {
self.audio_bits = audio_bits;
self
}
pub fn with_audio_sample_rate(mut self, audio_sample_rate: u32) -> Self {
self.audio_sample_rate = audio_sample_rate;
self
}
pub fn with_bpm(mut self, bpm: f64) -> Self {
self.bpm = vec![Bpm {
value: bpm,
time: 0,
}];
self
}
pub fn with_beat_per_bar(mut self, beat_per_bar: u8) -> Self {
self.beat_per_bar = vec![BeatPerBar {
value: beat_per_bar,
time: 0,
}];
self
}
pub fn set_note_track(&mut self, id: u16, name: &str, inst: Instrument) {
for track in &mut self.track_tags {
if track.id == id {
track.name = name.to_string();
track.instrument = inst;
return;
}
}
self.track_tags.push(TrackTag {
id,
name: name.to_string(),
instrument: inst,
});
}
pub fn insert_note(&mut self, sound_id: u16, time: u32, track: u16) {
let mut ids: Vec<u16> = Vec::new();
for n in &self.notes {
ids.push(n.id);
}
if self.notes.len() == 0 {
self.notes.push(Note {
id: 0,
sound_id,
time,
track,
});
} else {
for (index, note_id) in ids.iter().enumerate() {
if index != *note_id as usize {
self.notes.push(Note {
id: index as u16,
sound_id,
time,
track,
});
break;
}
else if index == (ids.len() - 1) {
self.notes.push(Note {
id: (index as u16) + 1,
sound_id,
time,
track,
});
}
}
}
}
}