pixtone fixes

This commit is contained in:
Alula 2020-09-16 21:53:42 +02:00
parent bd3f91c1b1
commit bc0a33cd7e
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
3 changed files with 49 additions and 31 deletions

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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
}