use std::collections::{BTreeMap, BTreeSet}; use std::any::Any; use std::cell::RefCell; use std::rc::Rc; use crate::itfile; use crate::utils; use crate::midifile; struct PlayerState { skip_row: u16, skip_ord: u8, current_ord: u8, current_row: u16, in_loop: bool } struct Player<'a> { h: Rc>, it: &'a itfile::ITFile } pub struct Converter<'a> { instch: Option>, it: &'a itfile::ITFile } trait CellHandler { fn process(&mut self, ch: u8, cell: itfile::Cell, player: &mut Player); fn result_data(&mut self) -> Box; } trait EffectHandler { fn process(&mut self, ch: u8, cell: itfile::Cell, chmem: &mut ChannelMemory) -> Vec; fn handled_effects(&self) -> Vec; } struct PrePassCellHandler { instchmap: Option>, chinst: [u8; 64] } #[derive(Default)] struct ChannelMemory { note: u8, vol: u8, efxmem: [u8; 32], pitch: utils::Rational } struct ConvertCellHandler<'a> { chmem: [ChannelMemory; 64], fx_handlers: [Rc>; 32] } impl<'a> Player<'a> { fn new(handler: Rc>, it: &'a itfile::ITFile) -> Player<'a> { Player { h: handler, it } } fn process_pattern(&mut self, pat: usize, st: PlayerState) -> PlayerState { let skip_row = if !st.skip_row == 0 { 0 } else { st.skip_row }; let ret = PlayerState{ skip_row: !0, skip_ord: !0, current_ord: 0, current_row: 0, in_loop: false }; self.skip_row = !0; for r in skip_row..self.it.patterns[pat].nrows { self.current_row = r; for c in 0..64 { let cell = *self.it.patterns[pat].cell_at(r, c); Rc::clone(&self.h).borrow_mut().process(c as u8, cell, self); } Rc::clone(&self.h).borrow_mut().process(!0, itfile::Cell::default(), self); if (!self.skip_row) != 0 || (!self.skip_ord) != 0 { return; } } ret } /// Used for effects Bxx, Cxx and SBx /// /// passing !0 to row or ord if it's unused /// /// in_loop == true inhibits loop detection and should only be used for SBx fn skip_to(&mut self, row: u16, ord: u8, in_loop: bool) { self.skip_row = if !row != 0 { row } else { self.skip_row }; self.skip_ord = if !ord != 0 { ord } else { self.skip_ord }; self.in_loop = in_loop; } fn process_orders(&mut self) { self.skip_to(!0, !0, false); let mut oid = 0; loop { if oid >= self.it.orders.len() { break; } if self.it.orders[oid] == 0xff { break; } if self.it.orders[oid] == 0xfe { continue; } self.process_pattern(self.it.orders[oid].into()); if !self.skip_ord != 0 { if self.skip_ord as usize <= oid && !self.in_loop { println!("loop?"); } else { oid = self.skip_ord as usize; } self.skip_ord = !0; } else { oid += 1; } } } } impl CellHandler for PrePassCellHandler { fn process(&mut self, ch: u8, cell: itfile::Cell, _p: &mut Player) { if ch == 0xff { return; } let itfile::Cell{mask, mut inst, ..} = cell; if mask & 0x22 != 0 { self.chinst[ch as usize] = inst; } else { inst = self.chinst[ch as usize]; } if mask & 0x11 != 0 { self.instchmap.as_mut().unwrap().insert((ch, inst)); } } fn result_data(&mut self) -> Box { Box::new(self.instchmap.take().unwrap()) } } impl<'a> ConvertCellHandler<'a> { fn register_fx_handler(&mut self, hndlr: Rc>) { let efxs = hndlr.borrow().handled_effects(); efxs.iter() .filter(|e| **e < 32) .for_each(|e| self.fx_handlers[*e as usize] = Rc::clone(&hndlr)); } } impl<'a> CellHandler for ConvertCellHandler<'a> { fn process(&mut self, ch: u8, cell: itfile::Cell, player: &mut Player) { let itfile::Cell{mask, note, inst, vol, efx, fxp} = cell; } fn result_data(&mut self) -> Box { Box::new(()) } } impl<'a> Converter<'a> { pub fn new(it: &itfile::ITFile) -> Converter { Converter{instch: None, it} } fn pre_pass(&'a mut self) { let h = PrePassCellHandler{instchmap: Some(BTreeSet::new()), chinst: [0; 64]}; let mut p = Player::new(Rc::new(RefCell::new(h)), self.it); p.process_orders(); let Player{mut h, ..} = p; if let Ok(m) = h.borrow_mut().result_data().downcast::>() { let mut instch = BTreeMap::new(); m.iter().enumerate().for_each( |(i, p)| { instch.insert(*p, i + 1); } ); self.instch = Some(instch); } println!("{:?}", self.instch); } pub fn convert(&'a mut self) { self.pre_pass(); } }