diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index 68e01b7..756405e 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -24,6 +24,7 @@ #include "serial_io.h" #endif #include "gbint.h" +#include "sound.h" #include #include @@ -140,6 +141,7 @@ public: void *rombank1_ptr() const; void *zeropage_ptr() const; void *oamram_ptr() const; + PSG *getPSG() const; #endif private: diff --git a/libgambatte/libretro/libretro.cpp b/libgambatte/libretro/libretro.cpp index 2fdb1d6..dfc2e1a 100644 --- a/libgambatte/libretro/libretro.cpp +++ b/libgambatte/libretro/libretro.cpp @@ -1144,6 +1144,17 @@ static void check_variables(void) /* Interframe blending option has its own handler */ check_frame_blend_variable(); + + char sound_channel_volume_base_str[] = "gambatte_channel_1_volume"; + var.key = sound_channel_volume_base_str; + for (unsigned c = 0; c < 4; c++) { + sound_channel_volume_base_str[17] = c+'1'; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + gb.getPSG()->setSoChanVolume(unsigned(atoi(var.value)), c); + } + } + #ifdef HAVE_NETWORK diff --git a/libgambatte/libretro/libretro_core_options.h b/libgambatte/libretro/libretro_core_options.h index 6942e0e..d174678 100644 --- a/libgambatte/libretro/libretro_core_options.h +++ b/libgambatte/libretro/libretro_core_options.h @@ -322,6 +322,86 @@ struct retro_core_option_definition option_defs_us[] = { }, "10" }, + { + "gambatte_channel_1_volume", + "Square 1 Channel volume %", + "Modify Square 1 Volume %.", + { + { "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" + }, + { + "gambatte_channel_2_volume", + "Square 2 Channel volume %", + "Modify Square 2 Volume %.", + { + { "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" + }, + { + "gambatte_channel_3_volume", + "Wave Channel volume %", + "Modify Wave Volume %.", + { + { "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" + }, + { + "gambatte_channel_4_volume", + "Noise Channel volume %", + "Modify Noise Volume %.", + { + { "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" + }, #ifdef HAVE_NETWORK { "gambatte_show_gb_link_settings", diff --git a/libgambatte/src/gambatte-memory.h b/libgambatte/src/gambatte-memory.h index c2d8868..d47f0e1 100644 --- a/libgambatte/src/gambatte-memory.h +++ b/libgambatte/src/gambatte-memory.h @@ -62,6 +62,7 @@ public: void *rombank1_ptr() const { return cart_.romdata(0) + 0x4000; } void *zeropage_ptr() const { return (void*)(ioamhram_ + 0x0180); } void *oamram_ptr() const { return (void*)ioamhram_; } + PSG *psg_ptr() const { return (PSG*)&psg_; } #else void loadSavedata() { cart_.loadSavedata(); } void saveSavedata() { cart_.saveSavedata(); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index 8208b5f..3ac5bf6 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -219,6 +219,10 @@ void *GB::zeropage_ptr() const { void *GB::oamram_ptr() const { return p_->cpu.oamram_ptr(); } + +PSG *GB::getPSG() const { + return p_->cpu.mem_.psg_ptr(); +} #endif } diff --git a/libgambatte/src/sound.cpp b/libgambatte/src/sound.cpp index 5533e6f..1b0f3a0 100644 --- a/libgambatte/src/sound.cpp +++ b/libgambatte/src/sound.cpp @@ -51,6 +51,11 @@ namespace gambatte , rsum_(0x8000) // initialize to 0x8000 to prevent borrows from high word, xor away later , enabled_(false) { + // init as full volume + setSoChanVolume(100, 0); + setSoChanVolume(100, 1); + setSoChanVolume(100, 2); + setSoChanVolume(100, 3); } void PSG::init(const bool cgb) @@ -98,10 +103,10 @@ namespace gambatte uint_least32_t *const buf = buffer_ + bufferPos_; std::memset(buf, 0, cycles * sizeof(uint_least32_t)); - ch1_.update(buf, soVol_, cycles); - ch2_.update(buf, soVol_, cycles); - ch3_.update(buf, soVol_, cycles); - ch4_.update(buf, soVol_, cycles); + ch1_.update(buf, (soChVol_[0] * soVol_ * 0x1999999A) >> 32, cycles); + ch2_.update(buf, (soChVol_[1] * soVol_ * 0x1999999A) >> 32, cycles); + ch3_.update(buf, (soChVol_[2] * soVol_ * 0x1999999A) >> 32, cycles); + ch4_.update(buf, (soChVol_[3] * soVol_ * 0x1999999A) >> 32, cycles); } void PSG::generateSamples(unsigned long const cycleCounter, bool const doubleSpeed) @@ -180,6 +185,14 @@ namespace gambatte soVol_ = (((nr50 & 0x7) + 1) * so1Mul + ((nr50 >> 4 & 0x7) + 1) * so2Mul) * 64; } + + void PSG::setSoChanVolume(const unsigned percent, const unsigned ch) + { + if( ch > 3 || percent > 100 ) + return; // invalid arg + + soChVol_[ch] = int(percent / 10); + } void PSG::mapSo(const unsigned nr51) { diff --git a/libgambatte/src/sound.h b/libgambatte/src/sound.h index 5e8d15b..0c22b55 100644 --- a/libgambatte/src/sound.h +++ b/libgambatte/src/sound.h @@ -71,6 +71,7 @@ public: void setNr44(unsigned data) { ch4_.setNr4(data); } void setSoVolume(unsigned nr50); + void setSoChanVolume(unsigned percent, unsigned ch); void mapSo(unsigned nr51); unsigned getStatus() const; @@ -83,6 +84,7 @@ private: std::size_t bufferPos_; unsigned long lastUpdate_; unsigned long soVol_; + unsigned long soChVol_[4]; uint_least32_t rsum_; bool enabled_;