Compare commits
No commits in common. "a1eadc0bc446c581ebed009ce7dd2cf35235a20c" and "08bd33b4d4d8af509b352ef9ea701591c065b299" have entirely different histories.
a1eadc0bc4
...
08bd33b4d4
|
@ -1,92 +0,0 @@
|
||||||
use super::{AUDIO_BUFFER_LEN, CHANNEL_COUNT, SAMPLE_RATE};
|
|
||||||
use crossbeam_channel::{Receiver, Sender, TrySendError};
|
|
||||||
use rodio::Source;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
pub struct AudioMPSC;
|
|
||||||
|
|
||||||
impl AudioMPSC {
|
|
||||||
pub fn new() -> (AudioSender<f32>, AudioReceiver<f32>) {
|
|
||||||
// TODO: Can we provide an upper limit for this?
|
|
||||||
// The larger this channel is, the more lag there is between the Audio and
|
|
||||||
// Emulator
|
|
||||||
let (send, recv) = crossbeam_channel::unbounded();
|
|
||||||
|
|
||||||
(AudioSender { inner: send }, AudioReceiver { inner: recv })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct AudioSender<T> {
|
|
||||||
inner: Sender<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> AudioSender<T> {
|
|
||||||
pub(crate) fn send_samples(&self, left: T, right: T) -> Result<(), TrySendError<T>> {
|
|
||||||
self.inner.try_send(left).and(self.inner.try_send(right))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AudioReceiver<T> {
|
|
||||||
inner: Receiver<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Iterator for AudioReceiver<T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
// TODO: Should this never return none?
|
|
||||||
self.inner.recv().ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: rodio::Sample> Source for AudioReceiver<T> {
|
|
||||||
fn current_frame_len(&self) -> Option<usize> {
|
|
||||||
// A frame changes when the samples rate or
|
|
||||||
// number of channels change. This will never happen, so
|
|
||||||
// we return
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn channels(&self) -> u16 {
|
|
||||||
// The Gameboy supports two channels
|
|
||||||
CHANNEL_COUNT as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sample_rate(&self) -> u32 {
|
|
||||||
SAMPLE_RATE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn total_duration(&self) -> Option<std::time::Duration> {
|
|
||||||
// The duration of this source is infinite
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub(crate) struct AudioBuffer<T> {
|
|
||||||
inner: VecDeque<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for AudioBuffer<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: VecDeque::with_capacity(AUDIO_BUFFER_LEN * CHANNEL_COUNT),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> AudioBuffer<T> {
|
|
||||||
pub(crate) fn push_back(&mut self, value: T) {
|
|
||||||
self.inner.push_back(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn pop_front(&mut self) -> Option<T> {
|
|
||||||
self.inner.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn len(&self) -> usize {
|
|
||||||
self.inner.len()
|
|
||||||
}
|
|
||||||
}
|
|
535
src/apu/types.rs
535
src/apu/types.rs
|
@ -1,535 +0,0 @@
|
||||||
use bitfield::bitfield;
|
|
||||||
|
|
||||||
pub(crate) mod ch1 {
|
|
||||||
use super::bitfield;
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct Sweep(u8);
|
|
||||||
impl Debug;
|
|
||||||
_period, _: 6, 4;
|
|
||||||
from into SweepDirection, _direction, _: 3, 3;
|
|
||||||
_shift_count, _: 2, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sweep {
|
|
||||||
pub(crate) fn period(&self) -> u8 {
|
|
||||||
self._period()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn shift_count(&self) -> u8 {
|
|
||||||
self._shift_count()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn direction(&self) -> SweepDirection {
|
|
||||||
self._direction()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for Sweep {}
|
|
||||||
impl Clone for Sweep {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Sweep {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for Sweep {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Sweep> for u8 {
|
|
||||||
fn from(sweep: Sweep) -> Self {
|
|
||||||
sweep.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum SweepDirection {
|
|
||||||
Increase = 0,
|
|
||||||
Decrease = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for SweepDirection {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
match byte & 0x01 {
|
|
||||||
0b00 => Self::Increase,
|
|
||||||
0b01 => Self::Decrease,
|
|
||||||
_ => unreachable!("{:04X} is not a valid value for SweepChange", byte),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SweepDirection> for u8 {
|
|
||||||
fn from(change: SweepDirection) -> Self {
|
|
||||||
change as u8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod ch3 {
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum Volume {
|
|
||||||
Mute = 0,
|
|
||||||
Full = 1,
|
|
||||||
Half = 2,
|
|
||||||
Quarter = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Volume {
|
|
||||||
pub(crate) fn shift_count(&self) -> u8 {
|
|
||||||
use Volume::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
Mute => 4,
|
|
||||||
Full => 0,
|
|
||||||
Half => 1,
|
|
||||||
Quarter => 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Volume {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Mute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod ch4 {
|
|
||||||
use super::bitfield;
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct PolynomialCounter(u8);
|
|
||||||
impl Debug;
|
|
||||||
_shift_count, _: 7, 4;
|
|
||||||
from into CounterWidth, _counter_width, _: 3, 3;
|
|
||||||
_divisor_code, _: 2, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolynomialCounter {
|
|
||||||
pub(crate) fn divisor_code(&self) -> u8 {
|
|
||||||
self._divisor_code()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn counter_width(&self) -> CounterWidth {
|
|
||||||
self._counter_width()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn shift_count(&self) -> u8 {
|
|
||||||
self._shift_count()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for PolynomialCounter {}
|
|
||||||
impl Clone for PolynomialCounter {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PolynomialCounter {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for PolynomialCounter {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PolynomialCounter> for u8 {
|
|
||||||
fn from(poly: PolynomialCounter) -> Self {
|
|
||||||
poly.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum CounterWidth {
|
|
||||||
Long, // 15 bits long
|
|
||||||
Short, // 7 bits long
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for CounterWidth {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
match byte & 0x01 {
|
|
||||||
0b00 => Self::Short,
|
|
||||||
0b01 => Self::Long,
|
|
||||||
_ => unreachable!("{:#04X} is not a valid value for CounterWidth"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CounterWidth> for u8 {
|
|
||||||
fn from(counter_width: CounterWidth) -> Self {
|
|
||||||
counter_width as u8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct Frequency(u8);
|
|
||||||
impl Debug;
|
|
||||||
_initial, _: 7;
|
|
||||||
_idk, _: 6; // TODO: same as FrequencyHigh, figure out what this is
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frequency {
|
|
||||||
pub(crate) fn idk(&self) -> bool {
|
|
||||||
self._idk()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn initial(&self) -> bool {
|
|
||||||
self._initial()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for Frequency {}
|
|
||||||
impl Clone for Frequency {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Frequency {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for Frequency {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte & 0xC0) // Only bits 7 and 6 hold anything of value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Frequency> for u8 {
|
|
||||||
fn from(state: Frequency) -> Self {
|
|
||||||
state.0 & 0x40 // Only bit 6 holds anything of value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod common {
|
|
||||||
use super::bitfield;
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct FrequencyHigh(u8);
|
|
||||||
impl Debug;
|
|
||||||
_initial, _: 7;
|
|
||||||
_idk, _: 6; // TODO: Figure out what the hell this is
|
|
||||||
pub freq_bits, set_freq_bits: 2, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrequencyHigh {
|
|
||||||
pub(crate) fn initial(&self) -> bool {
|
|
||||||
self._initial()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn idk(&self) -> bool {
|
|
||||||
self._idk()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for FrequencyHigh {}
|
|
||||||
impl Clone for FrequencyHigh {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FrequencyHigh {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for FrequencyHigh {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FrequencyHigh> for u8 {
|
|
||||||
fn from(freq: FrequencyHigh) -> Self {
|
|
||||||
freq.0 & 0x40 // Only bit 6 can be read
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct VolumeEnvelope(u8);
|
|
||||||
impl Debug;
|
|
||||||
_init_vol, _: 7, 4;
|
|
||||||
from into EnvelopeDirection, _direction, _: 3, 3;
|
|
||||||
_period, _: 2, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VolumeEnvelope {
|
|
||||||
pub(crate) fn init_vol(&self) -> u8 {
|
|
||||||
self._init_vol()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn direction(&self) -> EnvelopeDirection {
|
|
||||||
self._direction()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn period(&self) -> u8 {
|
|
||||||
self._period()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for VolumeEnvelope {}
|
|
||||||
impl Clone for VolumeEnvelope {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for VolumeEnvelope {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for VolumeEnvelope {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<VolumeEnvelope> for u8 {
|
|
||||||
fn from(envelope: VolumeEnvelope) -> Self {
|
|
||||||
envelope.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum EnvelopeDirection {
|
|
||||||
Decrease = 0,
|
|
||||||
Increase = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for EnvelopeDirection {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
match byte & 0b01 {
|
|
||||||
0b00 => Self::Decrease,
|
|
||||||
0b01 => Self::Increase,
|
|
||||||
_ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EnvelopeDirection> for u8 {
|
|
||||||
fn from(direction: EnvelopeDirection) -> Self {
|
|
||||||
direction as u8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for EnvelopeDirection {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Decrease
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct SoundDuty(u8);
|
|
||||||
impl Debug;
|
|
||||||
from into WavePattern, _wave_pattern, _: 7, 6;
|
|
||||||
_sound_length, _: 5, 0; // TODO: Getter only used if bit 6 in NR14 is set
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SoundDuty {
|
|
||||||
pub(crate) fn wave_pattern(&self) -> WavePattern {
|
|
||||||
self._wave_pattern()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn sound_length(&self) -> u8 {
|
|
||||||
self._sound_length()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for SoundDuty {}
|
|
||||||
impl Clone for SoundDuty {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SoundDuty {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for SoundDuty {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SoundDuty> for u8 {
|
|
||||||
fn from(duty: SoundDuty) -> Self {
|
|
||||||
duty.0 & 0xC0 // Only bits 7 and 6 can be read
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum WavePattern {
|
|
||||||
OneEighth = 0, // 12.5% ( _-------_-------_------- )
|
|
||||||
OneQuarter = 1, // 25% ( __------__------__------ )
|
|
||||||
OneHalf = 2, // 50% ( ____----____----____---- ) (normal)
|
|
||||||
ThreeQuarters = 3, // 75% ( ______--______--______-- )
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WavePattern {
|
|
||||||
pub(crate) const fn amplitude(&self, index: u8) -> u8 {
|
|
||||||
use WavePattern::*;
|
|
||||||
let i = 7 - index; // an index of 0 should get the highest bit
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
OneEighth => (0b00000001 >> i) & 0x01,
|
|
||||||
OneQuarter => (0b10000001 >> i) & 0x01,
|
|
||||||
OneHalf => (0b10000111 >> i) & 0x01,
|
|
||||||
ThreeQuarters => (0b01111110 >> i) & 0x01,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for WavePattern {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::OneEighth // Rationale: OneEighth is 0x00
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WavePattern> for u8 {
|
|
||||||
fn from(pattern: WavePattern) -> Self {
|
|
||||||
pattern as Self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for WavePattern {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
match byte & 0b11 {
|
|
||||||
0b00 => Self::OneEighth,
|
|
||||||
0b01 => Self::OneQuarter,
|
|
||||||
0b10 => Self::OneHalf,
|
|
||||||
0b11 => Self::ThreeQuarters,
|
|
||||||
_ => unreachable!("{:#04X} is not a valid value for WavePattern", byte),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub(crate) enum FrameSequencerState {
|
|
||||||
Step0Length,
|
|
||||||
Step1Nothing,
|
|
||||||
Step2LengthAndSweep,
|
|
||||||
Step3Nothing,
|
|
||||||
Step4Length,
|
|
||||||
Step5Nothing,
|
|
||||||
Step6LengthAndSweep,
|
|
||||||
Step7VolumeEnvelope,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrameSequencerState {
|
|
||||||
pub(crate) fn step(&mut self) {
|
|
||||||
use FrameSequencerState::*;
|
|
||||||
|
|
||||||
*self = match *self {
|
|
||||||
Step0Length => Step1Nothing,
|
|
||||||
Step1Nothing => Step2LengthAndSweep,
|
|
||||||
Step2LengthAndSweep => Step3Nothing,
|
|
||||||
Step3Nothing => Step4Length,
|
|
||||||
Step4Length => Step5Nothing,
|
|
||||||
Step5Nothing => Step6LengthAndSweep,
|
|
||||||
Step6LengthAndSweep => Step7VolumeEnvelope,
|
|
||||||
Step7VolumeEnvelope => Step0Length,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FrameSequencerState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Step0Length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct SoundOutput(u8);
|
|
||||||
impl Debug;
|
|
||||||
pub ch4_left, _: 7;
|
|
||||||
pub ch3_left, _: 6;
|
|
||||||
pub ch2_left, _: 5;
|
|
||||||
pub ch1_left, _: 4;
|
|
||||||
pub ch4_right, _: 3;
|
|
||||||
pub ch3_right, _: 2;
|
|
||||||
pub ch2_right, _: 1;
|
|
||||||
pub ch1_right, _: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for SoundOutput {}
|
|
||||||
impl Clone for SoundOutput {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SoundOutput {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for SoundOutput {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SoundOutput> for u8 {
|
|
||||||
fn from(output: SoundOutput) -> Self {
|
|
||||||
output.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield! {
|
|
||||||
pub struct ChannelControl(u8);
|
|
||||||
impl Debug;
|
|
||||||
vin_so2, _: 7;
|
|
||||||
so2_level, _: 6, 4;
|
|
||||||
vin_so1, _: 3;
|
|
||||||
so1_level, _: 2, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Copy for ChannelControl {}
|
|
||||||
impl Clone for ChannelControl {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ChannelControl {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for ChannelControl {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
Self(byte)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ChannelControl> for u8 {
|
|
||||||
fn from(ctrl: ChannelControl) -> Self {
|
|
||||||
ctrl.0
|
|
||||||
}
|
|
||||||
}
|
|
109
src/bus.rs
109
src/bus.rs
|
@ -1,11 +1,10 @@
|
||||||
use crate::apu::gen::AudioSender;
|
|
||||||
use crate::apu::Apu;
|
|
||||||
use crate::cartridge::Cartridge;
|
use crate::cartridge::Cartridge;
|
||||||
use crate::high_ram::HighRam;
|
use crate::high_ram::HighRam;
|
||||||
use crate::interrupt::{Interrupt, InterruptFlag};
|
use crate::interrupt::{Interrupt, InterruptFlag};
|
||||||
use crate::joypad::Joypad;
|
use crate::joypad::Joypad;
|
||||||
use crate::ppu::{Ppu, PpuMode};
|
use crate::ppu::{Ppu, PpuMode};
|
||||||
use crate::serial::Serial;
|
use crate::serial::Serial;
|
||||||
|
use crate::sound::{AudioSender, Sound};
|
||||||
use crate::timer::Timer;
|
use crate::timer::Timer;
|
||||||
use crate::work_ram::{VariableWorkRam, WorkRam};
|
use crate::work_ram::{VariableWorkRam, WorkRam};
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::Read};
|
||||||
|
@ -21,7 +20,7 @@ pub struct Bus {
|
||||||
var_ram: VariableWorkRam,
|
var_ram: VariableWorkRam,
|
||||||
pub(crate) timer: Timer,
|
pub(crate) timer: Timer,
|
||||||
int: Interrupt,
|
int: Interrupt,
|
||||||
apu: Apu,
|
snd: Sound,
|
||||||
high_ram: HighRam,
|
high_ram: HighRam,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
pub(crate) joypad: Joypad,
|
pub(crate) joypad: Joypad,
|
||||||
|
@ -37,7 +36,7 @@ impl Default for Bus {
|
||||||
var_ram: Default::default(),
|
var_ram: Default::default(),
|
||||||
timer: Default::default(),
|
timer: Default::default(),
|
||||||
int: Default::default(),
|
int: Default::default(),
|
||||||
apu: Default::default(),
|
snd: Default::default(),
|
||||||
high_ram: Default::default(),
|
high_ram: Default::default(),
|
||||||
serial: Default::default(),
|
serial: Default::default(),
|
||||||
joypad: Default::default(),
|
joypad: Default::default(),
|
||||||
|
@ -67,22 +66,22 @@ impl Bus {
|
||||||
self.cartridge.as_ref()?.title()
|
self.cartridge.as_ref()?.title()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn apu(&self) -> &Apu {
|
|
||||||
&self.apu
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn apu_mut(&mut self) -> &mut Apu {
|
|
||||||
&mut self.apu
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn pass_audio_src(&mut self, sender: AudioSender<f32>) {
|
pub(crate) fn pass_audio_src(&mut self, sender: AudioSender<f32>) {
|
||||||
self.apu.set_audio_src(sender)
|
self.snd.set_audio_src(sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_full(&self) -> bool {
|
||||||
|
self.snd.is_full()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn flush_samples(&mut self) {
|
||||||
|
self.snd.flush_samples()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clock(&mut self) {
|
pub(crate) fn clock(&mut self) {
|
||||||
self.ppu.clock();
|
self.ppu.clock();
|
||||||
self.timer.clock();
|
self.timer.clock();
|
||||||
self.apu.clock(self.timer.divider);
|
self.snd.clock(self.timer.divider);
|
||||||
self.clock_dma();
|
self.clock_dma();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,25 +228,25 @@ impl BusIo for Bus {
|
||||||
0x06 => self.timer.modulo,
|
0x06 => self.timer.modulo,
|
||||||
0x07 => self.timer.ctrl.into(),
|
0x07 => self.timer.ctrl.into(),
|
||||||
0x0F => self.interrupt_flag().into(),
|
0x0F => self.interrupt_flag().into(),
|
||||||
0x10 => self.apu.ch1.sweep.into(),
|
0x10 => self.snd.ch1.sweep.into(),
|
||||||
0x11 => self.apu.ch1.duty(),
|
0x11 => self.snd.ch1.duty(),
|
||||||
0x12 => self.apu.ch1.envelope.into(),
|
0x12 => self.snd.ch1.envelope.into(),
|
||||||
0x14 => self.apu.ch1.freq_hi(),
|
0x14 => self.snd.ch1.freq_hi(),
|
||||||
0x16 => self.apu.ch2.duty(),
|
0x16 => self.snd.ch2.duty(),
|
||||||
0x17 => self.apu.ch2.envelope.into(),
|
0x17 => self.snd.ch2.envelope.into(),
|
||||||
0x19 => self.apu.ch2.freq_hi(),
|
0x19 => self.snd.ch2.freq_hi(),
|
||||||
0x1A => self.apu.ch3.enabled(),
|
0x1A => self.snd.ch3.enabled(),
|
||||||
0x1B => self.apu.ch3.len(),
|
0x1B => self.snd.ch3.len(),
|
||||||
0x1C => self.apu.ch3.volume(),
|
0x1C => self.snd.ch3.volume(),
|
||||||
0x1E => self.apu.ch3.freq_hi(),
|
0x1E => self.snd.ch3.freq_hi(),
|
||||||
0x20 => self.apu.ch4.len(),
|
0x20 => self.snd.ch4.len(),
|
||||||
0x21 => self.apu.ch4.envelope.into(),
|
0x21 => self.snd.ch4.envelope.into(),
|
||||||
0x22 => self.apu.ch4.poly.into(),
|
0x22 => self.snd.ch4.poly.into(),
|
||||||
0x23 => self.apu.ch4.freq_data(),
|
0x23 => self.snd.ch4.freq_data(),
|
||||||
0x24 => self.apu.ctrl.channel.into(),
|
0x24 => self.snd.ctrl.channel.into(),
|
||||||
0x25 => self.apu.ctrl.output.into(),
|
0x25 => self.snd.ctrl.output.into(),
|
||||||
0x26 => self.apu.ctrl.status(&self.apu),
|
0x26 => self.snd.ctrl.status(&self.snd),
|
||||||
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30],
|
0x30..=0x3F => self.snd.ch3.wave_ram[addr as usize - 0xFF30],
|
||||||
0x40 => self.ppu.ctrl.into(),
|
0x40 => self.ppu.ctrl.into(),
|
||||||
0x41 => self.ppu.stat.into(),
|
0x41 => self.ppu.stat.into(),
|
||||||
0x42 => self.ppu.pos.scroll_y,
|
0x42 => self.ppu.pos.scroll_y,
|
||||||
|
@ -344,28 +343,28 @@ impl BusIo for Bus {
|
||||||
0x06 => self.timer.modulo = byte,
|
0x06 => self.timer.modulo = byte,
|
||||||
0x07 => self.timer.ctrl = byte.into(),
|
0x07 => self.timer.ctrl = byte.into(),
|
||||||
0x0F => self.set_interrupt_flag(byte),
|
0x0F => self.set_interrupt_flag(byte),
|
||||||
0x10 => self.apu.ch1.sweep = byte.into(),
|
0x10 => self.snd.ch1.sweep = byte.into(),
|
||||||
0x11 => self.apu.ch1.set_duty(byte),
|
0x11 => self.snd.ch1.set_duty(byte),
|
||||||
0x12 => self.apu.ch1.envelope = byte.into(),
|
0x12 => self.snd.ch1.envelope = byte.into(),
|
||||||
0x13 => self.apu.ch1.set_freq_lo(byte),
|
0x13 => self.snd.ch1.set_freq_lo(byte),
|
||||||
0x14 => self.apu.ch1.set_freq_hi(byte),
|
0x14 => self.snd.ch1.set_freq_hi(byte),
|
||||||
0x16 => self.apu.ch2.set_duty(byte),
|
0x16 => self.snd.ch2.set_duty(byte),
|
||||||
0x17 => self.apu.ch2.envelope = byte.into(),
|
0x17 => self.snd.ch2.envelope = byte.into(),
|
||||||
0x18 => self.apu.ch2.set_freq_lo(byte),
|
0x18 => self.snd.ch2.set_freq_lo(byte),
|
||||||
0x19 => self.apu.ch2.set_freq_hi(byte),
|
0x19 => self.snd.ch2.set_freq_hi(byte),
|
||||||
0x1A => self.apu.ch3.set_enabled(byte),
|
0x1A => self.snd.ch3.set_enabled(byte),
|
||||||
0x1B => self.apu.ch3.set_len(byte),
|
0x1B => self.snd.ch3.set_len(byte),
|
||||||
0x1C => self.apu.ch3.set_volume(byte),
|
0x1C => self.snd.ch3.set_volume(byte),
|
||||||
0x1D => self.apu.ch3.set_freq_lo(byte),
|
0x1D => self.snd.ch3.set_freq_lo(byte),
|
||||||
0x1E => self.apu.ch3.set_freq_hi(byte),
|
0x1E => self.snd.ch3.set_freq_hi(byte),
|
||||||
0x20 => self.apu.ch4.set_len(byte),
|
0x20 => self.snd.ch4.set_len(byte),
|
||||||
0x21 => self.apu.ch4.envelope = byte.into(),
|
0x21 => self.snd.ch4.envelope = byte.into(),
|
||||||
0x22 => self.apu.ch4.poly = byte.into(),
|
0x22 => self.snd.ch4.poly = byte.into(),
|
||||||
0x23 => self.apu.ch4.set_freq_data(byte),
|
0x23 => self.snd.ch4.set_freq_data(byte),
|
||||||
0x24 => self.apu.ctrl.channel = byte.into(),
|
0x24 => self.snd.ctrl.channel = byte.into(),
|
||||||
0x25 => self.apu.ctrl.output = byte.into(),
|
0x25 => self.snd.ctrl.output = byte.into(),
|
||||||
0x26 => self.apu.ctrl.set_status(byte), // FIXME: Should we control which bytes are written to here?
|
0x26 => self.snd.ctrl.set_status(byte), // FIXME: Should we control which bytes are written to here?
|
||||||
0x30..=0x3F => self.apu.ch3.wave_ram[addr as usize - 0xFF30] = byte,
|
0x30..=0x3F => self.snd.ch3.wave_ram[addr as usize - 0xFF30] = byte,
|
||||||
0x40 => self.ppu.ctrl = byte.into(),
|
0x40 => self.ppu.ctrl = byte.into(),
|
||||||
0x41 => self.ppu.stat.update(byte),
|
0x41 => self.ppu.stat.update(byte),
|
||||||
0x42 => self.ppu.pos.scroll_y = byte,
|
0x42 => self.ppu.pos.scroll_y = byte,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::apu::gen::AudioSender;
|
|
||||||
use crate::bus::{Bus, BusIo};
|
use crate::bus::{Bus, BusIo};
|
||||||
use crate::instruction::{Cycle, Instruction};
|
use crate::instruction::{Cycle, Instruction};
|
||||||
use crate::interrupt::{InterruptEnable, InterruptFlag};
|
use crate::interrupt::{InterruptEnable, InterruptFlag};
|
||||||
use crate::joypad::Joypad;
|
use crate::joypad::Joypad;
|
||||||
use crate::ppu::Ppu;
|
use crate::ppu::Ppu;
|
||||||
|
use crate::sound::AudioSender;
|
||||||
use crate::timer::Timer;
|
use crate::timer::Timer;
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
@ -128,11 +128,11 @@ impl Cpu {
|
||||||
let mut elapsed = 0x00;
|
let mut elapsed = 0x00;
|
||||||
let pending: u32 = cycles.into();
|
let pending: u32 = cycles.into();
|
||||||
while elapsed < pending {
|
while elapsed < pending {
|
||||||
if !self.bus.apu().is_full() {
|
if !self.bus.is_full() {
|
||||||
self.bus.clock();
|
self.bus.clock();
|
||||||
elapsed += 1;
|
elapsed += 1;
|
||||||
} else {
|
} else {
|
||||||
self.bus.apu_mut().flush_samples();
|
self.bus.flush_samples();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
pub use apu::gen::AudioMPSC;
|
|
||||||
pub use gui::Egui;
|
pub use gui::Egui;
|
||||||
pub use instruction::Cycle;
|
pub use instruction::Cycle;
|
||||||
|
pub use sound::AudioMPSC;
|
||||||
|
|
||||||
pub const GB_WIDTH: usize = 160;
|
pub const GB_WIDTH: usize = 160;
|
||||||
pub const GB_HEIGHT: usize = 144;
|
pub const GB_HEIGHT: usize = 144;
|
||||||
|
|
||||||
mod apu;
|
|
||||||
mod bus;
|
mod bus;
|
||||||
mod cartridge;
|
mod cartridge;
|
||||||
mod cpu;
|
mod cpu;
|
||||||
|
@ -17,5 +16,6 @@ mod interrupt;
|
||||||
mod joypad;
|
mod joypad;
|
||||||
mod ppu;
|
mod ppu;
|
||||||
mod serial;
|
mod serial;
|
||||||
|
mod sound;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod work_ram;
|
mod work_ram;
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
use crate::emu::SM83_CLOCK_SPEED;
|
use std::collections::VecDeque;
|
||||||
use gen::{AudioBuffer, AudioSender};
|
|
||||||
use types::ch1::{Sweep, SweepDirection};
|
|
||||||
use types::ch3::Volume as Ch3Volume;
|
|
||||||
use types::ch4::{CounterWidth, Frequency as Ch4Frequency, PolynomialCounter};
|
|
||||||
use types::common::{EnvelopeDirection, FrequencyHigh, SoundDuty, VolumeEnvelope};
|
|
||||||
use types::{ChannelControl, FrameSequencerState, SoundOutput};
|
|
||||||
|
|
||||||
pub mod gen;
|
use bitfield::bitfield;
|
||||||
mod types;
|
use crossbeam_channel::{Receiver, Sender, TrySendError};
|
||||||
|
use rodio::Source;
|
||||||
|
|
||||||
|
use crate::emu::SM83_CLOCK_SPEED;
|
||||||
|
|
||||||
const WAVE_PATTERN_RAM_LEN: usize = 0x10;
|
const WAVE_PATTERN_RAM_LEN: usize = 0x10;
|
||||||
|
|
||||||
|
@ -17,7 +14,7 @@ const CHANNEL_COUNT: usize = 2;
|
||||||
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
|
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub(crate) struct Apu {
|
pub(crate) struct Sound {
|
||||||
pub(crate) ctrl: SoundControl,
|
pub(crate) ctrl: SoundControl,
|
||||||
/// Tone & Sweep
|
/// Tone & Sweep
|
||||||
pub(crate) ch1: Channel1,
|
pub(crate) ch1: Channel1,
|
||||||
|
@ -38,7 +35,7 @@ pub(crate) struct Apu {
|
||||||
buffer: AudioBuffer<(f32, f32)>,
|
buffer: AudioBuffer<(f32, f32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Apu {
|
impl Sound {
|
||||||
pub(crate) fn clock(&mut self, div: u16) {
|
pub(crate) fn clock(&mut self, div: u16) {
|
||||||
use FrameSequencerState::*;
|
use FrameSequencerState::*;
|
||||||
self.sample_counter += SAMPLE_INCREMENT;
|
self.sample_counter += SAMPLE_INCREMENT;
|
||||||
|
@ -139,7 +136,7 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clock_length_ch4(freq_data: &Ch4Frequency, length_timer: &mut u16, enabled: &mut bool) {
|
fn clock_length_ch4(freq_data: &Channel4Frequency, length_timer: &mut u16, enabled: &mut bool) {
|
||||||
if freq_data.idk() && *length_timer > 0 {
|
if freq_data.idk() && *length_timer > 0 {
|
||||||
*length_timer -= 1;
|
*length_timer -= 1;
|
||||||
|
|
||||||
|
@ -171,7 +168,7 @@ impl Apu {
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::clock_length_ch4(
|
Self::clock_length_ch4(
|
||||||
&self.ch4.freq,
|
&self.ch4.freq_data,
|
||||||
&mut self.ch4.length_timer,
|
&mut self.ch4.length_timer,
|
||||||
&mut self.ch4.enabled,
|
&mut self.ch4.enabled,
|
||||||
);
|
);
|
||||||
|
@ -245,6 +242,41 @@ impl Apu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum FrameSequencerState {
|
||||||
|
Step0Length,
|
||||||
|
Step1Nothing,
|
||||||
|
Step2LengthAndSweep,
|
||||||
|
Step3Nothing,
|
||||||
|
Step4Length,
|
||||||
|
Step5Nothing,
|
||||||
|
Step6LengthAndSweep,
|
||||||
|
Step7VolumeEnvelope,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameSequencerState {
|
||||||
|
fn step(&mut self) {
|
||||||
|
use FrameSequencerState::*;
|
||||||
|
|
||||||
|
*self = match *self {
|
||||||
|
Step0Length => Step1Nothing,
|
||||||
|
Step1Nothing => Step2LengthAndSweep,
|
||||||
|
Step2LengthAndSweep => Step3Nothing,
|
||||||
|
Step3Nothing => Step4Length,
|
||||||
|
Step4Length => Step5Nothing,
|
||||||
|
Step5Nothing => Step6LengthAndSweep,
|
||||||
|
Step6LengthAndSweep => Step7VolumeEnvelope,
|
||||||
|
Step7VolumeEnvelope => Step0Length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FrameSequencerState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Step0Length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct SoundControl {
|
pub(crate) struct SoundControl {
|
||||||
/// 0xFF24 | NR50 - Channel Control
|
/// 0xFF24 | NR50 - Channel Control
|
||||||
|
@ -257,7 +289,7 @@ pub(crate) struct SoundControl {
|
||||||
|
|
||||||
impl SoundControl {
|
impl SoundControl {
|
||||||
/// 0xFF26 | NR52 - Sound On/Off
|
/// 0xFF26 | NR52 - Sound On/Off
|
||||||
pub(crate) fn status(&self, snd: &Apu) -> u8 {
|
pub fn status(&self, snd: &Sound) -> u8 {
|
||||||
(self.enabled as u8) << 7
|
(self.enabled as u8) << 7
|
||||||
| (snd.ch4.enabled as u8) << 3
|
| (snd.ch4.enabled as u8) << 3
|
||||||
| (snd.ch3.enabled as u8) << 2
|
| (snd.ch3.enabled as u8) << 2
|
||||||
|
@ -266,12 +298,82 @@ impl SoundControl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF26 | NR52 - Sound On/Off
|
/// 0xFF26 | NR52 - Sound On/Off
|
||||||
pub(crate) fn set_status(&mut self, byte: u8) {
|
pub fn set_status(&mut self, byte: u8) {
|
||||||
// TODO: Should all channel enabled fields be disabled when this is reset?
|
// TODO: Should all channel enabled fields be disabled when this is reset?
|
||||||
self.enabled = (byte >> 7) & 0x01 == 0x01;
|
self.enabled = (byte >> 7) & 0x01 == 0x01;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: What to do about the separation of freq bits
|
||||||
|
// across multiple registers?
|
||||||
|
bitfield! {
|
||||||
|
pub struct FrequencyHigh(u8);
|
||||||
|
impl Debug;
|
||||||
|
initial, set_initial: 7;
|
||||||
|
idk, set_idk: 6; // TODO: Figure out what the hell this is
|
||||||
|
freq_bits, set_freq_bits: 2, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for FrequencyHigh {}
|
||||||
|
impl Clone for FrequencyHigh {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FrequencyHigh {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for FrequencyHigh {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FrequencyHigh> for u8 {
|
||||||
|
fn from(freq: FrequencyHigh) -> Self {
|
||||||
|
freq.0 & 0x40 // Only bit 6 can be read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct SoundStatus(u8);
|
||||||
|
impl Debug;
|
||||||
|
pub all_enabled, set_all_enabled: 7;
|
||||||
|
pub sound_4, _: 3;
|
||||||
|
pub sound_3, _: 2;
|
||||||
|
pub sound_2, _: 1;
|
||||||
|
pub sound_1, _: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for SoundStatus {}
|
||||||
|
impl Clone for SoundStatus {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SoundStatus {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for SoundStatus {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SoundStatus> for u8 {
|
||||||
|
fn from(status: SoundStatus) -> Self {
|
||||||
|
status.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct Channel1 {
|
pub(crate) struct Channel1 {
|
||||||
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
/// 0xFF10 | NR10 - Channel 1 Sweep Register
|
||||||
|
@ -405,6 +507,61 @@ impl Channel1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct Sweep(u8);
|
||||||
|
impl Debug;
|
||||||
|
period, set_period: 6, 4;
|
||||||
|
from into SweepDirection, direction, set_direction: 3, 3;
|
||||||
|
shift_count, set_shift_count: 2, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for Sweep {}
|
||||||
|
impl Clone for Sweep {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Sweep {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for Sweep {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Sweep> for u8 {
|
||||||
|
fn from(sweep: Sweep) -> Self {
|
||||||
|
sweep.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum SweepDirection {
|
||||||
|
Increase = 0,
|
||||||
|
Decrease = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for SweepDirection {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
match byte & 0x01 {
|
||||||
|
0b00 => Self::Increase,
|
||||||
|
0b01 => Self::Decrease,
|
||||||
|
_ => unreachable!("{:04X} is not a valid value for SweepChange", byte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SweepDirection> for u8 {
|
||||||
|
fn from(change: SweepDirection) -> Self {
|
||||||
|
change as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct Channel2 {
|
pub(crate) struct Channel2 {
|
||||||
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
/// 0xFF16 | NR21 - Channel 2 Sound length / Wave Pattern Duty
|
||||||
|
@ -490,6 +647,145 @@ impl Channel2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct VolumeEnvelope(u8);
|
||||||
|
impl Debug;
|
||||||
|
pub init_vol, set_init_vol: 7, 4;
|
||||||
|
pub from into EnvelopeDirection, direction, set_direction: 3, 3;
|
||||||
|
pub period, set_period: 2, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for VolumeEnvelope {}
|
||||||
|
impl Clone for VolumeEnvelope {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VolumeEnvelope {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for VolumeEnvelope {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VolumeEnvelope> for u8 {
|
||||||
|
fn from(envelope: VolumeEnvelope) -> Self {
|
||||||
|
envelope.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum EnvelopeDirection {
|
||||||
|
Decrease = 0,
|
||||||
|
Increase = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for EnvelopeDirection {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
match byte & 0b01 {
|
||||||
|
0b00 => Self::Decrease,
|
||||||
|
0b01 => Self::Increase,
|
||||||
|
_ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EnvelopeDirection> for u8 {
|
||||||
|
fn from(direction: EnvelopeDirection) -> Self {
|
||||||
|
direction as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EnvelopeDirection {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Decrease
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct SoundDuty(u8);
|
||||||
|
impl Debug;
|
||||||
|
pub from into WavePattern, wave_pattern, set_wave_pattern: 7, 6;
|
||||||
|
pub sound_length, _: 5, 0; // TODO: Getter only used if bit 6 in NR14 is set
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for SoundDuty {}
|
||||||
|
impl Clone for SoundDuty {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SoundDuty {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for SoundDuty {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SoundDuty> for u8 {
|
||||||
|
fn from(duty: SoundDuty) -> Self {
|
||||||
|
duty.0 & 0xC0 // Only bits 7 and 6 can be read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum WavePattern {
|
||||||
|
OneEighth = 0, // 12.5% ( _-------_-------_------- )
|
||||||
|
OneQuarter = 1, // 25% ( __------__------__------ )
|
||||||
|
OneHalf = 2, // 50% ( ____----____----____---- ) (normal)
|
||||||
|
ThreeQuarters = 3, // 75% ( ______--______--______-- )
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WavePattern {
|
||||||
|
pub const fn amplitude(&self, index: u8) -> u8 {
|
||||||
|
use WavePattern::*;
|
||||||
|
let i = 7 - index; // an index of 0 should get the highest bit
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
OneEighth => (0b00000001 >> i) & 0x01,
|
||||||
|
OneQuarter => (0b10000001 >> i) & 0x01,
|
||||||
|
OneHalf => (0b10000111 >> i) & 0x01,
|
||||||
|
ThreeQuarters => (0b01111110 >> i) & 0x01,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for WavePattern {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::OneEighth // Rationale: OneEighth is 0x00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WavePattern> for u8 {
|
||||||
|
fn from(pattern: WavePattern) -> Self {
|
||||||
|
pattern as Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for WavePattern {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
match byte & 0b11 {
|
||||||
|
0b00 => Self::OneEighth,
|
||||||
|
0b01 => Self::OneQuarter,
|
||||||
|
0b10 => Self::OneHalf,
|
||||||
|
0b11 => Self::ThreeQuarters,
|
||||||
|
_ => unreachable!("{:#04X} is not a valid value for WavePattern", byte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct Channel3 {
|
pub(crate) struct Channel3 {
|
||||||
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
/// 0xFF1A | NR30 - Channel 3 Sound on/off
|
||||||
|
@ -497,7 +793,7 @@ pub(crate) struct Channel3 {
|
||||||
/// 0xFF1B | NR31 - Sound Length
|
/// 0xFF1B | NR31 - Sound Length
|
||||||
len: u8,
|
len: u8,
|
||||||
/// 0xFF1C | NR32 - Channel 3 Volume
|
/// 0xFF1C | NR32 - Channel 3 Volume
|
||||||
volume: Ch3Volume,
|
volume: Channel3Volume,
|
||||||
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
|
/// 0xFF1D | NR33 - Channel 3 Frequency low (lower 8 bits)
|
||||||
freq_lo: u8,
|
freq_lo: u8,
|
||||||
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
/// 0xFF1E | NR34 - Channel 3 Frequency high
|
||||||
|
@ -558,7 +854,7 @@ impl Channel3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_volume(&mut self, byte: u8) {
|
pub(crate) fn set_volume(&mut self, byte: u8) {
|
||||||
use Ch3Volume::*;
|
use Channel3Volume::*;
|
||||||
|
|
||||||
self.volume = match (byte >> 5) & 0x03 {
|
self.volume = match (byte >> 5) & 0x03 {
|
||||||
0b00 => Mute,
|
0b00 => Mute,
|
||||||
|
@ -603,6 +899,33 @@ impl Channel3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Channel3Volume {
|
||||||
|
Mute = 0,
|
||||||
|
Full = 1,
|
||||||
|
Half = 2,
|
||||||
|
Quarter = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Channel3Volume {
|
||||||
|
pub fn shift_count(&self) -> u8 {
|
||||||
|
use Channel3Volume::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
Mute => 4,
|
||||||
|
Full => 0,
|
||||||
|
Half => 1,
|
||||||
|
Quarter => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Channel3Volume {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Mute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub(crate) struct Channel4 {
|
pub(crate) struct Channel4 {
|
||||||
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
/// 0xFF20 | NR41 - Channel 4 Sound Length
|
||||||
|
@ -612,7 +935,7 @@ pub(crate) struct Channel4 {
|
||||||
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
/// 0xFF22 | NR43 - Chanel 4 Polynomial Counter
|
||||||
pub(crate) poly: PolynomialCounter,
|
pub(crate) poly: PolynomialCounter,
|
||||||
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
||||||
freq: Ch4Frequency,
|
freq_data: Channel4Frequency,
|
||||||
|
|
||||||
// Envelope Functionality
|
// Envelope Functionality
|
||||||
period_timer: u8,
|
period_timer: u8,
|
||||||
|
@ -643,14 +966,14 @@ impl Channel4 {
|
||||||
|
|
||||||
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
||||||
pub(crate) fn freq_data(&self) -> u8 {
|
pub(crate) fn freq_data(&self) -> u8 {
|
||||||
u8::from(self.freq) & 0x40 // only bit 6 readable
|
u8::from(self.freq_data) & 0x40 // only bit 6 readable
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
/// 0xFF23 | NR44 - Channel 4 Counter / Consecutive Selector and Restart
|
||||||
pub(crate) fn set_freq_data(&mut self, byte: u8) {
|
pub(crate) fn set_freq_data(&mut self, byte: u8) {
|
||||||
self.freq = byte.into();
|
self.freq_data = byte.into();
|
||||||
|
|
||||||
if self.freq.initial() {
|
if self.freq_data.initial() {
|
||||||
// Envelope behaviour during trigger event
|
// Envelope behaviour during trigger event
|
||||||
self.period_timer = self.envelope.period();
|
self.period_timer = self.envelope.period();
|
||||||
self.current_volume = self.envelope.init_vol();
|
self.current_volume = self.envelope.init_vol();
|
||||||
|
@ -697,3 +1020,250 @@ impl Channel4 {
|
||||||
code << 4
|
code << 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct PolynomialCounter(u8);
|
||||||
|
impl Debug;
|
||||||
|
shift_count, set_shift_count: 7, 4;
|
||||||
|
from into CounterWidth, counter_width, set_counter_width: 3, 3;
|
||||||
|
divisor_code, set_divisor_code: 2, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for PolynomialCounter {}
|
||||||
|
impl Clone for PolynomialCounter {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PolynomialCounter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for PolynomialCounter {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PolynomialCounter> for u8 {
|
||||||
|
fn from(poly: PolynomialCounter) -> Self {
|
||||||
|
poly.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum CounterWidth {
|
||||||
|
Long, // 15 bits long
|
||||||
|
Short, // 7 bits long
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for CounterWidth {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
match byte & 0x01 {
|
||||||
|
0b00 => Self::Short,
|
||||||
|
0b01 => Self::Long,
|
||||||
|
_ => unreachable!("{:#04X} is not a valid value for CounterWidth"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CounterWidth> for u8 {
|
||||||
|
fn from(counter_width: CounterWidth) -> Self {
|
||||||
|
counter_width as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct Channel4Frequency(u8);
|
||||||
|
impl Debug;
|
||||||
|
initial, set_initial: 7;
|
||||||
|
idk, set_idk: 6; // TODO: same as FrequencyHigh, figure out what this is
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for Channel4Frequency {}
|
||||||
|
impl Clone for Channel4Frequency {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Channel4Frequency {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for Channel4Frequency {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte & 0xC0) // Only bits 7 and 6 hold anything of value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Channel4Frequency> for u8 {
|
||||||
|
fn from(state: Channel4Frequency) -> Self {
|
||||||
|
state.0 & 0x40 // Only bit 6 holds anything of value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct SoundOutput(u8);
|
||||||
|
impl Debug;
|
||||||
|
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 {}
|
||||||
|
impl Clone for SoundOutput {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SoundOutput {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for SoundOutput {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SoundOutput> for u8 {
|
||||||
|
fn from(output: SoundOutput) -> Self {
|
||||||
|
output.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct ChannelControl(u8);
|
||||||
|
impl Debug;
|
||||||
|
pub vin_so2, set_vin_so2: 7;
|
||||||
|
pub so2_level, set_so2_level: 6, 4;
|
||||||
|
pub vin_so1, set_vin_so1: 3;
|
||||||
|
pub so1_level, set_so1_level: 2, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for ChannelControl {}
|
||||||
|
impl Clone for ChannelControl {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ChannelControl {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for ChannelControl {
|
||||||
|
fn from(byte: u8) -> Self {
|
||||||
|
Self(byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ChannelControl> for u8 {
|
||||||
|
fn from(ctrl: ChannelControl) -> Self {
|
||||||
|
ctrl.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AudioMPSC;
|
||||||
|
|
||||||
|
impl AudioMPSC {
|
||||||
|
pub fn new() -> (AudioSender<f32>, AudioReceiver<f32>) {
|
||||||
|
// TODO: Can we provide an upper limit for this?
|
||||||
|
// The larger this channel is, the more lag there is between the Audio and
|
||||||
|
// Emulator
|
||||||
|
let (send, recv) = crossbeam_channel::unbounded();
|
||||||
|
|
||||||
|
(AudioSender { inner: send }, AudioReceiver { inner: recv })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AudioSender<T> {
|
||||||
|
inner: Sender<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AudioSender<T> {
|
||||||
|
fn send_samples(&self, left: T, right: T) -> Result<(), TrySendError<T>> {
|
||||||
|
self.inner.try_send(left).and(self.inner.try_send(right))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AudioReceiver<T> {
|
||||||
|
inner: Receiver<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Iterator for AudioReceiver<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
// TODO: Should this never return none?
|
||||||
|
self.inner.recv().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: rodio::Sample> Source for AudioReceiver<T> {
|
||||||
|
fn current_frame_len(&self) -> Option<usize> {
|
||||||
|
// A frame changes when the samples rate or
|
||||||
|
// number of channels change. This will never happen, so
|
||||||
|
// we return
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn channels(&self) -> u16 {
|
||||||
|
// The Gameboy supports two channels
|
||||||
|
CHANNEL_COUNT as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample_rate(&self) -> u32 {
|
||||||
|
SAMPLE_RATE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_duration(&self) -> Option<std::time::Duration> {
|
||||||
|
// The duration of this source is infinite
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct AudioBuffer<T> {
|
||||||
|
inner: VecDeque<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for AudioBuffer<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: VecDeque::with_capacity(AUDIO_BUFFER_LEN * CHANNEL_COUNT),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AudioBuffer<T> {
|
||||||
|
pub fn push_back(&mut self, value: T) {
|
||||||
|
self.inner.push_back(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_front(&mut self) -> Option<T> {
|
||||||
|
self.inner.pop_front()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue