diff --git a/include/PSX/Auxiliary/io_class_helper.hpp b/include/PSX/Auxiliary/io_class_helper.hpp index e99e236f..9052fdb9 100644 --- a/include/PSX/Auxiliary/io_class_helper.hpp +++ b/include/PSX/Auxiliary/io_class_helper.hpp @@ -23,7 +23,7 @@ } template -static constexpr __always_inline void io_class__volatile_assign(T& dst, const T& src) { +static constexpr __always_inline void io_class__update_with(T& dst, const T& src) { typedef decltype(dst.raw_value) DST_VALUE; const_cast(dst.raw_value) = src.raw_value; diff --git a/include/PSX/System/IOPorts/SPU_IO.hpp b/include/PSX/System/IOPorts/SPU_IO.hpp index 65ca28a0..5d780ac4 100644 --- a/include/PSX/System/IOPorts/SPU_IO.hpp +++ b/include/PSX/System/IOPorts/SPU_IO.hpp @@ -4,6 +4,29 @@ #include namespace SPU { + struct __no_align ubus32_t + { + uint16_t low; + uint16_t high; + + constexpr ubus32_t() : low(0), high(0) { + } + + constexpr operator uint32_t() const { + return ((this->high << 16) | this->low); + } + + constexpr void operator=(uint32_t value) { + this->low = (value & 0xFFFF); + this->high = (value >> 16); + } + + constexpr void operator=(ubus32_t value) volatile { + this->low = value.low; + this->high = value.high; + } + }; + enum Mode { Linear = 0, Exponential = 1, @@ -86,9 +109,41 @@ namespace SPU { uint32_t raw_value = 0; }; + struct __no_align KeyW { + ubus32_t raw_value; + + constexpr KeyW() = default; + + static constexpr KeyW All1() { + KeyW value; + + value.raw_value = static_cast(0xFFFFFFFF); + return value; + } + + constexpr KeyW& set(size_t id) { + this->raw_value = bit::set(this->raw_value, id); + return *this; + } + }; + + struct __no_align KeyR { + ubus32_t raw_value; + + constexpr bool is_set(size_t id) const { + return bit::is_set(this->raw_value, id); + } + }; + + struct __no_align Key { + static inline __always_inline auto& on = *reinterpret_cast(0x1F801D88); + static inline __always_inline auto& off = *reinterpret_cast(0x1F801D8C); + static inline __always_inline auto& state = *reinterpret_cast(0x1F801D9C); + }; + struct __no_align Voice { - static constexpr size_t Count = 24; - static inline __always_inline auto& Channel = reinterpret_cast(*reinterpret_cast(0x1f801c00)); + static constexpr size_t Count = 24; + static inline __always_inline auto& Channel = reinterpret_cast(*reinterpret_cast(0x1f801c00)); SweepVolume volumeLeft; SweepVolume volumeRight; diff --git a/src/Library/src/BootLoader/boot_spu.cpp b/src/Library/src/BootLoader/boot_spu.cpp index 14721fcd..d880f54d 100644 --- a/src/Library/src/BootLoader/boot_spu.cpp +++ b/src/Library/src/BootLoader/boot_spu.cpp @@ -1,23 +1,32 @@ #include namespace SPU { - static void clear_voice(Voice& voice) { - io_class__volatile_assign(voice.volumeLeft, SweepVolume()); - io_class__volatile_assign(voice.volumeRight, SweepVolume()); + static void clear_main_volume() { + static constexpr auto StartVol = SweepVolume().set_volume_mode().set_volume_percent(50.0); - io_class__volatile_assign(voice.sampleRate, SampleRate::from_HZ(0.0)); - io_class__volatile_assign(voice.adsr, ADSR()); - io_class__volatile_assign(voice.currentVolume, SweepVolume()); + io_class__update_with(MainVolume::Left, StartVol); + io_class__update_with(MainVolume::Right, StartVol); + } + + static void clear_keys() { + io_class__update_with(Key::off, KeyW::All1()); + } + + static void clear_voice(Voice& voice) { + io_class__update_with(voice.volumeLeft, SweepVolume()); + io_class__update_with(voice.volumeRight, SweepVolume()); + + io_class__update_with(voice.sampleRate, SampleRate::from_HZ(0.0)); + io_class__update_with(voice.adsr, ADSR()); + io_class__update_with(voice.currentVolume, SweepVolume()); voice.adr = 0x200; voice.repeatAdr = 0x200; } void setup() { - static constexpr auto StartVol = SweepVolume().set_volume_mode().set_volume_percent(50.0); - - io_class__volatile_assign(MainVolume::Left, StartVol); - io_class__volatile_assign(MainVolume::Right, StartVol); + clear_main_volume(); + clear_keys(); for(auto& voice : Voice::Channel) { clear_voice(voice);