Better data structure for tracker effects

master
Ashley N. 2023-08-22 11:12:38 -04:00
parent 8e6e0d9fb8
commit d86efb29f2
2 changed files with 95 additions and 7 deletions

View File

@ -2,7 +2,7 @@ use std::{error::Error, fs::File, io::Read, convert::TryInto, collections::HashM
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
use samplerate::convert; use samplerate::convert;
use uuid::Uuid; use uuid::Uuid;
use crate::reskit::{utility::{get_string, get_u8, skip, get_u32, get_i8, get_i32, get_u16, get_i16, Ring, print_warning}, soundtrack::{types::{SampleFormat, PsgEnvelope, Note, Sample, PsgSettings, PatternRow, Effect}, engines::echo::{EchoFormat, EchoEvent}}}; use crate::reskit::{utility::{get_string, get_u8, skip, get_u32, get_i8, get_i32, get_u16, get_i16, Ring, print_warning}, soundtrack::{types::{SampleFormat, PsgEnvelope, Note, Sample, PsgSettings, PatternRow, Effect, DcsgChannelMode, NoiseType}, engines::echo::{EchoFormat, EchoEvent}}};
const DMF_MAGIC_NUMBER: &'static str = ".DelekDefleMask."; const DMF_MAGIC_NUMBER: &'static str = ".DelekDefleMask.";
const DMF_SUPPORTED_VERSION: u8 = 27; const DMF_SUPPORTED_VERSION: u8 = 27;
@ -10,6 +10,17 @@ const DMF_MD: u8 = 0x02;
const DMF_MD_ENHANCED_CH3: u8 = 0x42; const DMF_MD_ENHANCED_CH3: u8 = 0x42;
const ECHO_EWF_SAMPLE_RATE: u32 = 10650; const ECHO_EWF_SAMPLE_RATE: u32 = 10650;
const DMF_EFFECT_ARPEGGIO: u8 = 0x00;
const DMF_EFFECT_PORTAMENTO_UP: u8 = 0x01;
const DMF_EFFECT_PORTAMENTO_DOWN: u8 = 0x02;
const DMF_EFFECT_PORTA_TO_NOTE: u8 = 0x03;
const DMF_EFFECT_SET_PANNING: u8 = 0x08;
const DMF_EFFECT_POSITION_JUMP: u8 = 0x0B;
const DMF_EFFECT_PATTERN_BREAK: u8 = 0x0D;
const DMF_EFFECT_DAC_ENABLE: u8 = 0x17;
const DMF_EFFECT_PSG_NOISE_MODE: u8 = 0x20;
const DMF_EFFECT_NOTE_CUT: u8 = 0xEC;
#[derive(Debug)] #[derive(Debug)]
pub enum FrameMode { pub enum FrameMode {
Ntsc, Ntsc,
@ -525,12 +536,68 @@ impl DmfModule {
for _ in 0..num_effects { for _ in 0..num_effects {
let effect_code = get_i16( bytes.by_ref() )?; let effect_code = get_i16( bytes.by_ref() )?;
let effect_value = get_i16( bytes.by_ref() )?; let effect_value = get_i16( bytes.by_ref() )?;
let effect_value: Option<u8> = if effect_value == -1 { None } else { Some( effect_value as u8 ) };
if effect_code != -1 { if effect_code != -1 {
effects.push( effects.push(
Effect{ match effect_code as u8 {
effect_code, DMF_EFFECT_ARPEGGIO => Effect::Arpeggio {
effect_value: if effect_value != -1 { Some( effect_value ) } else { None } first_shift: effect_value.ok_or( "invalid file: expected effect value for arpeggio" )? >> 4,
second_shift: effect_value.ok_or( "invalid file: expected effect value for arpeggio" )? & 0x0F
},
DMF_EFFECT_PORTAMENTO_UP => Effect::PortamentoUp {
speed: effect_value.ok_or( "invalid file: expected effect value for portamento up" )?
},
DMF_EFFECT_PORTAMENTO_DOWN => Effect::PortamentoDown {
speed: effect_value.ok_or( "invalid file: expected effect value for portamento down`" )?
},
DMF_EFFECT_PORTA_TO_NOTE => Effect::PortamentoToNote {
speed: effect_value.ok_or( "invalid file: expected effect value for porta to note" )?
},
DMF_EFFECT_SET_PANNING => {
let effect_value = effect_value.ok_or( "invalid file: expected effect value for panning" )?;
Effect::SetPanning {
left: effect_value == 0x10 || effect_value == 0x11,
right: effect_value == 0x01 || effect_value == 0x11
}
},
DMF_EFFECT_POSITION_JUMP => {
let pattern = effect_value.ok_or( "invalid file: expected effect value for position jump" )?;
Effect::PositionJump { pattern }
},
DMF_EFFECT_PATTERN_BREAK => {
let start_row = effect_value.ok_or( "invalid file: expected effect value for start row" )?;
Effect::JumpToNextPattern { start_row }
},
DMF_EFFECT_DAC_ENABLE => {
let enabled = effect_value.ok_or( "invalid file: expected effect value for dac enable" )? != 0;
Effect::DacEnable { enabled }
},
DMF_EFFECT_PSG_NOISE_MODE => {
let effect_value = effect_value.ok_or( "invalid file: expected effect value for psg noise mode" )?;
let mode = match effect_value {
0x00 | 0x01 => DcsgChannelMode::FixedFrequency,
0x10 | 0x11 => DcsgChannelMode::Ch3Frequency,
_ => return Err( "invalid file: invalid effect value setting for psg noise mode" )?
};
let noise_type = match effect_value {
0x00 | 0x10 => NoiseType::PeriodicNoise,
0x01 | 0x11 => NoiseType::WhiteNoise,
_ => return Err( "invalid file: invalid effect value setting for psg noise mode" )?
};
Effect::DcsgNoiseMode { mode, noise_type }
},
DMF_EFFECT_NOTE_CUT => {
let after_ticks = effect_value.ok_or( "invalid file: expected effect value setting for note cut" )?;
Effect::NoteCut { after_ticks }
}
_ => Effect::UnknownEffect{ code: effect_code as u8, parameter: effect_value }
} }
); );
} }

View File

@ -49,9 +49,30 @@ pub enum Note {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Effect { pub enum DcsgChannelMode {
pub effect_code: i16, Ch3Frequency,
pub effect_value: Option<i16> FixedFrequency
}
#[derive(Debug)]
pub enum NoiseType {
PeriodicNoise,
WhiteNoise
}
#[derive(Debug)]
pub enum Effect {
Arpeggio { first_shift: u8, second_shift: u8 },
PortamentoUp { speed: u8 },
PortamentoDown { speed: u8 },
PortamentoToNote { speed: u8 },
SetPanning { left: bool, right: bool },
PositionJump { pattern: u8 },
JumpToNextPattern { start_row: u8 },
DacEnable { enabled: bool },
DcsgNoiseMode { mode: DcsgChannelMode, noise_type: NoiseType },
NoteCut { after_ticks: u8 },
UnknownEffect { code: u8, parameter: Option<u8> }
} }
#[derive(Debug)] #[derive(Debug)]