Compare commits

...

10 Commits

6 changed files with 334 additions and 139 deletions

4
Cargo.lock generated
View File

@ -71,9 +71,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
[[package]]
name = "arrayvec"

View File

@ -338,16 +338,16 @@ impl BusIo for Bus {
0x10 => self.snd.ch1.sweep = byte.into(),
0x11 => self.snd.ch1.set_duty(byte),
0x12 => self.snd.ch1.envelope = byte.into(),
0x13 => self.snd.ch1.freq_lo = byte,
0x13 => self.snd.ch1.set_freq_lo(byte),
0x14 => self.snd.ch1.set_freq_hi(byte),
0x16 => self.snd.ch2.set_duty(byte),
0x17 => self.snd.ch2.envelope = byte.into(),
0x18 => self.snd.ch2.freq_lo = byte,
0x18 => self.snd.ch2.set_freq_lo(byte),
0x19 => self.snd.ch2.set_freq_hi(byte),
0x1A => self.snd.ch3.set_enabled(byte),
0x1B => self.snd.ch3.set_len(byte),
0x1C => self.snd.ch3.set_volume(byte),
0x1D => self.snd.ch3.freq_lo = byte,
0x1D => self.snd.ch3.set_freq_lo(byte),
0x1E => self.snd.ch3.set_freq_hi(byte),
0x20 => self.snd.ch4.set_len(byte),
0x21 => self.snd.ch4.envelope = byte.into(),

View File

@ -4,8 +4,8 @@ use crate::joypad;
use crate::ppu::Ppu;
use anyhow::Result;
use gilrs::Gilrs;
use rodio::OutputStreamHandle;
use std::time::Duration;
use winit_input_helper::WinitInputHelper;
pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED);
pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines
@ -28,19 +28,26 @@ pub fn rom_title(game_boy: &SM83) -> &str {
game_boy.rom_title().unwrap_or(DEFAULT_TITLE)
}
pub fn run(game_boy: &mut SM83, gamepad: &mut Gilrs, pending: Cycle) -> Cycle {
pub fn run(
game_boy: &mut SM83,
gamepad: &mut Gilrs,
input: &WinitInputHelper,
pending: Cycle,
) -> Cycle {
let mut elapsed = Cycle::new(0);
while elapsed < pending {
elapsed += run_unsynced(game_boy, gamepad);
elapsed += run_unsynced(game_boy, gamepad, input);
}
elapsed
}
pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs) -> Cycle {
pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle {
if let Some(event) = gamepad.next_event() {
joypad::handle_gamepad_input(&mut game_boy.joypad_mut(), event);
joypad::handle_gamepad_input(game_boy.joypad_mut(), event);
} else {
joypad::handle_keyboard_input(game_boy.joypad_mut(), input);
}
game_boy.step()

View File

@ -1,4 +1,5 @@
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType};
use winit_input_helper::WinitInputHelper;
#[derive(Debug, Clone, Copy)]
pub struct Joypad {
@ -109,6 +110,63 @@ impl ButtonEvent {
}
}
pub fn handle_keyboard_input(pad: &mut Joypad, input: &WinitInputHelper) {
use winit::event::VirtualKeyCode;
// TODO: What do I have to do to get a match statement here?
let state = &mut pad.ext;
let irq = &mut pad.interrupt;
if input.key_pressed(VirtualKeyCode::Down) {
state.dpad_down.update(true, irq);
} else if input.key_released(VirtualKeyCode::Down) {
state.dpad_down.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Up) {
state.dpad_up.update(true, irq);
} else if input.key_released(VirtualKeyCode::Up) {
state.dpad_up.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Left) {
state.dpad_left.update(true, irq);
} else if input.key_released(VirtualKeyCode::Left) {
state.dpad_left.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Right) {
state.dpad_right.update(true, irq);
} else if input.key_released(VirtualKeyCode::Right) {
state.dpad_right.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::T) {
state.start.update(true, irq);
} else if input.key_released(VirtualKeyCode::T) {
state.start.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Y) {
state.select.update(true, irq);
} else if input.key_released(VirtualKeyCode::Y) {
state.select.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::Z) {
state.south.update(true, irq);
} else if input.key_released(VirtualKeyCode::Z) {
state.south.update(false, irq);
}
if input.key_pressed(VirtualKeyCode::X) {
state.east.update(true, irq);
} else if input.key_released(VirtualKeyCode::X) {
state.east.update(false, irq);
}
}
pub fn handle_gamepad_input(pad: &mut Joypad, event: GamepadEvent) {
use Button::*;
use GamepadEventType::*;

View File

@ -8,11 +8,10 @@ use std::time::Instant;
use winit::dpi::LogicalSize;
use winit::event::{Event, VirtualKeyCode};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::platform::windows::WindowBuilderExtWindows;
use winit::window::{Window, WindowBuilder};
use winit_input_helper::WinitInputHelper;
const SCALE: f64 = 5.0;
const SCALE: f64 = 2.0;
fn main() -> Result<()> {
let app = App::new(crate_name!())
@ -128,7 +127,7 @@ fn main() -> Result<()> {
now = Instant::now();
let pending = Cycle::new(delta / gb::emu::SM83_CYCLE_TIME.subsec_nanos());
cycle_count += gb::emu::run(&mut game_boy, &mut gamepad, pending);
cycle_count += gb::emu::run(&mut game_boy, &mut gamepad, &input, pending);
if cycle_count >= gb::emu::CYCLES_IN_FRAME {
// Draw Frame
@ -150,6 +149,6 @@ fn create_window(event_loop: &EventLoop<()>, title: &str) -> Result<Window> {
.with_resizable(true)
.with_decorations(true)
.with_transparent(false)
.with_drag_and_drop(false) // OleInitialize failed error if this is set to true
// .with_drag_and_drop(false) // OleInitialize failed error if this is set to true
.build(event_loop)?)
}

View File

@ -3,11 +3,10 @@ use crossbeam_channel::{Receiver, Sender};
use rodio::Source;
use crate::emu::SM83_CLOCK_SPEED;
use crate::Cycle;
const WAVE_PATTERN_RAM_LEN: usize = 0x10;
const SAMPLE_RATE: u32 = 4800; // Hz
const SAMPLE_RATE_IN_CYCLES: Cycle = Cycle::new((SM83_CLOCK_SPEED / SAMPLE_RATE as u64) as u32);
const SAMPLE_RATE: u32 = 48000; // Hz
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
#[derive(Debug, Clone, Default)]
pub(crate) struct Sound {
@ -26,13 +25,13 @@ pub(crate) struct Sound {
div_prev: Option<u8>,
sender: Option<SampleSender>,
cycle: Cycle,
sample_counter: u64,
}
impl Sound {
pub(crate) fn clock(&mut self, div: u16) {
use FrameSequencerState::*;
self.cycle += 1;
self.sample_counter += SAMPLE_INCREMENT;
// the 5th bit of the high byte
let bit_5 = (div >> 13 & 0x01) as u8;
@ -59,19 +58,38 @@ impl Sound {
}
}
self.ch1.clock();
self.ch2.clock();
self.ch3.clock();
self.ch4.clock();
self.div_prev = Some(bit_5);
// TODO: Should the FrameSequencer be run first?
if self.cycle > SAMPLE_RATE_IN_CYCLES {
if self.sample_counter >= SM83_CLOCK_SPEED {
self.sample_counter %= SM83_CLOCK_SPEED;
// Sample the APU
self.cycle %= SAMPLE_RATE_IN_CYCLES;
let left_sample = self.ch2.clock();
let right_sample = self.ch2.clock();
let ch1_amplitude = self.ch1.amplitude();
let ch1_left = self.ctrl.output.ch1_left() as u8 as f32 * ch1_amplitude;
let ch1_right = self.ctrl.output.ch1_right() as u8 as f32 * ch1_amplitude;
let ch2_amplitude = self.ch2.amplitude();
let ch2_left = self.ctrl.output.ch2_left() as u8 as f32 * ch2_amplitude;
let ch2_right = self.ctrl.output.ch2_right() as u8 as f32 * ch2_amplitude;
let ch3_amplitude = self.ch3.amplitude();
let ch3_left = self.ctrl.output.ch3_left() as u8 as f32 * ch3_amplitude;
let ch3_right = self.ctrl.output.ch3_right() as u8 as f32 * ch3_amplitude;
let ch4_amplitude = self.ch4.amplitude();
let ch4_left = self.ctrl.output.ch4_left() as u8 as f32 * ch4_amplitude;
let ch4_right = self.ctrl.output.ch4_right() as u8 as f32 * ch4_amplitude;
let left_sample = (ch1_left + ch2_left + ch3_left + ch4_left) / 4.0;
let right_sample = (ch1_right + ch2_right + ch3_right + ch4_right) / 4.0;
if let Some(send) = self.sender.as_ref() {
send.add_sample(left_sample);
send.add_sample(right_sample);
send.add_sample(left_sample, right_sample);
}
}
}
@ -80,46 +98,54 @@ impl Sound {
self.sender = Some(sender);
}
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
if freq_hi.idk() && *length_timer > 0 {
*length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if *length_timer == 0 {
*enabled = false;
}
}
}
fn clock_length_ch4(freq_data: &Channel4Frequency, length_timer: &mut u16, enabled: &mut bool) {
if freq_data.idk() && *length_timer > 0 {
*length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if *length_timer == 0 {
*enabled = false;
}
}
}
fn handle_length(&mut self) {
if self.ch1.freq_hi.idk() && self.ch1.length_timer > 0 {
self.ch1.length_timer -= 1;
Self::clock_length(
&self.ch1.freq_hi,
&mut self.ch1.length_timer,
&mut self.ch1.enabled,
);
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if self.ch1.length_timer == 0 {
self.ch1.enabled = false;
}
}
Self::clock_length(
&self.ch2.freq_hi,
&mut self.ch2.length_timer,
&mut self.ch2.enabled,
);
if self.ch2.freq_hi.idk() && self.ch2.length_timer > 0 {
self.ch2.length_timer -= 1;
Self::clock_length(
&self.ch3.freq_hi,
&mut self.ch3.length_timer,
&mut self.ch3.enabled,
);
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if self.ch2.length_timer == 0 {
self.ch2.enabled = false;
}
}
if self.ch3.freq_hi.idk() && self.ch3.length_timer > 0 {
self.ch3.length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if self.ch3.length_timer == 0 {
self.ch3.enabled = false;
}
}
if self.ch4.freq_data.idk() && self.ch4.length_timer > 0 {
self.ch4.length_timer -= 1;
// Check in this scope ensures (only) the above subtraction
// made length_timer 0
if self.ch4.length_timer == 0 {
self.ch4.enabled = false;
}
}
Self::clock_length_ch4(
&self.ch4.freq_data,
&mut self.ch4.length_timer,
&mut self.ch4.enabled,
);
}
fn handle_sweep(&mut self) {
@ -147,57 +173,46 @@ impl Sound {
}
}
fn handle_volume(&mut self) {
fn clock_envelope(envelope: &VolumeEnvelope, period_timer: &mut u8, current_volume: &mut u8) {
use EnvelopeDirection::*;
if envelope.period() != 0 {
if *period_timer != 0 {
*period_timer -= 1;
}
if *period_timer == 0 {
*period_timer = envelope.period();
match envelope.direction() {
Decrease if *current_volume > 0x00 => *current_volume -= 1,
Increase if *current_volume < 0x0F => *current_volume += 1,
_ => {}
}
}
}
}
fn handle_volume(&mut self) {
// Channels 1, 2 and 4 have Volume Envelopes
if self.ch1.envelope.period() != 0 {
if self.ch1.period_timer > 0 {
self.ch1.period_timer -= 1;
}
Self::clock_envelope(
&self.ch1.envelope,
&mut self.ch1.period_timer,
&mut self.ch1.current_volume,
);
if self.ch1.period_timer == 0 {
self.ch1.period_timer = self.ch1.envelope.period();
Self::clock_envelope(
&self.ch2.envelope,
&mut self.ch2.period_timer,
&mut self.ch2.current_volume,
);
match self.ch1.envelope.direction() {
Decrease if self.ch1.current_volume > 0x00 => self.ch1.current_volume -= 1,
Increase if self.ch1.current_volume < 0x0F => self.ch1.current_volume += 1,
_ => {}
}
}
}
if self.ch2.envelope.period() != 0 {
if self.ch2.period_timer > 0 {
self.ch2.period_timer -= 1;
}
if self.ch2.period_timer == 0 {
self.ch2.period_timer = self.ch2.envelope.period();
match self.ch2.envelope.direction() {
Decrease if self.ch2.current_volume > 0x00 => self.ch2.current_volume -= 1,
Increase if self.ch2.current_volume < 0x0F => self.ch2.current_volume += 1,
_ => {}
}
}
}
if self.ch4.envelope.period() != 0 {
if self.ch4.period_timer > 0 {
self.ch4.period_timer -= 1;
}
if self.ch4.period_timer == 0 {
self.ch4.period_timer = self.ch4.envelope.period();
match self.ch4.envelope.direction() {
Decrease if self.ch4.current_volume > 0x00 => self.ch4.current_volume -= 1,
Increase if self.ch4.current_volume < 0x0F => self.ch4.current_volume += 1,
_ => {}
}
}
}
Self::clock_envelope(
&self.ch4.envelope,
&mut self.ch4.period_timer,
&mut self.ch4.current_volume,
);
}
}
@ -342,7 +357,7 @@ pub(crate) struct Channel1 {
/// 0xFF12 | NR12 - Channel 1 Volume Envelope
pub(crate) envelope: VolumeEnvelope,
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
pub(crate) freq_lo: u8,
freq_lo: u8,
/// 0xFF14 | NR14 - Channel 1 Frequency high
freq_hi: FrequencyHigh,
@ -358,13 +373,34 @@ pub(crate) struct Channel1 {
// Length Functionality
length_timer: u16,
freq_timer: u16,
duty_pos: u8,
enabled: bool,
}
impl Channel1 {
fn amplitude(&self) -> f32 {
let dac_input = self.duty.wave_pattern().amplitude(self.duty_pos) * self.current_volume;
(dac_input as f32 / 7.5) - 1.0
}
fn clock(&mut self) {
if self.freq_timer != 0 {
self.freq_timer -= 1;
}
if self.freq_timer == 0 {
// TODO: Why is this 2048?
self.freq_timer = (2048 - self.frequency()) * 4;
self.duty_pos = (self.duty_pos + 1) % 8;
}
}
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
pub(crate) fn duty(&self) -> u8 {
self.duty.into()
u8::from(self.duty) & 0xC0 // Only bits 7 and 6 can be read
}
/// 0xFF11 | NR11 - Channel 1 Sound length / Wave pattern duty
@ -373,9 +409,14 @@ impl Channel1 {
self.length_timer = 64 - self.duty.sound_length() as u16;
}
/// 0xFF13 | NR13 - Channel 1 Frequency low (lower 8 bits only)
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
self.freq_lo = byte;
}
/// 0xFF14 | NR14 - Channel 1 Frequency high
pub(crate) fn freq_hi(&self) -> u8 {
self.freq_hi.into()
u8::from(self.freq_hi) & 0x40 // Only bit 6 is readable
}
/// 0xFF14 | NR14 - Channel 1 Frequency high
@ -502,7 +543,7 @@ pub(crate) struct Channel2 {
/// 0xFF17 | NR22 - Channel 2 Volume ENvelope
pub(crate) envelope: VolumeEnvelope,
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
pub(crate) freq_lo: u8,
freq_lo: u8,
/// 0xFF19 | NR24 - Channel 2 Frequency high
freq_hi: FrequencyHigh,
@ -520,21 +561,27 @@ pub(crate) struct Channel2 {
}
impl Channel2 {
fn clock(&mut self) -> u8 {
fn amplitude(&self) -> f32 {
let dac_input = self.duty.wave_pattern().amplitude(self.duty_pos) * self.current_volume;
(dac_input as f32 / 7.5) - 1.0
}
fn clock(&mut self) {
if self.freq_timer != 0 {
self.freq_timer -= 1;
}
if self.freq_timer == 0 {
// TODO: Why is this 2048?
self.freq_timer = (2048 - self.frequency()) * 4;
self.duty_pos = (self.duty_pos + 1) % 8;
}
self.duty.wave_pattern().amplitude(self.duty_pos)
}
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
pub(crate) fn duty(&self) -> u8 {
self.duty.into()
u8::from(self.duty) & 0xC0 // Only bits 7 & 6 are readable
}
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
@ -543,9 +590,14 @@ impl Channel2 {
self.length_timer = 64 - self.duty.sound_length() as u16;
}
/// 0xFF18 | NR23 - Channel 2 Frequency low (lower 8 bits only)
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
self.freq_lo = byte;
}
/// 0xFF19 | NR24 - Channel 2 Frequency high
pub(crate) fn freq_hi(&self) -> u8 {
self.freq_hi.into()
u8::from(self.freq_hi) & 0x40 // only bit 6 is readable
}
/// 0xFF19 | NR24 - Channel 2 Frequency high
@ -717,13 +769,16 @@ pub(crate) struct Channel3 {
/// 0xFF1C | NR32 - Channel 3 Volume
volume: Channel3Volume,
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
pub(crate) freq_lo: u8,
freq_lo: u8,
/// 0xFF1E | NR34 - Channel 3 Frequency high
freq_hi: FrequencyHigh,
pub(crate) wave_ram: [u8; WAVE_PATTERN_RAM_LEN],
// Length Functionality
length_timer: u16,
freq_timer: u16,
offset: u8,
}
impl Channel3 {
@ -738,9 +793,14 @@ impl Channel3 {
self.length_timer = 256 - self.len as u16;
}
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
pub(crate) fn set_freq_lo(&mut self, byte: u8) {
self.freq_lo = byte;
}
/// 0xFF1E | NR34 - Channel 3 Frequency high
pub(crate) fn freq_hi(&self) -> u8 {
self.freq_hi.into()
u8::from(self.freq_hi) & 0x40 // Only bit 6 readable
}
/// 0xFF1E | NR34 - Channel 3 Frequency high
@ -756,7 +816,7 @@ impl Channel3 {
}
pub(crate) fn enabled(&self) -> u8 {
self.enabled as u8
(self.enabled as u8) << 7
}
pub(crate) fn set_enabled(&mut self, byte: u8) {
@ -778,6 +838,39 @@ impl Channel3 {
_ => unreachable!("{:#04X} is not a valid value for Channel3Volume", byte),
};
}
fn amplitude(&self) -> f32 {
let dac_input = self.read_sample(self.offset) >> self.volume.shift_count();
(dac_input as f32 / 7.5) - 1.0
}
fn clock(&mut self) {
if self.freq_timer != 0 {
self.freq_timer -= 1;
}
if self.freq_timer == 0 {
self.freq_timer = (2048 - self.frequency()) * 4;
self.offset = (self.offset + 1) % 8;
}
}
fn read_sample(&self, index: u8) -> u8 {
let i = index as usize / 2;
if index % 2 == 0 {
// We grab the high nibble on even indexes
self.wave_ram[i] >> 4
} else {
// We grab the low nibble on odd indexes
self.wave_ram[i] & 0x0F
}
}
fn frequency(&self) -> u16 {
(self.freq_hi.freq_bits() as u16) << 8 | self.freq_lo as u16
}
}
#[derive(Debug, Clone, Copy)]
@ -826,7 +919,9 @@ pub(crate) struct Channel4 {
length_timer: u16,
/// Linear Feedback Shift Register (15-bit)
shift_register: u16,
lf_shift: u16,
freq_timer: u16,
enabled: bool,
}
@ -845,7 +940,7 @@ impl Channel4 {
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
pub(crate) fn freq_data(&self) -> u8 {
self.freq_data.into()
u8::from(self.freq_data) & 0x40 // only bit 6 readable
}
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
@ -863,17 +958,49 @@ impl Channel4 {
}
// LFSR behaviour during trigger event
self.shift_register = 0x7FFF;
self.lf_shift = 0x7FFF;
}
}
fn amplitude(&self) -> f32 {
let dac_input = (!self.lf_shift & 0x01) as u8 * self.current_volume;
(dac_input as f32 / 7.5) - 1.0
}
fn clock(&mut self) {
if self.freq_timer != 0 {
self.freq_timer -= 1;
}
if self.freq_timer == 0 {
let divisor = Self::divisor(self.poly.divisor_code()) as u16;
self.freq_timer = divisor << self.poly.shift_count();
let xor_result = (self.lf_shift & 0x01) ^ ((self.lf_shift & 0x02) >> 1);
self.lf_shift = (self.lf_shift >> 1) | xor_result << 14;
if let CounterWidth::Long = self.poly.counter_width() {
self.lf_shift = (self.lf_shift & !(0x01 << 6)) | xor_result << 6;
}
}
}
fn divisor(code: u8) -> u8 {
if code == 0 {
return 8;
}
code << 4
}
}
bitfield! {
pub struct PolynomialCounter(u8);
impl Debug;
freq, set_freq: 7, 4;
shift_count, set_shift_count: 7, 4;
from into CounterWidth, counter_width, set_counter_width: 3, 3;
div_ratio, set_div_ratio: 2, 0;
divisor_code, set_divisor_code: 2, 0;
}
impl Copy for PolynomialCounter {}
@ -958,14 +1085,14 @@ impl From<Channel4Frequency> for u8 {
bitfield! {
pub struct SoundOutput(u8);
impl Debug;
pub snd4_so2, set_snd4_so2: 7;
pub snd3_so2, set_snd3_so2: 6;
pub snd2_so2, set_snd2_so2: 5;
pub snd1_so2, set_snd1_so2: 4;
pub snd4_so1, set_snd4_so1: 3;
pub snd3_so1, set_snd3_so1: 2;
pub snd2_so1, set_snd2_so1: 1;
pub snd1_so1, set_snd1_so1: 0;
pub ch4_left, set_ch4_left: 7;
pub ch3_left, set_ch3_left: 6;
pub ch2_left, set_ch2_left: 5;
pub ch1_left, set_ch1_left: 4;
pub ch4_right, set_ch4_right: 3;
pub ch3_right, set_ch3_right: 2;
pub ch2_right, set_ch2_right: 1;
pub ch1_right, set_ch1_right: 0;
}
impl Copy for SoundOutput {}
@ -1039,19 +1166,23 @@ impl AudioSenderReceiver {
#[derive(Debug, Clone)]
pub struct SampleSender {
send: Sender<u8>,
send: Sender<f32>,
}
impl SampleSender {
fn add_sample(&self, sample: u8) {
fn add_sample(&self, left: f32, right: f32) {
self.send
.send(sample)
.send(left)
.expect("Send audio sample across threads");
self.send
.send(right)
.expect("Send audio sample across threads");
}
}
pub struct SampleReceiver {
recv: Receiver<u8>,
recv: Receiver<f32>,
}
impl Iterator for SampleReceiver {
@ -1059,7 +1190,7 @@ impl Iterator for SampleReceiver {
fn next(&mut self) -> Option<Self::Item> {
// TODO: Should this never return none?
self.recv.recv().ok().map(|num| num as f32)
self.recv.recv().ok()
}
}