Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Libretro frontend #140

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ members = [
"sdl",
"core",
"rpi",
"common"
"common",
"libretro"
]

[workspace.package]
alloncm marked this conversation as resolved.
Show resolved Hide resolved
version = "4.0.0"
authors = ["alloncm <alloncm@gmail.com>"]
rust-version = "1.70" # cause of once cell
rust-version = "1.73" # cause of cargo-ndk used to build for android platform
14 changes: 12 additions & 2 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
default_to_workspace = false

[tasks.all]
dependencies = ["test", "sdl", "rpios", "rpibm"]
dependencies = ["test", "sdl", "rpios", "rpibm", "libretro"]

[tasks.test]
command = "cargo"
Expand Down Expand Up @@ -57,4 +57,14 @@ install_crate = {rustup_component_name = "llvm-tools-preview"}
[tasks.install_rust_src]
toolchain = "nightly"
command = "rustup"
args = ["component", "add", "rust-src"]
args = ["component", "add", "rust-src"]

[tasks.libretro]
command = "cargo"
args = ["build", "--release", "--package", "magenboy_libretro"]
dependencies = ["libretro_android"]

[tasks.libretro_android]
install_crate = {crate_name = "cargo-ndk", binary = "cargo", test_arg = "ndk"}
command = "cargo"
args = ["ndk", "--target=aarch64-linux-android", "build", "--release", "--package", "magenboy_libretro"]
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ rustup component add llvm-tools-preview

3. Builds the image

### Libretro

See - [LibretroDocs](docs/Libretro.md)

## Running

### Desktop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ pub trait AudioResampler{
}

