aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2022-12-16 18:03:42 -0500
committerGravatar Chris Xiong <chirs241097@gmail.com> 2022-12-16 18:36:30 -0500
commit19560c3f39110fbff910091b5b25e69a044ed18e (patch)
treeba4b9cda58c2c9ef326401f3607e5cb1f0a6180f /src
parent7dfed69f5b181c6368ac55e50192b967c0bb4b80 (diff)
downloadit2midi-19560c3f39110fbff910091b5b25e69a044ed18e.tar.xz
Initial note volume handling.
Diffstat (limited to 'src')
-rw-r--r--src/convert.rs31
-rw-r--r--src/itfile.rs26
-rw-r--r--src/main.rs4
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<Rc<RefCell<ChannelMemory>>>,
trks: Vec<MidiTrack>,
- fx_handlers: Vec<Box<RefCell<EfxHandlerFn<'a>>>>
+ fx_handlers: Vec<Box<RefCell<EfxHandlerFn<'b>>>>
}
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<RefCell<ChannelMemory>>, 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(&note)
+ {
+ 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<ITFile, self::Error>
{
return Err(self::Error::InvalidHeader);
}
- println!("{}", inst.inst_name());
+ let mut sampsused = HashSet::<u8>::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<ITFile, self::Error>
}
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<Patt> = 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(())