torque_tracker_engine/project/
note_event.rs1use std::{
2 error::Error,
3 fmt::{Display, Write},
4};
5
6use crate::project::event_command::NoteCommand;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
9pub struct Note(u8);
10
11impl Note {
12 pub fn new(value: u8) -> Result<Note, u8> {
13 if value > 199 {
14 Err(value)
15 } else {
16 Ok(Note(value))
17 }
18 }
19
20 pub const fn get_octave(self) -> u8 {
21 self.0 / 12
22 }
23
24 pub const fn get_note_name(self) -> &'static str {
25 match self.0 % 12 {
26 0 => "C",
27 1 => "C#",
28 2 => "D",
29 3 => "D#",
30 4 => "E",
31 5 => "F",
32 6 => "F#",
33 7 => "G",
34 8 => "G#",
35 9 => "A",
36 10 => "A#",
37 11 => "B",
38 _ => panic!(),
39 }
40 }
41
42 pub fn get_frequency(self) -> f32 {
43 440. * ((f32::from(self.0) - 69.) / 12.).exp2()
45 }
46
47 pub const fn get(self) -> u8 {
48 self.0
49 }
50}
51
52impl Display for Note {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.write_str(self.get_note_name())?;
55 f.write_char('-')?;
56 self.get_octave().fmt(f)?;
57 Ok(())
58 }
59}
60
61impl Default for Note {
62 fn default() -> Self {
63 Self(60) }
65}
66
67#[derive(Clone, Copy, Debug, Default)]
68pub struct NoteEvent {
69 pub note: Note,
70 pub sample_instr: u8,
71 pub vol: VolumeEffect,
72 pub command: NoteCommand,
73}
74
75#[derive(Debug, Clone, Copy, Default)]
76pub enum VolumeEffect {
77 FineVolSlideUp(u8),
78 FineVolSlideDown(u8),
79 VolSlideUp(u8),
80 VolSlideDown(u8),
81 PitchSlideUp(u8),
82 PitchSlideDown(u8),
83 SlideToNoteWithSpeed(u8),
84 VibratoWithSpeed(u8),
85 Volume(u8),
86 Panning(u8),
87 #[default]
89 None,
90}
91
92#[derive(Debug, Clone, Copy)]
93pub struct InvalidVolumeEffect;
94
95impl Display for InvalidVolumeEffect {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 write!(f, "Invalid Volume Effect")
98 }
99}
100
101impl Error for InvalidVolumeEffect {}
102
103impl TryFrom<u8> for VolumeEffect {
104 type Error = InvalidVolumeEffect;
105
106 fn try_from(value: u8) -> Result<Self, Self::Error> {
109 match value {
110 0..=64 => Ok(Self::Volume(value)),
111 65..=74 => Ok(Self::FineVolSlideUp(value - 65)),
112 75..=84 => Ok(Self::FineVolSlideDown(value - 75)),
113 85..=94 => Ok(Self::VolSlideUp(value - 85)),
114 95..=104 => Ok(Self::VolSlideDown(value - 95)),
115 105..=114 => Ok(Self::PitchSlideDown(value - 105)),
116 115..=124 => Ok(Self::PitchSlideUp(value - 115)),
117 128..=192 => Ok(Self::Panning(value - 128)),
118 193..=202 => Ok(Self::SlideToNoteWithSpeed(value - 193)),
119 203..=212 => Ok(Self::VibratoWithSpeed(value - 203)),
120 _ => Err(InvalidVolumeEffect),
121 }
122 }
123}