Skip to content
Snippets Groups Projects
Verified Commit 2faa3e75 authored by João Magalhães's avatar João Magalhães :rocket:
Browse files

chore: audio support for libretro

parent 90f38b2c
No related branches found
No related tags found
1 merge request!29Support for Libretro
Pipeline #3078 passed
......@@ -9,7 +9,7 @@ use std::{
};
use boytacean::{
gb::GameBoy,
gb::{AudioProvider, GameBoy},
pad::PadKey,
ppu::{DISPLAY_HEIGHT, DISPLAY_WIDTH, RGB1555_SIZE},
rom::Cartridge,
......@@ -288,6 +288,8 @@ pub extern "C" fn retro_set_controller_port_device() {
#[no_mangle]
pub extern "C" fn retro_run() {
let emulator = unsafe { EMULATOR.as_mut().unwrap() };
let sample_batch_cb = unsafe { AUDIO_SAMPLE_BATCH_CALLBACK.as_ref().unwrap() };
let channels = emulator.audio_channels();
let mut counter_cycles = 0_u32;
let cycle_limit = 4194304 / 60; //@TODO this is super tricky
......@@ -304,6 +306,21 @@ pub extern "C" fn retro_run() {
// include the advance of both the CPU, PPU, APU
// and any other frequency based component of the system
counter_cycles += emulator.clock() as u32;
// obtains the audio buffer reference and queues it
// in a batch manner using the audio callback at the
// the end of the operation clears the buffer
let audio_buffer = emulator
.audio_buffer()
.iter()
.map(|v| *v as i16 * 256)
.collect::<Vec<i16>>();
sample_batch_cb(
audio_buffer.as_ptr(),
audio_buffer.len() / channels as usize,
);
emulator.clear_audio_buffer();
}
unsafe {
......
......@@ -2,8 +2,6 @@ use std::collections::VecDeque;
use crate::{gb::GameBoy, warnln};
const CHANNELS: u8 = 2;
const DUTY_TABLE: [[u8; 8]; 4] = [
[0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
......@@ -93,9 +91,22 @@ pub struct Apu {
ch3_out_enabled: bool,
ch4_out_enabled: bool,
/// The RAM that is used to sore the wave information
/// to be used in channel 3 audio
wave_ram: [u8; 16],
/// The rate at which audio samples are going to be
/// taken, ideally this value should be aligned with
/// the sampling rate of the output device. A typical
/// sampling rate would be of 44.1kHz.
sampling_rate: u16,
/// The number of audion channels that are going to be
/// outputted as part fo the audio buffer)
channels: u8,
/// Internal sequencer counter that runs at 512Hz
/// used for the activation of the tick actions.
sequencer: u16,
sequencer_step: u8,
output_timer: i16,
......@@ -106,7 +117,7 @@ pub struct Apu {
}
impl Apu {
pub fn new(sampling_rate: u16, buffer_size: f32, clock_freq: u32) -> Self {
pub fn new(sampling_rate: u16, channels: u8, buffer_size: f32, clock_freq: u32) -> Self {
Self {
ch1_timer: 0,
ch1_sequence: 0,
......@@ -180,25 +191,18 @@ impl Apu {
ch3_out_enabled: true,
ch4_out_enabled: true,
/// The RAM that is used to sore the wave information
/// to be used in channel 3 audio
wave_ram: [0u8; 16],
/// The rate at which audio samples are going to be
/// taken, ideally this value should be aligned with
/// the sampling rate of the output device. A typical
/// sampling rate would be of 44.1kHz.
sampling_rate,
channels,
/// Internal sequencer counter that runs at 512Hz
/// used for the activation of the tick actions.
sequencer: 0,
sequencer_step: 0,
output_timer: 0,
audio_buffer: VecDeque::with_capacity(
(sampling_rate as f32 * buffer_size) as usize * CHANNELS as usize,
(sampling_rate as f32 * buffer_size) as usize * channels as usize,
),
audio_buffer_max: (sampling_rate as f32 * buffer_size) as usize * CHANNELS as usize,
audio_buffer_max: (sampling_rate as f32 * buffer_size) as usize * channels as usize,
clock_freq,
}
}
......@@ -324,13 +328,14 @@ impl Apu {
// the buffer (avoiding overflow) and then then the new audio
// volume item is added to the queue
if self.audio_buffer.len() >= self.audio_buffer_max {
self.audio_buffer.pop_front();
self.audio_buffer.pop_front();
for _ in 0..self.channels {
self.audio_buffer.pop_front();
}
}
if self.left_enabled {
self.audio_buffer.push_back(self.output());
}
if self.right_enabled {
if self.right_enabled && self.channels > 1 {
self.audio_buffer.push_back(self.output());
}
......@@ -729,7 +734,7 @@ impl Apu {
}
pub fn channels(&self) -> u8 {
CHANNELS
self.channels
}
pub fn audio_buffer(&self) -> &VecDeque<u8> {
......@@ -1061,7 +1066,7 @@ impl Apu {
impl Default for Apu {
fn default() -> Self {
Self::new(44100, 1.0, GameBoy::CPU_FREQ)
Self::new(44100, 2, 1.0, GameBoy::CPU_FREQ)
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment