channel 3 audio

This commit is contained in:
Alex Janka 2023-02-20 14:26:30 +11:00
parent 62b7bced99
commit 83080ed806
5 changed files with 107 additions and 20 deletions

16
Cargo.lock generated
View file

@ -279,6 +279,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "errno"
version = "0.2.8"
@ -413,6 +419,7 @@ dependencies = [
"cpal",
"futures",
"gilrs",
"itertools",
"minifb",
"once_cell",
"rand",
@ -546,6 +553,15 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "jni"
version = "0.19.0"

View file

@ -17,3 +17,4 @@ ringbuf = "0.3.2"
async-ringbuf = "0.1.2"
futures = "0.3.26"
once_cell = "1.17.1"
itertools = "0.10.5"

View file

@ -13,6 +13,7 @@ use cpal::{
Device, Stream, StreamConfig,
};
use futures::executor;
use itertools::izip;
use samplerate::{ConverterType, Samplerate};
mod channels;
@ -27,8 +28,12 @@ const fn reg(a: Address) -> usize {
impl DacSample {
fn mixed(&self, mixer: &Mixer) -> Vec<f32> {
let left = (self.one * mixer.ch1.left.scale()) + (self.two * mixer.ch2.left.scale());
let right = (self.one * mixer.ch1.right.scale()) + (self.two * mixer.ch2.right.scale());
let left = (self.one * mixer.ch1.left.scale())
+ (self.two * mixer.ch2.left.scale())
+ (self.three * mixer.ch3.left.scale());
let right = (self.one * mixer.ch1.right.scale())
+ (self.two * mixer.ch2.right.scale())
+ (self.three * mixer.ch3.right.scale());
vec![
self.mix_channel(left, mixer.vol_left),
self.mix_channel(right, mixer.vol_right),
@ -150,19 +155,19 @@ impl Apu {
// tick sound length timers
self.channels.one.length_tick();
self.channels.two.length_tick();
self.channels.three.length_tick();
}
}
fn tick(&mut self, steps: usize) {
self.buffer.append(
&mut self
.channels
.one
.tick(steps)
.into_iter()
.zip(self.channels.two.tick(steps).into_iter())
.map(|(one, two)| DacSample { one, two })
.collect(),
&mut izip!(
self.channels.one.tick(steps).into_iter(),
self.channels.two.tick(steps).into_iter(),
self.channels.three.tick(steps).into_iter()
)
.map(|(one, two, three)| DacSample { one, two, three })
.collect(),
);
if self.buffer.len() >= CYCLES_PER_FRAME {
self.next_audio();

View file

@ -1,6 +1,6 @@
use crate::{
processor::memory::Address,
util::{get_bit, set_or_clear_bit},
util::{get_bit, set_or_clear_bit, Nibbles},
};
#[derive(Clone, Copy, PartialEq)]
@ -180,7 +180,7 @@ impl PwmChannel {
}
pub(super) fn frequency_tick(&mut self) {
if self.sweep.slope == 0 || !self.enabled {
if self.sweep.slope == 0 || self.sweep.pace == 0 || !self.enabled {
return;
}
self.sweep.counter += 1;
@ -279,6 +279,7 @@ impl PwmChannel {
}
}
#[derive(Debug, PartialEq)]
enum ShiftVolumePercent {
Zero,
TwentyFive,
@ -286,6 +287,30 @@ enum ShiftVolumePercent {
OneHundred,
}
impl ShiftVolumePercent {
fn as_shift_amount(&self) -> u8 {
match self {
ShiftVolumePercent::Zero => 8,
ShiftVolumePercent::TwentyFive => 2,
ShiftVolumePercent::Fifty => 1,
ShiftVolumePercent::OneHundred => 0,
}
}
}
struct WaveRam {
data: [u8; 16],
}
impl WaveRam {
fn as_samples(&self) -> Vec<u8> {
self.data
.into_iter()
.flat_map(|v| [v.get_high_nibble(), v.get_low_nibble()])
.collect()
}
}
pub(super) struct WaveChannel {
pub(super) enabled: bool,
dac_enabled: bool,
@ -295,7 +320,7 @@ pub(super) struct WaveChannel {
wavelength: u16,
wave_timer: u16,
wave_position: usize,
wave_ram: [u8; 16],
wave_ram: WaveRam,
}
impl WaveChannel {
@ -308,9 +333,9 @@ impl WaveChannel {
length_timer: 0xFF,
volume: ShiftVolumePercent::Zero,
wavelength,
wave_timer: (2048 - wavelength) * 4,
wave_timer: (2048 - wavelength) * 2,
wave_position: 1,
wave_ram: [0; 16],
wave_ram: WaveRam { data: [0; 16] },
}
}
@ -318,6 +343,41 @@ impl WaveChannel {
self.enabled = true;
}
pub fn tick(&mut self, steps: usize) -> Vec<f32> {
if self.enabled {
(0..steps)
.map(|_| {
let b;
(self.wave_timer, b) = self.wave_timer.overflowing_sub(1);
if b {
self.wave_position = (self.wave_position + 1) % 32;
self.set_wave_timer();
}
self.dac(self.wave_ram.as_samples()[self.wave_position])
})
.collect()
} else {
vec![0.; steps]
}
}
fn dac(&self, digital: u8) -> f32 {
if self.dac_enabled && self.volume != ShiftVolumePercent::Zero {
((((digital >> self.volume.as_shift_amount()) as f32) * (-2.)) + 1.) / 15.
} else {
0.
}
}
pub(super) fn length_tick(&mut self) {
if self.length_enable && self.enabled {
self.length_timer += 1;
if self.length_timer >= 64 {
self.enabled = false;
}
}
}
pub(super) fn update_dac(&mut self, data: u8) {
self.dac_enabled = get_bit(data, 7);
}
@ -337,7 +397,7 @@ impl WaveChannel {
0b10 => ShiftVolumePercent::Fifty,
0b11 => ShiftVolumePercent::TwentyFive,
_ => panic!("should be unreachable"),
}
};
}
pub(super) fn get_volume(&self) -> u8 {
@ -370,14 +430,14 @@ impl WaveChannel {
pub(super) fn update_wave_ram(&mut self, addr: Address, data: u8) {
let real_addr = (addr - 0xFF30) as usize;
if real_addr >= self.wave_ram.len() {
if real_addr >= self.wave_ram.data.len() {
panic!("sent the wrong address to update_wave_ram");
}
self.wave_ram[real_addr] = data;
self.wave_ram.data[real_addr] = data;
}
fn set_wave_timer(&mut self) {
self.wave_timer = (2048 - self.wavelength) * 4;
self.wave_timer = (2048 - self.wavelength) * 2;
}
}

View file

@ -93,10 +93,15 @@ impl Default for Mixer {
pub(super) struct DacSample {
pub(super) one: f32,
pub(super) two: f32,
pub(super) three: f32,
}
impl Default for DacSample {
fn default() -> Self {
Self { one: 0., two: 0. }
Self {
one: 0.,
two: 0.,
three: 0.,
}
}
}