pub trait ResampledAudioDevice<AR:AudioResampler> : AudioDevice{
const VOLUME:Sample = 10 as Sample;

fn push_buffer(&mut self, buffer:&[StereoSample; BUFFER_SIZE]){
let resample = self.get_resampler().resample(buffer);
for sample in resample{
let(buffer, index) = self.get_audio_buffer();
buffer[*index] = sample.left_sample * Self::VOLUME;
buffer[*index + 1] = sample.left_sample * Self::VOLUME;
buffer[*index] = sample.left_sample;
buffer[*index + 1] = sample.right_sample;
*index += 2;
if *index == BUFFER_SIZE{
*index = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use magenboy_core::apu::audio_device::{BUFFER_SIZE, DEFAULT_SAPMPLE, Sample, StereoSample};
use magenboy_core::apu::audio_device::{BUFFER_SIZE, StereoSample};
use super::audio_resampler::AudioResampler;


Expand All @@ -12,15 +12,6 @@ pub struct ManualAudioResampler{
skip_to_use:u32,
}

impl ManualAudioResampler{
fn interpolate_sample(samples:&[StereoSample])->StereoSample{
let interpulated_left_sample = samples.iter().fold(DEFAULT_SAPMPLE, |acc, x| acc + x.left_sample) / samples.len() as Sample;
let interpulated_right_sample = samples.iter().fold(DEFAULT_SAPMPLE, |acc, x| acc + x.right_sample) / samples.len() as Sample;

return StereoSample{left_sample: interpulated_left_sample, right_sample: interpulated_right_sample};
}
}

impl AudioResampler for ManualAudioResampler{
fn new(original_frequency:u32, target_frequency:u32)->Self{
// Calling round in order to get the nearest integer and resample as precise as possible
Expand Down Expand Up @@ -59,7 +50,7 @@ impl AudioResampler for ManualAudioResampler{
self.sampling_counter += 1;

if self.sampling_counter == self.skip_to_use {
let interpolated_sample = Self::interpolate_sample(&self.sampling_buffer);
let interpolated_sample = StereoSample::interpolate(&self.sampling_buffer);
self.sampling_counter = 0;
self.sampling_buffer.clear();

Expand Down
6 changes: 6 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ cfg_if::cfg_if!{ if #[cfg(feature = "std")] {
pub mod mbc_handler;
pub mod mpmc_gfx_device;
pub mod logging;
pub mod audio{
mod audio_resampler;
mod manual_audio_resampler;
pub use audio_resampler::*;
pub use manual_audio_resampler::*;
}
}}

pub mod menu;
Expand Down
2 changes: 1 addition & 1 deletion common/src/mbc_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn try_get_save_data(name:&String)->Option<Vec<u8>>{
}
}

pub fn release_mbc<'a>(program_name:&String, mbc: &'a dyn Mbc){
pub fn release_mbc<'a>(program_name:&String, mbc: &'a mut dyn Mbc){
if mbc.has_battery(){
while fs::write(format!("{}{}", program_name, ".sav"), mbc.get_ram()).is_err() {}
info!("saved succesfully");
Expand Down
2 changes: 1 addition & 1 deletion common/src/scale.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ extern void scale_buffer(const uint16_t* input_buffer, int input_buffer_width, i
const uint16_t pixel = ((uint16_t)blue) | (((uint16_t)green) << 5) | (((uint16_t)red) << 11);

output_buffer[output_offset_counter * 2] = (uint8_t)(pixel >> 8);
output_buffer[(output_offset_counter * 2) + 1] = (uint8_t)(pixel && 0xFF);
output_buffer[(output_offset_counter * 2) + 1] = (uint8_t)(pixel & 0xFF);
output_offset_counter++;
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/apu/apu_registers_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::{
square_sample_producer::SquareSampleProducer,
volume_envelop::VolumeEnvlope,
wave_sample_producer::WaveSampleProducer,
sound_utils::NUMBER_OF_CHANNELS
NUMBER_OF_CHANNELS
};


Expand Down
16 changes: 11 additions & 5 deletions core/src/apu/audio_device.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use super::NUMBER_OF_CHANNELS;

pub type Sample = i16;
pub const DEFAULT_SAPMPLE:Sample = 0 as Sample;
const MAX_MASTER_VOLUME:Sample = 8;
pub const SAMPLE_MAX: Sample = Sample::MAX / (MAX_MASTER_VOLUME * NUMBER_OF_CHANNELS as Sample);

pub const BUFFER_SIZE:usize = 2048;
pub const BUFFER_SIZE:usize = 0x2000;

#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct StereoSample{
pub left_sample:Sample,
Expand All @@ -13,11 +18,12 @@ impl StereoSample{
pub const fn const_defualt()->Self{
Self{left_sample:DEFAULT_SAPMPLE, right_sample:DEFAULT_SAPMPLE}
}
}

impl Clone for StereoSample{
fn clone(&self) -> Self {
Self{left_sample:self.left_sample,right_sample:self.right_sample}
pub fn interpolate(samples:&[StereoSample])->StereoSample{
let left_sample = (samples.iter().fold(0, |acc, x| acc + x.left_sample as i64) / samples.len() as i64) as Sample;
let right_sample = (samples.iter().fold(0, |acc, x| acc + x.right_sample as i64) / samples.len() as i64) as Sample;

return StereoSample{left_sample, right_sample};
}
}

Expand Down
30 changes: 16 additions & 14 deletions core/src/apu/channel.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use super::audio_device::{DEFAULT_SAPMPLE, Sample};
use super::sample_producer::SampleProducer;
use super::timer::Timer;
use super::{audio_device::{Sample, DEFAULT_SAPMPLE, SAMPLE_MAX}, sample_producer::*, timer::Timer};

pub struct Channel<Procuder: SampleProducer>{
pub enabled:bool,
Expand Down Expand Up @@ -50,20 +48,24 @@ impl<Procuder: SampleProducer> Channel<Procuder>{

pub fn get_audio_sample(&mut self)->Sample{
if self.enabled{

let sample = if self.timer.cycle(){
if self.timer.cycle(){
self.timer.update_cycles_to_tick(self.sample_producer.get_updated_frequency_ticks(self.frequency));
self.sample_producer.produce() as Sample
let digital_sample = self.sample_producer.produce();
self.last_sample = Self::convert_digital_to_analog(digital_sample);
}
else{
self.last_sample
};

self.last_sample = sample;

return self.last_sample;
}
else{
self.last_sample = DEFAULT_SAPMPLE;
}

return self.last_sample;
}

fn convert_digital_to_analog(digital_sample:u8)->Sample{
const RATIO:Sample = SAMPLE_MAX / MAX_DIGITAL_SAMPLE as Sample;

return DEFAULT_SAPMPLE;
// Expandibg the sample to the full range of the Sample type while still
// allowing furhter calculations without overflowing
return (digital_sample as Sample - (MAX_DIGITAL_SAMPLE as Sample / 2)) * RATIO;
}
}
2 changes: 1 addition & 1 deletion core/src/apu/gb_apu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::{
sound_terminal::SoundTerminal,
square_sample_producer::SquareSampleProducer,
wave_sample_producer::WaveSampleProducer,
sound_utils::NUMBER_OF_CHANNELS
NUMBER_OF_CHANNELS
};

pub struct GbApu<Device: AudioDevice>{
Expand Down
2 changes: 1 addition & 1 deletion core/src/apu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pub mod freq_sweep;
pub mod volume_envelop;
pub mod noise_sample_producer;

mod sound_utils;
mod apu_registers_updater;

pub use apu_registers_updater::*;

pub(self) const NUMBER_OF_CHANNELS:usize = 4;
4 changes: 4 additions & 0 deletions core/src/apu/sample_producer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/// Max value for digital sample according to the Pandocs
pub const MAX_DIGITAL_SAMPLE:u8 = 0xF;

pub trait SampleProducer{
/// Produces a digital sample in range of 0 to 0xF
alloncm marked this conversation as resolved.
Show resolved Hide resolved
fn produce(&mut self)->u8;
fn get_updated_frequency_ticks(&self, freq:u16)->u16;
fn reset(&mut self);
Expand Down
2 changes: 1 addition & 1 deletion core/src/apu/sound_terminal.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{audio_device::{DEFAULT_SAPMPLE, Sample}, sound_utils::NUMBER_OF_CHANNELS};
use super::{audio_device::{DEFAULT_SAPMPLE, Sample}, NUMBER_OF_CHANNELS};

type ChannelMask = u16;

Expand Down
8 changes: 0 additions & 8 deletions core/src/apu/sound_utils.rs

This file was deleted.

11 changes: 8 additions & 3 deletions core/src/apu/square_sample_producer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use super::{sample_producer::SampleProducer, sound_utils::DUTY_TABLE};
use super::freq_sweep::FreqSweep;
use super::volume_envelop::VolumeEnvlope;
use super::{freq_sweep::FreqSweep, sample_producer::SampleProducer, volume_envelop::VolumeEnvlope};

const DUTY_TABLE:[[u8; 8]; 4] = [
[0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,1],
[1,0,0,0,0,1,1,1],
[0,1,1,1,1,1,1,0],
];

pub struct SquareSampleProducer{
pub wave_duty:u8,
Expand Down
9 changes: 6 additions & 3 deletions core/src/keypad/joypad_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use super::{joypad_provider::JoypadProvider, joypad::Joypad, button::Button};


pub struct JoypadHandler<JP:JoypadProvider>{
pub register:u8,

register:u8,
joypad:Joypad,
joypad_provider:JP,
}
Expand All @@ -20,7 +19,9 @@ impl<JP:JoypadProvider> JoypadHandler<JP>{

pub fn poll_joypad_state(&mut self){
self.joypad_provider.provide(&mut self.joypad);
}

pub fn get_register(&mut self) -> u8{
let buttons = (self.register & BIT_5_MASK) == 0;
let directions = (self.register & BIT_4_MASK) == 0;

Expand All @@ -36,8 +37,10 @@ impl<JP:JoypadProvider> JoypadHandler<JP>{
flip_bit_u8(&mut self.register, 2, !self.joypad.buttons[Button::Up as usize]);
flip_bit_u8(&mut self.register, 3, !self.joypad.buttons[Button::Down as usize]);
}
}

return self.register;
}

pub fn set_register(&mut self, value:u8){
self.register &= 0b1100_1111; // Reset bit 4 & 5
self.register |= value & 0b0011_0000; // Seting the bits
Expand Down
8 changes: 3 additions & 5 deletions core/src/machine/gameboy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ impl<'a, JP:JoypadProvider, AD:AudioDevice, GFX:GfxDevice> GameBoy<'a, JP, AD, G
}

pub fn cycle_frame(&mut self){
while self.mmu.m_cycle_counter < CYCLES_PER_FRAME{
self.mmu.poll_joypad_state();

self.mmu.poll_joypad_state();

while !self.mmu.consume_vblank_event(){
//CPU
let mut cpu_cycles_passed = 1;
if !self.cpu.halt && !self.mmu.dma_block_cpu(){
Expand All @@ -72,8 +72,6 @@ impl<'a, JP:JoypadProvider, AD:AudioDevice, GFX:GfxDevice> GameBoy<'a, JP, AD, G
self.mmu.cycle(interrupt_cycles);
}
}

self.mmu.m_cycle_counter = 0;
}

fn execute_opcode(&mut self)->u8{
Expand Down
2 changes: 1 addition & 1 deletion core/src/mmu/carts/mbc1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Mbc1<'a>{
}

impl<'a> Mbc for Mbc1<'a>{
fn get_ram(&self) ->&[u8] {
fn get_ram(&mut self) ->&mut [u8] {
self.ram
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/mmu/carts/mbc3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct Mbc3<'a>{

impl<'a> Mbc for Mbc3<'a>{

fn get_ram(&self) ->&[u8] {
fn get_ram(&mut self) ->&mut [u8] {
self.ram
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/mmu/carts/mbc5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ pub struct Mbc5<'a>{
}

impl<'a> Mbc for Mbc5<'a> {
fn get_ram(&self)->&[u8] {
&self.ram
fn get_ram(&mut self)->&mut [u8] {
self.ram
}

fn has_battery(&self)->bool {
Expand Down
Loading
Loading