aboutsummaryrefslogtreecommitdiff
path: root/src/convert.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/convert.rs')
-rw-r--r--src/convert.rs107
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);
}
}