From bc0a33cd7ec505e713f33592948fe3d61dea8737 Mon Sep 17 00:00:00 2001 From: Alula Date: Wed, 16 Sep 2020 21:53:42 +0200 Subject: [PATCH] pixtone fixes --- src/sound/pixtone.rs | 47 +++++++++++++++++++++++++++++-------------- src/sound/playback.rs | 18 ++--------------- src/sound/stuff.rs | 15 ++++++++++++++ 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/src/sound/pixtone.rs b/src/sound/pixtone.rs index a77ad30..b08aeaf 100644 --- a/src/sound/pixtone.rs +++ b/src/sound/pixtone.rs @@ -1,10 +1,12 @@ use std::collections::HashMap; +use num_traits::clamp; use vec_mut_scan::VecMutScan; use lazy_static::lazy_static; use crate::sound::pixtone_sfx::PIXTONE_TABLE; +use crate::sound::stuff::cubic_interp; lazy_static! { static ref WAVEFORMS: [[i8; 0x100]; 6] = { @@ -26,7 +28,7 @@ lazy_static! { } // todo i can't get this shit right - /* +/* let mut seed = 0i32; for i in 0..255 { @@ -36,7 +38,7 @@ lazy_static! { saw_up[i] = (-0x40i32).wrapping_add(i as i32 / 2) as i8; saw_down[i] = (0x40i32.wrapping_sub(i as i32 / 2)) as i8; square[i] = (0x40i32.wrapping_sub(i as i32 & 0x80)) as i8; - random[i] = ((seed >> 16) / 2) as i8; + random[i] = (seed >> 16) as i8 / 2; }*/ [sine, triangle, saw_up, saw_down, square, random] @@ -79,17 +81,6 @@ pub struct Envelope { impl Envelope { pub fn evaluate(&self, i: i32) -> i32 { - let (prev_time, prev_val) = { - if i >= self.time_a { - (self.time_a, self.value_a) - } else if i >= self.time_b { - (self.time_b, self.value_b) - } else if i >= self.time_c { - (self.time_c, self.value_c) - } else { - (0, self.initial) - } - }; let (next_time, next_val) = { if i < self.time_c { (self.time_c, self.value_c) @@ -102,6 +93,18 @@ impl Envelope { } }; + let (prev_time, prev_val) = { + if i >= self.time_a { + (self.time_a, self.value_a) + } else if i >= self.time_b { + (self.time_b, self.value_b) + } else if i >= self.time_c { + (self.time_c, self.value_c) + } else { + (0, self.initial) + } + }; + if next_time <= prev_time { return prev_val; } @@ -188,11 +191,15 @@ impl PixToneParameters { let amplitude_wave = channel.amplitude.get_waveform(); for (i, result) in samples.iter_mut().enumerate() { + if i == channel.length as usize { + break; + } + let carrier = carrier_wave[0xff & phase as usize] as i32 * channel.carrier.level; let freq = frequency_wave[0xff & (channel.frequency.offset as f32 + s(channel.frequency.pitch, i, channel.length)) as usize] as i32 * channel.frequency.level; let amp = amplitude_wave[0xff & (channel.amplitude.offset as f32 + s(channel.amplitude.pitch, i, channel.length)) as usize] as i32 * channel.amplitude.level; - *result += ((carrier * (amp + 4096) / 4096 * channel.envelope.evaluate(s(1.0, i, channel.length) as i32) / 4096) * 256) as i16; + *result = clamp((*result as i32) + (carrier * (amp + 4096) / 4096 * channel.envelope.evaluate(s(1.0, i, channel.length) as i32) / 4096) * 256, -32767, 32767) as i16; phase += delta * (1.0 + (freq as f32 / (if freq < 0 { 8192.0 } else { 2048.0 }))); } @@ -258,7 +265,17 @@ impl PixTonePlayback { remove = true; break; } else { - *result = ((*result as u16 ^ 0x8000u16) as i16).saturating_add(sample[state.1 as usize]) as u16 ^ 0x8000u16; + let pos = state.1 as usize; + let s1 = (sample[pos] as f32) / 32768.0; + let s2 = (sample[clamp(pos + 1, 0, sample.len() - 1)] as f32) / 32768.0; + let s3 = (sample[clamp(pos + 2, 0, sample.len() - 1)] as f32) / 32768.0; + let s4 = (sample[pos.saturating_sub(1)] as f32) / 32768.0; + + let s = cubic_interp(s1, s2, s4, s3, state.1.fract()) * 32768.0; + let sam = (*result ^ 0x8000) as i16; + + *result = sam.saturating_add(s as i16) as u16 ^ 0x8000; + state.1 += delta; } } diff --git a/src/sound/playback.rs b/src/sound/playback.rs index 452801c..8a3e056 100644 --- a/src/sound/playback.rs +++ b/src/sound/playback.rs @@ -4,6 +4,7 @@ use crate::sound::organya::Song as Organya; use crate::sound::stuff::*; use crate::sound::wav::*; use crate::sound::wave_bank::SoundBank; +use num_traits::real::Real; pub struct PlaybackEngine { song: Organya, @@ -328,7 +329,7 @@ impl PlaybackEngine { } // TODO: Create a MixingBuffer or something... -fn mix(dst: &mut [u16], dst_fmt: WavFormat, srcs: &mut [RenderBuffer]) { +pub fn mix(dst: &mut [u16], dst_fmt: WavFormat, srcs: &mut [RenderBuffer]) { let freq = dst_fmt.sample_rate as f64; for buf in srcs { @@ -354,21 +355,6 @@ fn mix(dst: &mut [u16], dst_fmt: WavFormat, srcs: &mut [RenderBuffer]) { } } - // s1: sample 1 - // s2: sample 2 - // sp: previous sample (before s1) - // sn: next sample (after s2) - // mu: position to interpolate for - fn cubic_interp(s1: f32, s2: f32, sp: f32, sn: f32, mu: f32) -> f32 { - let mu2 = mu * mu; - let a0 = sn - s2 - sp + s1; - let a1 = sp - s1 - a0; - let a2 = s2 - sp; - let a3 = s1; - - a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3 - } - #[allow(unused_variables)] for frame in dst.iter_mut() { diff --git a/src/sound/stuff.rs b/src/sound/stuff.rs index 6285f58..6b9cadb 100644 --- a/src/sound/stuff.rs +++ b/src/sound/stuff.rs @@ -34,3 +34,18 @@ pub fn org_vol_to_vol(vol: u8) -> i32 { pub fn org_key_to_oct_pitch(key: u8) -> (u8, u8) { (key/12, key%12) } + +// s1: sample 1 +// s2: sample 2 +// sp: previous sample (before s1) +// sn: next sample (after s2) +// mu: position to interpolate for +pub fn cubic_interp(s1: f32, s2: f32, sp: f32, sn: f32, mu: f32) -> f32 { + let mu2 = mu * mu; + let a0 = sn - s2 - sp + s1; + let a1 = sp - s1 - a0; + let a2 = s2 - sp; + let a3 = s1; + + a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3 +}