aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/convert.rs8
-rw-r--r--src/portmod.rs203
2 files changed, 198 insertions, 13 deletions
diff --git a/src/convert.rs b/src/convert.rs
index 05866f3..2cbe15b 100644
--- a/src/convert.rs
+++ b/src/convert.rs
@@ -17,6 +17,7 @@ struct PlayerState
tempo: u8,
loop_start: u8,
loop_ctr: u8,
+ row_extension: u8,
in_rep: bool
}
@@ -85,6 +86,7 @@ impl<'a> Player<'a>
Effect::SetSpeed(s) => PlayerState{speed: s, ..ps},
Effect::PattLoopStart => PlayerState{loop_start: ps.current_row, ..ps},
Effect::SetTempo(t) => PlayerState{tempo: t, ..ps},
+ Effect::RowExtention(t) => PlayerState{row_extension: ps.row_extension + t, ..ps},
_ => ps
}
}
@@ -130,7 +132,7 @@ impl<'a> Player<'a>
{
ret.current_row = r;
ret.current_tick = 0;
- while ret.current_tick < ret.speed
+ while ret.current_tick < ret.speed + ret.row_extension
{
for c in 0..64
{
@@ -141,6 +143,7 @@ impl<'a> Player<'a>
ret.current_tick += 1;
}
ret = (&self.h).borrow_mut().process(!0, itfile::Cell::default(), ret);
+ ret.row_extension = 0;
if (!ret.skip_row) != 0 || (!ret.skip_ord) != 0 { return ret; }
}
ret
@@ -148,8 +151,6 @@ impl<'a> Player<'a>
/// 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: u8, ord: u8, ps: PlayerState) -> PlayerState
{
PlayerState {
@@ -172,6 +173,7 @@ impl<'a> Player<'a>
tempo: self.it.header.tempo,
loop_start: 0,
loop_ctr: !0,
+ row_extension: 0,
in_rep: false
};
diff --git a/src/portmod.rs b/src/portmod.rs
index 52c27ee..125fdab 100644
--- a/src/portmod.rs
+++ b/src/portmod.rs
@@ -1,14 +1,65 @@
+pub enum Slide
+{
+ Up(u8),
+ Down(u8),
+ FineUp(u8),
+ FineDown(u8)
+}
+
pub enum Effect
{
SetSpeed(u8),
PosJump(u8),
PattBreak(u8),
+ SetVolume(u8),
+ VolumeSlide(Slide),
+ PortaDown(u8),
+ PortaFineDown(u8),
+ PortaExFineDown(u8),
+ PortaUp(u8),
+ PortaFineUp(u8),
+ PortaExFineUp(u8),
+ TonePorta(u8),
+ Vibrato(u8, u8),
+ Tremor(u8, u8),
+ Arpeggio(u8, u8),
+ VolumeSlideVib(Slide),
+ VolumeSlideTPorta(Slide),
+ SetChannelVolume(u8),
+ ChVolSlide(Slide),
+ SampleOffset(u8),
+ PanSlide(Slide),
+ Retrigger(u8, u8),
+ Tremolo(u8, u8),
+ GlissandoCtrl(bool),
+ SetFinetune(u8),
+ SetVibWaveform(u8),
+ SetTremWaveform(u8),
+ SetPanWaveform(u8),
+ RowExtention(u8),
+ VirtChanOp(u8),
+ NNAOverride(u8),
+ VolumeEnvEnable(bool),
+ PanEnvEnable(bool),
+ PitchEnvEnable(bool),
+ SoundCtrl(u8),
+ SampleOffsetHigh(u8),
PattLoopStart,
PattLoop(u8),
+ NoteCut(u8),
+ NoteDelay(u8),
PattDelay(u8),
+ SetActiveMacro(u8),
SetTempo(u8),
TempoSlideDown(u8),
TempoSlideUp(u8),
+ VibFine(u8, u8),
+ SetGlobalVolume(u8),
+ GlobalVolumeSlide(Slide),
+ SetPan(u8),
+ AutoPan(u8, u8),
+ MidiMacro(u8),
+ SmoothMidiMacro(u8),
NoEffect
}
@@ -17,17 +68,149 @@ impl Effect
pub fn from_it_efx(f: (u8, u8)) -> Effect
{
let (efx, fxp) = f;
- match (efx as char, fxp)
+ match efx as char
+ {
+ 'A' => Effect::SetSpeed(fxp),
+ 'B' => Effect::PosJump(fxp),
+ 'C' => Effect::PattBreak(fxp),
+ 'D' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0, y) => Effect::VolumeSlide(Slide::Down(y)),
+ (x, 0) => Effect::VolumeSlide(Slide::Up(x)),
+ (0xf, 0xf) => Effect::NoEffect,
+ (0xf, y) => Effect::VolumeSlide(Slide::FineDown(y)),
+ (x, 0xf) => Effect::VolumeSlide(Slide::FineUp(x)),
+ _ => Effect::NoEffect
+ },
+ 'E' =>
+ match fxp & 0xf0
+ {
+ 0xF0 => Effect::PortaFineDown(fxp & 0x0f),
+ 0xE0 => Effect::PortaExFineDown(fxp & 0x0f),
+ _ => Effect::PortaDown(fxp)
+ },
+ 'F' =>
+ match fxp & 0xf0
+ {
+ 0xF0 => Effect::PortaFineUp(fxp & 0x0f),
+ 0xE0 => Effect::PortaExFineUp(fxp & 0x0f),
+ _ => Effect::PortaUp(fxp)
+ },
+ 'G' => Effect::TonePorta(fxp),
+ 'H' => Effect::Vibrato(fxp >> 8, fxp & 0x0f),
+ 'I' => Effect::Tremor(fxp >> 8, fxp & 0x0f),
+ 'J' => Effect::Arpeggio(fxp >> 8, fxp & 0x0f),
+ 'K' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0, y) => Effect::VolumeSlideVib(Slide::Down(y)),
+ (x, 0) => Effect::VolumeSlideVib(Slide::Up(x)),
+ (0xf, 0xf) => Effect::NoEffect,
+ (0xf, y) => Effect::VolumeSlideVib(Slide::FineDown(y)),
+ (x, 0xf) => Effect::VolumeSlideVib(Slide::FineUp(x)),
+ _ => Effect::NoEffect
+ },
+ 'L' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0, y) => Effect::VolumeSlideTPorta(Slide::Down(y)),
+ (x, 0) => Effect::VolumeSlideTPorta(Slide::Up(x)),
+ (0xf, 0xf) => Effect::NoEffect,
+ (0xf, y) => Effect::VolumeSlideTPorta(Slide::FineDown(y)),
+ (x, 0xf) => Effect::VolumeSlideTPorta(Slide::FineUp(x)),
+ _ => Effect::NoEffect
+ },
+ 'M' => Effect::SetChannelVolume(fxp),
+ 'N' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0, y) => Effect::ChVolSlide(Slide::Down(y)),
+ (x, 0) => Effect::ChVolSlide(Slide::Up(x)),
+ (0xf, 0xf) => Effect::NoEffect,
+ (0xf, y) => Effect::ChVolSlide(Slide::FineDown(y)),
+ (x, 0xf) => Effect::ChVolSlide(Slide::FineUp(x)),
+ _ => Effect::NoEffect
+ },
+ 'O' => Effect::SampleOffset(fxp),
+ 'P' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0, y) => Effect::PanSlide(Slide::Up(y)),
+ (x, 0) => Effect::PanSlide(Slide::Down(x)),
+ (0xf, 0xf) => Effect::NoEffect,
+ (0xf, y) => Effect::PanSlide(Slide::FineUp(y)),
+ (x, 0xf) => Effect::PanSlide(Slide::FineDown(x)),
+ _ => Effect::NoEffect
+ },
+ 'Q' => Effect::Retrigger(fxp >> 8, fxp & 0x0f),
+ 'R' => Effect::Tremolo(fxp >> 8, fxp & 0x0f),
+ 'S' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0x1, e) => Effect::GlissandoCtrl(e != 0),
+ (0x2, t) => Effect::SetFinetune(t),
+ (0x3, w) => Effect::SetVibWaveform(w),
+ (0x4, w) => Effect::SetTremWaveform(w),
+ (0x5, w) => Effect::SetPanWaveform(w),
+ (0x6, d) => Effect::RowExtention(d),
+ (0x7, x @ 0..=2) => Effect::VirtChanOp(x),
+ (0x7, x @ 3..=6) => Effect::NNAOverride(x - 3),
+ (0x7, x @ 7..=8) => Effect::VolumeEnvEnable(x == 8),
+ (0x7, x @ 9..=10) => Effect::PanEnvEnable(x == 10),
+ (0x7, x @ 11..=12) => Effect::PitchEnvEnable(x == 10),
+ (0x8, p) => Effect::SetPan(p * (255 / 15)),
+ (0x9, c) => Effect::SoundCtrl(c),
+ (0xa, o) => Effect::SampleOffsetHigh(o),
+ (0xb, 0x0) => Effect::PattLoopStart,
+ (0xb, r) => Effect::PattLoop(r),
+ (0xc, t) => Effect::NoteCut(t),
+ (0xd, t) => Effect::NoteDelay(t),
+ (0xe, d) => Effect::PattDelay(d),
+ (0xf, m) => Effect::SetActiveMacro(m),
+ _ => Effect::NoEffect
+ },
+ 'T' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0x0, v) => Effect::TempoSlideDown(v),
+ (0x1, v) => Effect::TempoSlideUp(v),
+ _ => Effect::SetTempo(fxp)
+ },
+ 'U' => Effect::VibFine(fxp >> 8, fxp & 0x0f),
+ 'V' => Effect::SetGlobalVolume(fxp),
+ 'W' =>
+ match (fxp >> 8, fxp & 0x0f)
+ {
+ (0, y) => Effect::GlobalVolumeSlide(Slide::Down(y)),
+ (x, 0) => Effect::GlobalVolumeSlide(Slide::Up(x)),
+ (0xf, 0xf) => Effect::NoEffect,
+ (0xf, y) => Effect::GlobalVolumeSlide(Slide::FineDown(y)),
+ (x, 0xf) => Effect::GlobalVolumeSlide(Slide::FineUp(x)),
+ _ => Effect::NoEffect
+ },
+ 'X' => Effect::SetPan(fxp),
+ 'Y' => Effect::AutoPan(fxp >> 8, fxp & 0x0f),
+ 'Z' => Effect::MidiMacro(fxp),
+ '\\' => Effect::SmoothMidiMacro(fxp),
+ _ => Effect::NoEffect
+ }
+ }
+ pub fn from_it_vol(v: u8) -> Effect
+ {
+ const GMAP: [u8; 10] = [0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60, 0x80, 0xFF];
+ match v
{
- ('A', _) => Effect::SetSpeed(fxp),
- ('B', _) => Effect::PosJump(fxp),
- ('C', _) => Effect::PattBreak(fxp),
- ('S', 0xb0) => Effect::PattLoopStart,
- ('S', _) if fxp & 0xf0 == 0xb0 => Effect::PattLoop(fxp & 0x0f),
- ('S', _) if fxp & 0xf0 == 0xe0 => Effect::PattDelay(fxp & 0x0f),
- ('T', _) if fxp & 0xf0 == 0x00 => Effect::TempoSlideDown(fxp & 0x0f),
- ('T', _) if fxp & 0xf0 == 0x10 => Effect::TempoSlideUp(fxp & 0x0f),
- ('T', _) => Effect::SetTempo(fxp),
+ 0..=64 => Effect::SetVolume(v),
+ 65..=74 => Effect::VolumeSlide(Slide::FineUp(v - 65)),
+ 75..=84 => Effect::VolumeSlide(Slide::FineDown(v - 75)),
+ 85..=94 => Effect::VolumeSlide(Slide::Up(v - 85)),
+ 95..=104 => Effect::VolumeSlide(Slide::Down(v - 95)),
+ 105..=114 => Effect::PortaDown((v - 105) * 4),
+ 115..=124 => Effect::PortaUp((v - 115) * 4),
+ 128..=192 => Effect::SetPan(v - 128),
+ 193..=202 => Effect::TonePorta(GMAP[(v - 193) as usize]),
+ 203..=212 => Effect::Vibrato(0, v - 203),
_ => Effect::NoEffect
}
}