old school music tracker
at main 189 lines 7.2 kB view raw
1use std::{io::Write, str::from_utf8}; 2 3use font8x8::UnicodeFonts; 4use torque_tracker_engine::{ 5 audio_processing::playback::PlaybackPosition, manager::PlaybackSettings, 6 project::pattern::Pattern, 7}; 8 9use crate::{ 10 coordinates::{CharPosition, CharRect}, 11 draw_buffer::DrawBuffer, 12}; 13 14#[derive(Debug, Clone)] 15pub enum HeaderEvent { 16 SetCursorRow(u16), 17 SetMaxCursorRow(u16), 18 SetPattern(u8), 19 SetMaxCursorPattern(u8), 20 SetOrder(u16), 21 SetOrderLen(u16), 22 SetSample(u8, Box<str>), 23 SetSpeed(usize), 24 SetTempo(usize), 25 SetPlayback(Option<PlaybackPosition>), 26} 27 28#[derive(Debug)] 29pub struct Header { 30 row: u16, 31 max_row: u16, 32 pattern: u8, 33 max_pattern: u8, 34 order: u16, 35 order_len: u16, 36 selected_sample: (u8, Box<str>), 37 playback: Option<PlaybackPosition>, 38} 39 40impl Default for Header { 41 fn default() -> Self { 42 Self { 43 row: 0, 44 max_row: Pattern::DEFAULT_ROWS, 45 pattern: 0, 46 max_pattern: 0, 47 order: 0, 48 order_len: 0, 49 selected_sample: (0, Box::from("")), 50 playback: None, 51 } 52 } 53} 54 55impl Header { 56 pub fn play_current_pattern(&self) -> PlaybackSettings { 57 PlaybackSettings::Pattern { 58 idx: self.pattern, 59 should_loop: true, 60 } 61 } 62 63 pub fn play_current_order(&self) -> PlaybackSettings { 64 PlaybackSettings::Order { 65 idx: self.order, 66 should_loop: true, 67 } 68 } 69 70 /// Header always needs a redraw after processing an event 71 pub fn process_event(&mut self, event: HeaderEvent) { 72 match event { 73 HeaderEvent::SetCursorRow(r) => self.row = r, 74 HeaderEvent::SetPattern(p) => self.pattern = p, 75 HeaderEvent::SetOrder(o) => self.order = o, 76 HeaderEvent::SetOrderLen(l) => self.order_len = l, 77 HeaderEvent::SetSample(i, n) => { 78 self.selected_sample.0 = i; 79 self.selected_sample.1 = n 80 } 81 HeaderEvent::SetSpeed(_) => todo!(), 82 HeaderEvent::SetTempo(_) => todo!(), 83 HeaderEvent::SetMaxCursorRow(r) => self.max_row = r, 84 HeaderEvent::SetMaxCursorPattern(p) => self.max_pattern = p, 85 HeaderEvent::SetPlayback(p) => self.playback = p, 86 } 87 } 88 89 pub fn draw(&self, draw_buffer: &mut DrawBuffer) { 90 let mut buf = [0; 3]; 91 // row 92 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 93 write!(&mut curse, "{:03}", self.row).unwrap(); 94 draw_buffer.draw_string(from_utf8(&buf).unwrap(), CharPosition::new(12, 7), 5, 0); 95 // row max 96 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 97 write!(&mut curse, "{:03}", self.max_row).unwrap(); 98 draw_buffer.draw_string(from_utf8(&buf).unwrap(), CharPosition::new(16, 7), 5, 0); 99 // pattern 100 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 101 write!(&mut curse, "{:03}", self.pattern).unwrap(); 102 draw_buffer.draw_string(from_utf8(&buf).unwrap(), CharPosition::new(12, 6), 5, 0); 103 // max pattern 104 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 105 write!(&mut curse, "{:03}", self.max_pattern).unwrap(); 106 draw_buffer.draw_string(from_utf8(&buf).unwrap(), CharPosition::new(16, 6), 5, 0); 107 108 // order 109 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 110 write!(&mut curse, "{:03}", self.order).unwrap(); 111 draw_buffer.draw_string(from_utf8(&buf).unwrap(), CharPosition::new(12, 5), 5, 0); 112 // order len 113 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 114 write!(&mut curse, "{:03}", self.order_len).unwrap(); 115 draw_buffer.draw_string(from_utf8(&buf).unwrap(), CharPosition::new(16, 5), 5, 0); 116 // sample 117 draw_buffer.draw_string_length(&self.selected_sample.1, CharPosition::new(53, 3), 24, 5, 0); 118 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 119 write!(&mut curse, "{:02}", self.selected_sample.0).unwrap(); 120 draw_buffer.draw_string( 121 from_utf8(&buf[..2]).unwrap(), 122 CharPosition::new(50, 3), 123 5, 124 0, 125 ); 126 // playback position 127 if let Some(position) = self.playback { 128 // Window width - 20 129 let mut buf = [b' '; 60]; 130 let mut curse: std::io::Cursor<&mut [u8]> = std::io::Cursor::new(&mut buf); 131 write!(&mut curse, "Playing, ").unwrap(); 132 if let Some(order) = position.order { 133 write!(&mut curse, "Order: {}/{}, ", order, self.order_len).unwrap(); 134 } 135 // TODO: figure out how to get the row count of the currently playing pattern in here 136 write!( 137 &mut curse, 138 "Pattern: {}, Row: {}", 139 position.pattern, position.row 140 ) 141 .unwrap(); 142 // TODO: add voice count 143 let string = from_utf8(&buf).unwrap(); 144 for (index, char) in string.char_indices() { 145 let char_color = if char.is_ascii_digit() { 3 } else { 0 }; 146 draw_buffer.draw_char( 147 font8x8::BASIC_FONTS.get(char).unwrap(), 148 CharPosition::new(2 + index, 9), 149 char_color, 150 2, 151 ); 152 } 153 } else { 154 draw_buffer.draw_rect(2, CharRect::new(9, 9, 2, 62)); 155 } 156 } 157 158 pub fn draw_constant(&self, buffer: &mut DrawBuffer) { 159 buffer.draw_rect(2, CharRect::new(0, 11, 0, 79)); 160 buffer.draw_string("Torque Tracker", CharPosition::new(34, 1), 0, 2); 161 buffer.draw_string("Song Name", CharPosition::new(2, 3), 0, 2); 162 buffer.draw_string("File Name", CharPosition::new(2, 4), 0, 2); 163 buffer.draw_string("Order", CharPosition::new(6, 5), 0, 2); 164 buffer.draw_string("Pattern", CharPosition::new(4, 6), 0, 2); 165 buffer.draw_string("Row", CharPosition::new(8, 7), 0, 2); 166 buffer.draw_string("Speed/Tempo", CharPosition::new(38, 4), 0, 2); 167 buffer.draw_string("Octave", CharPosition::new(43, 5), 0, 2); 168 buffer.draw_string( 169 "F1...Help F9.....Load", 170 CharPosition::new(21, 6), 171 0, 172 2, 173 ); 174 buffer.draw_string( 175 "ESC..Main Menu F5/F8..Play / Stop", 176 CharPosition::new(21, 7), 177 0, 178 2, 179 ); 180 buffer.draw_string("Time", CharPosition::new(63, 9), 0, 2); 181 buffer.draw_string("/", CharPosition::new(15, 5), 1, 0); 182 buffer.draw_string("/", CharPosition::new(15, 6), 1, 0); 183 buffer.draw_string("/", CharPosition::new(15, 7), 1, 0); 184 buffer.draw_string("/", CharPosition::new(53, 4), 1, 0); 185 buffer.draw_string(":", CharPosition::new(52, 3), 7, 0); 186 // TODO: Not actually constant as it changes between Sample and Instrument mode 187 buffer.draw_string("Sample", CharPosition::new(43, 3), 0, 2); 188 } 189}