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<RefCell<dyn CellHandler>>,
it: &'a itfile::ITFile
}
pub struct Converter<'a>
{
instch: Option<BTreeMap<(u8, u8), usize>>,
it: &'a itfile::ITFile
}
trait CellHandler
{
fn process(&mut self, ch: u8, cell: itfile::Cell, player: &mut Player);
fn result_data(&mut self) -> Box<dyn Any>;
}
trait EffectHandler
{
fn process(&mut self, ch: u8, cell: itfile::Cell, chmem: &mut ChannelMemory) -> Vec<midifile::TimedMidiEvent>;
fn handled_effects(&self) -> Vec<u8>;
}
struct PrePassCellHandler
{
instchmap: Option<BTreeSet<(u8, u8)>>,
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<RefCell<dyn EffectHandler + 'a>>; 32]
}
impl<'a> Player<'a>
{
fn new(handler: Rc<RefCell<dyn CellHandler>>, 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<dyn Any>
{ Box::new(self.instchmap.take().unwrap()) }
}
impl<'a> ConvertCellHandler<'a>
{
fn register_fx_handler(&mut self, hndlr: Rc<RefCell<dyn EffectHandler + 'a>>)
{
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<dyn Any>
{ 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::<BTreeSet<(u8, u8)>>()
{
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();
}
}