diff options
Diffstat (limited to 'src/convert.rs')
-rw-r--r-- | src/convert.rs | 107 |
1 files changed, 81 insertions, 26 deletions
diff --git a/src/convert.rs b/src/convert.rs index 5ae394c..05866f3 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,18 +1,23 @@ 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; +use crate::portmod::Effect; struct PlayerState { - skip_row: u16, + skip_row: u8, skip_ord: u8, current_ord: u8, - current_row: u16, - in_loop: bool + current_row: u8, + current_tick: u8, + speed: u8, + tempo: u8, + loop_start: u8, + loop_ctr: u8, + in_rep: bool } struct Player<'a> @@ -57,7 +62,7 @@ struct ChannelMemory struct ConvertCellHandler<'a> { chmem: [ChannelMemory; 64], - fx_handlers: [Rc<RefCell<dyn EffectHandler + 'a>>; 32] + fx_handlers: Vec<Box<RefCell<dyn EffectHandler + 'a>>> } impl<'a> Player<'a> @@ -70,23 +75,70 @@ impl<'a> Player<'a> it } } + fn process_timingfx(&self, cell: itfile::Cell, ps: PlayerState) -> PlayerState + { + let e = Effect::from_it_efx((cell.efx, cell.fxp)); + if ps.current_tick == 0 + { + match e + { + Effect::SetSpeed(s) => PlayerState{speed: s, ..ps}, + Effect::PattLoopStart => PlayerState{loop_start: ps.current_row, ..ps}, + Effect::SetTempo(t) => PlayerState{tempo: t, ..ps}, + _ => ps + } + } + else if ps.current_tick == ps.speed - 1 + { + match e + { + Effect::PosJump(p) => self.skip_to(!0, p, ps), + Effect::PattBreak(r) => self.skip_to(r, !0, ps), + Effect::PattLoop(c) => + match ps.loop_ctr + { + u8::MAX => PlayerState{loop_ctr: 1, .. self.skip_to(ps.loop_start, ps.current_ord, ps)}, + _ if ps.loop_ctr >= c => PlayerState{loop_ctr: !0, ..ps}, + _ => PlayerState{loop_ctr: ps.loop_start + 1, .. self.skip_to(ps.loop_start, ps.current_ord, ps)} + }, + Effect::PattDelay(c) => + match ps.loop_ctr + { + u8::MAX => PlayerState{loop_ctr: 1, in_rep: true, .. self.skip_to(ps.current_row, ps.current_ord, ps)}, + _ if ps.loop_ctr >= c => PlayerState{loop_ctr: !0, in_rep: false, ..ps}, + _ => PlayerState{loop_ctr: ps.loop_start + 1, .. self.skip_to(ps.current_row, ps.current_ord, ps)} + }, + Effect::TempoSlideDown(v) => PlayerState{tempo: ps.tempo - v, ..ps}, + Effect::TempoSlideUp(v) => PlayerState{tempo: ps.tempo + v, ..ps}, + _ => ps + } + } + else { + match e + { + Effect::TempoSlideDown(v) => PlayerState{tempo: ps.tempo - v, ..ps}, + Effect::TempoSlideUp(v) => PlayerState{tempo: ps.tempo + v, ..ps}, + _ => ps + } + } + } 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 - }; + let mut ret = st; for r in skip_row..self.it.patterns[pat].nrows { ret.current_row = r; - for c in 0..64 + ret.current_tick = 0; + while ret.current_tick < ret.speed { - let cell = *self.it.patterns[pat].cell_at(r, c); - ret = (&self.h).borrow_mut().process(c as u8, cell, ret); + 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.process_timingfx(cell, ret); + } + ret.current_tick += 1; } ret = (&self.h).borrow_mut().process(!0, itfile::Cell::default(), ret); if (!ret.skip_row) != 0 || (!ret.skip_ord) != 0 { return ret; } @@ -98,12 +150,13 @@ impl<'a> Player<'a> /// 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 + fn skip_to(&self, row: u8, ord: u8, 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, + skip_ord: if !ord != 0 { ord } else { + if (!row != 0) && (!ps.skip_ord == 0) { ps.current_ord + 1 } else { ps.skip_ord } + }, ..ps } } @@ -114,7 +167,12 @@ impl<'a> Player<'a> skip_ord: !0, current_ord: 0, current_row: 0, - in_loop: false + current_tick: 0, + speed: self.it.header.speed, + tempo: self.it.header.tempo, + loop_start: 0, + loop_ctr: !0, + in_rep: false }; let mut oid = 0; @@ -127,7 +185,7 @@ impl<'a> Player<'a> 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 + if ps.skip_ord as usize <= oid && !ps.loop_ctr == 0 { println!("loop?"); } else { oid = ps.skip_ord as usize; } ps.skip_ord = !0; @@ -141,7 +199,7 @@ impl CellHandler for PrePassCellHandler { fn process(&mut self, ch: u8, cell: itfile::Cell, ps: PlayerState) -> PlayerState { - if ch == 0xff { return ps; } + if (ch == 0xff) || (ps.current_tick != 0) { return ps; } let itfile::Cell{mask, mut inst, ..} = cell; if mask & 0x22 != 0 { self.chinst[ch as usize] = inst; } @@ -157,12 +215,9 @@ impl CellHandler for PrePassCellHandler impl<'a> ConvertCellHandler<'a> { - fn register_fx_handler(&mut self, hndlr: Rc<RefCell<dyn EffectHandler + 'a>>) + fn register_fx_handler(&mut self, hndlr: Box<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)); + self.fx_handlers.push(hndlr); } } |