From 19560c3f39110fbff910091b5b25e69a044ed18e Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Fri, 16 Dec 2022 18:03:42 -0500 Subject: Initial note volume handling. --- src/convert.rs | 31 ++++++++++++++++++++++--------- src/itfile.rs | 26 ++++++++++++++++++++++---- src/main.rs | 4 ++-- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/convert.rs b/src/convert.rs index 56ab4f7..d3e1a4b 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -39,6 +39,7 @@ struct ChannelMemory postnote: u8, inst: u8, postinst: u8, + initvol: u8, vol: u8, efxmem: [u8; 32], pitch: Rational @@ -53,6 +54,7 @@ impl Default for ChannelMemory postnote: 0xff, inst: 0xff, postinst: 0xff, + initvol: 0, vol: 0, efxmem: Default::default(), pitch: 0u32.into() @@ -60,12 +62,13 @@ impl Default for ChannelMemory } } -pub struct Converter<'a> +pub struct Converter<'a, 'b> where 'a: 'b { + it: &'a ITFile, miditick: Rational, chmem: Vec>>, trks: Vec, - fx_handlers: Vec>>> + fx_handlers: Vec>>> } impl<'a, 'b> Player<'a, 'b> @@ -201,12 +204,13 @@ impl<'a, 'b> Player<'a, 'b> } } -impl<'a> Converter<'a> +impl<'a, 'b> Converter<'a, 'b> { - pub fn new() -> Converter<'a> + pub fn new(it: &'a ITFile) -> Converter<'a, 'b> { let mut ret = Converter { + it, miditick: 0u32.into(), chmem: Vec::new(), trks: Vec::new(), @@ -220,15 +224,21 @@ impl<'a> Converter<'a> fn setup_fx_handlers<'x, 'y>(&mut self) { let nonfx = |ch: u8, cell, chmem: Rc>, ps: PlayerState, t: Rational| { - if !ch == 0 { return Vec::new(); } + if !ch == 0 || ps.in_rep { return Vec::new(); } let mut ret = Vec::new(); - let Cell { mask, note, mut inst, .. } = cell; + let Cell { mask, note, mut inst, mut vol, .. } = cell; if mask & 0x11 != 0 && ps.current_tick == 0 { if mask & 0x22 == 0 { inst = chmem.borrow().postinst; } + if mask & 0x44 == 0 && (0u8..0x78).contains(¬e) + { + let samp = if self.it.inst_mode() { self.it.insts[(inst - 1) as usize].samp_for_key(note) } else { inst }; + if samp != 0 + { vol = self.it.samps[(samp - 1) as usize].default_vol(); } + } match note { 0x78..=0xff => @@ -237,16 +247,18 @@ impl<'a> Converter<'a> ret.push((TimedMidiEvent{t: t.as_int_trunc() as u32, e: MidiEvent::NoteOff{ch: 0, key: chmem.borrow().postnote, vel: 0x40}}, (ch, inst))); chmem.borrow_mut().postnote = 0xff; }, - 0 => (), _ => { if chmem.borrow().postnote != 0xff { ret.push((TimedMidiEvent{t: t.as_int_trunc() as u32, e: MidiEvent::NoteOff{ch: 0, key: chmem.borrow().postnote, vel: 0x40}}, (ch, chmem.borrow().postinst))); } - ret.push((TimedMidiEvent{t: t.as_int_trunc() as u32, e: MidiEvent::NoteOn{ch: 0, key: note, vel: 0x40}}, (ch, inst))); + if vol == 0 { vol = 1; } //TODO: investigate + ret.push((TimedMidiEvent{t: t.as_int_trunc() as u32, e: MidiEvent::NoteOn{ch: 0, key: note, vel: vol}}, (ch, inst))); chmem.borrow_mut().postnote = note; chmem.borrow_mut().postinst = inst; + chmem.borrow_mut().initvol = vol; + chmem.borrow_mut().vol = vol; } } } @@ -278,8 +290,9 @@ impl<'a> Converter<'a> |(i, p)| { instch.insert(*p, i + 1); } ); instch } - pub fn convert(&mut self, it: &ITFile) + pub fn convert(&mut self) { + let it = self.it; let instch = Converter::pre_pass(it); println!("{:?}", instch); self.trks.resize_with(instch.len() + 1, Default::default); diff --git a/src/itfile.rs b/src/itfile.rs index e744ce3..6d85a87 100644 --- a/src/itfile.rs +++ b/src/itfile.rs @@ -3,6 +3,7 @@ use std::io::prelude::*; use std::io::SeekFrom; use std::fs::File; use std::mem::{size_of, zeroed}; +use std::collections::HashSet; use crate::portmod::{Effect, Slide}; @@ -112,7 +113,8 @@ pub struct Inst pub header: InstHeader, pub env_vol: Envelope, pub env_pan: Envelope, - pub env_pit: Envelope + pub env_pit: Envelope, + key_samples: [u8; 120] } impl Inst @@ -125,12 +127,20 @@ impl Inst let env_pan: Envelope = read_struct(f)?; f.seek(SeekFrom::Start(1))?; let env_pit: Envelope = read_struct(f)?; - Ok(Inst{header, env_vol, env_pan, env_pit}) + let mut ks = [0u8; 120]; + for i in 0..120 + { + if header.sample_table[i * 2] < 120 + { ks[header.sample_table[i * 2] as usize] = header.sample_table[i * 2 + 1]; } + } + Ok(Inst{header, env_vol, env_pan, env_pit, key_samples: ks}) } pub fn inst_name(self: &Self) -> String { String::from_utf8_lossy(terminate_cstr(&self.header.inst_name)).into_owned() } pub fn filename(self: &Self) -> String { String::from_utf8_lossy(terminate_cstr(&self.header.dos_filename)).into_owned() } + pub fn samp_for_key(self: &Self, key: u8) -> u8 + { self.key_samples[key as usize] } } #[repr(C, packed)] @@ -178,6 +188,7 @@ impl Samp pub fn is_compressed(self: &Self) -> bool { self.header.flag & 0x8 != 0 } pub fn num_channels(self: &Self) -> u8 { if self.header.flag & 0x4 != 0 { 2 } else { 1 }} pub fn bits_per_sample(self: &Self) -> u8 { if self.header.flag & 0x2 != 0 { 16 } else { 8 }} + pub fn default_vol(self: &Self) -> u8 { self.header.default_volume } } #[derive(Copy, Clone, Default)] @@ -357,6 +368,7 @@ impl ITFile } else { None } } } + pub fn inst_mode(self: &Self) -> bool { self.header.ninst > 0 } } #[derive(Debug)] @@ -549,7 +561,13 @@ pub fn load(filename: &str) -> Result { return Err(self::Error::InvalidHeader); } - println!("{}", inst.inst_name()); + let mut sampsused = HashSet::::new(); + for i in 0u8..120 + { + if inst.samp_for_key(i) > 0 + { sampsused.insert(inst.samp_for_key(i)); } + } + println!("{} [{}] samples {:?}", inst.inst_name(), inst.filename(), sampsused); insts.push(inst); } @@ -577,7 +595,7 @@ pub fn load(filename: &str) -> Result } let dataend_off = f.stream_position()?; last_samp_off = std::cmp::max(last_samp_off, dataend_off); - println!("{}", samp.sample_name()); + println!("{} [{}]", samp.sample_name(), samp.filename()); samps.push(samp); } let mut patterns: Vec = Vec::new(); diff --git a/src/main.rs b/src/main.rs index 8280e5e..e7520c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,8 @@ fn main() -> Result<(), itfile::Error> { { Ok(f) => { - let mut conv = convert::Converter::new(); - conv.convert(&f); + let mut conv = convert::Converter::new(&f); + conv.convert(); let mf = conv.result(); midifile::write_file("output.mid", &mf)?; Ok(()) -- cgit v1.2.3