channel 3 audio
This commit is contained in:
parent
62b7bced99
commit
83080ed806
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -279,6 +279,12 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -413,6 +419,7 @@ dependencies = [
|
||||||
"cpal",
|
"cpal",
|
||||||
"futures",
|
"futures",
|
||||||
"gilrs",
|
"gilrs",
|
||||||
|
"itertools",
|
||||||
"minifb",
|
"minifb",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand",
|
||||||
|
@ -546,6 +553,15 @@ dependencies = [
|
||||||
"windows-sys 0.42.0",
|
"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]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
|
|
|
@ -17,3 +17,4 @@ ringbuf = "0.3.2"
|
||||||
async-ringbuf = "0.1.2"
|
async-ringbuf = "0.1.2"
|
||||||
futures = "0.3.26"
|
futures = "0.3.26"
|
||||||
once_cell = "1.17.1"
|
once_cell = "1.17.1"
|
||||||
|
itertools = "0.10.5"
|
||||||
|
|
|
@ -13,6 +13,7 @@ use cpal::{
|
||||||
Device, Stream, StreamConfig,
|
Device, Stream, StreamConfig,
|
||||||
};
|
};
|
||||||
use futures::executor;
|
use futures::executor;
|
||||||
|
use itertools::izip;
|
||||||
use samplerate::{ConverterType, Samplerate};
|
use samplerate::{ConverterType, Samplerate};
|
||||||
|
|
||||||
mod channels;
|
mod channels;
|
||||||
|
@ -27,8 +28,12 @@ const fn reg(a: Address) -> usize {
|
||||||
|
|
||||||
impl DacSample {
|
impl DacSample {
|
||||||
fn mixed(&self, mixer: &Mixer) -> Vec<f32> {
|
fn mixed(&self, mixer: &Mixer) -> Vec<f32> {
|
||||||
let left = (self.one * mixer.ch1.left.scale()) + (self.two * mixer.ch2.left.scale());
|
let left = (self.one * mixer.ch1.left.scale())
|
||||||
let right = (self.one * mixer.ch1.right.scale()) + (self.two * mixer.ch2.right.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![
|
vec![
|
||||||
self.mix_channel(left, mixer.vol_left),
|
self.mix_channel(left, mixer.vol_left),
|
||||||
self.mix_channel(right, mixer.vol_right),
|
self.mix_channel(right, mixer.vol_right),
|
||||||
|
@ -150,18 +155,18 @@ impl Apu {
|
||||||
// tick sound length timers
|
// tick sound length timers
|
||||||
self.channels.one.length_tick();
|
self.channels.one.length_tick();
|
||||||
self.channels.two.length_tick();
|
self.channels.two.length_tick();
|
||||||
|
self.channels.three.length_tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self, steps: usize) {
|
fn tick(&mut self, steps: usize) {
|
||||||
self.buffer.append(
|
self.buffer.append(
|
||||||
&mut self
|
&mut izip!(
|
||||||
.channels
|
self.channels.one.tick(steps).into_iter(),
|
||||||
.one
|
self.channels.two.tick(steps).into_iter(),
|
||||||
.tick(steps)
|
self.channels.three.tick(steps).into_iter()
|
||||||
.into_iter()
|
)
|
||||||
.zip(self.channels.two.tick(steps).into_iter())
|
.map(|(one, two, three)| DacSample { one, two, three })
|
||||||
.map(|(one, two)| DacSample { one, two })
|
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
if self.buffer.len() >= CYCLES_PER_FRAME {
|
if self.buffer.len() >= CYCLES_PER_FRAME {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::Address,
|
processor::memory::Address,
|
||||||
util::{get_bit, set_or_clear_bit},
|
util::{get_bit, set_or_clear_bit, Nibbles},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
@ -180,7 +180,7 @@ impl PwmChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn frequency_tick(&mut self) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
self.sweep.counter += 1;
|
self.sweep.counter += 1;
|
||||||
|
@ -279,6 +279,7 @@ impl PwmChannel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
enum ShiftVolumePercent {
|
enum ShiftVolumePercent {
|
||||||
Zero,
|
Zero,
|
||||||
TwentyFive,
|
TwentyFive,
|
||||||
|
@ -286,6 +287,30 @@ enum ShiftVolumePercent {
|
||||||
OneHundred,
|
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) struct WaveChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
dac_enabled: bool,
|
dac_enabled: bool,
|
||||||
|
@ -295,7 +320,7 @@ pub(super) struct WaveChannel {
|
||||||
wavelength: u16,
|
wavelength: u16,
|
||||||
wave_timer: u16,
|
wave_timer: u16,
|
||||||
wave_position: usize,
|
wave_position: usize,
|
||||||
wave_ram: [u8; 16],
|
wave_ram: WaveRam,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaveChannel {
|
impl WaveChannel {
|
||||||
|
@ -308,9 +333,9 @@ impl WaveChannel {
|
||||||
length_timer: 0xFF,
|
length_timer: 0xFF,
|
||||||
volume: ShiftVolumePercent::Zero,
|
volume: ShiftVolumePercent::Zero,
|
||||||
wavelength,
|
wavelength,
|
||||||
wave_timer: (2048 - wavelength) * 4,
|
wave_timer: (2048 - wavelength) * 2,
|
||||||
wave_position: 1,
|
wave_position: 1,
|
||||||
wave_ram: [0; 16],
|
wave_ram: WaveRam { data: [0; 16] },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +343,41 @@ impl WaveChannel {
|
||||||
self.enabled = true;
|
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) {
|
pub(super) fn update_dac(&mut self, data: u8) {
|
||||||
self.dac_enabled = get_bit(data, 7);
|
self.dac_enabled = get_bit(data, 7);
|
||||||
}
|
}
|
||||||
|
@ -337,7 +397,7 @@ impl WaveChannel {
|
||||||
0b10 => ShiftVolumePercent::Fifty,
|
0b10 => ShiftVolumePercent::Fifty,
|
||||||
0b11 => ShiftVolumePercent::TwentyFive,
|
0b11 => ShiftVolumePercent::TwentyFive,
|
||||||
_ => panic!("should be unreachable"),
|
_ => panic!("should be unreachable"),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_volume(&self) -> u8 {
|
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) {
|
pub(super) fn update_wave_ram(&mut self, addr: Address, data: u8) {
|
||||||
let real_addr = (addr - 0xFF30) as usize;
|
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");
|
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) {
|
fn set_wave_timer(&mut self) {
|
||||||
self.wave_timer = (2048 - self.wavelength) * 4;
|
self.wave_timer = (2048 - self.wavelength) * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,10 +93,15 @@ impl Default for Mixer {
|
||||||
pub(super) struct DacSample {
|
pub(super) struct DacSample {
|
||||||
pub(super) one: f32,
|
pub(super) one: f32,
|
||||||
pub(super) two: f32,
|
pub(super) two: f32,
|
||||||
|
pub(super) three: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DacSample {
|
impl Default for DacSample {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { one: 0., two: 0. }
|
Self {
|
||||||
|
one: 0.,
|
||||||
|
two: 0.,
|
||||||
|
three: 0.,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue