diff --git a/bsnes/sfc/cartridge/cartridge.cpp b/bsnes/sfc/cartridge/cartridge.cpp index b39ceb66b..875a63475 100644 --- a/bsnes/sfc/cartridge/cartridge.cpp +++ b/bsnes/sfc/cartridge/cartridge.cpp @@ -158,4 +158,21 @@ auto Cartridge::unload() -> void { ram.reset(); } +auto Cartridge::getSaveRAM() -> uint8_t* { + return ram.data(); +} + +auto Cartridge::getSaveRAMSize() -> size_t { + return ram.size(); +} + + +auto Cartridge::getROM() -> uint8_t* { + return rom.data(); +} + +auto Cartridge::getROMSize() -> size_t { + return rom.size(); +} + } diff --git a/bsnes/sfc/cartridge/cartridge.hpp b/bsnes/sfc/cartridge/cartridge.hpp index b975c19be..b89bf876c 100644 --- a/bsnes/sfc/cartridge/cartridge.hpp +++ b/bsnes/sfc/cartridge/cartridge.hpp @@ -11,6 +11,10 @@ struct Cartridge { auto load() -> bool; auto save() -> void; auto unload() -> void; + auto getSaveRAM() -> uint8_t*; + auto getSaveRAMSize() -> size_t; + auto getROM() -> uint8_t*; + auto getROMSize() -> size_t; auto serialize(serializer&) -> void; diff --git a/bsnes/sfc/dsp/SPC_DSP.cpp b/bsnes/sfc/dsp/SPC_DSP.cpp index a89d491f9..d77e36381 100644 --- a/bsnes/sfc/dsp/SPC_DSP.cpp +++ b/bsnes/sfc/dsp/SPC_DSP.cpp @@ -510,11 +510,16 @@ VOICE_CLOCK( V3c ) if ( !v->kon_delay ) run_envelope( v ); } + inline void SPC_DSP::voice_output( voice_t const* v, int ch ) { // Apply left/right volume int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; - + + // Apply user volume if set + if (v->user_volume < 100) // 16384 / 100 is approx 163.84. + amp = (amp * v->user_volume * 164) >> 14; + // Add to output total m.t_main_out [ch] += amp; CLAMP16( m.t_main_out [ch] ); @@ -892,6 +897,7 @@ void SPC_DSP::load( uint8_t const regs [register_count] ) v->brr_offset = 1; v->vbit = 1 << i; v->regs = &m.regs [i * 0x10]; + v->user_volume = 100; } m.new_kon = REG(kon); m.t_dir = REG(dir); diff --git a/bsnes/sfc/dsp/SPC_DSP.h b/bsnes/sfc/dsp/SPC_DSP.h index 50fd7beab..66504ccca 100644 --- a/bsnes/sfc/dsp/SPC_DSP.h +++ b/bsnes/sfc/dsp/SPC_DSP.h @@ -50,6 +50,8 @@ class SPC_DSP { // Reduces emulation accuracy. enum { voice_count = 8 }; void mute_voices( int mask ); + + void set_user_volume( int voice_no, int volume_percent ){ m.voices[voice_no].user_volume = volume_percent; } // State @@ -118,6 +120,7 @@ class SPC_DSP { int env; // current envelope level int hidden_env; // used by GAIN mode 7, very obscure quirk uint8_t t_envx_out; + int user_volume; // range: 0-100% }; private: enum { brr_block_size = 9 }; diff --git a/bsnes/sfc/dsp/dsp.hpp b/bsnes/sfc/dsp/dsp.hpp index 1cc97f052..4326cabfa 100644 --- a/bsnes/sfc/dsp/dsp.hpp +++ b/bsnes/sfc/dsp/dsp.hpp @@ -15,6 +15,8 @@ struct DSP { auto serialize(serializer&) -> void; int64 clock = 0; + + auto get_spc_dsp() -> SPC_DSP* { return &spc_dsp ; } private: bool fastDSP = false; diff --git a/bsnes/sfc/interface/interface.hpp b/bsnes/sfc/interface/interface.hpp index d9437487a..145544925 100644 --- a/bsnes/sfc/interface/interface.hpp +++ b/bsnes/sfc/interface/interface.hpp @@ -1,3 +1,5 @@ +#pragma once + namespace SuperFamicom { struct ID { diff --git a/bsnes/sfc/ppu-fast/io.cpp b/bsnes/sfc/ppu-fast/io.cpp index 24843e9b1..823083444 100644 --- a/bsnes/sfc/ppu-fast/io.cpp +++ b/bsnes/sfc/ppu-fast/io.cpp @@ -40,6 +40,10 @@ auto PPU::writeVRAM(uint8 data) -> void { } } +auto PPU::getVRAM() -> uint16* { + return vram; +} + auto PPU::readOAM(uint10 address) -> uint8 { if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress; return readObject(address); diff --git a/bsnes/sfc/ppu-fast/ppu.hpp b/bsnes/sfc/ppu-fast/ppu.hpp index b4a71c011..234f3ac0a 100644 --- a/bsnes/sfc/ppu-fast/ppu.hpp +++ b/bsnes/sfc/ppu-fast/ppu.hpp @@ -266,6 +266,7 @@ struct PPU : PPUcounter { //io.cpp auto latchCounters(uint hcounter, uint vcounter) -> void; auto latchCounters() -> void; + auto getVRAM() -> uint16*; alwaysinline auto vramAddress() const -> uint; alwaysinline auto readVRAM() -> uint16; template alwaysinline auto writeVRAM(uint8 data) -> void; diff --git a/bsnes/sfc/ppu/io.cpp b/bsnes/sfc/ppu/io.cpp index 745b33310..fe5a3b926 100644 --- a/bsnes/sfc/ppu/io.cpp +++ b/bsnes/sfc/ppu/io.cpp @@ -43,6 +43,10 @@ auto PPU::writeVRAM(bool byte, uint8 data) -> void { if(byte == 1) vram[address] = vram[address] & 0x00ff | data << 8; } +auto PPU::getVRAM() -> uint16* { + return vram.data; +} + auto PPU::readOAM(uint10 addr) -> uint8 { if(!io.displayDisable && vcounter() < vdisp()) addr = latch.oamAddress; return obj.oam.read(addr); diff --git a/bsnes/sfc/ppu/ppu.hpp b/bsnes/sfc/ppu/ppu.hpp index ed18b553c..dd35ec454 100644 --- a/bsnes/sfc/ppu/ppu.hpp +++ b/bsnes/sfc/ppu/ppu.hpp @@ -25,6 +25,7 @@ struct PPU : Thread, PPUcounter { //io.cpp auto latchCounters(uint hcounter, uint vcounter) -> void; auto latchCounters() -> void; + auto getVRAM() -> uint16*; //serialization.cpp auto serialize(serializer&) -> void; diff --git a/bsnes/target-libretro/libretro.cpp b/bsnes/target-libretro/libretro.cpp index 8a50f5313..84f217d29 100644 --- a/bsnes/target-libretro/libretro.cpp +++ b/bsnes/target-libretro/libretro.cpp @@ -32,6 +32,7 @@ static void audio_queue(int16_t left, int16_t right) } #include "program.cpp" +#include static string sgb_bios; static vector cheatList; @@ -642,6 +643,18 @@ static bool update_variables() // returns whether video dimensions have changed emulator->configure("Hacks/PPU/Mode7/StrwinE", false); } + strcpy(key, "bsnes_sndchan_volume_x"); + var.key = key; + for (int i=0;i<8;i++) + { + key[strlen("bsnes_sndchan_volume_")] = '1'+i; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) + { + SuperFamicom::dsp.get_spc_dsp()->set_user_volume( i, atoi(var.value) ); + } + } + //override with setting overrides (BSO) if any program->applySettingOverrides(); @@ -966,6 +979,7 @@ size_t retro_serialize_size() bool retro_serialize(void *data, size_t size) { memcpy(data, emulator->serialize().data(), size); + update_variables(); // needed for custom volumes init return true; } @@ -1068,6 +1082,8 @@ bool retro_load_game(const retro_game_info *game) program->base_name = string(game->path); program->load(); + + update_variables(); // needed for custom volumes init emulator->connect(SuperFamicom::ID::Port::Controller1, SuperFamicom::ID::Device::Gamepad); emulator->connect(SuperFamicom::ID::Port::Controller2, SuperFamicom::ID::Device::Gamepad); @@ -1129,10 +1145,37 @@ unsigned retro_get_region() // Rely on higan to load and save SRAM until there is really compelling reason not to. void *retro_get_memory_data(unsigned id) { - return nullptr; + switch(id) + { + case RETRO_MEMORY_SAVE_RAM: + return SuperFamicom::cartridge.getSaveRAM(); + case RETRO_MEMORY_SYSTEM_RAM: + return SuperFamicom::cpu.wram; + case RETRO_MEMORY_VIDEO_RAM: + if(emulator->configuration("Hacks/PPU/Fast") == "true") + return SuperFamicom::ppufast.getVRAM(); + else + return SuperFamicom::ppu.getVRAM(); + case RETRO_MEMORY_ROM: + return SuperFamicom::cartridge.getROM(); + } + + return nullptr; } size_t retro_get_memory_size(unsigned id) { - return 0; + switch(id) + { + case RETRO_MEMORY_SAVE_RAM: + return SuperFamicom::cartridge.getSaveRAMSize(); + case RETRO_MEMORY_SYSTEM_RAM: + return 128 * 1024; + case RETRO_MEMORY_VIDEO_RAM: + return 64 * 1024; + case RETRO_MEMORY_ROM: + return SuperFamicom::cartridge.getROMSize(); + } + + return 0; } diff --git a/bsnes/target-libretro/libretro.h b/bsnes/target-libretro/libretro.h index bda0b77ed..5f9a6b784 100644 --- a/bsnes/target-libretro/libretro.h +++ b/bsnes/target-libretro/libretro.h @@ -313,6 +313,9 @@ enum retro_language /* Video ram lets a frontend peek into a game systems video RAM (VRAM). */ #define RETRO_MEMORY_VIDEO_RAM 3 +/* ROM lets a frontend peek into a game systems ROM. */ +#define RETRO_MEMORY_ROM 4 + /* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */ enum retro_key { diff --git a/bsnes/target-libretro/libretro_core_options.h b/bsnes/target-libretro/libretro_core_options.h index 6f92a28cb..88cf759fe 100644 --- a/bsnes/target-libretro/libretro_core_options.h +++ b/bsnes/target-libretro/libretro_core_options.h @@ -830,6 +830,166 @@ struct retro_core_option_definition option_defs_us[] = { }, "OFF" }, + { + "bsnes_sndchan_volume_1", + "Volume % for Sound Channel 1", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_2", + "Volume % for Sound Channel 2", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_3", + "Volume % for Sound Channel 3", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_4", + "Volume % for Sound Channel 4", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_5", + "Volume % for Sound Channel 5", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_6", + "Volume % for Sound Channel 6", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_7", + "Volume % for Sound Channel 7", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, + { + "bsnes_sndchan_volume_8", + "Volume % for Sound Channel 8", + NULL, + { + { "0", NULL }, + { "10", NULL }, + { "20", NULL }, + { "30", NULL }, + { "40", NULL }, + { "50", NULL }, + { "60", NULL }, + { "70", NULL }, + { "80", NULL }, + { "90", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100" + }, { NULL, NULL, NULL, {{0}}, NULL }, };