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: Box>, 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, ps: PlayerState) -> PlayerState; 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: Box>, it: &'a itfile::ITFile) -> Player<'a> { Player { h: handler, it } } fn process_pattern(&self, pat: usize, st: PlayerState) -> PlayerState { let skip_row = if !st.skip_row == 0 { 0 } else { st.skip_row }; let mut ret = PlayerState { skip_row: !0, skip_ord: !0, current_ord: 0, current_row: 0, in_loop: false }; for r in skip_row..self.it.patterns[pat].nrows { ret.current_row = r; for c in 0..64 { let cell = *self.it.patterns[pat].cell_at(r, c); ret = (&self.h).borrow_mut().process(c as u8, cell, ret); } ret = (&self.h).borrow_mut().process(!0, itfile::Cell::default(), ret); if (!ret.skip_row) != 0 || (!ret.skip_ord) != 0 { return ret; } } 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(&self, row: u16, ord: u8, in_loop: bool, ps: PlayerState) -> PlayerState { PlayerState { skip_row: if !row != 0 { row } else { ps.skip_row }, skip_ord: if !ord != 0 { ord } else { ps.skip_ord }, in_loop, ..ps } } fn process_orders(&self) { let mut ps = PlayerState { skip_row: !0, skip_ord: !0, current_ord: 0, current_row: 0, in_loop: 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; } ps.current_ord = oid as u8; ps = self.process_pattern(self.it.orders[oid].into(), ps); if !ps.skip_ord != 0 { if ps.skip_ord as usize <= oid && !ps.in_loop { println!("loop?"); } else { oid = ps.skip_ord as usize; } ps.skip_ord = !0; } else { oid += 1; } } } } impl CellHandler for PrePassCellHandler { fn process(&mut self, ch: u8, cell: itfile::Cell, ps: PlayerState) -> PlayerState { if ch == 0xff { return ps; } 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)); } ps } 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, ps: PlayerState) -> PlayerState { let itfile::Cell{mask, note, inst, vol, efx, fxp} = cell; ps } 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 p = Player::new(Box::new(RefCell::new(h)), self.it); p.process_orders(); let Player{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(); } }