old school music tracker audio backend
1use core::fmt::{Display, Write};
2
3use crate::project::event_command::NoteCommand;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
6pub struct Note(u8);
7
8impl Note {
9 pub fn new(value: u8) -> Result<Note, u8> {
10 if value > 199 {
11 Err(value)
12 } else {
13 Ok(Note(value))
14 }
15 }
16
17 pub const fn get_octave(self) -> u8 {
18 self.0 / 12
19 }
20
21 pub const fn get_note_name(self) -> &'static str {
22 match self.0 % 12 {
23 0 => "C",
24 1 => "C#",
25 2 => "D",
26 3 => "D#",
27 4 => "E",
28 5 => "F",
29 6 => "F#",
30 7 => "G",
31 8 => "G#",
32 9 => "A",
33 10 => "A#",
34 11 => "B",
35 _ => panic!(),
36 }
37 }
38
39 pub fn get_frequency(self) -> f32 {
40 // taken from https://en.wikipedia.org/wiki/MIDI_tuning_standard
41 440. * ((f32::from(self.0) - 69.) / 12.).exp2()
42 }
43
44 pub const fn get(self) -> u8 {
45 self.0
46 }
47}
48
49impl Display for Note {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 f.write_str(self.get_note_name())?;
52 f.write_char('-')?;
53 self.get_octave().fmt(f)?;
54 Ok(())
55 }
56}
57
58impl Default for Note {
59 fn default() -> Self {
60 Self(60) // C-5
61 }
62}
63
64#[derive(Clone, Copy, Debug, Default)]
65pub struct NoteEvent {
66 pub note: Note,
67 pub sample_instr: u8,
68 pub vol: VolumeEffect,
69 pub command: NoteCommand,
70}
71
72#[derive(Debug, Clone, Copy, Default)]
73pub enum VolumeEffect {
74 FineVolSlideUp(u8),
75 FineVolSlideDown(u8),
76 VolSlideUp(u8),
77 VolSlideDown(u8),
78 PitchSlideUp(u8),
79 PitchSlideDown(u8),
80 SlideToNoteWithSpeed(u8),
81 VibratoWithSpeed(u8),
82 Volume(u8),
83 Panning(u8),
84 /// Uses Instr / Sample Default Volume
85 // TODO: figure out if i want to have that in here or if i want to use it with Option around it
86 #[default]
87 None,
88}