Skip to content

Commit

Permalink
refactor: volume envelope
Browse files Browse the repository at this point in the history
  • Loading branch information
nenikitov committed Feb 17, 2024
1 parent 84aa652 commit f0a998a
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 30 deletions.
2 changes: 1 addition & 1 deletion engine/src/asset/sound/dat/mixer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl TSongMixerUtils for TSong {

for (i, c) in channels.iter_mut().enumerate() {
let data = c.tick(sample_length);
if i != 255 {
if i == 0 {
m.add_sample(&data, offset);
}
}
Expand Down
2 changes: 1 addition & 1 deletion engine/src/asset/sound/dat/pattern_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ impl AssetParser<Wildcard> for Option<PatternEventVolume> {
Ok((
input,
should_parse.then(|| {
if volume == 255 {
if volume == u8::MAX {
PatternEventVolume::Sample
} else {
PatternEventVolume::Value(volume as f32 / u8::MAX as f32)
Expand Down
122 changes: 100 additions & 22 deletions engine/src/asset/sound/dat/t_instrument.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::rc::Rc;
use std::{cmp, rc::Rc};

use bitflags::bitflags;

Expand All @@ -12,8 +12,28 @@ use crate::{
bitflags! {
#[derive(Debug, Clone, Copy)]
pub struct TInstrumentFlags: u8 {
const HasVolumeEnveloppe = 1 << 0;
const HasPanEnveloppe = 1 << 1;
const HasVolumeEnvelope = 1 << 0;
const HasPanEnvelope = 1 << 1;
}
}

impl AssetParser<Wildcard> for TInstrumentFlags {
type Output = Self;

type Context<'ctx> = ();

fn parser((): Self::Context<'_>) -> impl Fn(Input) -> Result<Self::Output> {
move |input| {
let (input, flags) = number::le_u8(input)?;

Ok((
input,
// TODO(nenikitov): Should be a `Result`
TInstrumentFlags::from_bits(flags).expect(&format!(
"PatternEvent flags should be valid: received: {flags:b}"
)),

Check warning on line 34 in engine/src/asset/sound/dat/t_instrument.rs

View workflow job for this annotation

GitHub Actions / clippy

use of `expect` followed by a function call

warning: use of `expect` followed by a function call --> engine/src/asset/sound/dat/t_instrument.rs:32:52 | 32 | TInstrumentFlags::from_bits(flags).expect(&format!( | ____________________________________________________^ 33 | | "PatternEvent flags should be valid: received: {flags:b}" 34 | | )), | |__________________^ help: try: `unwrap_or_else(|| panic!("PatternEvent flags should be valid: received: {flags:b}"))` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
))
}
}
}

Expand All @@ -25,15 +45,79 @@ pub enum TInstrumentSampleKind {
Predefined(Rc<TSample>),
}

#[derive(Debug)]
pub struct TInstrumentVolumeEnvelope {
data: Vec<f32>,
sustain: Option<usize>,
}

impl TInstrumentVolumeEnvelope {
pub fn volume_beginning(&self) -> &[f32] {
if let Some(sustain) = self.sustain {
&self.data[0..sustain]
} else {
&self.data
}
}

pub fn volume_loop(&self) -> f32 {
if let Some(sustain) = self.sustain {
self.data[sustain]
} else {
64.0 / u8::MAX as f32
}
}

pub fn volume_end(&self) -> &[f32] {
if let Some(sustain) = self.sustain {
&self.data[sustain + 1..]
} else {
&[]
}
}
}

impl AssetParser<Wildcard> for Option<TInstrumentVolumeEnvelope> {
type Output = Self;

type Context<'ctx> = bool;

fn parser(should_parse: Self::Context<'_>) -> impl Fn(Input) -> Result<Self::Output> {
move |input| {
let (input, begin) = number::le_u16(input)?;
let (input, end) = number::le_u16(input)?;
let (input, sustain) = number::le_u16(input)?;
let (input, end_total) = number::le_u16(input)?;
let (input, data) = multi::count!(number::le_u8, 325)(input)?;

Ok((
input,
should_parse.then(|| {
let data = data
.into_iter()
.skip(begin as usize)
.take(cmp::min(cmp::min(end, end_total), 325) as usize)
.map(|v| v as f32 / u8::MAX as f32)
.collect::<Vec<_>>();
TInstrumentVolumeEnvelope {
data,
sustain: if sustain == u16::MAX {
None
} else {
Some((sustain - begin) as usize)
},
}
}),
))
}
}
}

#[derive(Debug)]
pub struct TInstrument {
pub flags: TInstrumentFlags,

pub volume_begin: u16,
pub volume_end: u16,
pub volume_sustain: u16,
pub volume_envelope_border: u16,
pub volume_envelope: Box<[u8; 325]>,
pub volume_envelope: Option<TInstrumentVolumeEnvelope>,

pub pan_begin: u16,
pub pan_end: u16,
Expand All @@ -58,15 +142,13 @@ impl AssetParser<Wildcard> for TInstrument {

fn parser(samples: Self::Context<'_>) -> impl Fn(Input) -> Result<Self::Output> {
move |input| {
let (input, flags) = number::le_u8(input)?;
let (input, flags) = TInstrumentFlags::parser(())(input)?;

let (input, _) = bytes::take(1usize)(input)?;

let (input, volume_begin) = number::le_u16(input)?;
let (input, volume_end) = number::le_u16(input)?;
let (input, volume_sustain) = number::le_u16(input)?;
let (input, volume_envelope_border) = number::le_u16(input)?;
let (input, volume_envelope) = multi::count!(number::le_u8)(input)?;
let (input, volume_envelope) = <Option<TInstrumentVolumeEnvelope>>::parser(
flags.contains(TInstrumentFlags::HasVolumeEnvelope),
)(input)?;

let (input, pan_begin) = number::le_u16(input)?;
let (input, pan_end) = number::le_u16(input)?;
Expand All @@ -83,17 +165,13 @@ impl AssetParser<Wildcard> for TInstrument {
let (input, fadeout) = number::le_u32(input)?;
let (input, vibrato_table) = number::le_u32(input)?;

let (input, sample_indexes): (_, [u8; 96]) = multi::count!(number::le_u8)(input)?;
let (input, sample_indexes): (_, [_; 96]) = multi::count!(number::le_u8)(input)?;

Ok((
input,
Self {
flags: TInstrumentFlags::from_bits(flags).expect("Flags should be valid"),
volume_begin,
volume_end,
volume_sustain,
volume_envelope_border,
volume_envelope: Box::new(volume_envelope),
flags,
volume_envelope,
pan_begin,
pan_end,
pan_sustain,
Expand All @@ -108,7 +186,7 @@ impl AssetParser<Wildcard> for TInstrument {
sample_indexes
.into_iter()
.map(|i| {
if i == 255 {
if i == u8::MAX {
TInstrumentSampleKind::Special
} else {
TInstrumentSampleKind::Predefined(samples[i as usize].clone())
Expand Down
19 changes: 13 additions & 6 deletions engine/src/asset/sound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,19 @@ mod tests {
Sound::Song(s) => Some(s),
Sound::Effect(_) => None,
})
.collect::<Vec<_>>()[0x8];

dbg!(&test_music.patterns[1]
.iter()
.map(|r| &r[2].effects)
.collect::<Vec<_>>());
.collect::<Vec<_>>()[0xC];

// dbg!(&test_music
// .instruments
// .iter()
// .map(|i| (
// i.flags,
// i.volume_envelope_border,
// i.volume_begin,
// i.volume_end,
// i.volume_sustain,
// ))
// .collect::<Vec<_>>());

test_music
.samples
Expand Down

0 comments on commit f0a998a

Please sign in to comment.