From 0ee4575512307dfd989b5db78497f74f68a5cbc3 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 27 May 2020 19:17:37 +0200 Subject: [PATCH 01/26] Fxing MOVW, fixing 0xEB MOV Adding better temporary CPU-APU synchro --- sources/APU/APU.cpp | 2 +- sources/APU/Instructions/16bitDataTransmission.cpp | 6 ++++-- sources/CPU/CPU.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index dacb563..ced139b 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -656,7 +656,7 @@ namespace ComSquare::APU case 0xEA: return this->NOT1(this->_getAbsoluteBit()); case 0xEB: - return this->MOV(this->_getDirectAddr(), this->_internalRegisters.y, 3); + return this->MOV(this->_internalRead(this->_getDirectAddr()), this->_internalRegisters.y, 3); case 0xEC: return this->MOV(this->_getAbsoluteAddr(), this->_internalRegisters.y, 4); case 0xED: diff --git a/sources/APU/Instructions/16bitDataTransmission.cpp b/sources/APU/Instructions/16bitDataTransmission.cpp index cfa8009..5a28ce6 100644 --- a/sources/APU/Instructions/16bitDataTransmission.cpp +++ b/sources/APU/Instructions/16bitDataTransmission.cpp @@ -11,9 +11,11 @@ namespace ComSquare::APU uint24_t addr2 = addr + 1 + (this->_internalRegisters.p ? 0x0100 : 0); if (to_ya) { - uint16_t value = ((this->_internalRead(addr2) << 8u) | this->_internalRead(addr)); + uint8_t tmp = this->_internalRead(addr2); + uint16_t value = (tmp << 8) | this->_internalRead(addr); - this->_internalRegisters.ya = value; + this->_internalRegisters.a = value; + this->_internalRegisters.y = (value >> 8); this->_setNZflags(value); } else { diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index e507265..a6dec27 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -209,7 +209,7 @@ namespace ComSquare::CPU unsigned CPU::update() { unsigned cycles = 0; - const unsigned maxCycles = 0x17; + const unsigned maxCycles = 0x0C; for (int i = 0; i < 8; i++) { if (!(this->_internalRegisters.dmaEnableRegister & (0xF << i))) From 694ea7f9d418e91955499460b39f2d3f59127aa0 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Tue, 2 Feb 2021 15:46:30 +0100 Subject: [PATCH 02/26] Adding renderer to APU to play the samples generated --- CMakeLists.txt | 12 +- sources/APU/APU.cpp | 16 +- sources/APU/APU.hpp | 16 +- sources/APU/DSP/DSP.cpp | 399 +++++++++++++------------ sources/APU/DSP/DSP.hpp | 154 +++++++--- sources/Debugger/APUDebug.cpp | 244 +++++++-------- sources/Renderer/IRenderer.hpp | 5 + sources/Renderer/NoRenderer.cpp | 4 + sources/Renderer/NoRenderer.hpp | 6 +- sources/Renderer/QtRenderer/QtSFML.cpp | 5 + sources/Renderer/QtRenderer/QtSFML.hpp | 6 +- sources/Renderer/SFRenderer.cpp | 9 +- sources/Renderer/SFRenderer.hpp | 9 + sources/SNES.cpp | 2 +- ui/ui_cpu.h | 6 +- 15 files changed, 517 insertions(+), 376 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2f7462..3197b77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,11 @@ add_executable(unit_tests tests/testRectangleMemory.cpp tests/CPU/Math/testCMP.cpp sources/PPU/Backgrounds.cpp - sources/PPU/Background.cpp sources/PPU/Background.hpp sources/CPU/DMA/DMA.cpp sources/CPU/DMA/DMA.hpp) + sources/PPU/Background.cpp + sources/PPU/Background.hpp + sources/CPU/DMA/DMA.cpp + sources/CPU/DMA/DMA.hpp + ) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -215,7 +219,11 @@ add_executable(ComSquare sources/Debugger/CGramDebug.hpp sources/Models/Vector2.hpp sources/PPU/Backgrounds.cpp - sources/PPU/Background.cpp sources/PPU/Background.hpp sources/CPU/DMA/DMA.cpp sources/CPU/DMA/DMA.hpp) + sources/PPU/Background.cpp + sources/PPU/Background.hpp + sources/CPU/DMA/DMA.cpp + sources/CPU/DMA/DMA.hpp + ) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index ced139b..82068a7 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -7,13 +7,14 @@ #include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp" #include "../Exceptions/InvalidOpcode.hpp" -#include "../Utility/Utility.hpp" namespace ComSquare::APU { - APU::APU(std::shared_ptr &map) : + APU::APU(std::shared_ptr &map, Renderer::IRenderer &renderer) : + _renderer(renderer), _map(map), - _dsp(new DSP::DSP()) + _soundBuffer(), + _dsp(new DSP::DSP(_soundBuffer, APU::bufferSize / 2)) { this->reset(); } @@ -42,7 +43,7 @@ namespace ComSquare::APU case 0xF2: return this->_registers.dspregAddr; case 0xF3: - return this->_registers.dspregData; + return this->_dsp->read(this->_registers.dspregAddr); case 0xF4: return this->_registers.port0; case 0xF5: @@ -87,7 +88,7 @@ namespace ComSquare::APU this->_registers.dspregAddr = data; break; case 0xF3: - this->_registers.dspregData = data; + this->_dsp->write(this->_registers.dspregAddr, data); break; case 0xF4: this->_registers.port0 = data; @@ -705,6 +706,7 @@ namespace ComSquare::APU void APU::update(unsigned cycles) { unsigned total = 0; + int32_t samples = 0; if (this->_paddingCycles > cycles) { this->_paddingCycles -= cycles; @@ -715,6 +717,10 @@ namespace ComSquare::APU total += this->_executeInstruction(); if (this->_state == Running) this->_paddingCycles = total - cycles; + + samples = this->_dsp->getSamplesCount(); + if (samples > 0) + this->_renderer.playAudio(this->_soundBuffer, samples / 2); } void APU::_setNZflags(uint8_t value) diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 6503207..f13447b 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -10,6 +10,7 @@ #include "../Memory/AMemory.hpp" #include "../Ram/Ram.hpp" #include "IPL/IPL.hpp" +#include "../Renderer/IRenderer.hpp" namespace ComSquare::APU { @@ -75,8 +76,6 @@ namespace ComSquare::APU //! @brief DSP Register Address register uint8_t dspregAddr; - //! @brief DSP Register data register - uint8_t dspregData; //! @brief Port 0 register uint8_t port0; @@ -138,12 +137,19 @@ namespace ComSquare::APU Registers _registers{}; //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F). InternalRegisters _internalRegisters{}; + //! @brief Renderer used to play sounds + Renderer::IRenderer &_renderer; //! @brief Internal APU memory separated according to their utility std::shared_ptr _map; - //! @brief The DSP component used to produce sound - std::shared_ptr _dsp; + //! @brief Total size of the buffer containing samples + static constexpr int32_t bufferSize = 0x20000; + //! @brief Buffer containing samples to be played + int16_t _soundBuffer[bufferSize]; + + //! @brief The DSP component used to produce sound + std::shared_ptr _dsp; //! @brief Read from the APU ram. //! @param addr The address to read from. The address 0x0000 should refer to the first byte of the register. @@ -367,7 +373,7 @@ namespace ComSquare::APU int MOV(uint24_t memFrom, uint8_t ®To, int cycles, bool incrementX = false); int MOV(uint24_t memTo, uint24_t memFrom); public: - explicit APU(std::shared_ptr &map); + explicit APU(std::shared_ptr &map, Renderer::IRenderer &renderer); APU(const APU &) = default; APU &operator=(const APU &) = default; ~APU() override = default; diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 421826e..75e604e 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -7,169 +7,176 @@ namespace ComSquare::APU::DSP { + DSP::DSP(int16_t *buffer, int32_t size) + { + this->_state.buffer = buffer; + this->_state.bufferStart = buffer; + this->_state.bufferEnd = buffer + size; + } + uint8_t DSP::read(uint24_t addr) { switch (addr) { case 0x00: - return this->_channels[0].volL; + return this->_voices[0].volL; case 0x10: - return this->_channels[1].volL; + return this->_voices[1].volL; case 0x20: - return this->_channels[2].volL; + return this->_voices[2].volL; case 0x30: - return this->_channels[3].volL; + return this->_voices[3].volL; case 0x40: - return this->_channels[4].volL; + return this->_voices[4].volL; case 0x50: - return this->_channels[5].volL; + return this->_voices[5].volL; case 0x60: - return this->_channels[6].volL; + return this->_voices[6].volL; case 0x70: - return this->_channels[7].volL; + return this->_voices[7].volL; case 0x01: - return this->_channels[0].volR; + return this->_voices[0].volR; case 0x11: - return this->_channels[1].volR; + return this->_voices[1].volR; case 0x21: - return this->_channels[2].volR; + return this->_voices[2].volR; case 0x31: - return this->_channels[3].volR; + return this->_voices[3].volR; case 0x41: - return this->_channels[4].volR; + return this->_voices[4].volR; case 0x51: - return this->_channels[5].volR; + return this->_voices[5].volR; case 0x61: - return this->_channels[6].volR; + return this->_voices[6].volR; case 0x71: - return this->_channels[7].volR; + return this->_voices[7].volR; case 0x02: - return this->_channels[0].pitchL; + return this->_voices[0].pitchL; case 0x12: - return this->_channels[1].pitchL; + return this->_voices[1].pitchL; case 0x22: - return this->_channels[2].pitchL; + return this->_voices[2].pitchL; case 0x32: - return this->_channels[3].pitchL; + return this->_voices[3].pitchL; case 0x42: - return this->_channels[4].pitchL; + return this->_voices[4].pitchL; case 0x52: - return this->_channels[5].pitchL; + return this->_voices[5].pitchL; case 0x62: - return this->_channels[6].pitchL; + return this->_voices[6].pitchL; case 0x72: - return this->_channels[7].pitchL; + return this->_voices[7].pitchL; case 0x03: - return this->_channels[0].pitchH; + return this->_voices[0].pitchH; case 0x13: - return this->_channels[1].pitchH; + return this->_voices[1].pitchH; case 0x23: - return this->_channels[2].pitchH; + return this->_voices[2].pitchH; case 0x33: - return this->_channels[3].pitchH; + return this->_voices[3].pitchH; case 0x43: - return this->_channels[4].pitchH; + return this->_voices[4].pitchH; case 0x53: - return this->_channels[5].pitchH; + return this->_voices[5].pitchH; case 0x63: - return this->_channels[6].pitchH; + return this->_voices[6].pitchH; case 0x73: - return this->_channels[7].pitchH; + return this->_voices[7].pitchH; case 0x04: - return this->_channels[0].srcn; + return this->_voices[0].srcn; case 0x14: - return this->_channels[1].srcn; + return this->_voices[1].srcn; case 0x24: - return this->_channels[2].srcn; + return this->_voices[2].srcn; case 0x34: - return this->_channels[3].srcn; + return this->_voices[3].srcn; case 0x44: - return this->_channels[4].srcn; + return this->_voices[4].srcn; case 0x54: - return this->_channels[5].srcn; + return this->_voices[5].srcn; case 0x64: - return this->_channels[6].srcn; + return this->_voices[6].srcn; case 0x74: - return this->_channels[7].srcn; + return this->_voices[7].srcn; case 0x05: - return this->_channels[0].adsr1; + return this->_voices[0].adsr1; case 0x15: - return this->_channels[1].adsr1; + return this->_voices[1].adsr1; case 0x25: - return this->_channels[2].adsr1; + return this->_voices[2].adsr1; case 0x35: - return this->_channels[3].adsr1; + return this->_voices[3].adsr1; case 0x45: - return this->_channels[4].adsr1; + return this->_voices[4].adsr1; case 0x55: - return this->_channels[5].adsr1; + return this->_voices[5].adsr1; case 0x65: - return this->_channels[6].adsr1; + return this->_voices[6].adsr1; case 0x75: - return this->_channels[7].adsr1; + return this->_voices[7].adsr1; case 0x06: - return this->_channels[0].adsr2; + return this->_voices[0].adsr2; case 0x16: - return this->_channels[1].adsr2; + return this->_voices[1].adsr2; case 0x26: - return this->_channels[2].adsr2; + return this->_voices[2].adsr2; case 0x36: - return this->_channels[3].adsr2; + return this->_voices[3].adsr2; case 0x46: - return this->_channels[4].adsr2; + return this->_voices[4].adsr2; case 0x56: - return this->_channels[5].adsr2; + return this->_voices[5].adsr2; case 0x66: - return this->_channels[6].adsr2; + return this->_voices[6].adsr2; case 0x76: - return this->_channels[7].adsr2; + return this->_voices[7].adsr2; case 0x07: - return this->_channels[0].gain; + return this->_voices[0].gain; case 0x17: - return this->_channels[1].gain; + return this->_voices[1].gain; case 0x27: - return this->_channels[2].gain; + return this->_voices[2].gain; case 0x37: - return this->_channels[3].gain; + return this->_voices[3].gain; case 0x47: - return this->_channels[4].gain; + return this->_voices[4].gain; case 0x57: - return this->_channels[5].gain; + return this->_voices[5].gain; case 0x67: - return this->_channels[6].gain; + return this->_voices[6].gain; case 0x77: - return this->_channels[7].gain; + return this->_voices[7].gain; case 0x08: - return this->_channels[0].envx; + return this->_voices[0].envx; case 0x18: - return this->_channels[1].envx; + return this->_voices[1].envx; case 0x28: - return this->_channels[2].envx; + return this->_voices[2].envx; case 0x38: - return this->_channels[3].envx; + return this->_voices[3].envx; case 0x48: - return this->_channels[4].envx; + return this->_voices[4].envx; case 0x58: - return this->_channels[5].envx; + return this->_voices[5].envx; case 0x68: - return this->_channels[6].envx; + return this->_voices[6].envx; case 0x78: - return this->_channels[7].envx; + return this->_voices[7].envx; case 0x09: - return this->_channels[0].outx; + return this->_voices[0].outx; case 0x19: - return this->_channels[1].outx; + return this->_voices[1].outx; case 0x29: - return this->_channels[2].outx; + return this->_voices[2].outx; case 0x39: - return this->_channels[3].outx; + return this->_voices[3].outx; case 0x49: - return this->_channels[4].outx; + return this->_voices[4].outx; case 0x59: - return this->_channels[5].outx; + return this->_voices[5].outx; case 0x69: - return this->_channels[6].outx; + return this->_voices[6].outx; case 0x79: - return this->_channels[7].outx; + return this->_voices[7].outx; case 0x0C: return this->_registers.mvolL; case 0x1C: @@ -182,14 +189,14 @@ namespace ComSquare::APU::DSP uint8_t kon = 0; for (int i = 0; i < 8; i++) - kon |= this->_channels[i].kon << i; + kon |= this->_voices[i].kon << i; return kon; } case 0x5C: { uint8_t kof = 0; for (int i = 0; i < 8; i++) - kof |= this->_channels[i].kof << i; + kof |= this->_voices[i].kof << i; return kof; } case 0x6C: @@ -198,7 +205,7 @@ namespace ComSquare::APU::DSP uint8_t endx = 0; for (int i = 0; i < 8; i++) - endx |= this->_channels[i].endx << i; + endx |= this->_voices[i].endx << i; return endx; } case 0x0D: @@ -209,21 +216,21 @@ namespace ComSquare::APU::DSP uint8_t pmon = 0; for (int i = 0; i < 8; i++) - pmon |= this->_channels[i].pmon << i; + pmon |= this->_voices[i].pmon << i; return pmon; } case 0x3D: { uint8_t non = 0; for (int i = 0; i < 8; i++) - non |= this->_channels[i].non << i; + non |= this->_voices[i].non << i; return non; } case 0x4D: { uint8_t eon = 0; for (int i = 0; i < 8; i++) - eon |= this->_channels[i].eon << i; + eon |= this->_voices[i].eon << i; return eon; } case 0x5D: @@ -233,21 +240,21 @@ namespace ComSquare::APU::DSP case 0x7D: return this->_registers.edl; case 0x0F: - return this->_channels[0].coeff; + return this->_voices[0].coeff; case 0x1F: - return this->_channels[1].coeff; + return this->_voices[1].coeff; case 0x2F: - return this->_channels[2].coeff; + return this->_voices[2].coeff; case 0x3F: - return this->_channels[3].coeff; + return this->_voices[3].coeff; case 0x4F: - return this->_channels[4].coeff; + return this->_voices[4].coeff; case 0x5F: - return this->_channels[5].coeff; + return this->_voices[5].coeff; case 0x6F: - return this->_channels[6].coeff; + return this->_voices[6].coeff; case 0x7F: - return this->_channels[7].coeff; + return this->_voices[7].coeff; default: throw InvalidAddress("DSP Registers read", addr); } @@ -257,244 +264,244 @@ namespace ComSquare::APU::DSP { switch (addr) { case 0x00: - this->_channels[0].volL = data; + this->_voices[0].volL = data; break; case 0x10: - this->_channels[1].volL = data; + this->_voices[1].volL = data; break; case 0x20: - this->_channels[2].volL = data; + this->_voices[2].volL = data; break; case 0x30: - this->_channels[3].volL = data; + this->_voices[3].volL = data; break; case 0x40: - this->_channels[4].volL = data; + this->_voices[4].volL = data; break; case 0x50: - this->_channels[5].volL = data; + this->_voices[5].volL = data; break; case 0x60: - this->_channels[6].volL = data; + this->_voices[6].volL = data; break; case 0x70: - this->_channels[7].volL = data; + this->_voices[7].volL = data; break; case 0x01: - this->_channels[0].volR = data; + this->_voices[0].volR = data; break; case 0x11: - this->_channels[1].volR = data; + this->_voices[1].volR = data; break; case 0x21: - this->_channels[2].volR = data; + this->_voices[2].volR = data; break; case 0x31: - this->_channels[3].volR = data; + this->_voices[3].volR = data; break; case 0x41: - this->_channels[4].volR = data; + this->_voices[4].volR = data; break; case 0x51: - this->_channels[5].volR = data; + this->_voices[5].volR = data; break; case 0x61: - this->_channels[6].volR = data; + this->_voices[6].volR = data; break; case 0x71: - this->_channels[7].volR = data; + this->_voices[7].volR = data; break; case 0x02: - this->_channels[0].pitchL = data; + this->_voices[0].pitchL = data; break; case 0x12: - this->_channels[1].pitchL = data; + this->_voices[1].pitchL = data; break; case 0x22: - this->_channels[2].pitchL = data; + this->_voices[2].pitchL = data; break; case 0x32: - this->_channels[3].pitchL = data; + this->_voices[3].pitchL = data; break; case 0x42: - this->_channels[4].pitchL = data; + this->_voices[4].pitchL = data; break; case 0x52: - this->_channels[5].pitchL = data; + this->_voices[5].pitchL = data; break; case 0x62: - this->_channels[6].pitchL = data; + this->_voices[6].pitchL = data; break; case 0x72: - this->_channels[7].pitchL = data; + this->_voices[7].pitchL = data; break; case 0x03: - this->_channels[0].pitchH = data; + this->_voices[0].pitchH = data; break; case 0x13: - this->_channels[1].pitchH = data; + this->_voices[1].pitchH = data; break; case 0x23: - this->_channels[2].pitchH = data; + this->_voices[2].pitchH = data; break; case 0x33: - this->_channels[3].pitchH = data; + this->_voices[3].pitchH = data; break; case 0x43: - this->_channels[4].pitchH = data; + this->_voices[4].pitchH = data; break; case 0x53: - this->_channels[5].pitchH = data; + this->_voices[5].pitchH = data; break; case 0x63: - this->_channels[6].pitchH = data; + this->_voices[6].pitchH = data; break; case 0x73: - this->_channels[7].pitchH = data; + this->_voices[7].pitchH = data; break; case 0x04: - this->_channels[0].srcn = data; + this->_voices[0].srcn = data; break; case 0x14: - this->_channels[1].srcn = data; + this->_voices[1].srcn = data; break; case 0x24: - this->_channels[2].srcn = data; + this->_voices[2].srcn = data; break; case 0x34: - this->_channels[3].srcn = data; + this->_voices[3].srcn = data; break; case 0x44: - this->_channels[4].srcn = data; + this->_voices[4].srcn = data; break; case 0x54: - this->_channels[5].srcn = data; + this->_voices[5].srcn = data; break; case 0x64: - this->_channels[6].srcn = data; + this->_voices[6].srcn = data; break; case 0x74: - this->_channels[7].srcn = data; + this->_voices[7].srcn = data; break; case 0x05: - this->_channels[0].adsr1 = data; + this->_voices[0].adsr1 = data; break; case 0x15: - this->_channels[1].adsr1 = data; + this->_voices[1].adsr1 = data; break; case 0x25: - this->_channels[2].adsr1 = data; + this->_voices[2].adsr1 = data; break; case 0x35: - this->_channels[3].adsr1 = data; + this->_voices[3].adsr1 = data; break; case 0x45: - this->_channels[4].adsr1 = data; + this->_voices[4].adsr1 = data; break; case 0x55: - this->_channels[5].adsr1 = data; + this->_voices[5].adsr1 = data; break; case 0x65: - this->_channels[6].adsr1 = data; + this->_voices[6].adsr1 = data; break; case 0x75: - this->_channels[7].adsr1 = data; + this->_voices[7].adsr1 = data; break; case 0x06: - this->_channels[0].adsr2 = data; + this->_voices[0].adsr2 = data; break; case 0x16: - this->_channels[1].adsr2 = data; + this->_voices[1].adsr2 = data; break; case 0x26: - this->_channels[2].adsr2 = data; + this->_voices[2].adsr2 = data; break; case 0x36: - this->_channels[3].adsr2 = data; + this->_voices[3].adsr2 = data; break; case 0x46: - this->_channels[4].adsr2 = data; + this->_voices[4].adsr2 = data; break; case 0x56: - this->_channels[5].adsr2 = data; + this->_voices[5].adsr2 = data; break; case 0x66: - this->_channels[6].adsr2 = data; + this->_voices[6].adsr2 = data; break; case 0x76: - this->_channels[7].adsr2 = data; + this->_voices[7].adsr2 = data; break; case 0x07: - this->_channels[0].gain = data; + this->_voices[0].gain = data; break; case 0x17: - this->_channels[1].gain = data; + this->_voices[1].gain = data; break; case 0x27: - this->_channels[2].gain = data; + this->_voices[2].gain = data; break; case 0x37: - this->_channels[3].gain = data; + this->_voices[3].gain = data; break; case 0x47: - this->_channels[4].gain = data; + this->_voices[4].gain = data; break; case 0x57: - this->_channels[5].gain = data; + this->_voices[5].gain = data; break; case 0x67: - this->_channels[6].gain = data; + this->_voices[6].gain = data; break; case 0x77: - this->_channels[7].gain = data; + this->_voices[7].gain = data; break; case 0x08: - this->_channels[0].envx = data; + this->_voices[0].envx = data; break; case 0x18: - this->_channels[1].envx = data; + this->_voices[1].envx = data; break; case 0x28: - this->_channels[2].envx = data; + this->_voices[2].envx = data; break; case 0x38: - this->_channels[3].envx = data; + this->_voices[3].envx = data; break; case 0x48: - this->_channels[4].envx = data; + this->_voices[4].envx = data; break; case 0x58: - this->_channels[5].envx = data; + this->_voices[5].envx = data; break; case 0x68: - this->_channels[6].envx = data; + this->_voices[6].envx = data; break; case 0x78: - this->_channels[7].envx = data; + this->_voices[7].envx = data; break; case 0x09: - this->_channels[0].outx = data; + this->_voices[0].outx = data; break; case 0x19: - this->_channels[1].outx = data; + this->_voices[1].outx = data; break; case 0x29: - this->_channels[2].outx = data; + this->_voices[2].outx = data; break; case 0x39: - this->_channels[3].outx = data; + this->_voices[3].outx = data; break; case 0x49: - this->_channels[4].outx = data; + this->_voices[4].outx = data; break; case 0x59: - this->_channels[5].outx = data; + this->_voices[5].outx = data; break; case 0x69: - this->_channels[6].outx = data; + this->_voices[6].outx = data; break; case 0x79: - this->_channels[7].outx = data; + this->_voices[7].outx = data; break; case 0x0C: this->_registers.mvolL = data; @@ -510,18 +517,18 @@ namespace ComSquare::APU::DSP break; case 0x4C: for (int i = 0; i < 8; i++) - this->_channels[i].kon |= data << i; + this->_voices[i].kon |= data << i; break; case 0x5C: for (int i = 0; i < 8; i++) - this->_channels[i].kof |= data << i; + this->_voices[i].kof |= data << i; break; case 0x6C: this->_registers.flg = data; break; case 0x7C: for (int i = 0; i < 8; i++) - this->_channels[i].endx |= data << i; + this->_voices[i].endx |= data << i; break; case 0x0D: this->_registers.efb = data; @@ -531,15 +538,15 @@ namespace ComSquare::APU::DSP break; case 0x2D: for (int i = 0; i < 8; i++) - this->_channels[i].pmon |= data << i; + this->_voices[i].pmon |= data << i; break; case 0x3D: for (int i = 0; i < 8; i++) - this->_channels[i].non |= data << i; + this->_voices[i].non |= data << i; break; case 0x4D: for (int i = 0; i < 8; i++) - this->_channels[i].eon |= data << i; + this->_voices[i].eon |= data << i; break; case 0x5D: this->_registers.dir = data; @@ -551,45 +558,55 @@ namespace ComSquare::APU::DSP this->_registers.edl = data; break; case 0x0F: - this->_channels[0].coeff = data; + this->_voices[0].coeff = data; break; case 0x1F: - this->_channels[1].coeff = data; + this->_voices[1].coeff = data; break; case 0x2F: - this->_channels[2].coeff = data; + this->_voices[2].coeff = data; break; case 0x3F: - this->_channels[3].coeff = data; + this->_voices[3].coeff = data; break; case 0x4F: - this->_channels[4].coeff = data; + this->_voices[4].coeff = data; break; case 0x5F: - this->_channels[5].coeff = data; + this->_voices[5].coeff = data; break; case 0x6F: - this->_channels[6].coeff = data; + this->_voices[6].coeff = data; break; case 0x7F: - this->_channels[7].coeff = data; + this->_voices[7].coeff = data; break; default: throw InvalidAddress("DSP Registers write", addr); } } + void DSP::update() + { + this->_state.voice = (this->_state.voice + 1) % 32; + } + Registers DSP::getRegisters() { return this->_registers; } - std::array DSP::getChannels() + std::array DSP::getVoices() { - return this->_channels; + return this->_voices; } - std::string DSP::getName() + int32_t DSP::getSamplesCount() + { + return this->_state.buffer - this->_state.bufferStart; + } + + std::string DSP::getName() { return "DSP"; } diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 1676cd5..cc09e0d 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -41,24 +41,26 @@ namespace ComSquare::APU::DSP uint8_t edl; }; - struct Channel { - //! @brief BRR Header - union { - struct { - //! @brief Shift value range - unsigned range : 4; - //! @brief Decompression filter - unsigned filter : 2; - //! @brief Flag if the sample loops - bool loop : 1; - //! @brief Stop the sample (or restart from loop point) - bool end : 1; - }; - uint8_t brrHead; - }; - //! @brief Sample data inside BRR - uint64_t brrData; + struct BRR { + //! @brief BRR Header + union { + struct { + //! @brief Shift value range + unsigned range : 4; + //! @brief Decompression filter + unsigned filter : 2; + //! @brief Flag if the sample loops + bool loop : 1; + //! @brief Stop the sample (or restart from loop point) + bool end : 1; + }; + uint8_t head; + }; + //! @brief Sample data inside BRR + uint64_t block; + }; + struct Voice { //! @brief Left channel volume register uint8_t volL; //! @brief Left channel volume register @@ -74,6 +76,27 @@ namespace ComSquare::APU::DSP uint16_t pitch; }; + //! @brief Source number register + uint8_t srcn; + + union { + struct { + //! @brief Envelope register + uint8_t adsr1; + //! @brief Envelope controllers register + uint8_t adsr2; + }; + uint16_t envelope; + }; + + //! @brief Gain register + uint8_t gain; + + //! @brief Envelope value register + uint8_t envx; + //! @brief Wave height register + uint8_t outx; + //! @brief Key On register bool kon : 1; //! @brief Key Off register @@ -81,7 +104,6 @@ namespace ComSquare::APU::DSP //! @brief Sample end register bool endx : 1; - //! @brief Noise enable register bool non : 1; //! @brief Echo enable register @@ -90,45 +112,87 @@ namespace ComSquare::APU::DSP //! @brief Pitch modulation register bool pmon : 1; - //! @brief Source number register - uint8_t srcn; - - union { - struct { - //! @brief Envelope register - uint8_t adsr1; - //! @brief Envelope controllers register - uint8_t adsr2; - }; - uint16_t envelope; - }; - //! @brief Gain register - uint8_t gain; - //! @brief Envelope value register - uint8_t envx; - //! @brief Wave height register - uint8_t outx; - //! @brief Echo FIR filter coefficients uint8_t coeff; + + //! @brief Bit Rate Reduction associated to + BRR brr; + //! @brief Relative position in sample + uint16_t gaussOffset; + //! @brief Position of the next sample + unsigned sampleOffset : 4; + std::array decodedSamples; }; + //! @brief Current state of the DSP + struct State + { + //! @brief Current voice modification to do + uint8_t voice = 0; + //! @brief Current buffer of samples + int16_t *buffer; + //! @brief Limit of the buffer + int16_t *bufferEnd; + //! @brief Beginning of the buffer + int16_t *bufferStart; + }; + class DSP : public Memory::AMemory { private: //! @brief All registers of the DSP Registers _registers{}; - //! @brief 8x channels of sample used to make sound - std::array _channels{}; - public: - DSP() = default; + //! @brief 8x voices of sample used to make sound + std::array _voices{}; + + //! @brief Gaussian table used for making waves + std::array _gauss = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, + 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, + 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, + 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, + 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, + 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, + 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, + 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305 + }; + + //! @brief State of DSP with buffer + State _state {}; + public: + DSP(int16_t *buffer, int32_t size); DSP(const DSP &) = default; DSP &operator=(const DSP &) = default; ~DSP() override = default; Registers getRegisters(); - std::array getChannels(); + //! @brief Return all 8 voices from DSP + std::array getVoices(); //! @brief Read from the internal DSP register. //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register. @@ -141,6 +205,12 @@ namespace ComSquare::APU::DSP //! @throw InvalidAddress will be thrown if the address is more than $7F (the number of register). void write(uint24_t addr, uint8_t data) override; + //! @brief Execute current voice transformation + void update(); + + //! @brief Return the number of samples written + int32_t getSamplesCount(); + //! @brief Get the name of this accessor (used for debug purpose) std::string getName() override; diff --git a/sources/Debugger/APUDebug.cpp b/sources/Debugger/APUDebug.cpp index 6e11913..040ad7b 100644 --- a/sources/Debugger/APUDebug.cpp +++ b/sources/Debugger/APUDebug.cpp @@ -47,8 +47,8 @@ namespace ComSquare::Debugger this->_ui.dSPRegAddresshexaLineEdit->setText(Utility::to_hex(this->_registers.dspregAddr).c_str()); this->_ui.dSPRegAddressLineEdit->setText(Utility::to_binary(this->_registers.dspregAddr).c_str()); - this->_ui.dSPRegDatahexaLineEdit->setText(Utility::to_hex(this->_registers.dspregData).c_str()); - this->_ui.dSPRegDataLineEdit->setText(Utility::to_binary(this->_registers.dspregData).c_str()); + this->_ui.dSPRegDatahexaLineEdit->setText(Utility::to_hex(this->_dsp->read(this->_registers.dspregAddr)).c_str()); + this->_ui.dSPRegDataLineEdit->setText(Utility::to_binary(this->_dsp->read(this->_registers.dspregAddr)).c_str()); this->_ui.timer0hexaLineEdit->setText(Utility::to_hex(this->_registers.timer0).c_str()); this->_ui.timer0LineEdit->setText(Utility::to_binary(this->_registers.timer0).c_str()); @@ -94,133 +94,133 @@ namespace ComSquare::Debugger this->_ui.echoBufferOffsetLineEdit->setText(Utility::to_hex(this->_dsp->getRegisters().esa).c_str()); this->_ui.echoDelayLineEdit->setText(Utility::to_hex(this->_dsp->getRegisters().edl).c_str()); - this->_ui.VolumeLprogressBar->setValue(this->_dsp->getChannels()[0].volL); - this->_ui.VolumeRprogressBar->setValue(this->_dsp->getChannels()[0].volR); - this->_ui.WaveHeightprogressBar->setValue(this->_dsp->getChannels()[0].outx); - this->_ui.EchoFIRCoeffprogressBar->setValue(this->_dsp->getChannels()[0].coeff); - this->_ui.PitchlineEdit->setText(Utility::to_hex(this->_dsp->getChannels()[0].pitch).c_str()); - this->_ui.sourceNumberLineEdit->setText(Utility::to_hex(this->_dsp->getChannels()[0].srcn).c_str()); - this->_ui.GainlineEdit->setText(Utility::to_hex(this->_dsp->getChannels()[0].gain).c_str()); - this->_ui.EnvelopelineEdit->setText(Utility::to_hex(this->_dsp->getChannels()[0].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit->setText(Utility::to_hex(this->_dsp->getChannels()[0].envx).c_str()); - this->_ui.KeyOncheckBox->setChecked(this->_dsp->getChannels()[0].kon); - this->_ui.KeyOffcheckBox->setChecked(this->_dsp->getChannels()[0].kof); - this->_ui.NoisecheckBox->setChecked(this->_dsp->getChannels()[0].non); - this->_ui.EchocheckBox->setChecked(this->_dsp->getChannels()[0].eon); - this->_ui.SampleEndcheckBox->setChecked(this->_dsp->getChannels()[0].endx); - this->_ui.PitchModulationcheckBox->setChecked(this->_dsp->getChannels()[0].pmon); + this->_ui.VolumeLprogressBar->setValue(this->_dsp->getVoices()[0].volL); + this->_ui.VolumeRprogressBar->setValue(this->_dsp->getVoices()[0].volR); + this->_ui.WaveHeightprogressBar->setValue(this->_dsp->getVoices()[0].outx); + this->_ui.EchoFIRCoeffprogressBar->setValue(this->_dsp->getVoices()[0].coeff); + this->_ui.PitchlineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].pitch).c_str()); + this->_ui.sourceNumberLineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].srcn).c_str()); + this->_ui.GainlineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].gain).c_str()); + this->_ui.EnvelopelineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].envx).c_str()); + this->_ui.KeyOncheckBox->setChecked(this->_dsp->getVoices()[0].kon); + this->_ui.KeyOffcheckBox->setChecked(this->_dsp->getVoices()[0].kof); + this->_ui.NoisecheckBox->setChecked(this->_dsp->getVoices()[0].non); + this->_ui.EchocheckBox->setChecked(this->_dsp->getVoices()[0].eon); + this->_ui.SampleEndcheckBox->setChecked(this->_dsp->getVoices()[0].endx); + this->_ui.PitchModulationcheckBox->setChecked(this->_dsp->getVoices()[0].pmon); - this->_ui.VolumeLprogressBar_2->setValue(this->_dsp->getChannels()[1].volL); - this->_ui.VolumeRprogressBar_2->setValue(this->_dsp->getChannels()[1].volR); - this->_ui.WaveHeightprogressBar_2->setValue(this->_dsp->getChannels()[1].outx); - this->_ui.EchoFIRCoeffprogressBar_2->setValue(this->_dsp->getChannels()[1].coeff); - this->_ui.PitchlineEdit_2->setText(Utility::to_hex(this->_dsp->getChannels()[1].pitch).c_str()); - this->_ui.sourceNumberLineEdit_2->setText(Utility::to_hex(this->_dsp->getChannels()[1].srcn).c_str()); - this->_ui.GainlineEdit_2->setText(Utility::to_hex(this->_dsp->getChannels()[1].gain).c_str()); - this->_ui.EnvelopelineEdit_2->setText(Utility::to_hex(this->_dsp->getChannels()[1].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_2->setText(Utility::to_hex(this->_dsp->getChannels()[1].envx).c_str()); - this->_ui.KeyOncheckBox_2->setChecked(this->_dsp->getChannels()[1].kon); - this->_ui.KeyOffcheckBox_2->setChecked(this->_dsp->getChannels()[1].kof); - this->_ui.NoisecheckBox_2->setChecked(this->_dsp->getChannels()[1].non); - this->_ui.EchocheckBox_2->setChecked(this->_dsp->getChannels()[1].eon); - this->_ui.SampleEndcheckBox_2->setChecked(this->_dsp->getChannels()[1].endx); - this->_ui.PitchModulationcheckBox_2->setChecked(this->_dsp->getChannels()[1].pmon); + this->_ui.VolumeLprogressBar_2->setValue(this->_dsp->getVoices()[1].volL); + this->_ui.VolumeRprogressBar_2->setValue(this->_dsp->getVoices()[1].volR); + this->_ui.WaveHeightprogressBar_2->setValue(this->_dsp->getVoices()[1].outx); + this->_ui.EchoFIRCoeffprogressBar_2->setValue(this->_dsp->getVoices()[1].coeff); + this->_ui.PitchlineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].pitch).c_str()); + this->_ui.sourceNumberLineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].srcn).c_str()); + this->_ui.GainlineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].gain).c_str()); + this->_ui.EnvelopelineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].envx).c_str()); + this->_ui.KeyOncheckBox_2->setChecked(this->_dsp->getVoices()[1].kon); + this->_ui.KeyOffcheckBox_2->setChecked(this->_dsp->getVoices()[1].kof); + this->_ui.NoisecheckBox_2->setChecked(this->_dsp->getVoices()[1].non); + this->_ui.EchocheckBox_2->setChecked(this->_dsp->getVoices()[1].eon); + this->_ui.SampleEndcheckBox_2->setChecked(this->_dsp->getVoices()[1].endx); + this->_ui.PitchModulationcheckBox_2->setChecked(this->_dsp->getVoices()[1].pmon); - this->_ui.VolumeLprogressBar_3->setValue(this->_dsp->getChannels()[2].volL); - this->_ui.VolumeRprogressBar_3->setValue(this->_dsp->getChannels()[2].volR); - this->_ui.WaveHeightprogressBar_3->setValue(this->_dsp->getChannels()[2].outx); - this->_ui.EchoFIRCoeffprogressBar_3->setValue(this->_dsp->getChannels()[2].coeff); - this->_ui.PitchlineEdit_3->setText(Utility::to_hex(this->_dsp->getChannels()[2].pitch).c_str()); - this->_ui.sourceNumberLineEdit_3->setText(Utility::to_hex(this->_dsp->getChannels()[2].srcn).c_str()); - this->_ui.GainlineEdit_3->setText(Utility::to_hex(this->_dsp->getChannels()[2].gain).c_str()); - this->_ui.EnvelopelineEdit_3->setText(Utility::to_hex(this->_dsp->getChannels()[2].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_3->setText(Utility::to_hex(this->_dsp->getChannels()[2].envx).c_str()); - this->_ui.KeyOncheckBox_3->setChecked(this->_dsp->getChannels()[2].kon); - this->_ui.KeyOffcheckBox_3->setChecked(this->_dsp->getChannels()[2].kof); - this->_ui.NoisecheckBox_3->setChecked(this->_dsp->getChannels()[2].non); - this->_ui.EchocheckBox_3->setChecked(this->_dsp->getChannels()[2].eon); - this->_ui.SampleEndcheckBox_3->setChecked(this->_dsp->getChannels()[2].endx); - this->_ui.PitchModulationcheckBox_3->setChecked(this->_dsp->getChannels()[2].pmon); + this->_ui.VolumeLprogressBar_3->setValue(this->_dsp->getVoices()[2].volL); + this->_ui.VolumeRprogressBar_3->setValue(this->_dsp->getVoices()[2].volR); + this->_ui.WaveHeightprogressBar_3->setValue(this->_dsp->getVoices()[2].outx); + this->_ui.EchoFIRCoeffprogressBar_3->setValue(this->_dsp->getVoices()[2].coeff); + this->_ui.PitchlineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].pitch).c_str()); + this->_ui.sourceNumberLineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].srcn).c_str()); + this->_ui.GainlineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].gain).c_str()); + this->_ui.EnvelopelineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].envx).c_str()); + this->_ui.KeyOncheckBox_3->setChecked(this->_dsp->getVoices()[2].kon); + this->_ui.KeyOffcheckBox_3->setChecked(this->_dsp->getVoices()[2].kof); + this->_ui.NoisecheckBox_3->setChecked(this->_dsp->getVoices()[2].non); + this->_ui.EchocheckBox_3->setChecked(this->_dsp->getVoices()[2].eon); + this->_ui.SampleEndcheckBox_3->setChecked(this->_dsp->getVoices()[2].endx); + this->_ui.PitchModulationcheckBox_3->setChecked(this->_dsp->getVoices()[2].pmon); - this->_ui.VolumeLprogressBar_4->setValue(this->_dsp->getChannels()[3].volL); - this->_ui.VolumeRprogressBar_4->setValue(this->_dsp->getChannels()[3].volR); - this->_ui.WaveHeightprogressBar_4->setValue(this->_dsp->getChannels()[3].outx); - this->_ui.EchoFIRCoeffprogressBar_4->setValue(this->_dsp->getChannels()[3].coeff); - this->_ui.PitchlineEdit_4->setText(Utility::to_hex(this->_dsp->getChannels()[3].pitch).c_str()); - this->_ui.sourceNumberLineEdit_4->setText(Utility::to_hex(this->_dsp->getChannels()[3].srcn).c_str()); - this->_ui.GainlineEdit_4->setText(Utility::to_hex(this->_dsp->getChannels()[3].gain).c_str()); - this->_ui.EnvelopelineEdit_4->setText(Utility::to_hex(this->_dsp->getChannels()[3].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_4->setText(Utility::to_hex(this->_dsp->getChannels()[3].envx).c_str()); - this->_ui.KeyOncheckBox_4->setChecked(this->_dsp->getChannels()[3].kon); - this->_ui.KeyOffcheckBox_4->setChecked(this->_dsp->getChannels()[3].kof); - this->_ui.NoisecheckBox_4->setChecked(this->_dsp->getChannels()[3].non); - this->_ui.EchocheckBox_4->setChecked(this->_dsp->getChannels()[3].eon); - this->_ui.SampleEndcheckBox_4->setChecked(this->_dsp->getChannels()[3].endx); - this->_ui.PitchModulationcheckBox_4->setChecked(this->_dsp->getChannels()[3].pmon); + this->_ui.VolumeLprogressBar_4->setValue(this->_dsp->getVoices()[3].volL); + this->_ui.VolumeRprogressBar_4->setValue(this->_dsp->getVoices()[3].volR); + this->_ui.WaveHeightprogressBar_4->setValue(this->_dsp->getVoices()[3].outx); + this->_ui.EchoFIRCoeffprogressBar_4->setValue(this->_dsp->getVoices()[3].coeff); + this->_ui.PitchlineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].pitch).c_str()); + this->_ui.sourceNumberLineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].srcn).c_str()); + this->_ui.GainlineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].gain).c_str()); + this->_ui.EnvelopelineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].envx).c_str()); + this->_ui.KeyOncheckBox_4->setChecked(this->_dsp->getVoices()[3].kon); + this->_ui.KeyOffcheckBox_4->setChecked(this->_dsp->getVoices()[3].kof); + this->_ui.NoisecheckBox_4->setChecked(this->_dsp->getVoices()[3].non); + this->_ui.EchocheckBox_4->setChecked(this->_dsp->getVoices()[3].eon); + this->_ui.SampleEndcheckBox_4->setChecked(this->_dsp->getVoices()[3].endx); + this->_ui.PitchModulationcheckBox_4->setChecked(this->_dsp->getVoices()[3].pmon); - this->_ui.VolumeLprogressBar_5->setValue(this->_dsp->getChannels()[4].volL); - this->_ui.VolumeRprogressBar_5->setValue(this->_dsp->getChannels()[4].volR); - this->_ui.WaveHeightprogressBar_5->setValue(this->_dsp->getChannels()[4].outx); - this->_ui.EchoFIRCoeffprogressBar_5->setValue(this->_dsp->getChannels()[4].coeff); - this->_ui.PitchlineEdit_5->setText(Utility::to_hex(this->_dsp->getChannels()[4].pitch).c_str()); - this->_ui.sourceNumberLineEdit_5->setText(Utility::to_hex(this->_dsp->getChannels()[4].srcn).c_str()); - this->_ui.GainlineEdit_5->setText(Utility::to_hex(this->_dsp->getChannels()[4].gain).c_str()); - this->_ui.EnvelopelineEdit_5->setText(Utility::to_hex(this->_dsp->getChannels()[4].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_5->setText(Utility::to_hex(this->_dsp->getChannels()[4].envx).c_str()); - this->_ui.KeyOncheckBox_5->setChecked(this->_dsp->getChannels()[4].kon); - this->_ui.KeyOffcheckBox_5->setChecked(this->_dsp->getChannels()[4].kof); - this->_ui.NoisecheckBox_5->setChecked(this->_dsp->getChannels()[4].non); - this->_ui.EchocheckBox_5->setChecked(this->_dsp->getChannels()[4].eon); - this->_ui.SampleEndcheckBox_5->setChecked(this->_dsp->getChannels()[4].endx); - this->_ui.PitchModulationcheckBox_5->setChecked(this->_dsp->getChannels()[4].pmon); + this->_ui.VolumeLprogressBar_5->setValue(this->_dsp->getVoices()[4].volL); + this->_ui.VolumeRprogressBar_5->setValue(this->_dsp->getVoices()[4].volR); + this->_ui.WaveHeightprogressBar_5->setValue(this->_dsp->getVoices()[4].outx); + this->_ui.EchoFIRCoeffprogressBar_5->setValue(this->_dsp->getVoices()[4].coeff); + this->_ui.PitchlineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].pitch).c_str()); + this->_ui.sourceNumberLineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].srcn).c_str()); + this->_ui.GainlineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].gain).c_str()); + this->_ui.EnvelopelineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].envx).c_str()); + this->_ui.KeyOncheckBox_5->setChecked(this->_dsp->getVoices()[4].kon); + this->_ui.KeyOffcheckBox_5->setChecked(this->_dsp->getVoices()[4].kof); + this->_ui.NoisecheckBox_5->setChecked(this->_dsp->getVoices()[4].non); + this->_ui.EchocheckBox_5->setChecked(this->_dsp->getVoices()[4].eon); + this->_ui.SampleEndcheckBox_5->setChecked(this->_dsp->getVoices()[4].endx); + this->_ui.PitchModulationcheckBox_5->setChecked(this->_dsp->getVoices()[4].pmon); - this->_ui.VolumeLprogressBar_6->setValue(this->_dsp->getChannels()[5].volL); - this->_ui.VolumeRprogressBar_6->setValue(this->_dsp->getChannels()[5].volR); - this->_ui.WaveHeightprogressBar_6->setValue(this->_dsp->getChannels()[5].outx); - this->_ui.EchoFIRCoeffprogressBar_6->setValue(this->_dsp->getChannels()[5].coeff); - this->_ui.PitchlineEdit_6->setText(Utility::to_hex(this->_dsp->getChannels()[5].pitch).c_str()); - this->_ui.sourceNumberLineEdit_6->setText(Utility::to_hex(this->_dsp->getChannels()[5].srcn).c_str()); - this->_ui.GainlineEdit_6->setText(Utility::to_hex(this->_dsp->getChannels()[5].gain).c_str()); - this->_ui.EnvelopelineEdit_6->setText(Utility::to_hex(this->_dsp->getChannels()[5].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_6->setText(Utility::to_hex(this->_dsp->getChannels()[5].envx).c_str()); - this->_ui.KeyOncheckBox_6->setChecked(this->_dsp->getChannels()[5].kon); - this->_ui.KeyOffcheckBox_6->setChecked(this->_dsp->getChannels()[5].kof); - this->_ui.NoisecheckBox_6->setChecked(this->_dsp->getChannels()[5].non); - this->_ui.EchocheckBox_6->setChecked(this->_dsp->getChannels()[5].eon); - this->_ui.SampleEndcheckBox_6->setChecked(this->_dsp->getChannels()[5].endx); - this->_ui.PitchModulationcheckBox_6->setChecked(this->_dsp->getChannels()[5].pmon); + this->_ui.VolumeLprogressBar_6->setValue(this->_dsp->getVoices()[5].volL); + this->_ui.VolumeRprogressBar_6->setValue(this->_dsp->getVoices()[5].volR); + this->_ui.WaveHeightprogressBar_6->setValue(this->_dsp->getVoices()[5].outx); + this->_ui.EchoFIRCoeffprogressBar_6->setValue(this->_dsp->getVoices()[5].coeff); + this->_ui.PitchlineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].pitch).c_str()); + this->_ui.sourceNumberLineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].srcn).c_str()); + this->_ui.GainlineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].gain).c_str()); + this->_ui.EnvelopelineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].envx).c_str()); + this->_ui.KeyOncheckBox_6->setChecked(this->_dsp->getVoices()[5].kon); + this->_ui.KeyOffcheckBox_6->setChecked(this->_dsp->getVoices()[5].kof); + this->_ui.NoisecheckBox_6->setChecked(this->_dsp->getVoices()[5].non); + this->_ui.EchocheckBox_6->setChecked(this->_dsp->getVoices()[5].eon); + this->_ui.SampleEndcheckBox_6->setChecked(this->_dsp->getVoices()[5].endx); + this->_ui.PitchModulationcheckBox_6->setChecked(this->_dsp->getVoices()[5].pmon); - this->_ui.VolumeLprogressBar_7->setValue(this->_dsp->getChannels()[6].volL); - this->_ui.VolumeRprogressBar_7->setValue(this->_dsp->getChannels()[6].volR); - this->_ui.WaveHeightprogressBar_7->setValue(this->_dsp->getChannels()[6].outx); - this->_ui.EchoFIRCoeffprogressBar_7->setValue(this->_dsp->getChannels()[6].coeff); - this->_ui.PitchlineEdit_7->setText(Utility::to_hex(this->_dsp->getChannels()[6].pitch).c_str()); - this->_ui.sourceNumberLineEdit_7->setText(Utility::to_hex(this->_dsp->getChannels()[6].srcn).c_str()); - this->_ui.GainlineEdit_7->setText(Utility::to_hex(this->_dsp->getChannels()[6].gain).c_str()); - this->_ui.EnvelopelineEdit_7->setText(Utility::to_hex(this->_dsp->getChannels()[6].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_7->setText(Utility::to_hex(this->_dsp->getChannels()[6].envx).c_str()); - this->_ui.KeyOncheckBox_7->setChecked(this->_dsp->getChannels()[6].kon); - this->_ui.KeyOffcheckBox_7->setChecked(this->_dsp->getChannels()[6].kof); - this->_ui.NoisecheckBox_7->setChecked(this->_dsp->getChannels()[6].non); - this->_ui.EchocheckBox_7->setChecked(this->_dsp->getChannels()[6].eon); - this->_ui.SampleEndcheckBox_7->setChecked(this->_dsp->getChannels()[6].endx); - this->_ui.PitchModulationcheckBox_7->setChecked(this->_dsp->getChannels()[6].pmon); + this->_ui.VolumeLprogressBar_7->setValue(this->_dsp->getVoices()[6].volL); + this->_ui.VolumeRprogressBar_7->setValue(this->_dsp->getVoices()[6].volR); + this->_ui.WaveHeightprogressBar_7->setValue(this->_dsp->getVoices()[6].outx); + this->_ui.EchoFIRCoeffprogressBar_7->setValue(this->_dsp->getVoices()[6].coeff); + this->_ui.PitchlineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].pitch).c_str()); + this->_ui.sourceNumberLineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].srcn).c_str()); + this->_ui.GainlineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].gain).c_str()); + this->_ui.EnvelopelineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].envx).c_str()); + this->_ui.KeyOncheckBox_7->setChecked(this->_dsp->getVoices()[6].kon); + this->_ui.KeyOffcheckBox_7->setChecked(this->_dsp->getVoices()[6].kof); + this->_ui.NoisecheckBox_7->setChecked(this->_dsp->getVoices()[6].non); + this->_ui.EchocheckBox_7->setChecked(this->_dsp->getVoices()[6].eon); + this->_ui.SampleEndcheckBox_7->setChecked(this->_dsp->getVoices()[6].endx); + this->_ui.PitchModulationcheckBox_7->setChecked(this->_dsp->getVoices()[6].pmon); - this->_ui.VolumeLprogressBar_8->setValue(this->_dsp->getChannels()[7].volL); - this->_ui.VolumeRprogressBar_8->setValue(this->_dsp->getChannels()[7].volR); - this->_ui.WaveHeightprogressBar_8->setValue(this->_dsp->getChannels()[7].outx); - this->_ui.EchoFIRCoeffprogressBar_8->setValue(this->_dsp->getChannels()[7].coeff); - this->_ui.PitchlineEdit_8->setText(Utility::to_hex(this->_dsp->getChannels()[7].pitch).c_str()); - this->_ui.sourceNumberLineEdit_8->setText(Utility::to_hex(this->_dsp->getChannels()[7].srcn).c_str()); - this->_ui.GainlineEdit_8->setText(Utility::to_hex(this->_dsp->getChannels()[7].gain).c_str()); - this->_ui.EnvelopelineEdit_8->setText(Utility::to_hex(this->_dsp->getChannels()[7].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_8->setText(Utility::to_hex(this->_dsp->getChannels()[7].envx).c_str()); - this->_ui.KeyOncheckBox_8->setChecked(this->_dsp->getChannels()[7].kon); - this->_ui.KeyOffcheckBox_8->setChecked(this->_dsp->getChannels()[7].kof); - this->_ui.NoisecheckBox_8->setChecked(this->_dsp->getChannels()[7].non); - this->_ui.EchocheckBox_8->setChecked(this->_dsp->getChannels()[7].eon); - this->_ui.SampleEndcheckBox_8->setChecked(this->_dsp->getChannels()[7].endx); - this->_ui.PitchModulationcheckBox_8->setChecked(this->_dsp->getChannels()[7].pmon); + this->_ui.VolumeLprogressBar_8->setValue(this->_dsp->getVoices()[7].volL); + this->_ui.VolumeRprogressBar_8->setValue(this->_dsp->getVoices()[7].volR); + this->_ui.WaveHeightprogressBar_8->setValue(this->_dsp->getVoices()[7].outx); + this->_ui.EchoFIRCoeffprogressBar_8->setValue(this->_dsp->getVoices()[7].coeff); + this->_ui.PitchlineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].pitch).c_str()); + this->_ui.sourceNumberLineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].srcn).c_str()); + this->_ui.GainlineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].gain).c_str()); + this->_ui.EnvelopelineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].envx).c_str()); + this->_ui.KeyOncheckBox_8->setChecked(this->_dsp->getVoices()[7].kon); + this->_ui.KeyOffcheckBox_8->setChecked(this->_dsp->getVoices()[7].kof); + this->_ui.NoisecheckBox_8->setChecked(this->_dsp->getVoices()[7].non); + this->_ui.EchocheckBox_8->setChecked(this->_dsp->getVoices()[7].eon); + this->_ui.SampleEndcheckBox_8->setChecked(this->_dsp->getVoices()[7].endx); + this->_ui.PitchModulationcheckBox_8->setChecked(this->_dsp->getVoices()[7].pmon); } std::string APUDebug::_getPSWString() diff --git a/sources/Renderer/IRenderer.hpp b/sources/Renderer/IRenderer.hpp index fd073f9..43b4aba 100644 --- a/sources/Renderer/IRenderer.hpp +++ b/sources/Renderer/IRenderer.hpp @@ -30,6 +30,11 @@ namespace ComSquare //! @param snes The snes game object (to call the update method). //! @param maxFPS The number of FPS you aim to run on. virtual void createWindow(SNES &snes, int maxFPS) = 0; + + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer + virtual void playAudio(int16_t *samples, uint64_t sampleCount) = 0; }; } } diff --git a/sources/Renderer/NoRenderer.cpp b/sources/Renderer/NoRenderer.cpp index 35fe608..505ebcc 100644 --- a/sources/Renderer/NoRenderer.cpp +++ b/sources/Renderer/NoRenderer.cpp @@ -20,6 +20,10 @@ namespace ComSquare::Renderer (void)rgba; } + void NoRenderer::playAudio(int16_t *, uint64_t) + { + } + void NoRenderer::getEvents() { } NoRenderer::NoRenderer(unsigned int height, unsigned int width, int maxFPS) diff --git a/sources/Renderer/NoRenderer.hpp b/sources/Renderer/NoRenderer.hpp index 9abf3f7..37fd940 100644 --- a/sources/Renderer/NoRenderer.hpp +++ b/sources/Renderer/NoRenderer.hpp @@ -21,7 +21,11 @@ namespace ComSquare::Renderer //! @param X horizontal index. //! @param Y vertical index. //! @param rgba The color of the pixel. - void putPixel(unsigned y, unsigned x, uint32_t rgba) override ; + void putPixel(unsigned y, unsigned x, uint32_t rgba) override; + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer + void playAudio(int16_t *samples, uint64_t sampleCount) override; //! @brief Get the inputs from the Window void getEvents(); //! @brief Use this function to create the window. diff --git a/sources/Renderer/QtRenderer/QtSFML.cpp b/sources/Renderer/QtRenderer/QtSFML.cpp index 760bfd8..b270f3c 100644 --- a/sources/Renderer/QtRenderer/QtSFML.cpp +++ b/sources/Renderer/QtRenderer/QtSFML.cpp @@ -75,6 +75,11 @@ namespace ComSquare::Renderer this->_sfWidget->putPixel(y, x, rgba); } + void QtSFML::playAudio(int16_t *samples, uint64_t sampleCount) + { + this->_sfWidget->playAudio(samples, sampleCount); + } + void QtSFML::drawScreen() { } void QtSFML::setWindowName(std::string &newWindowName) diff --git a/sources/Renderer/QtRenderer/QtSFML.hpp b/sources/Renderer/QtRenderer/QtSFML.hpp index 661422c..15afada 100644 --- a/sources/Renderer/QtRenderer/QtSFML.hpp +++ b/sources/Renderer/QtRenderer/QtSFML.hpp @@ -61,7 +61,11 @@ namespace ComSquare::Renderer void putPixel(unsigned y, unsigned x, uint32_t rgba) override; //! @brief This function doesn't do anything because QT internally handle drawing to the screen. void drawScreen() override; - //! @brief Set a new name to the window, if there is already a name it will be overwrite. + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer + void playAudio(int16_t *samples, uint64_t sampleCount) override; + //! @brief Set a new name to the window, if there is already a name it will be overwrite. //! @param newWindowName new title for the window. void setWindowName(std::string &newWindowName) override; //! @brief Constructor that return a SFML renderer inside a QT window. diff --git a/sources/Renderer/SFRenderer.cpp b/sources/Renderer/SFRenderer.cpp index d9de9a5..a7c99b3 100644 --- a/sources/Renderer/SFRenderer.cpp +++ b/sources/Renderer/SFRenderer.cpp @@ -18,7 +18,8 @@ namespace ComSquare::Renderer this->_texture.create(width, height); this->_sprite.setTexture(this->_texture); this->_pixelBuffer = new sf::Color[height * width]; - } + this->_sound.setBuffer(this->_soundBuffer); + } void SFRenderer::createWindow(SNES &snes, int maxFPS) { @@ -53,6 +54,12 @@ namespace ComSquare::Renderer this->_window.display(); } + void SFRenderer::playAudio(int16_t *samples, uint64_t sampleCount) + { + this->_soundBuffer.loadFromSamples(samples, sampleCount, 2, 32040); + this->_sound.play(); + } + void SFRenderer::putPixel(unsigned y, unsigned x, uint32_t rgba) { if (x >= this->_videoMode.width) diff --git a/sources/Renderer/SFRenderer.hpp b/sources/Renderer/SFRenderer.hpp index a81712a..9d902c8 100644 --- a/sources/Renderer/SFRenderer.hpp +++ b/sources/Renderer/SFRenderer.hpp @@ -36,6 +36,11 @@ namespace ComSquare::Renderer sf::Sprite _sprite; //! @brief The texture to render the array of pixels sf::Texture _texture; + + //! @brief The buffer containing samples to be played + sf::SoundBuffer _soundBuffer; + //! @brief the sound played + sf::Sound _sound; public: //! @brief Tells to the program if the window has been closed, and therefore if he should stop bool shouldExit = false; @@ -49,6 +54,10 @@ namespace ComSquare::Renderer //! @param Y vertical index. //! @param rgba The color of the pixel. void putPixel(unsigned y, unsigned x, uint32_t rgba) override; + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer + void playAudio(int16_t *samples, uint64_t sampleCount) override; //! @brief Get the inputs from the Window void getEvents(); //! @brief Use this function to create the window. diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 153c1e8..32752c1 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -22,7 +22,7 @@ namespace ComSquare apuRam(new APU::MemoryMap()), cpu(new CPU::CPU(this->_bus, cartridge->header)), ppu(new PPU::PPU(renderer)), - apu(new APU::APU(this->apuRam)) + apu(new APU::APU(this->apuRam, renderer)) { this->_bus->mapComponents(*this); } diff --git a/ui/ui_cpu.h b/ui/ui_cpu.h index 54b8db8..35c8512 100644 --- a/ui/ui_cpu.h +++ b/ui/ui_cpu.h @@ -1,11 +1,7 @@ /******************************************************************************** ** Form generated from reading UI file 'cpu.ui' ** -<<<<<<< HEAD -** Created by: Qt User Interface Compiler version 5.13.2 -======= -** Created by: Qt User Interface Compiler version 5.14.2 ->>>>>>> 24bcafeea3896022704904815d263f69f22e5096 +** Created by: Qt User Interface Compiler version 5.15.2 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ From 61ef40e9681b5163cdacaa7201fa26fdcd5a010c Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 3 Feb 2021 01:34:43 +0100 Subject: [PATCH 03/26] new DSP architecture (is this one correct ?) Start of voice & echo functions (need to name them) --- CMakeLists.txt | 4 + sources/APU/APU.cpp | 1 + sources/APU/DSP/DSP.cpp | 373 ++++++++++++++++++++++++---------- sources/APU/DSP/DSP.hpp | 270 ++++++++++++++++++------ sources/APU/DSP/Echo.cpp | 73 +++++++ sources/APU/DSP/Voice.cpp | 84 ++++++++ sources/Debugger/APUDebug.cpp | 271 ++++++++++++------------ 7 files changed, 774 insertions(+), 302 deletions(-) create mode 100644 sources/APU/DSP/Echo.cpp create mode 100644 sources/APU/DSP/Voice.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3197b77..0beb322 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,8 @@ add_executable(unit_tests sources/PPU/Background.hpp sources/CPU/DMA/DMA.cpp sources/CPU/DMA/DMA.hpp + sources/APU/DSP/Voice.cpp + sources/APU/DSP/Echo.cpp ) # include criterion & coverage @@ -223,6 +225,8 @@ add_executable(ComSquare sources/PPU/Background.hpp sources/CPU/DMA/DMA.cpp sources/CPU/DMA/DMA.hpp + sources/APU/DSP/Voice.cpp + sources/APU/DSP/Echo.cpp ) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 82068a7..fa616ab 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -718,6 +718,7 @@ namespace ComSquare::APU if (this->_state == Running) this->_paddingCycles = total - cycles; + this->_dsp->update(); samples = this->_dsp->getSamplesCount(); if (samples > 0) this->_renderer.playAudio(this->_soundBuffer, samples / 2); diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 75e604e..80635ef 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -18,37 +18,37 @@ namespace ComSquare::APU::DSP { switch (addr) { case 0x00: - return this->_voices[0].volL; + return this->_voices[0].volume[0]; case 0x10: - return this->_voices[1].volL; + return this->_voices[1].volume[0]; case 0x20: - return this->_voices[2].volL; + return this->_voices[2].volume[0]; case 0x30: - return this->_voices[3].volL; + return this->_voices[3].volume[0]; case 0x40: - return this->_voices[4].volL; + return this->_voices[4].volume[0]; case 0x50: - return this->_voices[5].volL; + return this->_voices[5].volume[0]; case 0x60: - return this->_voices[6].volL; + return this->_voices[6].volume[0]; case 0x70: - return this->_voices[7].volL; + return this->_voices[7].volume[0]; case 0x01: - return this->_voices[0].volR; + return this->_voices[0].volume[1]; case 0x11: - return this->_voices[1].volR; + return this->_voices[1].volume[1]; case 0x21: - return this->_voices[2].volR; + return this->_voices[2].volume[1]; case 0x31: - return this->_voices[3].volR; + return this->_voices[3].volume[1]; case 0x41: - return this->_voices[4].volR; + return this->_voices[4].volume[1]; case 0x51: - return this->_voices[5].volR; + return this->_voices[5].volume[1]; case 0x61: - return this->_voices[6].volR; + return this->_voices[6].volume[1]; case 0x71: - return this->_voices[7].volR; + return this->_voices[7].volume[1]; case 0x02: return this->_voices[0].pitchL; case 0x12: @@ -146,45 +146,31 @@ namespace ComSquare::APU::DSP case 0x77: return this->_voices[7].gain; case 0x08: - return this->_voices[0].envx; case 0x18: - return this->_voices[1].envx; case 0x28: - return this->_voices[2].envx; case 0x38: - return this->_voices[3].envx; case 0x48: - return this->_voices[4].envx; case 0x58: - return this->_voices[5].envx; case 0x68: - return this->_voices[6].envx; case 0x78: - return this->_voices[7].envx; + return this->_latch.envx; case 0x09: - return this->_voices[0].outx; case 0x19: - return this->_voices[1].outx; case 0x29: - return this->_voices[2].outx; case 0x39: - return this->_voices[3].outx; case 0x49: - return this->_voices[4].outx; case 0x59: - return this->_voices[5].outx; case 0x69: - return this->_voices[6].outx; case 0x79: - return this->_voices[7].outx; + return this->_latch.outx; case 0x0C: - return this->_registers.mvolL; + return this->_master.volume[0]; case 0x1C: - return this->_registers.mvolR; + return this->_master.volume[1]; case 0x2C: - return this->_registers.evolL; + return this->_echo.volume[0]; case 0x3C: - return this->_registers.evolR; + return this->_echo.volume[1]; case 0x4C: { uint8_t kon = 0; @@ -199,8 +185,14 @@ namespace ComSquare::APU::DSP kof |= this->_voices[i].kof << i; return kof; } - case 0x6C: - return this->_registers.flg; + case 0x6C: { + uint8_t flg = 0; + flg += this->_master.reset << 7; + flg += this->_master.mute << 6; + flg += this->_echo.enabled << 5; + flg += this->_noise.clock; + return flg; + } case 0x7C: { uint8_t endx = 0; @@ -209,9 +201,9 @@ namespace ComSquare::APU::DSP return endx; } case 0x0D: - return this->_registers.efb; + return this->_echo.feedback; case 0x1D: - return this->_registers.unused; + return this->_master.unused; case 0x2D: { uint8_t pmon = 0; @@ -234,27 +226,27 @@ namespace ComSquare::APU::DSP return eon; } case 0x5D: - return this->_registers.dir; + return this->_brr.offset; case 0x6D: - return this->_registers.esa; + return this->_echo.data; case 0x7D: - return this->_registers.edl; + return this->_echo.delay; case 0x0F: - return this->_voices[0].coeff; + return this->_echo.FIR[0]; case 0x1F: - return this->_voices[1].coeff; + return this->_echo.FIR[1]; case 0x2F: - return this->_voices[2].coeff; + return this->_echo.FIR[2]; case 0x3F: - return this->_voices[3].coeff; + return this->_echo.FIR[3]; case 0x4F: - return this->_voices[4].coeff; + return this->_echo.FIR[4]; case 0x5F: - return this->_voices[5].coeff; + return this->_echo.FIR[5]; case 0x6F: - return this->_voices[6].coeff; + return this->_echo.FIR[6]; case 0x7F: - return this->_voices[7].coeff; + return this->_echo.FIR[7]; default: throw InvalidAddress("DSP Registers read", addr); } @@ -264,52 +256,52 @@ namespace ComSquare::APU::DSP { switch (addr) { case 0x00: - this->_voices[0].volL = data; + this->_voices[0].volume[0] = data; break; case 0x10: - this->_voices[1].volL = data; + this->_voices[1].volume[0] = data; break; case 0x20: - this->_voices[2].volL = data; + this->_voices[2].volume[0] = data; break; case 0x30: - this->_voices[3].volL = data; + this->_voices[3].volume[0] = data; break; case 0x40: - this->_voices[4].volL = data; + this->_voices[4].volume[0] = data; break; case 0x50: - this->_voices[5].volL = data; + this->_voices[5].volume[0] = data; break; case 0x60: - this->_voices[6].volL = data; + this->_voices[6].volume[0] = data; break; case 0x70: - this->_voices[7].volL = data; + this->_voices[7].volume[0] = data; break; case 0x01: - this->_voices[0].volR = data; + this->_voices[0].volume[1] = data; break; case 0x11: - this->_voices[1].volR = data; + this->_voices[1].volume[1] = data; break; case 0x21: - this->_voices[2].volR = data; + this->_voices[2].volume[1] = data; break; case 0x31: - this->_voices[3].volR = data; + this->_voices[3].volume[1] = data; break; case 0x41: - this->_voices[4].volR = data; + this->_voices[4].volume[1] = data; break; case 0x51: - this->_voices[5].volR = data; + this->_voices[5].volume[1] = data; break; case 0x61: - this->_voices[6].volR = data; + this->_voices[6].volume[1] = data; break; case 0x71: - this->_voices[7].volR = data; + this->_voices[7].volume[1] = data; break; case 0x02: this->_voices[0].pitchL = data; @@ -480,61 +472,51 @@ namespace ComSquare::APU::DSP this->_voices[7].envx = data; break; case 0x09: - this->_voices[0].outx = data; - break; case 0x19: - this->_voices[1].outx = data; - break; case 0x29: - this->_voices[2].outx = data; - break; case 0x39: - this->_voices[3].outx = data; - break; case 0x49: - this->_voices[4].outx = data; - break; case 0x59: - this->_voices[5].outx = data; - break; case 0x69: - this->_voices[6].outx = data; - break; case 0x79: - this->_voices[7].outx = data; + this->_latch.outx = data; break; case 0x0C: - this->_registers.mvolL = data; + this->_master.volume[0] = data; break; case 0x1C: - this->_registers.mvolR = data; + this->_master.volume[1] = data; break; case 0x2C: - this->_registers.evolL = data; + this->_echo.volume[0] = data; break; case 0x3C: - this->_registers.evolR = data; + this->_echo.volume[1] = data; break; case 0x4C: - for (int i = 0; i < 8; i++) - this->_voices[i].kon |= data << i; + for (int i = 0; i < 8; i++) { + this->_voices[i].kon |= data << i; + } break; case 0x5C: for (int i = 0; i < 8; i++) this->_voices[i].kof |= data << i; break; case 0x6C: - this->_registers.flg = data; + this->_master.reset = data >> 7; + this->_master.mute = (data >> 6) & 0b1; + this->_echo.enabled = (data >> 5) & 0b1; + this->_noise.clock = data & 0b1111; break; case 0x7C: for (int i = 0; i < 8; i++) this->_voices[i].endx |= data << i; break; case 0x0D: - this->_registers.efb = data; + this->_echo.feedback = data; break; case 0x1D: - this->_registers.unused = data; + this->_master.unused = data; break; case 0x2D: for (int i = 0; i < 8; i++) @@ -549,37 +531,37 @@ namespace ComSquare::APU::DSP this->_voices[i].eon |= data << i; break; case 0x5D: - this->_registers.dir = data; + this->_brr.offset = data; break; case 0x6D: - this->_registers.esa = data; + this->_echo.data = data; break; case 0x7D: - this->_registers.edl = data; + this->_echo.delay = data; break; case 0x0F: - this->_voices[0].coeff = data; + this->_echo.FIR[0] = data; break; case 0x1F: - this->_voices[1].coeff = data; + this->_echo.FIR[1] = data; break; case 0x2F: - this->_voices[2].coeff = data; + this->_echo.FIR[2] = data; break; case 0x3F: - this->_voices[3].coeff = data; + this->_echo.FIR[3] = data; break; case 0x4F: - this->_voices[4].coeff = data; + this->_echo.FIR[4] = data; break; case 0x5F: - this->_voices[5].coeff = data; + this->_echo.FIR[5] = data; break; case 0x6F: - this->_voices[6].coeff = data; + this->_echo.FIR[6] = data; break; case 0x7F: - this->_voices[7].coeff = data; + this->_echo.FIR[7] = data; break; default: throw InvalidAddress("DSP Registers write", addr); @@ -588,20 +570,193 @@ namespace ComSquare::APU::DSP void DSP::update() { + switch (this->_state.voice) { + case 0: + this->voice5(this->_voices[0]); + this->voice2(this->_voices[1]); + break; + case 1: + this->voice6(this->_voices[0]); + this->voice3(this->_voices[1]); + break; + case 2: + this->voice7(this->_voices[0]); + this->voice4(this->_voices[1]); + this->voice1(this->_voices[3]); + break; + case 3: + this->voice8(this->_voices[0]); + this->voice5(this->_voices[1]); + this->voice2(this->_voices[2]); + break; + case 4: + this->voice9(this->_voices[0]); + this->voice6(this->_voices[1]); + this->voice3(this->_voices[2]); + break; + case 5: + this->voice7(this->_voices[1]); + this->voice4(this->_voices[2]); + this->voice1(this->_voices[4]); + break; + case 6: + this->voice8(this->_voices[1]); + this->voice5(this->_voices[2]); + this->voice2(this->_voices[3]); + break; + case 7: + this->voice9(this->_voices[1]); + this->voice6(this->_voices[2]); + this->voice3(this->_voices[3]); + break; + case 8: + this->voice7(this->_voices[2]); + this->voice4(this->_voices[3]); + this->voice1(this->_voices[5]); + break; + case 9: + this->voice8(this->_voices[2]); + this->voice5(this->_voices[3]); + this->voice2(this->_voices[4]); + break; + case 10: + this->voice9(this->_voices[2]); + this->voice6(this->_voices[3]); + this->voice3(this->_voices[4]); + break; + case 11: + this->voice7(this->_voices[3]); + this->voice4(this->_voices[4]); + this->voice1(this->_voices[6]); + break; + case 12: + this->voice8(this->_voices[3]); + this->voice5(this->_voices[4]); + this->voice2(this->_voices[5]); + break; + case 13: + this->voice9(this->_voices[3]); + this->voice6(this->_voices[4]); + this->voice3(this->_voices[5]); + break; + case 14: + this->voice7(this->_voices[4]); + this->voice4(this->_voices[5]); + this->voice1(this->_voices[7]); + break; + case 15: + this->voice8(this->_voices[4]); + this->voice5(this->_voices[5]); + this->voice2(this->_voices[6]); + break; + case 16: + this->voice9(this->_voices[4]); + this->voice6(this->_voices[5]); + this->voice3(this->_voices[6]); + break; + case 17: + this->voice1(this->_voices[0]); + this->voice7(this->_voices[5]); + this->voice4(this->_voices[6]); + break; + case 18: + this->voice8(this->_voices[5]); + this->voice5(this->_voices[6]); + this->voice2(this->_voices[7]); + break; + case 19: + this->voice9(this->_voices[5]); + this->voice6(this->_voices[6]); + this->voice3(this->_voices[7]); + break; + case 20: + this->voice1(this->_voices[1]); + this->voice7(this->_voices[6]); + this->voice4(this->_voices[7]); + break; + case 21: + this->voice8(this->_voices[6]); + this->voice5(this->_voices[7]); + this->voice2(this->_voices[0]); + break; + case 22: + this->voice3a(this->_voices[0]); + this->voice9(this->_voices[6]); + this->voice6(this->_voices[7]); + echo22(); + break; + case 23: + this->voice7(this->_voices[7]); + echo23(); + break; + case 24: + this->voice8(this->_voices[7]); + echo24(); + break; + case 25: + this->voice3b(this->_voices[0]); + this->voice9(this->_voices[7]); + echo25(); + break; + case 26: + echo26(); + break; + case 27: + this->misc27(); + this->echo27(); + break; + case 28: + this->misc28(); + this->echo28(); + break; + case 29: + this->misc29(); + this->echo29(); + break; + case 30: + this->misc30(); + this->voice3c(this->_voices[0]); + this->echo30(); + break; + case 31: + this->voice4(this->_voices[0]); + this->voice1(this->_voices[2]); + break; + } this->_state.voice = (this->_state.voice + 1) % 32; } - Registers DSP::getRegisters() - { - return this->_registers; - } - - std::array DSP::getVoices() + const std::array &DSP::getVoices() { return this->_voices; } - int32_t DSP::getSamplesCount() + const Master &DSP::getMaster() + { + return this->_master; + } + + const Echo &DSP::getEcho() + { + return this->_echo; + } + + const Noise &DSP::getNoise() + { + return this->_noise; + } + + const BRR &DSP::getBrr() + { + return this->_brr; + } + + const Latch &DSP::getLatch() + { + return this->_latch; + } + + int32_t DSP::getSamplesCount() const { return this->_state.buffer - this->_state.bufferStart; } diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index cc09e0d..8e7a0a0 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -11,34 +11,159 @@ namespace ComSquare::APU::DSP { - //! @brief All the registers of the DSP - struct Registers { - //! @brief Left output of the Main Volume register - uint8_t mvolL; - //! @brief Right output of the Main Volume register - uint8_t mvolR; + struct Master { + //! @brief Main Volume register (MVOL) + std::array volume; + //! @brief Mutes all channel (6th bit FLG) + bool mute : 1; + //! @brief Soft reset DSP (7th bit FLG) + bool reset : 1; + //! @brief Current sound produced + std::array output; + //! @brief Not used register + uint8_t unused; + }; - //! @brief Left output of the Echo Volume register - uint8_t evolL; - //! @brief Right output of the Echo Volume register - uint8_t evolR; + struct Echo { + //! @brief Echo Volume register (EVOL) + std::array volume; + //! @brief Echo feedback register (EFB) + uint8_t feedback; + //! @brief Echo FIR filter coefficients (COEF) + std::array FIR; + //! @brief Echo data start register (ESA) + uint8_t data; + //! @brief Echo delay size register (EDL) + uint8_t delay; + //! @brief Echo enabled (5th bit FLG) + bool enabled = true; + //! @brief Last sound produced for each voice in each channel + std::array, 2> history; + //! @brief Current sound to echo + std::array input; + //! @brief Current sound echoed produced + std::array output; + }; + + struct Noise { + //! @brief Frequency of white noise (the first 4 bits FLG) + uint8_t clock : 5; + //! @brief Linear feedback shift register used to shift final output + uint16_t lfsr = 0x4000; + }; + + struct BRR { + //! @brief Offset pointing to sample directory in external RAM (DIR) + uint8_t offset; + }; + + struct Latch { + //! @brief Current voice's adsr1 in use + uint8_t adsr1; + //! @brief Envelope value register (ENVX) + uint8_t envx; + //! @brief Wave height register (OUTX) + uint8_t outx; + //! @brief Current voice's pitch in use + uint16_t pitch; + //! @brief Output currently being modified + uint16_t output; + }; + + struct Voice { + //! @brief Volume register (VOL) + std::array volume; + //! @brief Pitch register (P) + union { + struct { + //! @brief Lower 8 bits of pitch register + uint8_t pitchL; + //! @brief Higher 8 bits of pitch register + uint8_t pitchH; + }; + uint16_t pitch; + }; + //! @brief Source number register (SRCN) + uint8_t srcn; + union { + struct { + //! @brief Envelope register (ADSR) + uint8_t adsr1; + //! @brief Envelope controllers register (ADSR) + uint8_t adsr2; + }; + uint16_t envelope; + }; + //! @brief Gain register (GAIN) + uint8_t gain; + //! @brief envelope associated with this voice + uint8_t envx; + //! @brief Sample end register (ENDX) + bool endx : 1; + + //! @brief Key On register (KON) + bool kon : 1; + //! @brief Key Off register (KOF) + bool kof : 1; + //! @brief Pitch modulation register (PMON) + bool pmon : 1; + //! @brief Noise enable register (NON) + bool non : 1; + //! @brief Echo enable register (EON) + bool eon : 1; + + //! @brief Check if voice is in setup phase + uint8_t konDelay; + //! @brief Check if the output will be echoed + bool echo; + //! @brief Check if this voice will be looped + bool loop; + }; + + //! @brief Current state of the DSP + struct State + { + //! @brief Current voice modification to do + uint8_t voice = 0; + //! @brief Current buffer of samples + int16_t *buffer; + //! @brief Limit of the buffer + int16_t *bufferEnd; + //! @brief Beginning of the buffer + int16_t *bufferStart; + }; + /*//! @brief All the registers of the DSP + struct Registers { + //! @brief Main Volume register + std::array mVol; //master.volume + + //! @brief Echo Volume register + std::array eVol; //echo.volume //! @brief Flags register - uint8_t flg; + union { + struct { + uint8_t noiseClock : 5; //noise.frequency + bool ecen : 1; //echo.readonly + bool mute : 1; //master.mute + bool reset : 1; //master.reset + }; + uint8_t flg; + }; //! @brief Echo feedback register - uint8_t efb; + uint8_t efb; //echo.feedback //! @brief Not used register uint8_t unused; //! @brief Source Directory offset register - uint8_t dir; + uint8_t dir; //brr.bank //! @brief Echo data start register - uint8_t esa; + uint8_t esa; //echo.bank //! @brief Echo delay size register - uint8_t edl; + uint8_t edl; //echo.delay }; struct BRR { @@ -61,10 +186,8 @@ namespace ComSquare::APU::DSP }; struct Voice { - //! @brief Left channel volume register - uint8_t volL; - //! @brief Left channel volume register - uint8_t volR; + //! @brief Volume register + std::array volume; //voice.volume union { struct { @@ -73,78 +196,61 @@ namespace ComSquare::APU::DSP //! @brief Higher 8 bits of pitch register uint8_t pitchH; }; - uint16_t pitch; + uint16_t pitch; //voice.pitch }; //! @brief Source number register - uint8_t srcn; + uint8_t srcn; //voice.source union { struct { //! @brief Envelope register - uint8_t adsr1; + uint8_t adsr1; //voice.adsr0 //! @brief Envelope controllers register - uint8_t adsr2; + uint8_t adsr2; //voice.adsr1 }; uint16_t envelope; }; //! @brief Gain register - uint8_t gain; + uint8_t gain; //voice.gain //! @brief Envelope value register - uint8_t envx; + uint8_t envx; //latch.envx //! @brief Wave height register - uint8_t outx; + uint8_t outx; //latch.outx //! @brief Key On register - bool kon : 1; + bool kon : 1; //voice.keyon //! @brief Key Off register - bool kof : 1; + bool kof : 1; //voice.keyoff + bool keyLatch : 1; //voice._keylatch //! @brief Sample end register - bool endx : 1; + bool endx : 1; //voice._end //! @brief Noise enable register - bool non : 1; + bool non : 1; //voice.noise //! @brief Echo enable register - bool eon : 1; + bool eon : 1; //voice.echo //! @brief Pitch modulation register - bool pmon : 1; + bool pmon : 1; //voice.modulate //! @brief Echo FIR filter coefficients - uint8_t coeff; + uint8_t coeff; //echo.fir - //! @brief Bit Rate Reduction associated to - BRR brr; - //! @brief Relative position in sample - uint16_t gaussOffset; - //! @brief Position of the next sample - unsigned sampleOffset : 4; - std::array decodedSamples; + bool latchEon : 1; //voice._echo }; - //! @brief Current state of the DSP - struct State + struct Latch { - //! @brief Current voice modification to do - uint8_t voice = 0; - //! @brief Current buffer of samples - int16_t *buffer; - //! @brief Limit of the buffer - int16_t *bufferEnd; - //! @brief Beginning of the buffer - int16_t *bufferStart; - }; + uint8_t adsr0; + uint16_t pitch; + uint16_t output; + };*/ class DSP : public Memory::AMemory { private: - //! @brief All registers of the DSP - Registers _registers{}; - - //! @brief 8x voices of sample used to make sound - std::array _voices{}; - //! @brief Gaussian table used for making waves std::array _gauss = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -181,18 +287,54 @@ namespace ComSquare::APU::DSP 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305 }; - //! @brief State of DSP with buffer - State _state {}; - public: + //! @brief 8x voices of sample used to make sound + std::array _voices {}; + Master _master {}; + Echo _echo {}; + Noise _noise {}; + BRR _brr {}; + Latch _latch {}; + State _state {}; + + void voiceOutput(Voice &voice, bool channel); + void voice1(Voice &voice); + void voice2(Voice &voice); + void voice3(Voice &voice); + void voice3a(Voice &voice); + void voice3b(Voice &voice); + void voice3c(Voice &voice); + void voice4(Voice &voice); + void voice5(Voice &voice); + void voice6(Voice &voice); + void voice7(Voice &voice); + void voice8(Voice &voice); + void voice9(Voice &voice); + void echo22(); + void echo23(); + void echo24(); + void echo25(); + void echo26(); + void echo27(); + void echo28(); + void echo29(); + void echo30(); + void misc27(); + void misc28(); + void misc29(); + void misc30(); + public: DSP(int16_t *buffer, int32_t size); DSP(const DSP &) = default; DSP &operator=(const DSP &) = default; ~DSP() override = default; - Registers getRegisters(); - //! @brief Return all 8 voices from DSP - std::array getVoices(); + const std::array &getVoices(); + const Master &getMaster(); + const Echo &getEcho(); + const Noise &getNoise(); + const BRR &getBrr(); + const Latch &getLatch(); //! @brief Read from the internal DSP register. //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register. @@ -209,7 +351,7 @@ namespace ComSquare::APU::DSP void update(); //! @brief Return the number of samples written - int32_t getSamplesCount(); + int32_t getSamplesCount() const; //! @brief Get the name of this accessor (used for debug purpose) std::string getName() override; diff --git a/sources/APU/DSP/Echo.cpp b/sources/APU/DSP/Echo.cpp new file mode 100644 index 0000000..ed2b365 --- /dev/null +++ b/sources/APU/DSP/Echo.cpp @@ -0,0 +1,73 @@ +// +// Created by melefo on 2/1/21. +// + +#include "DSP.hpp" + +namespace ComSquare::APU::DSP +{ + void DSP::echo22() + { + + } + + void DSP::echo23() + { + + } + + void DSP::echo24() + { + + } + + void DSP::echo25() + { + + } + + void DSP::echo26() + { + + } + + void DSP::echo27() + { + + } + + void DSP::echo28() + { + + } + + void DSP::echo29() + { + + } + + void DSP::echo30() + { + + } + + void DSP::misc27() + { + + } + + void DSP::misc28() + { + + } + + void DSP::misc29() + { + + } + + void DSP::misc30() + { + + } +} \ No newline at end of file diff --git a/sources/APU/DSP/Voice.cpp b/sources/APU/DSP/Voice.cpp new file mode 100644 index 0000000..3633a75 --- /dev/null +++ b/sources/APU/DSP/Voice.cpp @@ -0,0 +1,84 @@ +// +// Created by melefo on 2/1/21. +// + +#include "DSP.hpp" +#include + +namespace ComSquare::APU::DSP +{ + void DSP::voiceOutput(Voice &voice, bool channel) + { + int out = this->_latch.output * voice.volume[channel] >> 7; + + this->_master.output[channel] += out; + if (!voice.echo) + return; + this->_echo.volume[channel] += out; + } + + void DSP::voice1(Voice &voice) + { + + } + + void DSP::voice2(Voice &voice) + { + /*uint16_t addr = this->_brr. + this->_latch.adsr1 = voice.adsr1;*/ + } + + void DSP::voice3(Voice &voice) + { + + } + + void DSP::voice3a(Voice &voice) + { + + } + + void DSP::voice3b(Voice &voice) + { + + } + + void DSP::voice3c(Voice &voice) + { + + } + + void DSP::voice4(Voice &voice) + { + + } + + void DSP::voice5(Voice &voice) + { + this->voiceOutput(voice, 1); + + voice.endx |= voice.loop; + if (voice.konDelay == 5) + voice.endx &= ~voice.endx; + } + + void DSP::voice6(Voice &voice) + { + + } + + void DSP::voice7(Voice &voice) + { + + } + + void DSP::voice8(Voice &voice) + { + + } + + void DSP::voice9(Voice &voice) + { + + } +} \ No newline at end of file diff --git a/sources/Debugger/APUDebug.cpp b/sources/Debugger/APUDebug.cpp index 040ad7b..ee9183e 100644 --- a/sources/Debugger/APUDebug.cpp +++ b/sources/Debugger/APUDebug.cpp @@ -84,143 +84,156 @@ namespace ComSquare::Debugger this->_ui.programCounterLineEdit->setText(Utility::to_hex(this->_internalRegisters.pc + 0x0001u).c_str()); this->_ui.programStatusWordLineEdit->setText(this->_getPSWString().c_str()); - this->_ui.mvolLprogressBar->setValue(this->_dsp->getRegisters().mvolL); - this->_ui.mvolRprogressBar->setValue(this->_dsp->getRegisters().mvolR); - this->_ui.evolLprogressBar->setValue(this->_dsp->getRegisters().evolL); - this->_ui.evolRprogressBar->setValue(this->_dsp->getRegisters().evolR); - this->_ui.echoprogressBar->setValue(this->_dsp->getRegisters().efb); - this->_ui.flagslineEdit->setText(Utility::to_binary(this->_dsp->getRegisters().flg).c_str()); - this->_ui.sourceDirectoryLineEdit->setText(Utility::to_hex(this->_dsp->getRegisters().dir).c_str()); - this->_ui.echoBufferOffsetLineEdit->setText(Utility::to_hex(this->_dsp->getRegisters().esa).c_str()); - this->_ui.echoDelayLineEdit->setText(Utility::to_hex(this->_dsp->getRegisters().edl).c_str()); + auto voices = this->_dsp->getVoices(); + auto master = this->_dsp->getMaster(); + auto echo = this->_dsp->getEcho(); + auto noise = this->_dsp->getNoise(); + auto brr = this->_dsp->getBrr(); + auto latch = this->_dsp->getLatch(); - this->_ui.VolumeLprogressBar->setValue(this->_dsp->getVoices()[0].volL); - this->_ui.VolumeRprogressBar->setValue(this->_dsp->getVoices()[0].volR); - this->_ui.WaveHeightprogressBar->setValue(this->_dsp->getVoices()[0].outx); - this->_ui.EchoFIRCoeffprogressBar->setValue(this->_dsp->getVoices()[0].coeff); - this->_ui.PitchlineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].pitch).c_str()); - this->_ui.sourceNumberLineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].srcn).c_str()); - this->_ui.GainlineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].gain).c_str()); - this->_ui.EnvelopelineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit->setText(Utility::to_hex(this->_dsp->getVoices()[0].envx).c_str()); - this->_ui.KeyOncheckBox->setChecked(this->_dsp->getVoices()[0].kon); - this->_ui.KeyOffcheckBox->setChecked(this->_dsp->getVoices()[0].kof); - this->_ui.NoisecheckBox->setChecked(this->_dsp->getVoices()[0].non); - this->_ui.EchocheckBox->setChecked(this->_dsp->getVoices()[0].eon); - this->_ui.SampleEndcheckBox->setChecked(this->_dsp->getVoices()[0].endx); - this->_ui.PitchModulationcheckBox->setChecked(this->_dsp->getVoices()[0].pmon); + this->_ui.mvolLprogressBar->setValue(master.volume[0]); + this->_ui.mvolRprogressBar->setValue(master.volume[1]); + this->_ui.evolLprogressBar->setValue(echo.volume[0]); + this->_ui.evolRprogressBar->setValue(echo.volume[1]); + this->_ui.echoprogressBar->setValue(echo.feedback); - this->_ui.VolumeLprogressBar_2->setValue(this->_dsp->getVoices()[1].volL); - this->_ui.VolumeRprogressBar_2->setValue(this->_dsp->getVoices()[1].volR); - this->_ui.WaveHeightprogressBar_2->setValue(this->_dsp->getVoices()[1].outx); - this->_ui.EchoFIRCoeffprogressBar_2->setValue(this->_dsp->getVoices()[1].coeff); - this->_ui.PitchlineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].pitch).c_str()); - this->_ui.sourceNumberLineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].srcn).c_str()); - this->_ui.GainlineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].gain).c_str()); - this->_ui.EnvelopelineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_2->setText(Utility::to_hex(this->_dsp->getVoices()[1].envx).c_str()); - this->_ui.KeyOncheckBox_2->setChecked(this->_dsp->getVoices()[1].kon); - this->_ui.KeyOffcheckBox_2->setChecked(this->_dsp->getVoices()[1].kof); - this->_ui.NoisecheckBox_2->setChecked(this->_dsp->getVoices()[1].non); - this->_ui.EchocheckBox_2->setChecked(this->_dsp->getVoices()[1].eon); - this->_ui.SampleEndcheckBox_2->setChecked(this->_dsp->getVoices()[1].endx); - this->_ui.PitchModulationcheckBox_2->setChecked(this->_dsp->getVoices()[1].pmon); + uint8_t flg = 0; + flg += master.reset << 7; + flg += master.mute << 6; + flg += echo.enabled << 5; + flg += noise.clock; + this->_ui.flagslineEdit->setText(Utility::to_binary(flg).c_str()); + this->_ui.sourceDirectoryLineEdit->setText(Utility::to_hex(brr.offset).c_str()); + this->_ui.echoBufferOffsetLineEdit->setText(Utility::to_hex(echo.data).c_str()); + this->_ui.echoDelayLineEdit->setText(Utility::to_hex(echo.delay).c_str()); - this->_ui.VolumeLprogressBar_3->setValue(this->_dsp->getVoices()[2].volL); - this->_ui.VolumeRprogressBar_3->setValue(this->_dsp->getVoices()[2].volR); - this->_ui.WaveHeightprogressBar_3->setValue(this->_dsp->getVoices()[2].outx); - this->_ui.EchoFIRCoeffprogressBar_3->setValue(this->_dsp->getVoices()[2].coeff); - this->_ui.PitchlineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].pitch).c_str()); - this->_ui.sourceNumberLineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].srcn).c_str()); - this->_ui.GainlineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].gain).c_str()); - this->_ui.EnvelopelineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_3->setText(Utility::to_hex(this->_dsp->getVoices()[2].envx).c_str()); - this->_ui.KeyOncheckBox_3->setChecked(this->_dsp->getVoices()[2].kon); - this->_ui.KeyOffcheckBox_3->setChecked(this->_dsp->getVoices()[2].kof); - this->_ui.NoisecheckBox_3->setChecked(this->_dsp->getVoices()[2].non); - this->_ui.EchocheckBox_3->setChecked(this->_dsp->getVoices()[2].eon); - this->_ui.SampleEndcheckBox_3->setChecked(this->_dsp->getVoices()[2].endx); - this->_ui.PitchModulationcheckBox_3->setChecked(this->_dsp->getVoices()[2].pmon); + this->_ui.VolumeLprogressBar->setValue(voices[0].volume[0]); + this->_ui.VolumeRprogressBar->setValue(voices[0].volume[1]); + this->_ui.WaveHeightprogressBar->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar->setValue(echo.FIR[0]); + this->_ui.PitchlineEdit->setText(Utility::to_hex(voices[0].pitch).c_str()); + this->_ui.sourceNumberLineEdit->setText(Utility::to_hex(voices[0].srcn).c_str()); + this->_ui.GainlineEdit->setText(Utility::to_hex(voices[0].gain).c_str()); + this->_ui.EnvelopelineEdit->setText(Utility::to_hex(voices[0].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit->setText(Utility::to_hex(voices[0].envx).c_str()); + this->_ui.KeyOncheckBox->setChecked(voices[0].kon); + this->_ui.KeyOffcheckBox->setChecked(voices[0].kof); + this->_ui.NoisecheckBox->setChecked(voices[0].non); + this->_ui.EchocheckBox->setChecked(voices[0].eon); + this->_ui.SampleEndcheckBox->setChecked(voices[0].endx); + this->_ui.PitchModulationcheckBox->setChecked(voices[0].pmon); - this->_ui.VolumeLprogressBar_4->setValue(this->_dsp->getVoices()[3].volL); - this->_ui.VolumeRprogressBar_4->setValue(this->_dsp->getVoices()[3].volR); - this->_ui.WaveHeightprogressBar_4->setValue(this->_dsp->getVoices()[3].outx); - this->_ui.EchoFIRCoeffprogressBar_4->setValue(this->_dsp->getVoices()[3].coeff); - this->_ui.PitchlineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].pitch).c_str()); - this->_ui.sourceNumberLineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].srcn).c_str()); - this->_ui.GainlineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].gain).c_str()); - this->_ui.EnvelopelineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_4->setText(Utility::to_hex(this->_dsp->getVoices()[3].envx).c_str()); - this->_ui.KeyOncheckBox_4->setChecked(this->_dsp->getVoices()[3].kon); - this->_ui.KeyOffcheckBox_4->setChecked(this->_dsp->getVoices()[3].kof); - this->_ui.NoisecheckBox_4->setChecked(this->_dsp->getVoices()[3].non); - this->_ui.EchocheckBox_4->setChecked(this->_dsp->getVoices()[3].eon); - this->_ui.SampleEndcheckBox_4->setChecked(this->_dsp->getVoices()[3].endx); - this->_ui.PitchModulationcheckBox_4->setChecked(this->_dsp->getVoices()[3].pmon); + this->_ui.VolumeLprogressBar_2->setValue(voices[1].volume[0]); + this->_ui.VolumeRprogressBar_2->setValue(voices[1].volume[1]); + this->_ui.WaveHeightprogressBar_2->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_2->setValue(echo.FIR[1]); + this->_ui.PitchlineEdit_2->setText(Utility::to_hex(voices[1].pitch).c_str()); + this->_ui.sourceNumberLineEdit_2->setText(Utility::to_hex(voices[1].srcn).c_str()); + this->_ui.GainlineEdit_2->setText(Utility::to_hex(voices[1].gain).c_str()); + this->_ui.EnvelopelineEdit_2->setText(Utility::to_hex(voices[1].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_2->setText(Utility::to_hex(voices[1].envx).c_str()); + this->_ui.KeyOncheckBox_2->setChecked(voices[1].kon); + this->_ui.KeyOffcheckBox_2->setChecked(voices[1].kof); + this->_ui.NoisecheckBox_2->setChecked(voices[1].non); + this->_ui.EchocheckBox_2->setChecked(voices[1].eon); + this->_ui.SampleEndcheckBox_2->setChecked(voices[1].endx); + this->_ui.PitchModulationcheckBox_2->setChecked(voices[1].pmon); - this->_ui.VolumeLprogressBar_5->setValue(this->_dsp->getVoices()[4].volL); - this->_ui.VolumeRprogressBar_5->setValue(this->_dsp->getVoices()[4].volR); - this->_ui.WaveHeightprogressBar_5->setValue(this->_dsp->getVoices()[4].outx); - this->_ui.EchoFIRCoeffprogressBar_5->setValue(this->_dsp->getVoices()[4].coeff); - this->_ui.PitchlineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].pitch).c_str()); - this->_ui.sourceNumberLineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].srcn).c_str()); - this->_ui.GainlineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].gain).c_str()); - this->_ui.EnvelopelineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_5->setText(Utility::to_hex(this->_dsp->getVoices()[4].envx).c_str()); - this->_ui.KeyOncheckBox_5->setChecked(this->_dsp->getVoices()[4].kon); - this->_ui.KeyOffcheckBox_5->setChecked(this->_dsp->getVoices()[4].kof); - this->_ui.NoisecheckBox_5->setChecked(this->_dsp->getVoices()[4].non); - this->_ui.EchocheckBox_5->setChecked(this->_dsp->getVoices()[4].eon); - this->_ui.SampleEndcheckBox_5->setChecked(this->_dsp->getVoices()[4].endx); - this->_ui.PitchModulationcheckBox_5->setChecked(this->_dsp->getVoices()[4].pmon); + this->_ui.VolumeLprogressBar_3->setValue(voices[2].volume[0]); + this->_ui.VolumeRprogressBar_3->setValue(voices[2].volume[1]); + this->_ui.WaveHeightprogressBar_3->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_3->setValue(echo.FIR[2]); + this->_ui.PitchlineEdit_3->setText(Utility::to_hex(voices[2].pitch).c_str()); + this->_ui.sourceNumberLineEdit_3->setText(Utility::to_hex(voices[2].srcn).c_str()); + this->_ui.GainlineEdit_3->setText(Utility::to_hex(voices[2].gain).c_str()); + this->_ui.EnvelopelineEdit_3->setText(Utility::to_hex(voices[2].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_3->setText(Utility::to_hex(voices[2].envx).c_str()); + this->_ui.KeyOncheckBox_3->setChecked(voices[2].kon); + this->_ui.KeyOffcheckBox_3->setChecked(voices[2].kof); + this->_ui.NoisecheckBox_3->setChecked(voices[2].non); + this->_ui.EchocheckBox_3->setChecked(voices[2].eon); + this->_ui.SampleEndcheckBox_3->setChecked(voices[2].endx); + this->_ui.PitchModulationcheckBox_3->setChecked(voices[2].pmon); - this->_ui.VolumeLprogressBar_6->setValue(this->_dsp->getVoices()[5].volL); - this->_ui.VolumeRprogressBar_6->setValue(this->_dsp->getVoices()[5].volR); - this->_ui.WaveHeightprogressBar_6->setValue(this->_dsp->getVoices()[5].outx); - this->_ui.EchoFIRCoeffprogressBar_6->setValue(this->_dsp->getVoices()[5].coeff); - this->_ui.PitchlineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].pitch).c_str()); - this->_ui.sourceNumberLineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].srcn).c_str()); - this->_ui.GainlineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].gain).c_str()); - this->_ui.EnvelopelineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_6->setText(Utility::to_hex(this->_dsp->getVoices()[5].envx).c_str()); - this->_ui.KeyOncheckBox_6->setChecked(this->_dsp->getVoices()[5].kon); - this->_ui.KeyOffcheckBox_6->setChecked(this->_dsp->getVoices()[5].kof); - this->_ui.NoisecheckBox_6->setChecked(this->_dsp->getVoices()[5].non); - this->_ui.EchocheckBox_6->setChecked(this->_dsp->getVoices()[5].eon); - this->_ui.SampleEndcheckBox_6->setChecked(this->_dsp->getVoices()[5].endx); - this->_ui.PitchModulationcheckBox_6->setChecked(this->_dsp->getVoices()[5].pmon); + this->_ui.VolumeLprogressBar_4->setValue(voices[3].volume[0]); + this->_ui.VolumeRprogressBar_4->setValue(voices[3].volume[1]); + this->_ui.WaveHeightprogressBar_4->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_4->setValue(echo.FIR[3]); + this->_ui.PitchlineEdit_4->setText(Utility::to_hex(voices[3].pitch).c_str()); + this->_ui.sourceNumberLineEdit_4->setText(Utility::to_hex(voices[3].srcn).c_str()); + this->_ui.GainlineEdit_4->setText(Utility::to_hex(voices[3].gain).c_str()); + this->_ui.EnvelopelineEdit_4->setText(Utility::to_hex(voices[3].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_4->setText(Utility::to_hex(voices[3].envx).c_str()); + this->_ui.KeyOncheckBox_4->setChecked(voices[3].kon); + this->_ui.KeyOffcheckBox_4->setChecked(voices[3].kof); + this->_ui.NoisecheckBox_4->setChecked(voices[3].non); + this->_ui.EchocheckBox_4->setChecked(voices[3].eon); + this->_ui.SampleEndcheckBox_4->setChecked(voices[3].endx); + this->_ui.PitchModulationcheckBox_4->setChecked(voices[3].pmon); - this->_ui.VolumeLprogressBar_7->setValue(this->_dsp->getVoices()[6].volL); - this->_ui.VolumeRprogressBar_7->setValue(this->_dsp->getVoices()[6].volR); - this->_ui.WaveHeightprogressBar_7->setValue(this->_dsp->getVoices()[6].outx); - this->_ui.EchoFIRCoeffprogressBar_7->setValue(this->_dsp->getVoices()[6].coeff); - this->_ui.PitchlineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].pitch).c_str()); - this->_ui.sourceNumberLineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].srcn).c_str()); - this->_ui.GainlineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].gain).c_str()); - this->_ui.EnvelopelineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_7->setText(Utility::to_hex(this->_dsp->getVoices()[6].envx).c_str()); - this->_ui.KeyOncheckBox_7->setChecked(this->_dsp->getVoices()[6].kon); - this->_ui.KeyOffcheckBox_7->setChecked(this->_dsp->getVoices()[6].kof); - this->_ui.NoisecheckBox_7->setChecked(this->_dsp->getVoices()[6].non); - this->_ui.EchocheckBox_7->setChecked(this->_dsp->getVoices()[6].eon); - this->_ui.SampleEndcheckBox_7->setChecked(this->_dsp->getVoices()[6].endx); - this->_ui.PitchModulationcheckBox_7->setChecked(this->_dsp->getVoices()[6].pmon); + this->_ui.VolumeLprogressBar_5->setValue(voices[4].volume[0]); + this->_ui.VolumeRprogressBar_5->setValue(voices[4].volume[1]); + this->_ui.WaveHeightprogressBar_5->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_5->setValue(echo.FIR[4]); + this->_ui.PitchlineEdit_5->setText(Utility::to_hex(voices[4].pitch).c_str()); + this->_ui.sourceNumberLineEdit_5->setText(Utility::to_hex(voices[4].srcn).c_str()); + this->_ui.GainlineEdit_5->setText(Utility::to_hex(voices[4].gain).c_str()); + this->_ui.EnvelopelineEdit_5->setText(Utility::to_hex(voices[4].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_5->setText(Utility::to_hex(voices[4].envx).c_str()); + this->_ui.KeyOncheckBox_5->setChecked(voices[4].kon); + this->_ui.KeyOffcheckBox_5->setChecked(voices[4].kof); + this->_ui.NoisecheckBox_5->setChecked(voices[4].non); + this->_ui.EchocheckBox_5->setChecked(voices[4].eon); + this->_ui.SampleEndcheckBox_5->setChecked(voices[4].endx); + this->_ui.PitchModulationcheckBox_5->setChecked(voices[4].pmon); - this->_ui.VolumeLprogressBar_8->setValue(this->_dsp->getVoices()[7].volL); - this->_ui.VolumeRprogressBar_8->setValue(this->_dsp->getVoices()[7].volR); - this->_ui.WaveHeightprogressBar_8->setValue(this->_dsp->getVoices()[7].outx); - this->_ui.EchoFIRCoeffprogressBar_8->setValue(this->_dsp->getVoices()[7].coeff); - this->_ui.PitchlineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].pitch).c_str()); - this->_ui.sourceNumberLineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].srcn).c_str()); - this->_ui.GainlineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].gain).c_str()); - this->_ui.EnvelopelineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].envelope).c_str()); - this->_ui.EnvelopeValueLineEdit_8->setText(Utility::to_hex(this->_dsp->getVoices()[7].envx).c_str()); - this->_ui.KeyOncheckBox_8->setChecked(this->_dsp->getVoices()[7].kon); - this->_ui.KeyOffcheckBox_8->setChecked(this->_dsp->getVoices()[7].kof); - this->_ui.NoisecheckBox_8->setChecked(this->_dsp->getVoices()[7].non); - this->_ui.EchocheckBox_8->setChecked(this->_dsp->getVoices()[7].eon); - this->_ui.SampleEndcheckBox_8->setChecked(this->_dsp->getVoices()[7].endx); - this->_ui.PitchModulationcheckBox_8->setChecked(this->_dsp->getVoices()[7].pmon); + this->_ui.VolumeLprogressBar_6->setValue(voices[5].volume[0]); + this->_ui.VolumeRprogressBar_6->setValue(voices[5].volume[1]); + this->_ui.WaveHeightprogressBar_6->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_6->setValue(echo.FIR[5]); + this->_ui.PitchlineEdit_6->setText(Utility::to_hex(voices[5].pitch).c_str()); + this->_ui.sourceNumberLineEdit_6->setText(Utility::to_hex(voices[5].srcn).c_str()); + this->_ui.GainlineEdit_6->setText(Utility::to_hex(voices[5].gain).c_str()); + this->_ui.EnvelopelineEdit_6->setText(Utility::to_hex(voices[5].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_6->setText(Utility::to_hex(voices[5].envx).c_str()); + this->_ui.KeyOncheckBox_6->setChecked(voices[5].kon); + this->_ui.KeyOffcheckBox_6->setChecked(voices[5].kof); + this->_ui.NoisecheckBox_6->setChecked(voices[5].non); + this->_ui.EchocheckBox_6->setChecked(voices[5].eon); + this->_ui.SampleEndcheckBox_6->setChecked(voices[5].endx); + this->_ui.PitchModulationcheckBox_6->setChecked(voices[5].pmon); + + this->_ui.VolumeLprogressBar_7->setValue(voices[6].volume[0]); + this->_ui.VolumeRprogressBar_7->setValue(voices[6].volume[1]); + this->_ui.WaveHeightprogressBar_7->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_7->setValue(echo.FIR[6]); + this->_ui.PitchlineEdit_7->setText(Utility::to_hex(voices[6].pitch).c_str()); + this->_ui.sourceNumberLineEdit_7->setText(Utility::to_hex(voices[6].srcn).c_str()); + this->_ui.GainlineEdit_7->setText(Utility::to_hex(voices[6].gain).c_str()); + this->_ui.EnvelopelineEdit_7->setText(Utility::to_hex(voices[6].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_7->setText(Utility::to_hex(voices[6].envx).c_str()); + this->_ui.KeyOncheckBox_7->setChecked(voices[6].kon); + this->_ui.KeyOffcheckBox_7->setChecked(voices[6].kof); + this->_ui.NoisecheckBox_7->setChecked(voices[6].non); + this->_ui.EchocheckBox_7->setChecked(voices[6].eon); + this->_ui.SampleEndcheckBox_7->setChecked(voices[6].endx); + this->_ui.PitchModulationcheckBox_7->setChecked(voices[6].pmon); + + this->_ui.VolumeLprogressBar_8->setValue(voices[7].volume[0]); + this->_ui.VolumeRprogressBar_8->setValue(voices[7].volume[1]); + this->_ui.WaveHeightprogressBar_8->setValue(latch.outx); + this->_ui.EchoFIRCoeffprogressBar_8->setValue(echo.FIR[7]); + this->_ui.PitchlineEdit_8->setText(Utility::to_hex(voices[7].pitch).c_str()); + this->_ui.sourceNumberLineEdit_8->setText(Utility::to_hex(voices[7].srcn).c_str()); + this->_ui.GainlineEdit_8->setText(Utility::to_hex(voices[7].gain).c_str()); + this->_ui.EnvelopelineEdit_8->setText(Utility::to_hex(voices[7].envelope).c_str()); + this->_ui.EnvelopeValueLineEdit_8->setText(Utility::to_hex(voices[7].envx).c_str()); + this->_ui.KeyOncheckBox_8->setChecked(voices[7].kon); + this->_ui.KeyOffcheckBox_8->setChecked(voices[7].kof); + this->_ui.NoisecheckBox_8->setChecked(voices[7].non); + this->_ui.EchocheckBox_8->setChecked(voices[7].eon); + this->_ui.SampleEndcheckBox_8->setChecked(voices[7].endx); + this->_ui.PitchModulationcheckBox_8->setChecked(voices[7].pmon); } std::string APUDebug::_getPSWString() From b0fb1e33513db502110eac60b3d2f36c5b6a8ca8 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 4 Feb 2021 00:06:39 +0100 Subject: [PATCH 04/26] new MemoryMap architecture starting to working of voices and so on BRR, Envelopes, Gauss and Timers as they use each others --- CMakeLists.txt | 4 +- sources/APU/APU.cpp | 14 ++--- sources/APU/APU.hpp | 4 +- sources/APU/DSP/BRR.cpp | 66 ++++++++++++++++++++ sources/APU/DSP/DSP.cpp | 47 +++++++++++---- sources/APU/DSP/DSP.hpp | 109 ++++++++++++++++++++++++++++++---- sources/APU/DSP/Envelope.cpp | 78 ++++++++++++++++++++++++ sources/APU/DSP/Gauss.cpp | 30 ++++++++++ sources/APU/DSP/Timer.cpp | 22 +++++++ sources/APU/DSP/Voice.cpp | 88 ++++++++++++++++++++++++--- sources/Debugger/APUDebug.cpp | 16 ++--- sources/SNES.cpp | 3 +- sources/SNES.hpp | 2 - 13 files changed, 429 insertions(+), 54 deletions(-) create mode 100644 sources/APU/DSP/BRR.cpp create mode 100644 sources/APU/DSP/Envelope.cpp create mode 100644 sources/APU/DSP/Gauss.cpp create mode 100644 sources/APU/DSP/Timer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0beb322..3010726 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ add_executable(unit_tests sources/CPU/DMA/DMA.hpp sources/APU/DSP/Voice.cpp sources/APU/DSP/Echo.cpp - ) + sources/APU/DSP/Gauss.cpp sources/APU/DSP/Timer.cpp sources/APU/DSP/BRR.cpp) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -227,7 +227,7 @@ add_executable(ComSquare sources/CPU/DMA/DMA.hpp sources/APU/DSP/Voice.cpp sources/APU/DSP/Echo.cpp - ) + sources/APU/DSP/Gauss.cpp sources/APU/DSP/Envelope.cpp sources/APU/DSP/Timer.cpp sources/APU/DSP/BRR.cpp) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index fa616ab..d4623e6 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -10,11 +10,11 @@ namespace ComSquare::APU { - APU::APU(std::shared_ptr &map, Renderer::IRenderer &renderer) : + APU::APU(Renderer::IRenderer &renderer) : _renderer(renderer), - _map(map), + _map(new MemoryMap()), _soundBuffer(), - _dsp(new DSP::DSP(_soundBuffer, APU::bufferSize / 2)) + _dsp(_soundBuffer, APU::bufferSize / 2, _map) { this->reset(); } @@ -43,7 +43,7 @@ namespace ComSquare::APU case 0xF2: return this->_registers.dspregAddr; case 0xF3: - return this->_dsp->read(this->_registers.dspregAddr); + return this->_dsp.read(this->_registers.dspregAddr); case 0xF4: return this->_registers.port0; case 0xF5: @@ -88,7 +88,7 @@ namespace ComSquare::APU this->_registers.dspregAddr = data; break; case 0xF3: - this->_dsp->write(this->_registers.dspregAddr, data); + this->_dsp.write(this->_registers.dspregAddr, data); break; case 0xF4: this->_registers.port0 = data; @@ -718,8 +718,8 @@ namespace ComSquare::APU if (this->_state == Running) this->_paddingCycles = total - cycles; - this->_dsp->update(); - samples = this->_dsp->getSamplesCount(); + this->_dsp.update(); + samples = this->_dsp.getSamplesCount(); if (samples > 0) this->_renderer.playAudio(this->_soundBuffer, samples / 2); } diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index f13447b..e96c647 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -149,7 +149,7 @@ namespace ComSquare::APU int16_t _soundBuffer[bufferSize]; //! @brief The DSP component used to produce sound - std::shared_ptr _dsp; + DSP::DSP _dsp; //! @brief Read from the APU ram. //! @param addr The address to read from. The address 0x0000 should refer to the first byte of the register. @@ -373,7 +373,7 @@ namespace ComSquare::APU int MOV(uint24_t memFrom, uint8_t ®To, int cycles, bool incrementX = false); int MOV(uint24_t memTo, uint24_t memFrom); public: - explicit APU(std::shared_ptr &map, Renderer::IRenderer &renderer); + explicit APU(Renderer::IRenderer &renderer); APU(const APU &) = default; APU &operator=(const APU &) = default; ~APU() override = default; diff --git a/sources/APU/DSP/BRR.cpp b/sources/APU/DSP/BRR.cpp new file mode 100644 index 0000000..683c590 --- /dev/null +++ b/sources/APU/DSP/BRR.cpp @@ -0,0 +1,66 @@ +// +// Created by melefo on 2/3/21. +// + +#include +#include "DSP.hpp" + +namespace ComSquare::APU::DSP +{ + void DSP::decodeBRR(Voice &voice) + { + int32_t value = this->_brr.value << 8 | this->_readRAM(voice.brrAddress + voice.brrOffset + 1); + + int32_t filter = this->_brr.header >> 2 & 0b11; + int32_t range = this->_brr.header >> 4 & 0b1111; + + for (int i = 0; i < 4; i++) { + int32_t sample = value >> 12; + value <<= 4; + + if (range <= 12) { + sample <<= range; + sample >>= 1; + } + else + sample &= ~0x7FF; + + int offset = voice.sampleOffset; + int lastSample; + int afterLastSample; + + if (--offset < 0) + offset = 11; + lastSample = voice.samples[offset]; + if (--offset < 0) + offset = 11; + afterLastSample = voice.samples[offset]; + + switch (filter) { + case 0: + break; + case 1: + sample += lastSample; + sample += (lastSample) >> 4; + break; + case 2: + sample += lastSample << 1; + sample += -((lastSample << 1) + lastSample) >> 5; + sample -= afterLastSample; + sample += afterLastSample >> 4; + break; + case 3: + sample += lastSample << 1; + sample += -(lastSample + (lastSample << 2) + (lastSample << 3)) >> 6; + sample -= afterLastSample; + sample += ((afterLastSample << 1) + afterLastSample) >> 4; + break; + } + sample = std::clamp(sample, 0, 16); + sample <<= 1; + voice.samples[voice.sampleOffset] = sample; + if (++voice.sampleOffset >= 12) + voice.sampleOffset = 0; + } + } +} \ No newline at end of file diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 80635ef..2ca79b9 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -3,11 +3,12 @@ // #include "DSP.hpp" +#include "../APU.hpp" #include "../../Exceptions/InvalidAddress.hpp" namespace ComSquare::APU::DSP { - DSP::DSP(int16_t *buffer, int32_t size) + DSP::DSP(int16_t *buffer, int32_t size, std::weak_ptr map) : _map(map) { this->_state.buffer = buffer; this->_state.bufferStart = buffer; @@ -568,6 +569,40 @@ namespace ComSquare::APU::DSP } } + uint8_t DSP::_readRAM(uint24_t addr) { + switch (addr) { + case 0x0000 ... 0x00EF: + return this->_map.lock()->Page0.read_internal(addr); + case 0x0100 ... 0x01FF: + return this->_map.lock()->Page1.read_internal(addr - 0x0100); + case 0x0200 ... 0xFFBF: + return this->_map.lock()->Memory.read_internal(addr - 0x200); + case 0xFFC0 ... 0xFFFF: + return this->_map.lock()->IPL.read(addr - 0xFFC0); + default: + throw InvalidAddress("DSP read", addr); + } + } + + void DSP::_writeRAM(uint24_t addr, uint8_t data) { + switch (addr) { + case 0x0000 ... 0x00EF: + this->_map.lock()->Page0.write_internal(addr, data); + break; + case 0x0100 ... 0x01FF: + this->_map.lock()->Page1.write_internal(addr - 0x0100, data); + break; + case 0x0200 ... 0xFFBF: + this->_map.lock()->Memory.write_internal(addr - 0x200, data); + break; + case 0xFFC0 ... 0xFFFF: + this->_map.lock()->IPL.write(addr - 0xFFC0, data); + break; + default: + throw InvalidAddress("DSP write", addr); + } + } + void DSP::update() { switch (this->_state.voice) { @@ -760,14 +795,4 @@ namespace ComSquare::APU::DSP { return this->_state.buffer - this->_state.bufferStart; } - - std::string DSP::getName() - { - return "DSP"; - } - - Component DSP::getComponent() - { - return Apu; - } } \ No newline at end of file diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 8e7a0a0..a8fb57e 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -9,8 +9,21 @@ #include #include "../../Memory/AMemory.hpp" +namespace ComSquare::APU +{ + class APU; + struct MemoryMap; +} + namespace ComSquare::APU::DSP { + enum Envelope : uint { + Release, + Attack, + Decay, + Sustain + }; + struct Master { //! @brief Main Volume register (MVOL) std::array volume; @@ -55,6 +68,18 @@ namespace ComSquare::APU::DSP struct BRR { //! @brief Offset pointing to sample directory in external RAM (DIR) uint8_t offset; + //! @brief Address of the offset + uint8_t offsetAddr; + //! @brief Current address of the BRR in APU's RAM + uint16_t address; + //! @brief Next address of the BRR in APU's RAM + uint16_t nextAddress; + //! @brief Current value inside BRR + uint8_t value; + //! @brief Current header of BRR + uint8_t header; + //! @brief Current value of Voice ADSR1 loaded + uint8_t source; }; struct Latch { @@ -92,7 +117,7 @@ namespace ComSquare::APU::DSP //! @brief Envelope controllers register (ADSR) uint8_t adsr2; }; - uint16_t envelope; + uint16_t adsr; }; //! @brief Gain register (GAIN) uint8_t gain; @@ -118,6 +143,30 @@ namespace ComSquare::APU::DSP bool echo; //! @brief Check if this voice will be looped bool loop; + //! @brief Current BRR associated with this voice + uint16_t brrAddress; + //! @brief Current Offset in the BRR block + uint8_t brrOffset = 1; + //! @brief Previous modulation + bool prevPmon : 1; + //! @brief temporary NON register value + bool tempNon : 1; + //! @brief temporary Key On register value + bool tempKon : 1; + //! @brief temporary Key Off register value + bool tempKof : 1; + //! @brief all samples Decoded from BRR + std::array samples; + //! @brief Offset of current sample in samples buffer + uint8_t sampleOffset; + //! @brief Current envelope level + uint16_t envelope; + //! @brief Second envelope level used to make "special" waveforms + uint16_t hiddenEnvelope; + //! @brief current envelope Mode + Envelope envelopeMode; + //! @brief Relative fractional position in sample + uint16_t gaussOffset; }; //! @brief Current state of the DSP @@ -132,6 +181,14 @@ namespace ComSquare::APU::DSP //! @brief Beginning of the buffer int16_t *bufferStart; }; + + struct Timer { + //! @brief Ticks remaining in the timer + uint16_t counter; + //! @brief output every samples + bool sample = true; + }; + /*//! @brief All the registers of the DSP struct Registers { //! @brief Main Volume register @@ -249,8 +306,28 @@ namespace ComSquare::APU::DSP uint16_t output; };*/ - class DSP : public Memory::AMemory { + class DSP { private: + //! @brief Number of samples per counter event + std::array _rateModulus = { + 0, 2048, 1536, 1280, 1024, 768, + 640, 512, 384, 320, 256, 192, + 160, 128, 96, 80, 64, 48, + 40, 32, 24, 20, 16, 12, + 10, 8, 6, 5, 4, 3, + 2, 1 + }; + + //! @brief Counter offset + std::array _counterOffset = { + 0, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 0,0 + }; + //! @brief Gaussian table used for making waves std::array _gauss = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -295,6 +372,7 @@ namespace ComSquare::APU::DSP BRR _brr {}; Latch _latch {}; State _state {}; + Timer _timer {}; void voiceOutput(Voice &voice, bool channel); void voice1(Voice &voice); @@ -322,11 +400,24 @@ namespace ComSquare::APU::DSP void misc28(); void misc29(); void misc30(); + + int32_t interpolate(const Voice &voice); + void runEnvelope(Voice &voice); + + void timerTick(); + bool timerPoll(uint32_t rate); + + void decodeBRR(Voice &voice); + + std::weak_ptr _map; + + uint8_t _readRAM(uint24_t addr); + void _writeRAM(uint24_t addr, uint8_t data); public: - DSP(int16_t *buffer, int32_t size); + DSP(int16_t *buffer, int32_t size, std::weak_ptr map); DSP(const DSP &) = default; DSP &operator=(const DSP &) = default; - ~DSP() override = default; + ~DSP() = default; //! @brief Return all 8 voices from DSP const std::array &getVoices(); @@ -340,24 +431,18 @@ namespace ComSquare::APU::DSP //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register. //! @throw InvalidAddress will be thrown if the address is more than $7F (the number of register). //! @return Return the value of the register. - uint8_t read(uint24_t addr) override; + uint8_t read(uint24_t addr); //! @brief Write data to the internal DSP register. //! @param addr The address to write to. The address 0x0 should refer to the first byte of register. //! @param data The new value of the register. //! @throw InvalidAddress will be thrown if the address is more than $7F (the number of register). - void write(uint24_t addr, uint8_t data) override; + void write(uint24_t addr, uint8_t data); //! @brief Execute current voice transformation void update(); //! @brief Return the number of samples written int32_t getSamplesCount() const; - - //! @brief Get the name of this accessor (used for debug purpose) - std::string getName() override; - - //! @brief Get the component of this accessor (used for debug purpose) - Component getComponent() override; }; } diff --git a/sources/APU/DSP/Envelope.cpp b/sources/APU/DSP/Envelope.cpp new file mode 100644 index 0000000..47f4aae --- /dev/null +++ b/sources/APU/DSP/Envelope.cpp @@ -0,0 +1,78 @@ +// +// Created by melefo on 2/3/21. +// + +#include "DSP.hpp" + +namespace ComSquare::APU::DSP +{ + void DSP::runEnvelope(Voice &voice) + { + int32_t envelope = voice.envelope; + + if (voice.envelopeMode == Envelope::Release) { + envelope -= 0x08; + if (envelope < 0) + envelope = 0; + voice.envelope = envelope; + return; + } + + int32_t rate; + int32_t mode; + int32_t data = voice.adsr2; + if (this->_latch.adsr1 & 0b10000000) { + if (voice.envelopeMode >= Envelope::Decay) { + envelope -= 1; + envelope -= envelope >> 8; + rate = data & 0b11111; + if (voice.envelopeMode == Envelope::Decay) + rate = ((this->_latch.adsr1 >> 3) & 0x0E) + 0x10; + } + else { + rate = ((this->_latch.adsr1 & 0b1111) << 1) + 1; + if (rate < 0b11111) + envelope += 0x20; + else + envelope += 0x400; + } + } + else { + data = voice.gain; + mode = data >> 5; + if (mode < 4) { + envelope = data << 4; + rate = 0b11111; + } + else { + rate = data & 0b11111; + if (mode == 4) + envelope -= 0x20; + else if (mode < 6) { + envelope -= 1; + envelope -= envelope >> 8; + } + else { + envelope += 0x20; + if (mode > 6 && voice.hiddenEnvelope >= 0x600) + envelope += 0x08 - 0x20; + } + } + } + + if (envelope >> 8 == (data >> 5) && voice.envelopeMode == Envelope::Decay) + voice.envelopeMode = Envelope::Sustain; + voice.hiddenEnvelope = envelope; + if (static_cast(envelope) > 0x7FF) { + if (envelope < 0) + envelope = 0; + else + envelope = 0x7FF; + if (voice.envelopeMode == Envelope::Attack) + voice.envelopeMode = Envelope::Decay; + } + + if (this->timerPoll(rate)) + voice.envelope = envelope; + } +} \ No newline at end of file diff --git a/sources/APU/DSP/Gauss.cpp b/sources/APU/DSP/Gauss.cpp new file mode 100644 index 0000000..c6ad58a --- /dev/null +++ b/sources/APU/DSP/Gauss.cpp @@ -0,0 +1,30 @@ +// +// Created by melefo on 2/3/21. +// + +#include +#include +#include "DSP.hpp" + +namespace ComSquare::APU::DSP +{ + int32_t DSP::interpolate(const Voice &voice) + { + int32_t interpolated; + uint8_t offset = voice.gaussOffset >> 4; + int forward = 255 - offset; + int reverse = offset; + + offset = (voice.sampleOffset + (voice.gaussOffset >> 12)) % 12; + interpolated = this->_gauss[forward] * voice.samples[offset++] >> 11; + offset %= 12; + interpolated += this->_gauss[forward + 256] * voice.samples[offset++] >> 11; + offset %= 12; + interpolated += this->_gauss[reverse + 256] * voice.samples[offset++] >> 11; + offset %= 12; + interpolated = static_cast(interpolated); + interpolated += this->_gauss[reverse] * voice.samples[offset] >> 11; + + return std::clamp(interpolated, 0, 16) & ~1; + } +} \ No newline at end of file diff --git a/sources/APU/DSP/Timer.cpp b/sources/APU/DSP/Timer.cpp new file mode 100644 index 0000000..9e85488 --- /dev/null +++ b/sources/APU/DSP/Timer.cpp @@ -0,0 +1,22 @@ +// +// Created by melefo on 2/3/21. +// + +#include "DSP.hpp" + +namespace ComSquare::APU::DSP +{ + void DSP::timerTick() + { + if (!this->_timer.counter) + this->_timer.counter = 0x7800; + this->_timer.counter -= 1; + } + + bool DSP::timerPoll(uint32_t rate) + { + if (!rate) + return false; + return (this->_timer.counter + this->_counterOffset[rate]) % this->_rateModulus[rate] == 0; + } +} \ No newline at end of file diff --git a/sources/APU/DSP/Voice.cpp b/sources/APU/DSP/Voice.cpp index 3633a75..680642d 100644 --- a/sources/APU/DSP/Voice.cpp +++ b/sources/APU/DSP/Voice.cpp @@ -3,6 +3,7 @@ // #include "DSP.hpp" +#include "../APU.hpp" #include namespace ComSquare::APU::DSP @@ -19,38 +20,109 @@ namespace ComSquare::APU::DSP void DSP::voice1(Voice &voice) { - + this->_brr.address = (this->_brr.offsetAddr << 8) + (this->_brr.source << 2); + this->_brr.source = voice.srcn; } void DSP::voice2(Voice &voice) { - /*uint16_t addr = this->_brr. - this->_latch.adsr1 = voice.adsr1;*/ + uint16_t addr = this->_brr.address; + + if (!voice.konDelay) + addr += 2; + this->_brr.nextAddress = this->_readRAM(addr++); + this->_brr.nextAddress += this->_readRAM(addr++) << 8; + this->_latch.adsr1 = voice.adsr1; + this->_latch.pitch = voice.pitch & 0xFF; } void DSP::voice3(Voice &voice) { - + this->voice3a(voice); + this->voice3b(voice); + this->voice3c(voice); } void DSP::voice3a(Voice &voice) { - + this->_latch.pitch |= (voice.pitchH & 0x3F) << 8; } void DSP::voice3b(Voice &voice) { - + this->_brr.header = this->_readRAM(this->_brr.address); + this->_brr.value = this->_readRAM(this->_brr.address + voice.brrOffset); } void DSP::voice3c(Voice &voice) { + if (voice.prevPmon) + this->_latch.pitch += (this->_latch.output >> 5) * this->_latch.pitch >> 10; + if (voice.konDelay) { + if (voice.konDelay == 5) { + voice.brrAddress = this->_brr.nextAddress; + voice.brrOffset = 1; + voice.sampleOffset = 0; + this->_brr.header = 0; + } + + voice.envelope = 0; + voice.hiddenEnvelope = 0; + voice.gaussOffset = 0; + voice.konDelay -= 1; + if (voice.konDelay & 3) + voice.gaussOffset = 0x4000; + this->_latch.pitch = 0; + } + + int32_t interpolated = this->interpolate(voice); + + if (voice.tempNon) + interpolated = this->_noise.lfsr << 1; + + this->_latch.output = interpolated * voice.envelope >> 11 & ~1; + voice.envx = voice.envelope >> 4; + + if (this->_master.reset || (this->_brr.header & 3) == 1) { + voice.envelope = 0; + voice.envelopeMode = Envelope::Release; + } + + if (this->_timer.sample) + { + if (voice.tempKof) + voice.envelopeMode = Envelope::Release; + if (voice.tempKon) { + voice.konDelay = 5; + voice.envelopeMode = Envelope::Attack; + } + } + + if (!voice.konDelay) + this->runEnvelope(voice); } void DSP::voice4(Voice &voice) { + voice.loop = false; + if (voice.gaussOffset >= 0x4000) { + this->decodeBRR(voice); + voice.brrOffset += 2; + if (voice.brrOffset >= 9) { + voice.brrOffset = voice.brrAddress + 9; + if (this->_brr.header & 0b1) { + voice.brrAddress = this->_brr.nextAddress; + voice.loop = true; + } + voice.brrOffset = 1; + } + } + voice.gaussOffset = (voice.gaussOffset & 0x3FFF) + this->_latch.pitch; + if (voice.gaussOffset > 0x7FFF) + voice.gaussOffset = 0x7FFF; + this->voiceOutput(voice, 0); } void DSP::voice5(Voice &voice) @@ -62,9 +134,9 @@ namespace ComSquare::APU::DSP voice.endx &= ~voice.endx; } - void DSP::voice6(Voice &voice) + void DSP::voice6(Voice &) { - + this->_latch.outx = this->_latch.output >> 8; } void DSP::voice7(Voice &voice) diff --git a/sources/Debugger/APUDebug.cpp b/sources/Debugger/APUDebug.cpp index ee9183e..3161ff3 100644 --- a/sources/Debugger/APUDebug.cpp +++ b/sources/Debugger/APUDebug.cpp @@ -47,8 +47,8 @@ namespace ComSquare::Debugger this->_ui.dSPRegAddresshexaLineEdit->setText(Utility::to_hex(this->_registers.dspregAddr).c_str()); this->_ui.dSPRegAddressLineEdit->setText(Utility::to_binary(this->_registers.dspregAddr).c_str()); - this->_ui.dSPRegDatahexaLineEdit->setText(Utility::to_hex(this->_dsp->read(this->_registers.dspregAddr)).c_str()); - this->_ui.dSPRegDataLineEdit->setText(Utility::to_binary(this->_dsp->read(this->_registers.dspregAddr)).c_str()); + this->_ui.dSPRegDatahexaLineEdit->setText(Utility::to_hex(this->_dsp.read(this->_registers.dspregAddr)).c_str()); + this->_ui.dSPRegDataLineEdit->setText(Utility::to_binary(this->_dsp.read(this->_registers.dspregAddr)).c_str()); this->_ui.timer0hexaLineEdit->setText(Utility::to_hex(this->_registers.timer0).c_str()); this->_ui.timer0LineEdit->setText(Utility::to_binary(this->_registers.timer0).c_str()); @@ -84,12 +84,12 @@ namespace ComSquare::Debugger this->_ui.programCounterLineEdit->setText(Utility::to_hex(this->_internalRegisters.pc + 0x0001u).c_str()); this->_ui.programStatusWordLineEdit->setText(this->_getPSWString().c_str()); - auto voices = this->_dsp->getVoices(); - auto master = this->_dsp->getMaster(); - auto echo = this->_dsp->getEcho(); - auto noise = this->_dsp->getNoise(); - auto brr = this->_dsp->getBrr(); - auto latch = this->_dsp->getLatch(); + auto voices = this->_dsp.getVoices(); + auto master = this->_dsp.getMaster(); + auto echo = this->_dsp.getEcho(); + auto noise = this->_dsp.getNoise(); + auto brr = this->_dsp.getBrr(); + auto latch = this->_dsp.getLatch(); this->_ui.mvolLprogressBar->setValue(master.volume[0]); this->_ui.mvolRprogressBar->setValue(master.volume[1]); diff --git a/sources/SNES.cpp b/sources/SNES.cpp index 32752c1..ab007b7 100644 --- a/sources/SNES.cpp +++ b/sources/SNES.cpp @@ -19,10 +19,9 @@ namespace ComSquare cartridge(new Cartridge::Cartridge(romPath)), wram(new Ram::Ram(16384, WRam, "WRam")), sram(new Ram::Ram(this->cartridge->header.sramSize, SRam, "SRam")), - apuRam(new APU::MemoryMap()), cpu(new CPU::CPU(this->_bus, cartridge->header)), ppu(new PPU::PPU(renderer)), - apu(new APU::APU(this->apuRam, renderer)) + apu(new APU::APU(renderer)) { this->_bus->mapComponents(*this); } diff --git a/sources/SNES.hpp b/sources/SNES.hpp index 5babc05..aba2cfd 100644 --- a/sources/SNES.hpp +++ b/sources/SNES.hpp @@ -41,8 +41,6 @@ namespace ComSquare std::shared_ptr wram; //! @brief Save Ram residing inside the Cartridge in a real SNES. std::shared_ptr sram; - //! @brief External Ram used only by the Audio Processing Unit - std::shared_ptr apuRam; //! @brief Central Processing Unit of the SNES. std::shared_ptr cpu; //! @brief Picture Processing Unit of the SNES From 0b9d92766a7189fa46e0d56f04b0e2925c1031f1 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 4 Feb 2021 00:17:30 +0100 Subject: [PATCH 05/26] Fixing tests compilation --- CMakeLists.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3010726..a0b1a63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,11 @@ add_executable(unit_tests sources/CPU/DMA/DMA.hpp sources/APU/DSP/Voice.cpp sources/APU/DSP/Echo.cpp - sources/APU/DSP/Gauss.cpp sources/APU/DSP/Timer.cpp sources/APU/DSP/BRR.cpp) + sources/APU/DSP/Gauss.cpp + sources/APU/DSP/Envelope.cpp + sources/APU/DSP/Timer.cpp + sources/APU/DSP/BRR.cpp + ) # include criterion & coverage target_link_libraries(unit_tests criterion -lgcov) @@ -227,7 +231,11 @@ add_executable(ComSquare sources/CPU/DMA/DMA.hpp sources/APU/DSP/Voice.cpp sources/APU/DSP/Echo.cpp - sources/APU/DSP/Gauss.cpp sources/APU/DSP/Envelope.cpp sources/APU/DSP/Timer.cpp sources/APU/DSP/BRR.cpp) + sources/APU/DSP/Gauss.cpp + sources/APU/DSP/Envelope.cpp + sources/APU/DSP/Timer.cpp + sources/APU/DSP/BRR.cpp + ) target_compile_definitions(ComSquare PUBLIC DEBUGGER_ENABLED) From 96fe1a5e3366656ab0429247ec60785add506ae8 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Fri, 5 Feb 2021 14:48:02 +0100 Subject: [PATCH 06/26] Tabs instead of spaces --- sources/APU/DSP/BRR.cpp | 100 +++--- sources/APU/DSP/DSP.cpp | 462 ++++++++++++------------- sources/APU/DSP/DSP.hpp | 644 +++++++++++++++++------------------ sources/APU/DSP/Echo.cpp | 78 ++--- sources/APU/DSP/Envelope.cpp | 130 +++---- sources/APU/DSP/Gauss.cpp | 34 +- sources/APU/DSP/Timer.cpp | 24 +- sources/APU/DSP/Voice.cpp | 236 ++++++------- 8 files changed, 854 insertions(+), 854 deletions(-) diff --git a/sources/APU/DSP/BRR.cpp b/sources/APU/DSP/BRR.cpp index 683c590..27fa942 100644 --- a/sources/APU/DSP/BRR.cpp +++ b/sources/APU/DSP/BRR.cpp @@ -7,60 +7,60 @@ namespace ComSquare::APU::DSP { - void DSP::decodeBRR(Voice &voice) - { - int32_t value = this->_brr.value << 8 | this->_readRAM(voice.brrAddress + voice.brrOffset + 1); + void DSP::decodeBRR(Voice &voice) + { + int32_t value = this->_brr.value << 8 | this->_readRAM(voice.brrAddress + voice.brrOffset + 1); - int32_t filter = this->_brr.header >> 2 & 0b11; - int32_t range = this->_brr.header >> 4 & 0b1111; + int32_t filter = this->_brr.header >> 2 & 0b11; + int32_t range = this->_brr.header >> 4 & 0b1111; - for (int i = 0; i < 4; i++) { - int32_t sample = value >> 12; - value <<= 4; + for (int i = 0; i < 4; i++) { + int32_t sample = value >> 12; + value <<= 4; - if (range <= 12) { - sample <<= range; - sample >>= 1; - } - else - sample &= ~0x7FF; + if (range <= 12) { + sample <<= range; + sample >>= 1; + } + else + sample &= ~0x7FF; - int offset = voice.sampleOffset; - int lastSample; - int afterLastSample; + int offset = voice.sampleOffset; + int lastSample; + int afterLastSample; - if (--offset < 0) - offset = 11; - lastSample = voice.samples[offset]; - if (--offset < 0) - offset = 11; - afterLastSample = voice.samples[offset]; + if (--offset < 0) + offset = 11; + lastSample = voice.samples[offset]; + if (--offset < 0) + offset = 11; + afterLastSample = voice.samples[offset]; - switch (filter) { - case 0: - break; - case 1: - sample += lastSample; - sample += (lastSample) >> 4; - break; - case 2: - sample += lastSample << 1; - sample += -((lastSample << 1) + lastSample) >> 5; - sample -= afterLastSample; - sample += afterLastSample >> 4; - break; - case 3: - sample += lastSample << 1; - sample += -(lastSample + (lastSample << 2) + (lastSample << 3)) >> 6; - sample -= afterLastSample; - sample += ((afterLastSample << 1) + afterLastSample) >> 4; - break; - } - sample = std::clamp(sample, 0, 16); - sample <<= 1; - voice.samples[voice.sampleOffset] = sample; - if (++voice.sampleOffset >= 12) - voice.sampleOffset = 0; - } - } + switch (filter) { + case 0: + break; + case 1: + sample += lastSample; + sample += (lastSample) >> 4; + break; + case 2: + sample += lastSample << 1; + sample += -((lastSample << 1) + lastSample) >> 5; + sample -= afterLastSample; + sample += afterLastSample >> 4; + break; + case 3: + sample += lastSample << 1; + sample += -(lastSample + (lastSample << 2) + (lastSample << 3)) >> 6; + sample -= afterLastSample; + sample += ((afterLastSample << 1) + afterLastSample) >> 4; + break; + } + sample = std::clamp(sample, 0, 16); + sample <<= 1; + voice.samples[voice.sampleOffset] = sample; + if (++voice.sampleOffset >= 12) + voice.sampleOffset = 0; + } + } } \ No newline at end of file diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 710d343..2321ae7 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -8,12 +8,12 @@ namespace ComSquare::APU::DSP { - DSP::DSP(int16_t *buffer, int32_t size, std::weak_ptr map) : _map(map) - { - this->_state.buffer = buffer; - this->_state.bufferStart = buffer; - this->_state.bufferEnd = buffer + size; - } + DSP::DSP(int16_t *buffer, int32_t size, std::weak_ptr map) : _map(map) + { + this->_state.buffer = buffer; + this->_state.bufferStart = buffer; + this->_state.bufferEnd = buffer + size; + } uint8_t DSP::read(uint24_t addr) const { @@ -187,13 +187,13 @@ namespace ComSquare::APU::DSP return kof; } case 0x6C: { - uint8_t flg = 0; - flg += this->_master.reset << 7; - flg += this->_master.mute << 6; - flg += this->_echo.enabled << 5; - flg += this->_noise.clock; - return flg; - } + uint8_t flg = 0; + flg += this->_master.reset << 7; + flg += this->_master.mute << 6; + flg += this->_echo.enabled << 5; + flg += this->_noise.clock; + return flg; + } case 0x7C: { uint8_t endx = 0; @@ -496,18 +496,18 @@ namespace ComSquare::APU::DSP break; case 0x4C: for (int i = 0; i < 8; i++) { - this->_voices[i].kon |= data << i; - } + this->_voices[i].kon |= data << i; + } break; case 0x5C: for (int i = 0; i < 8; i++) this->_voices[i].kof |= data << i; break; case 0x6C: - this->_master.reset = data >> 7; - this->_master.mute = (data >> 6) & 0b1; - this->_echo.enabled = (data >> 5) & 0b1; - this->_noise.clock = data & 0b1111; + this->_master.reset = data >> 7; + this->_master.mute = (data >> 6) & 0b1; + this->_echo.enabled = (data >> 5) & 0b1; + this->_noise.clock = data & 0b1111; break; case 0x7C: for (int i = 0; i < 8; i++) @@ -568,197 +568,197 @@ namespace ComSquare::APU::DSP throw InvalidAddress("DSP Registers write", addr); } } - uint8_t DSP::_readRAM(uint24_t addr) { - switch (addr) { - case 0x0000 ... 0x00EF: - return this->_map.lock()->Page0.read(addr); - case 0x0100 ... 0x01FF: - return this->_map.lock()->Page1.read(addr - 0x0100); - case 0x0200 ... 0xFFBF: - return this->_map.lock()->Memory.read(addr - 0x200); - case 0xFFC0 ... 0xFFFF: - return this->_map.lock()->IPL.read(addr - 0xFFC0); - default: - throw InvalidAddress("DSP read", addr); - } - } + uint8_t DSP::_readRAM(uint24_t addr) { + switch (addr) { + case 0x0000 ... 0x00EF: + return this->_map.lock()->Page0.read(addr); + case 0x0100 ... 0x01FF: + return this->_map.lock()->Page1.read(addr - 0x0100); + case 0x0200 ... 0xFFBF: + return this->_map.lock()->Memory.read(addr - 0x200); + case 0xFFC0 ... 0xFFFF: + return this->_map.lock()->IPL.read(addr - 0xFFC0); + default: + throw InvalidAddress("DSP read", addr); + } + } - void DSP::_writeRAM(uint24_t addr, uint8_t data) { - switch (addr) { - case 0x0000 ... 0x00EF: - this->_map.lock()->Page0.write(addr, data); - break; - case 0x0100 ... 0x01FF: - this->_map.lock()->Page1.write(addr - 0x0100, data); - break; - case 0x0200 ... 0xFFBF: - this->_map.lock()->Memory.write(addr - 0x200, data); - break; - case 0xFFC0 ... 0xFFFF: - this->_map.lock()->IPL.write(addr - 0xFFC0, data); - break; - default: - throw InvalidAddress("DSP write", addr); - } - } + void DSP::_writeRAM(uint24_t addr, uint8_t data) { + switch (addr) { + case 0x0000 ... 0x00EF: + this->_map.lock()->Page0.write(addr, data); + break; + case 0x0100 ... 0x01FF: + this->_map.lock()->Page1.write(addr - 0x0100, data); + break; + case 0x0200 ... 0xFFBF: + this->_map.lock()->Memory.write(addr - 0x200, data); + break; + case 0xFFC0 ... 0xFFFF: + this->_map.lock()->IPL.write(addr - 0xFFC0, data); + break; + default: + throw InvalidAddress("DSP write", addr); + } + } void DSP::update() - { - switch (this->_state.voice) { - case 0: - this->voice5(this->_voices[0]); - this->voice2(this->_voices[1]); - break; - case 1: - this->voice6(this->_voices[0]); - this->voice3(this->_voices[1]); - break; - case 2: - this->voice7(this->_voices[0]); - this->voice4(this->_voices[1]); - this->voice1(this->_voices[3]); - break; - case 3: - this->voice8(this->_voices[0]); - this->voice5(this->_voices[1]); - this->voice2(this->_voices[2]); - break; - case 4: - this->voice9(this->_voices[0]); - this->voice6(this->_voices[1]); - this->voice3(this->_voices[2]); - break; - case 5: - this->voice7(this->_voices[1]); - this->voice4(this->_voices[2]); - this->voice1(this->_voices[4]); - break; - case 6: - this->voice8(this->_voices[1]); - this->voice5(this->_voices[2]); - this->voice2(this->_voices[3]); - break; - case 7: - this->voice9(this->_voices[1]); - this->voice6(this->_voices[2]); - this->voice3(this->_voices[3]); - break; - case 8: - this->voice7(this->_voices[2]); - this->voice4(this->_voices[3]); - this->voice1(this->_voices[5]); - break; - case 9: - this->voice8(this->_voices[2]); - this->voice5(this->_voices[3]); - this->voice2(this->_voices[4]); - break; - case 10: - this->voice9(this->_voices[2]); - this->voice6(this->_voices[3]); - this->voice3(this->_voices[4]); - break; - case 11: - this->voice7(this->_voices[3]); - this->voice4(this->_voices[4]); - this->voice1(this->_voices[6]); - break; - case 12: - this->voice8(this->_voices[3]); - this->voice5(this->_voices[4]); - this->voice2(this->_voices[5]); - break; - case 13: - this->voice9(this->_voices[3]); - this->voice6(this->_voices[4]); - this->voice3(this->_voices[5]); - break; - case 14: - this->voice7(this->_voices[4]); - this->voice4(this->_voices[5]); - this->voice1(this->_voices[7]); - break; - case 15: - this->voice8(this->_voices[4]); - this->voice5(this->_voices[5]); - this->voice2(this->_voices[6]); - break; - case 16: - this->voice9(this->_voices[4]); - this->voice6(this->_voices[5]); - this->voice3(this->_voices[6]); - break; - case 17: - this->voice1(this->_voices[0]); - this->voice7(this->_voices[5]); - this->voice4(this->_voices[6]); - break; - case 18: - this->voice8(this->_voices[5]); - this->voice5(this->_voices[6]); - this->voice2(this->_voices[7]); - break; - case 19: - this->voice9(this->_voices[5]); - this->voice6(this->_voices[6]); - this->voice3(this->_voices[7]); - break; - case 20: - this->voice1(this->_voices[1]); - this->voice7(this->_voices[6]); - this->voice4(this->_voices[7]); - break; - case 21: - this->voice8(this->_voices[6]); - this->voice5(this->_voices[7]); - this->voice2(this->_voices[0]); - break; - case 22: - this->voice3a(this->_voices[0]); - this->voice9(this->_voices[6]); - this->voice6(this->_voices[7]); - echo22(); - break; - case 23: - this->voice7(this->_voices[7]); - echo23(); - break; - case 24: - this->voice8(this->_voices[7]); - echo24(); - break; - case 25: - this->voice3b(this->_voices[0]); - this->voice9(this->_voices[7]); - echo25(); - break; - case 26: - echo26(); - break; - case 27: - this->misc27(); - this->echo27(); - break; - case 28: - this->misc28(); - this->echo28(); - break; - case 29: - this->misc29(); - this->echo29(); - break; - case 30: - this->misc30(); - this->voice3c(this->_voices[0]); - this->echo30(); - break; - case 31: - this->voice4(this->_voices[0]); - this->voice1(this->_voices[2]); - break; - } - this->_state.voice = (this->_state.voice + 1) % 32; - } + { + switch (this->_state.voice) { + case 0: + this->voice5(this->_voices[0]); + this->voice2(this->_voices[1]); + break; + case 1: + this->voice6(this->_voices[0]); + this->voice3(this->_voices[1]); + break; + case 2: + this->voice7(this->_voices[0]); + this->voice4(this->_voices[1]); + this->voice1(this->_voices[3]); + break; + case 3: + this->voice8(this->_voices[0]); + this->voice5(this->_voices[1]); + this->voice2(this->_voices[2]); + break; + case 4: + this->voice9(this->_voices[0]); + this->voice6(this->_voices[1]); + this->voice3(this->_voices[2]); + break; + case 5: + this->voice7(this->_voices[1]); + this->voice4(this->_voices[2]); + this->voice1(this->_voices[4]); + break; + case 6: + this->voice8(this->_voices[1]); + this->voice5(this->_voices[2]); + this->voice2(this->_voices[3]); + break; + case 7: + this->voice9(this->_voices[1]); + this->voice6(this->_voices[2]); + this->voice3(this->_voices[3]); + break; + case 8: + this->voice7(this->_voices[2]); + this->voice4(this->_voices[3]); + this->voice1(this->_voices[5]); + break; + case 9: + this->voice8(this->_voices[2]); + this->voice5(this->_voices[3]); + this->voice2(this->_voices[4]); + break; + case 10: + this->voice9(this->_voices[2]); + this->voice6(this->_voices[3]); + this->voice3(this->_voices[4]); + break; + case 11: + this->voice7(this->_voices[3]); + this->voice4(this->_voices[4]); + this->voice1(this->_voices[6]); + break; + case 12: + this->voice8(this->_voices[3]); + this->voice5(this->_voices[4]); + this->voice2(this->_voices[5]); + break; + case 13: + this->voice9(this->_voices[3]); + this->voice6(this->_voices[4]); + this->voice3(this->_voices[5]); + break; + case 14: + this->voice7(this->_voices[4]); + this->voice4(this->_voices[5]); + this->voice1(this->_voices[7]); + break; + case 15: + this->voice8(this->_voices[4]); + this->voice5(this->_voices[5]); + this->voice2(this->_voices[6]); + break; + case 16: + this->voice9(this->_voices[4]); + this->voice6(this->_voices[5]); + this->voice3(this->_voices[6]); + break; + case 17: + this->voice1(this->_voices[0]); + this->voice7(this->_voices[5]); + this->voice4(this->_voices[6]); + break; + case 18: + this->voice8(this->_voices[5]); + this->voice5(this->_voices[6]); + this->voice2(this->_voices[7]); + break; + case 19: + this->voice9(this->_voices[5]); + this->voice6(this->_voices[6]); + this->voice3(this->_voices[7]); + break; + case 20: + this->voice1(this->_voices[1]); + this->voice7(this->_voices[6]); + this->voice4(this->_voices[7]); + break; + case 21: + this->voice8(this->_voices[6]); + this->voice5(this->_voices[7]); + this->voice2(this->_voices[0]); + break; + case 22: + this->voice3a(this->_voices[0]); + this->voice9(this->_voices[6]); + this->voice6(this->_voices[7]); + echo22(); + break; + case 23: + this->voice7(this->_voices[7]); + echo23(); + break; + case 24: + this->voice8(this->_voices[7]); + echo24(); + break; + case 25: + this->voice3b(this->_voices[0]); + this->voice9(this->_voices[7]); + echo25(); + break; + case 26: + echo26(); + break; + case 27: + this->misc27(); + this->echo27(); + break; + case 28: + this->misc28(); + this->echo28(); + break; + case 29: + this->misc29(); + this->echo29(); + break; + case 30: + this->misc30(); + this->voice3c(this->_voices[0]); + this->echo30(); + break; + case 31: + this->voice4(this->_voices[0]); + this->voice1(this->_voices[2]); + break; + } + this->_state.voice = (this->_state.voice + 1) % 32; + } uint24_t DSP::getSize() const { return 0x7F; @@ -769,33 +769,33 @@ namespace ComSquare::APU::DSP return this->_voices; } - const Master &DSP::getMaster() const - { - return this->_master; - } + const Master &DSP::getMaster() const + { + return this->_master; + } - const Echo &DSP::getEcho() const - { - return this->_echo; - } + const Echo &DSP::getEcho() const + { + return this->_echo; + } - const Noise &DSP::getNoise() const - { - return this->_noise; - } + const Noise &DSP::getNoise() const + { + return this->_noise; + } - const BRR &DSP::getBrr() const - { - return this->_brr; - } + const BRR &DSP::getBrr() const + { + return this->_brr; + } - const Latch &DSP::getLatch() const - { - return this->_latch; - } + const Latch &DSP::getLatch() const + { + return this->_latch; + } - int32_t DSP::getSamplesCount() const - { - return this->_state.buffer - this->_state.bufferStart; - } + int32_t DSP::getSamplesCount() const + { + return this->_state.buffer - this->_state.bufferStart; + } } \ No newline at end of file diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 67cadc0..4ea52f4 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -11,202 +11,202 @@ namespace ComSquare::APU { - class APU; - struct MemoryMap; + class APU; + struct MemoryMap; } namespace ComSquare::APU::DSP { - enum Envelope : uint { - Release, - Attack, - Decay, - Sustain - }; + enum Envelope : uint { + Release, + Attack, + Decay, + Sustain + }; - struct Master { - //! @brief Main Volume register (MVOL) - std::array volume; - //! @brief Mutes all channel (6th bit FLG) - bool mute : 1; - //! @brief Soft reset DSP (7th bit FLG) - bool reset : 1; - //! @brief Current sound produced - std::array output; - //! @brief Not used register - uint8_t unused; - }; + struct Master { + //! @brief Main Volume register (MVOL) + std::array volume; + //! @brief Mutes all channel (6th bit FLG) + bool mute : 1; + //! @brief Soft reset DSP (7th bit FLG) + bool reset : 1; + //! @brief Current sound produced + std::array output; + //! @brief Not used register + uint8_t unused; + }; - struct Echo { - //! @brief Echo Volume register (EVOL) - std::array volume; - //! @brief Echo feedback register (EFB) - uint8_t feedback; - //! @brief Echo FIR filter coefficients (COEF) - std::array FIR; - //! @brief Echo data start register (ESA) - uint8_t data; - //! @brief Echo delay size register (EDL) - uint8_t delay; - //! @brief Echo enabled (5th bit FLG) - bool enabled = true; - //! @brief Last sound produced for each voice in each channel - std::array, 2> history; - //! @brief Current sound to echo - std::array input; - //! @brief Current sound echoed produced - std::array output; - }; + struct Echo { + //! @brief Echo Volume register (EVOL) + std::array volume; + //! @brief Echo feedback register (EFB) + uint8_t feedback; + //! @brief Echo FIR filter coefficients (COEF) + std::array FIR; + //! @brief Echo data start register (ESA) + uint8_t data; + //! @brief Echo delay size register (EDL) + uint8_t delay; + //! @brief Echo enabled (5th bit FLG) + bool enabled = true; + //! @brief Last sound produced for each voice in each channel + std::array, 2> history; + //! @brief Current sound to echo + std::array input; + //! @brief Current sound echoed produced + std::array output; + }; - struct Noise { - //! @brief Frequency of white noise (the first 4 bits FLG) - uint8_t clock : 5; - //! @brief Linear feedback shift register used to shift final output - uint16_t lfsr = 0x4000; - }; + struct Noise { + //! @brief Frequency of white noise (the first 4 bits FLG) + uint8_t clock : 5; + //! @brief Linear feedback shift register used to shift final output + uint16_t lfsr = 0x4000; + }; - struct BRR { - //! @brief Offset pointing to sample directory in external RAM (DIR) - uint8_t offset; - //! @brief Address of the offset - uint8_t offsetAddr; - //! @brief Current address of the BRR in APU's RAM - uint16_t address; - //! @brief Next address of the BRR in APU's RAM - uint16_t nextAddress; - //! @brief Current value inside BRR - uint8_t value; - //! @brief Current header of BRR - uint8_t header; - //! @brief Current value of Voice ADSR1 loaded - uint8_t source; - }; + struct BRR { + //! @brief Offset pointing to sample directory in external RAM (DIR) + uint8_t offset; + //! @brief Address of the offset + uint8_t offsetAddr; + //! @brief Current address of the BRR in APU's RAM + uint16_t address; + //! @brief Next address of the BRR in APU's RAM + uint16_t nextAddress; + //! @brief Current value inside BRR + uint8_t value; + //! @brief Current header of BRR + uint8_t header; + //! @brief Current value of Voice ADSR1 loaded + uint8_t source; + }; - struct Latch { - //! @brief Current voice's adsr1 in use - uint8_t adsr1; - //! @brief Envelope value register (ENVX) - uint8_t envx; - //! @brief Wave height register (OUTX) - uint8_t outx; - //! @brief Current voice's pitch in use - uint16_t pitch; - //! @brief Output currently being modified - uint16_t output; - }; + struct Latch { + //! @brief Current voice's adsr1 in use + uint8_t adsr1; + //! @brief Envelope value register (ENVX) + uint8_t envx; + //! @brief Wave height register (OUTX) + uint8_t outx; + //! @brief Current voice's pitch in use + uint16_t pitch; + //! @brief Output currently being modified + uint16_t output; + }; - struct Voice { - //! @brief Volume register (VOL) - std::array volume; - //! @brief Pitch register (P) - union { - struct { - //! @brief Lower 8 bits of pitch register - uint8_t pitchL; - //! @brief Higher 8 bits of pitch register - uint8_t pitchH; - }; - uint16_t pitch; - }; - //! @brief Source number register (SRCN) - uint8_t srcn; - union { - struct { - //! @brief Envelope register (ADSR) - uint8_t adsr1; - //! @brief Envelope controllers register (ADSR) - uint8_t adsr2; - }; - uint16_t adsr; - }; - //! @brief Gain register (GAIN) - uint8_t gain; - //! @brief envelope associated with this voice - uint8_t envx; - //! @brief Sample end register (ENDX) - bool endx : 1; + struct Voice { + //! @brief Volume register (VOL) + std::array volume; + //! @brief Pitch register (P) + union { + struct { + //! @brief Lower 8 bits of pitch register + uint8_t pitchL; + //! @brief Higher 8 bits of pitch register + uint8_t pitchH; + }; + uint16_t pitch; + }; + //! @brief Source number register (SRCN) + uint8_t srcn; + union { + struct { + //! @brief Envelope register (ADSR) + uint8_t adsr1; + //! @brief Envelope controllers register (ADSR) + uint8_t adsr2; + }; + uint16_t adsr; + }; + //! @brief Gain register (GAIN) + uint8_t gain; + //! @brief envelope associated with this voice + uint8_t envx; + //! @brief Sample end register (ENDX) + bool endx : 1; - //! @brief Key On register (KON) - bool kon : 1; - //! @brief Key Off register (KOF) - bool kof : 1; - //! @brief Pitch modulation register (PMON) - bool pmon : 1; - //! @brief Noise enable register (NON) - bool non : 1; - //! @brief Echo enable register (EON) - bool eon : 1; + //! @brief Key On register (KON) + bool kon : 1; + //! @brief Key Off register (KOF) + bool kof : 1; + //! @brief Pitch modulation register (PMON) + bool pmon : 1; + //! @brief Noise enable register (NON) + bool non : 1; + //! @brief Echo enable register (EON) + bool eon : 1; - //! @brief Check if voice is in setup phase - uint8_t konDelay; - //! @brief Check if the output will be echoed - bool echo; - //! @brief Check if this voice will be looped - bool loop; - //! @brief Current BRR associated with this voice - uint16_t brrAddress; - //! @brief Current Offset in the BRR block - uint8_t brrOffset = 1; - //! @brief Previous modulation - bool prevPmon : 1; - //! @brief temporary NON register value - bool tempNon : 1; - //! @brief temporary Key On register value - bool tempKon : 1; - //! @brief temporary Key Off register value - bool tempKof : 1; - //! @brief all samples Decoded from BRR - std::array samples; - //! @brief Offset of current sample in samples buffer - uint8_t sampleOffset; - //! @brief Current envelope level - uint16_t envelope; - //! @brief Second envelope level used to make "special" waveforms - uint16_t hiddenEnvelope; - //! @brief current envelope Mode - Envelope envelopeMode; - //! @brief Relative fractional position in sample - uint16_t gaussOffset; - }; + //! @brief Check if voice is in setup phase + uint8_t konDelay; + //! @brief Check if the output will be echoed + bool echo; + //! @brief Check if this voice will be looped + bool loop; + //! @brief Current BRR associated with this voice + uint16_t brrAddress; + //! @brief Current Offset in the BRR block + uint8_t brrOffset = 1; + //! @brief Previous modulation + bool prevPmon : 1; + //! @brief temporary NON register value + bool tempNon : 1; + //! @brief temporary Key On register value + bool tempKon : 1; + //! @brief temporary Key Off register value + bool tempKof : 1; + //! @brief all samples Decoded from BRR + std::array samples; + //! @brief Offset of current sample in samples buffer + uint8_t sampleOffset; + //! @brief Current envelope level + uint16_t envelope; + //! @brief Second envelope level used to make "special" waveforms + uint16_t hiddenEnvelope; + //! @brief current envelope Mode + Envelope envelopeMode; + //! @brief Relative fractional position in sample + uint16_t gaussOffset; + }; - //! @brief Current state of the DSP - struct State - { - //! @brief Current voice modification to do - uint8_t voice = 0; - //! @brief Current buffer of samples - int16_t *buffer; - //! @brief Limit of the buffer - int16_t *bufferEnd; - //! @brief Beginning of the buffer - int16_t *bufferStart; - }; + //! @brief Current state of the DSP + struct State + { + //! @brief Current voice modification to do + uint8_t voice = 0; + //! @brief Current buffer of samples + int16_t *buffer; + //! @brief Limit of the buffer + int16_t *bufferEnd; + //! @brief Beginning of the buffer + int16_t *bufferStart; + }; - struct Timer { - //! @brief Ticks remaining in the timer - uint16_t counter; - //! @brief output every samples - bool sample = true; - }; + struct Timer { + //! @brief Ticks remaining in the timer + uint16_t counter; + //! @brief output every samples + bool sample = true; + }; /*//! @brief All the registers of the DSP struct Registers { - //! @brief Main Volume register - std::array mVol; //master.volume + //! @brief Main Volume register + std::array mVol; //master.volume - //! @brief Echo Volume register - std::array eVol; //echo.volume + //! @brief Echo Volume register + std::array eVol; //echo.volume //! @brief Flags register union { - struct { - uint8_t noiseClock : 5; //noise.frequency - bool ecen : 1; //echo.readonly - bool mute : 1; //master.mute - bool reset : 1; //master.reset - }; - uint8_t flg; - }; + struct { + uint8_t noiseClock : 5; //noise.frequency + bool ecen : 1; //echo.readonly + bool mute : 1; //master.mute + bool reset : 1; //master.reset + }; + uint8_t flg; + }; //! @brief Echo feedback register uint8_t efb; //echo.feedback @@ -223,28 +223,28 @@ namespace ComSquare::APU::DSP uint8_t edl; //echo.delay }; - struct BRR { - //! @brief BRR Header - union { - struct { - //! @brief Shift value range - unsigned range : 4; - //! @brief Decompression filter - unsigned filter : 2; - //! @brief Flag if the sample loops - bool loop : 1; - //! @brief Stop the sample (or restart from loop point) - bool end : 1; - }; - uint8_t head; - }; - //! @brief Sample data inside BRR - uint64_t block; - }; + struct BRR { + //! @brief BRR Header + union { + struct { + //! @brief Shift value range + unsigned range : 4; + //! @brief Decompression filter + unsigned filter : 2; + //! @brief Flag if the sample loops + bool loop : 1; + //! @brief Stop the sample (or restart from loop point) + bool end : 1; + }; + uint8_t head; + }; + //! @brief Sample data inside BRR + uint64_t block; + }; - struct Voice { - //! @brief Volume register - std::array volume; //voice.volume + struct Voice { + //! @brief Volume register + std::array volume; //voice.volume union { struct { @@ -256,26 +256,26 @@ namespace ComSquare::APU::DSP uint16_t pitch; //voice.pitch }; - //! @brief Source number register - uint8_t srcn; //voice.source + //! @brief Source number register + uint8_t srcn; //voice.source - union { - struct { - //! @brief Envelope register - uint8_t adsr1; //voice.adsr0 - //! @brief Envelope controllers register - uint8_t adsr2; //voice.adsr1 - }; - uint16_t envelope; - }; + union { + struct { + //! @brief Envelope register + uint8_t adsr1; //voice.adsr0 + //! @brief Envelope controllers register + uint8_t adsr2; //voice.adsr1 + }; + uint16_t envelope; + }; - //! @brief Gain register - uint8_t gain; //voice.gain + //! @brief Gain register + uint8_t gain; //voice.gain - //! @brief Envelope value register - uint8_t envx; //latch.envx - //! @brief Wave height register - uint8_t outx; //latch.outx + //! @brief Envelope value register + uint8_t envx; //latch.envx + //! @brief Wave height register + uint8_t outx; //latch.outx //! @brief Key On register bool kon : 1; //voice.keyon @@ -299,120 +299,120 @@ namespace ComSquare::APU::DSP bool latchEon : 1; //voice._echo }; - struct Latch - { - uint8_t adsr0; - uint16_t pitch; - uint16_t output; - };*/ + struct Latch + { + uint8_t adsr0; + uint16_t pitch; + uint16_t output; + };*/ class DSP { private: - //! @brief Number of samples per counter event - std::array _rateModulus = { - 0, 2048, 1536, 1280, 1024, 768, - 640, 512, 384, 320, 256, 192, - 160, 128, 96, 80, 64, 48, - 40, 32, 24, 20, 16, 12, - 10, 8, 6, 5, 4, 3, - 2, 1 - }; + //! @brief Number of samples per counter event + std::array _rateModulus = { + 0, 2048, 1536, 1280, 1024, 768, + 640, 512, 384, 320, 256, 192, + 160, 128, 96, 80, 64, 48, + 40, 32, 24, 20, 16, 12, + 10, 8, 6, 5, 4, 3, + 2, 1 + }; - //! @brief Counter offset - std::array _counterOffset = { - 0, 0, 1040, 536, 0, 1040, - 536, 0, 1040, 536, 0, 1040, - 536, 0, 1040, 536, 0, 1040, - 536, 0, 1040, 536, 0, 1040, - 536, 0, 1040, 536, 0, 1040, - 0,0 - }; + //! @brief Counter offset + std::array _counterOffset = { + 0, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 536, 0, 1040, 536, 0, 1040, + 0,0 + }; //! @brief Gaussian table used for making waves std::array _gauss = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, - 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, - 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, - 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, - 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, - 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, - 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, - 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, - 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, - 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, - 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, - 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, - 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, - 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, - 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, - 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, - 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, - 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, - 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, - 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, - 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, - 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, - 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, - 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, - 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, - 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, - 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305 - }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, + 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, + 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, + 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, + 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, + 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, + 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, + 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, + 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, + 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, + 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, + 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, + 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, + 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, + 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, + 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, + 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, + 969, 974, 978, 983, 988, 992, 997, 1001, 1005, 1010, 1014, 1019, 1023, 1027, 1032, 1036, + 1040, 1045, 1049, 1053, 1057, 1061, 1066, 1070, 1074, 1078, 1082, 1086, 1090, 1094, 1098, 1102, + 1106, 1109, 1113, 1117, 1121, 1125, 1128, 1132, 1136, 1139, 1143, 1146, 1150, 1153, 1157, 1160, + 1164, 1167, 1170, 1174, 1177, 1180, 1183, 1186, 1190, 1193, 1196, 1199, 1202, 1205, 1207, 1210, + 1213, 1216, 1219, 1221, 1224, 1227, 1229, 1232, 1234, 1237, 1239, 1241, 1244, 1246, 1248, 1251, + 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280, + 1282, 1283, 1284, 1286, 1287, 1288, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1297, 1298, + 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1303, 1303, 1304, 1304, 1304, 1304, 1304, 1305, 1305 + }; - //! @brief 8x voices of sample used to make sound - std::array _voices {}; - Master _master {}; - Echo _echo {}; - Noise _noise {}; - BRR _brr {}; - Latch _latch {}; - State _state {}; - Timer _timer {}; + //! @brief 8x voices of sample used to make sound + std::array _voices {}; + Master _master {}; + Echo _echo {}; + Noise _noise {}; + BRR _brr {}; + Latch _latch {}; + State _state {}; + Timer _timer {}; - void voiceOutput(Voice &voice, bool channel); - void voice1(Voice &voice); - void voice2(Voice &voice); - void voice3(Voice &voice); - void voice3a(Voice &voice); - void voice3b(Voice &voice); - void voice3c(Voice &voice); - void voice4(Voice &voice); - void voice5(Voice &voice); - void voice6(Voice &voice); - void voice7(Voice &voice); - void voice8(Voice &voice); - void voice9(Voice &voice); - void echo22(); - void echo23(); - void echo24(); - void echo25(); - void echo26(); - void echo27(); - void echo28(); - void echo29(); - void echo30(); - void misc27(); - void misc28(); - void misc29(); - void misc30(); + void voiceOutput(Voice &voice, bool channel); + void voice1(Voice &voice); + void voice2(Voice &voice); + void voice3(Voice &voice); + void voice3a(Voice &voice); + void voice3b(Voice &voice); + void voice3c(Voice &voice); + void voice4(Voice &voice); + void voice5(Voice &voice); + void voice6(Voice &voice); + void voice7(Voice &voice); + void voice8(Voice &voice); + void voice9(Voice &voice); + void echo22(); + void echo23(); + void echo24(); + void echo25(); + void echo26(); + void echo27(); + void echo28(); + void echo29(); + void echo30(); + void misc27(); + void misc28(); + void misc29(); + void misc30(); - int32_t interpolate(const Voice &voice); - void runEnvelope(Voice &voice); + int32_t interpolate(const Voice &voice); + void runEnvelope(Voice &voice); - void timerTick(); - bool timerPoll(uint32_t rate); + void timerTick(); + bool timerPoll(uint32_t rate); - void decodeBRR(Voice &voice); + void decodeBRR(Voice &voice); - std::weak_ptr _map; + std::weak_ptr _map; - uint8_t _readRAM(uint24_t addr); - void _writeRAM(uint24_t addr, uint8_t data); + uint8_t _readRAM(uint24_t addr); + void _writeRAM(uint24_t addr, uint8_t data); public: DSP(int16_t *buffer, int32_t size, std::weak_ptr map); DSP(const DSP &) = default; @@ -421,11 +421,11 @@ namespace ComSquare::APU::DSP //! @brief Return all 8 voices from DSP const std::array &getVoices() const; - const Master &getMaster() const; - const Echo &getEcho() const; - const Noise &getNoise() const; - const BRR &getBrr() const; - const Latch &getLatch() const; + const Master &getMaster() const; + const Echo &getEcho() const; + const Noise &getNoise() const; + const BRR &getBrr() const; + const Latch &getLatch() const; //! @brief Read from the internal DSP register. //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register. @@ -440,8 +440,8 @@ namespace ComSquare::APU::DSP //! @brief Get the name of this accessor (used for debug purpose) std::string getName() const; - //! @brief Execute current voice transformation - void update(); + //! @brief Execute current voice transformation + void update(); //! @brief Get the component of this accessor (used for debug purpose) Component getComponent() const; @@ -449,8 +449,8 @@ namespace ComSquare::APU::DSP //! @brief Get the size of the data. This size can be lower than the mapped data. //! @return The number of bytes inside this memory. uint24_t getSize() const; - //! @brief Return the number of samples written - int32_t getSamplesCount() const; + //! @brief Return the number of samples written + int32_t getSamplesCount() const; }; } diff --git a/sources/APU/DSP/Echo.cpp b/sources/APU/DSP/Echo.cpp index ed2b365..5b4d999 100644 --- a/sources/APU/DSP/Echo.cpp +++ b/sources/APU/DSP/Echo.cpp @@ -6,68 +6,68 @@ namespace ComSquare::APU::DSP { - void DSP::echo22() - { + void DSP::echo22() + { - } + } - void DSP::echo23() - { + void DSP::echo23() + { - } + } - void DSP::echo24() - { + void DSP::echo24() + { - } + } - void DSP::echo25() - { + void DSP::echo25() + { - } + } - void DSP::echo26() - { + void DSP::echo26() + { - } + } - void DSP::echo27() - { + void DSP::echo27() + { - } + } - void DSP::echo28() - { + void DSP::echo28() + { - } + } - void DSP::echo29() - { + void DSP::echo29() + { - } + } - void DSP::echo30() - { + void DSP::echo30() + { - } + } - void DSP::misc27() - { + void DSP::misc27() + { - } + } - void DSP::misc28() - { + void DSP::misc28() + { - } + } - void DSP::misc29() - { + void DSP::misc29() + { - } + } - void DSP::misc30() - { + void DSP::misc30() + { - } + } } \ No newline at end of file diff --git a/sources/APU/DSP/Envelope.cpp b/sources/APU/DSP/Envelope.cpp index 47f4aae..ca8b506 100644 --- a/sources/APU/DSP/Envelope.cpp +++ b/sources/APU/DSP/Envelope.cpp @@ -6,73 +6,73 @@ namespace ComSquare::APU::DSP { - void DSP::runEnvelope(Voice &voice) - { - int32_t envelope = voice.envelope; + void DSP::runEnvelope(Voice &voice) + { + int32_t envelope = voice.envelope; - if (voice.envelopeMode == Envelope::Release) { - envelope -= 0x08; - if (envelope < 0) - envelope = 0; - voice.envelope = envelope; - return; - } + if (voice.envelopeMode == Envelope::Release) { + envelope -= 0x08; + if (envelope < 0) + envelope = 0; + voice.envelope = envelope; + return; + } - int32_t rate; - int32_t mode; - int32_t data = voice.adsr2; - if (this->_latch.adsr1 & 0b10000000) { - if (voice.envelopeMode >= Envelope::Decay) { - envelope -= 1; - envelope -= envelope >> 8; - rate = data & 0b11111; - if (voice.envelopeMode == Envelope::Decay) - rate = ((this->_latch.adsr1 >> 3) & 0x0E) + 0x10; - } - else { - rate = ((this->_latch.adsr1 & 0b1111) << 1) + 1; - if (rate < 0b11111) - envelope += 0x20; - else - envelope += 0x400; - } - } - else { - data = voice.gain; - mode = data >> 5; - if (mode < 4) { - envelope = data << 4; - rate = 0b11111; - } - else { - rate = data & 0b11111; - if (mode == 4) - envelope -= 0x20; - else if (mode < 6) { - envelope -= 1; - envelope -= envelope >> 8; - } - else { - envelope += 0x20; - if (mode > 6 && voice.hiddenEnvelope >= 0x600) - envelope += 0x08 - 0x20; - } - } - } + int32_t rate; + int32_t mode; + int32_t data = voice.adsr2; + if (this->_latch.adsr1 & 0b10000000) { + if (voice.envelopeMode >= Envelope::Decay) { + envelope -= 1; + envelope -= envelope >> 8; + rate = data & 0b11111; + if (voice.envelopeMode == Envelope::Decay) + rate = ((this->_latch.adsr1 >> 3) & 0x0E) + 0x10; + } + else { + rate = ((this->_latch.adsr1 & 0b1111) << 1) + 1; + if (rate < 0b11111) + envelope += 0x20; + else + envelope += 0x400; + } + } + else { + data = voice.gain; + mode = data >> 5; + if (mode < 4) { + envelope = data << 4; + rate = 0b11111; + } + else { + rate = data & 0b11111; + if (mode == 4) + envelope -= 0x20; + else if (mode < 6) { + envelope -= 1; + envelope -= envelope >> 8; + } + else { + envelope += 0x20; + if (mode > 6 && voice.hiddenEnvelope >= 0x600) + envelope += 0x08 - 0x20; + } + } + } - if (envelope >> 8 == (data >> 5) && voice.envelopeMode == Envelope::Decay) - voice.envelopeMode = Envelope::Sustain; - voice.hiddenEnvelope = envelope; - if (static_cast(envelope) > 0x7FF) { - if (envelope < 0) - envelope = 0; - else - envelope = 0x7FF; - if (voice.envelopeMode == Envelope::Attack) - voice.envelopeMode = Envelope::Decay; - } + if (envelope >> 8 == (data >> 5) && voice.envelopeMode == Envelope::Decay) + voice.envelopeMode = Envelope::Sustain; + voice.hiddenEnvelope = envelope; + if (static_cast(envelope) > 0x7FF) { + if (envelope < 0) + envelope = 0; + else + envelope = 0x7FF; + if (voice.envelopeMode == Envelope::Attack) + voice.envelopeMode = Envelope::Decay; + } - if (this->timerPoll(rate)) - voice.envelope = envelope; - } + if (this->timerPoll(rate)) + voice.envelope = envelope; + } } \ No newline at end of file diff --git a/sources/APU/DSP/Gauss.cpp b/sources/APU/DSP/Gauss.cpp index c6ad58a..0b8003a 100644 --- a/sources/APU/DSP/Gauss.cpp +++ b/sources/APU/DSP/Gauss.cpp @@ -8,23 +8,23 @@ namespace ComSquare::APU::DSP { - int32_t DSP::interpolate(const Voice &voice) - { - int32_t interpolated; - uint8_t offset = voice.gaussOffset >> 4; - int forward = 255 - offset; - int reverse = offset; + int32_t DSP::interpolate(const Voice &voice) + { + int32_t interpolated; + uint8_t offset = voice.gaussOffset >> 4; + int forward = 255 - offset; + int reverse = offset; - offset = (voice.sampleOffset + (voice.gaussOffset >> 12)) % 12; - interpolated = this->_gauss[forward] * voice.samples[offset++] >> 11; - offset %= 12; - interpolated += this->_gauss[forward + 256] * voice.samples[offset++] >> 11; - offset %= 12; - interpolated += this->_gauss[reverse + 256] * voice.samples[offset++] >> 11; - offset %= 12; - interpolated = static_cast(interpolated); - interpolated += this->_gauss[reverse] * voice.samples[offset] >> 11; + offset = (voice.sampleOffset + (voice.gaussOffset >> 12)) % 12; + interpolated = this->_gauss[forward] * voice.samples[offset++] >> 11; + offset %= 12; + interpolated += this->_gauss[forward + 256] * voice.samples[offset++] >> 11; + offset %= 12; + interpolated += this->_gauss[reverse + 256] * voice.samples[offset++] >> 11; + offset %= 12; + interpolated = static_cast(interpolated); + interpolated += this->_gauss[reverse] * voice.samples[offset] >> 11; - return std::clamp(interpolated, 0, 16) & ~1; - } + return std::clamp(interpolated, 0, 16) & ~1; + } } \ No newline at end of file diff --git a/sources/APU/DSP/Timer.cpp b/sources/APU/DSP/Timer.cpp index 9e85488..1b060d4 100644 --- a/sources/APU/DSP/Timer.cpp +++ b/sources/APU/DSP/Timer.cpp @@ -6,17 +6,17 @@ namespace ComSquare::APU::DSP { - void DSP::timerTick() - { - if (!this->_timer.counter) - this->_timer.counter = 0x7800; - this->_timer.counter -= 1; - } + void DSP::timerTick() + { + if (!this->_timer.counter) + this->_timer.counter = 0x7800; + this->_timer.counter -= 1; + } - bool DSP::timerPoll(uint32_t rate) - { - if (!rate) - return false; - return (this->_timer.counter + this->_counterOffset[rate]) % this->_rateModulus[rate] == 0; - } + bool DSP::timerPoll(uint32_t rate) + { + if (!rate) + return false; + return (this->_timer.counter + this->_counterOffset[rate]) % this->_rateModulus[rate] == 0; + } } \ No newline at end of file diff --git a/sources/APU/DSP/Voice.cpp b/sources/APU/DSP/Voice.cpp index 680642d..eccc7a2 100644 --- a/sources/APU/DSP/Voice.cpp +++ b/sources/APU/DSP/Voice.cpp @@ -8,149 +8,149 @@ namespace ComSquare::APU::DSP { - void DSP::voiceOutput(Voice &voice, bool channel) - { - int out = this->_latch.output * voice.volume[channel] >> 7; + void DSP::voiceOutput(Voice &voice, bool channel) + { + int out = this->_latch.output * voice.volume[channel] >> 7; - this->_master.output[channel] += out; - if (!voice.echo) - return; - this->_echo.volume[channel] += out; - } + this->_master.output[channel] += out; + if (!voice.echo) + return; + this->_echo.volume[channel] += out; + } - void DSP::voice1(Voice &voice) - { - this->_brr.address = (this->_brr.offsetAddr << 8) + (this->_brr.source << 2); - this->_brr.source = voice.srcn; - } + void DSP::voice1(Voice &voice) + { + this->_brr.address = (this->_brr.offsetAddr << 8) + (this->_brr.source << 2); + this->_brr.source = voice.srcn; + } - void DSP::voice2(Voice &voice) - { - uint16_t addr = this->_brr.address; + void DSP::voice2(Voice &voice) + { + uint16_t addr = this->_brr.address; - if (!voice.konDelay) - addr += 2; - this->_brr.nextAddress = this->_readRAM(addr++); - this->_brr.nextAddress += this->_readRAM(addr++) << 8; - this->_latch.adsr1 = voice.adsr1; - this->_latch.pitch = voice.pitch & 0xFF; - } + if (!voice.konDelay) + addr += 2; + this->_brr.nextAddress = this->_readRAM(addr++); + this->_brr.nextAddress += this->_readRAM(addr++) << 8; + this->_latch.adsr1 = voice.adsr1; + this->_latch.pitch = voice.pitch & 0xFF; + } - void DSP::voice3(Voice &voice) - { - this->voice3a(voice); - this->voice3b(voice); - this->voice3c(voice); - } + void DSP::voice3(Voice &voice) + { + this->voice3a(voice); + this->voice3b(voice); + this->voice3c(voice); + } - void DSP::voice3a(Voice &voice) - { - this->_latch.pitch |= (voice.pitchH & 0x3F) << 8; - } + void DSP::voice3a(Voice &voice) + { + this->_latch.pitch |= (voice.pitchH & 0x3F) << 8; + } - void DSP::voice3b(Voice &voice) - { - this->_brr.header = this->_readRAM(this->_brr.address); - this->_brr.value = this->_readRAM(this->_brr.address + voice.brrOffset); - } + void DSP::voice3b(Voice &voice) + { + this->_brr.header = this->_readRAM(this->_brr.address); + this->_brr.value = this->_readRAM(this->_brr.address + voice.brrOffset); + } - void DSP::voice3c(Voice &voice) - { - if (voice.prevPmon) - this->_latch.pitch += (this->_latch.output >> 5) * this->_latch.pitch >> 10; + void DSP::voice3c(Voice &voice) + { + if (voice.prevPmon) + this->_latch.pitch += (this->_latch.output >> 5) * this->_latch.pitch >> 10; - if (voice.konDelay) { - if (voice.konDelay == 5) { - voice.brrAddress = this->_brr.nextAddress; - voice.brrOffset = 1; - voice.sampleOffset = 0; - this->_brr.header = 0; - } + if (voice.konDelay) { + if (voice.konDelay == 5) { + voice.brrAddress = this->_brr.nextAddress; + voice.brrOffset = 1; + voice.sampleOffset = 0; + this->_brr.header = 0; + } - voice.envelope = 0; - voice.hiddenEnvelope = 0; - voice.gaussOffset = 0; - voice.konDelay -= 1; - if (voice.konDelay & 3) - voice.gaussOffset = 0x4000; - this->_latch.pitch = 0; - } + voice.envelope = 0; + voice.hiddenEnvelope = 0; + voice.gaussOffset = 0; + voice.konDelay -= 1; + if (voice.konDelay & 3) + voice.gaussOffset = 0x4000; + this->_latch.pitch = 0; + } - int32_t interpolated = this->interpolate(voice); + int32_t interpolated = this->interpolate(voice); - if (voice.tempNon) - interpolated = this->_noise.lfsr << 1; + if (voice.tempNon) + interpolated = this->_noise.lfsr << 1; - this->_latch.output = interpolated * voice.envelope >> 11 & ~1; - voice.envx = voice.envelope >> 4; + this->_latch.output = interpolated * voice.envelope >> 11 & ~1; + voice.envx = voice.envelope >> 4; - if (this->_master.reset || (this->_brr.header & 3) == 1) { - voice.envelope = 0; - voice.envelopeMode = Envelope::Release; - } + if (this->_master.reset || (this->_brr.header & 3) == 1) { + voice.envelope = 0; + voice.envelopeMode = Envelope::Release; + } - if (this->_timer.sample) - { - if (voice.tempKof) - voice.envelopeMode = Envelope::Release; - if (voice.tempKon) { - voice.konDelay = 5; - voice.envelopeMode = Envelope::Attack; - } - } + if (this->_timer.sample) + { + if (voice.tempKof) + voice.envelopeMode = Envelope::Release; + if (voice.tempKon) { + voice.konDelay = 5; + voice.envelopeMode = Envelope::Attack; + } + } - if (!voice.konDelay) - this->runEnvelope(voice); - } + if (!voice.konDelay) + this->runEnvelope(voice); + } - void DSP::voice4(Voice &voice) - { - voice.loop = false; - if (voice.gaussOffset >= 0x4000) { - this->decodeBRR(voice); - voice.brrOffset += 2; - if (voice.brrOffset >= 9) { - voice.brrOffset = voice.brrAddress + 9; - if (this->_brr.header & 0b1) { - voice.brrAddress = this->_brr.nextAddress; - voice.loop = true; - } - voice.brrOffset = 1; - } - } + void DSP::voice4(Voice &voice) + { + voice.loop = false; + if (voice.gaussOffset >= 0x4000) { + this->decodeBRR(voice); + voice.brrOffset += 2; + if (voice.brrOffset >= 9) { + voice.brrOffset = voice.brrAddress + 9; + if (this->_brr.header & 0b1) { + voice.brrAddress = this->_brr.nextAddress; + voice.loop = true; + } + voice.brrOffset = 1; + } + } - voice.gaussOffset = (voice.gaussOffset & 0x3FFF) + this->_latch.pitch; - if (voice.gaussOffset > 0x7FFF) - voice.gaussOffset = 0x7FFF; - this->voiceOutput(voice, 0); - } + voice.gaussOffset = (voice.gaussOffset & 0x3FFF) + this->_latch.pitch; + if (voice.gaussOffset > 0x7FFF) + voice.gaussOffset = 0x7FFF; + this->voiceOutput(voice, 0); + } - void DSP::voice5(Voice &voice) - { - this->voiceOutput(voice, 1); + void DSP::voice5(Voice &voice) + { + this->voiceOutput(voice, 1); - voice.endx |= voice.loop; - if (voice.konDelay == 5) - voice.endx &= ~voice.endx; - } + voice.endx |= voice.loop; + if (voice.konDelay == 5) + voice.endx &= ~voice.endx; + } - void DSP::voice6(Voice &) - { - this->_latch.outx = this->_latch.output >> 8; - } + void DSP::voice6(Voice &) + { + this->_latch.outx = this->_latch.output >> 8; + } - void DSP::voice7(Voice &voice) - { + void DSP::voice7(Voice &voice) + { - } + } - void DSP::voice8(Voice &voice) - { + void DSP::voice8(Voice &voice) + { - } + } - void DSP::voice9(Voice &voice) - { + void DSP::voice9(Voice &voice) + { - } + } } \ No newline at end of file From bdd0f2375dacd13f50c868f2e6ae527309754c87 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Fri, 5 Feb 2021 16:39:14 +0100 Subject: [PATCH 07/26] Finishing all voices Starting echos (random sound generator) --- sources/APU/APU.hpp | 2 +- sources/APU/DSP/DSP.cpp | 7 ++--- sources/APU/DSP/DSP.hpp | 24 ++++++++++++---- sources/APU/DSP/Echo.cpp | 59 +++++++++++++++++++++++++++++++++++++-- sources/APU/DSP/Voice.cpp | 6 ++-- 5 files changed, 83 insertions(+), 15 deletions(-) diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 780ef58..aaf273e 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -144,7 +144,7 @@ namespace ComSquare::APU std::shared_ptr _map; //! @brief Total size of the buffer containing samples - static constexpr int32_t bufferSize = 0x20000; + static constexpr int32_t bufferSize = 0x10000; //! @brief Buffer containing samples to be played int16_t _soundBuffer[bufferSize]; diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 2321ae7..a3036a0 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -8,11 +8,10 @@ namespace ComSquare::APU::DSP { - DSP::DSP(int16_t *buffer, int32_t size, std::weak_ptr map) : _map(map) + DSP::DSP(int16_t *buffer, uint32_t size, std::weak_ptr map) : _map(map) { this->_state.buffer = buffer; - this->_state.bufferStart = buffer; - this->_state.bufferEnd = buffer + size; + this->_state.bufferSize = size; } uint8_t DSP::read(uint24_t addr) const @@ -796,6 +795,6 @@ namespace ComSquare::APU::DSP int32_t DSP::getSamplesCount() const { - return this->_state.buffer - this->_state.bufferStart; + return this->_state.bufferOffset; } } \ No newline at end of file diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 4ea52f4..3ae3fd0 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -46,12 +46,20 @@ namespace ComSquare::APU::DSP std::array FIR; //! @brief Echo data start register (ESA) uint8_t data; + //! @brief Offset position after data start + uint16_t offset; //! @brief Echo delay size register (EDL) uint8_t delay; //! @brief Echo enabled (5th bit FLG) bool enabled = true; //! @brief Last sound produced for each voice in each channel std::array, 2> history; + //! @brief Current position inside history + uint8_t historyOffset; + //! @brief Address of the current echo + uint16_t address; + //! @brief Current of value of the echo + uint8_t value; //! @brief Current sound to echo std::array input; //! @brief Current sound echoed produced @@ -123,6 +131,8 @@ namespace ComSquare::APU::DSP uint8_t gain; //! @brief envelope associated with this voice uint8_t envx; + //! @brief Wave height associated with this voice + uint8_t outx; //! @brief Sample end register (ENDX) bool endx : 1; @@ -176,10 +186,10 @@ namespace ComSquare::APU::DSP uint8_t voice = 0; //! @brief Current buffer of samples int16_t *buffer; - //! @brief Limit of the buffer - int16_t *bufferEnd; - //! @brief Beginning of the buffer - int16_t *bufferStart; + //! @brief Size of buffer + uint32_t bufferSize; + //! @brief Current position in the buffer of samples + uint32_t bufferOffset; }; struct Timer { @@ -404,6 +414,10 @@ namespace ComSquare::APU::DSP int32_t interpolate(const Voice &voice); void runEnvelope(Voice &voice); + int32_t loadFIR(bool channel, int fir); + void loadEcho(bool channel); + int16_t outputEcho(bool channel); + void timerTick(); bool timerPoll(uint32_t rate); @@ -414,7 +428,7 @@ namespace ComSquare::APU::DSP uint8_t _readRAM(uint24_t addr); void _writeRAM(uint24_t addr, uint8_t data); public: - DSP(int16_t *buffer, int32_t size, std::weak_ptr map); + DSP(int16_t *buffer, uint32_t size, std::weak_ptr map); DSP(const DSP &) = default; DSP &operator=(const DSP &) = default; ~DSP() = default; diff --git a/sources/APU/DSP/Echo.cpp b/sources/APU/DSP/Echo.cpp index 5b4d999..51823c4 100644 --- a/sources/APU/DSP/Echo.cpp +++ b/sources/APU/DSP/Echo.cpp @@ -6,34 +6,89 @@ namespace ComSquare::APU::DSP { + int32_t DSP::loadFIR(bool channel, int fir) + { + int32_t sample = this->_echo.history[channel][this->_echo.historyOffset + fir + 1]; + + return (sample * this->_echo.FIR[fir]) >> 6; + } + + void DSP::loadEcho(bool channel) + { + uint16_t address = this->_echo.address + channel * 2; + uint8_t low = this->_readRAM(address++); + uint8_t high = this->_readRAM(address); + int16_t echo = (high << 8) + low; + + this->_echo.history[channel][this->_echo.historyOffset] = echo >> 1; + } + + int16_t DSP::outputEcho(bool channel) + { + int16_t master = this->_master.output[channel] * this->_master.volume[channel] >> 7; + int16_t echo = this->_echo.input[channel] * this->_echo.input[channel] >> 7; + + return master + echo; + } + void DSP::echo22() { + this->_echo.historyOffset += 1; + this->_echo.address = (this->_echo.value << 8) + this->_echo.offset; + this->loadEcho(0); + + this->_echo.input[0] = this->loadFIR(0, 0); + this->_echo.input[1] = this->loadFIR(1, 0); } void DSP::echo23() { + this->loadEcho(1); + this->_echo.input[0] += this->loadFIR(0, 1) + this->loadFIR(0, 2); + this->_echo.input[1] += this->loadFIR(1, 1) + this->loadFIR(1, 2); } void DSP::echo24() { - + this->_echo.input[0] += this->loadFIR(0, 3) + this->loadFIR(0, 4) + this->loadFIR(0, 5); + this->_echo.input[1] += this->loadFIR(1, 3) + this->loadFIR(1, 4) + this->loadFIR(1, 5); } void DSP::echo25() { - + this->_echo.input[0] += this->loadFIR(0, 6) + this->loadFIR(0, 7); + this->_echo.input[1] += this->loadFIR(1, 6) + this->loadFIR(1, 7); } void DSP::echo26() { + this->_master.output[0] = this->outputEcho(0); + this->_echo.output[0] += this->_echo.input[0] * this->_echo.feedback >> 7; + this->_echo.output[1] += this->_echo.input[1] * this->_echo.feedback >> 7; } void DSP::echo27() { + int16_t outputLeft = this->_master.output[0]; + int16_t outputRight = this->outputEcho(1); + this->_master.output[0] = 0; + this->_master.output[1] = 0; + + if (this->_master.mute) { + outputLeft = 0; + outputRight = 0; + } + + srand(time(NULL)); + this->_state.buffer[this->_state.bufferOffset] = outputLeft + (INT16_MIN + rand() % (INT16_MAX + 1 - INT16_MIN)); + this->_state.buffer[this->_state.bufferOffset + 1] = outputRight + (INT16_MIN + rand() % (INT16_MAX + 1 - INT16_MIN)); + this->_state.bufferOffset += 2; + if (this->_state.bufferOffset >= this->_state.bufferSize) + this->_state.bufferOffset = 0; } void DSP::echo28() diff --git a/sources/APU/DSP/Voice.cpp b/sources/APU/DSP/Voice.cpp index eccc7a2..197885b 100644 --- a/sources/APU/DSP/Voice.cpp +++ b/sources/APU/DSP/Voice.cpp @@ -141,16 +141,16 @@ namespace ComSquare::APU::DSP void DSP::voice7(Voice &voice) { - + this->_latch.envx = voice.envx; } void DSP::voice8(Voice &voice) { - + voice.outx = this->_latch.outx; } void DSP::voice9(Voice &voice) { - + voice.envx = this->_latch.envx; } } \ No newline at end of file From b33d816b625b043e8e37249e2a320a48b2c9a289 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Fri, 5 Feb 2021 17:29:37 +0100 Subject: [PATCH 08/26] Finishing all Echo functions --- sources/APU/DSP/DSP.hpp | 5 ++++ sources/APU/DSP/Echo.cpp | 51 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 3ae3fd0..6de6b07 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -48,10 +48,14 @@ namespace ComSquare::APU::DSP uint8_t data; //! @brief Offset position after data start uint16_t offset; + //! @brief offset maximum + uint16_t length; //! @brief Echo delay size register (EDL) uint8_t delay; //! @brief Echo enabled (5th bit FLG) bool enabled = true; + //! @brief Application of enabled to channels. + bool toggle; //! @brief Last sound produced for each voice in each channel std::array, 2> history; //! @brief Current position inside history @@ -417,6 +421,7 @@ namespace ComSquare::APU::DSP int32_t loadFIR(bool channel, int fir); void loadEcho(bool channel); int16_t outputEcho(bool channel); + void writeEcho(bool channel); void timerTick(); bool timerPoll(uint32_t rate); diff --git a/sources/APU/DSP/Echo.cpp b/sources/APU/DSP/Echo.cpp index 51823c4..d11a444 100644 --- a/sources/APU/DSP/Echo.cpp +++ b/sources/APU/DSP/Echo.cpp @@ -23,6 +23,18 @@ namespace ComSquare::APU::DSP this->_echo.history[channel][this->_echo.historyOffset] = echo >> 1; } + void DSP::writeEcho(bool channel) + { + if (!this->_echo.toggle) { + uint16_t address = this->_echo.address + channel * 2; + int16_t sample = this->_echo.output[channel]; + + this->_writeRAM(address++, sample); + this->_writeRAM(address, sample >> 8); + } + this->_echo.output[channel] = 0; + } + int16_t DSP::outputEcho(bool channel) { int16_t master = this->_master.output[channel] * this->_master.volume[channel] >> 7; @@ -93,36 +105,65 @@ namespace ComSquare::APU::DSP void DSP::echo28() { - + this->_echo.toggle = this->_echo.enabled; } void DSP::echo29() { + this->_echo.value = this->_echo.data; + if (!this->_echo.offset) + this->_echo.length = this->_echo.delay << 11; + + this->_echo.offset += 4; + if (this->_echo.offset >= this->_echo.length) + this->_echo.offset = 0; + + this->writeEcho(0); + + echo28(); } void DSP::echo30() { - + this->writeEcho(1); } void DSP::misc27() { - + for (int i = 0; i < 8; i++) + this->_voices[i].prevPmon = this->_voices[i].pmon; } void DSP::misc28() { - + for (int i = 0; i < 8; i++) + this->_voices[i].tempNon = this->_voices[i].non; + this->_brr.offsetAddr = this->_brr.offset; } void DSP::misc29() { - + this->_timer.sample = !this->_timer.sample; + if (this->_timer.sample) { + for (int i = 0; i < 8; i++) + this->_voices[i].kon = 0; + } } void DSP::misc30() { + if (this->_timer.sample) { + for (int i = 0; i < 8; i++) + this->_voices[i].kof = 0; + } + this->timerTick(); + + if (!this->timerPoll(this->_noise.clock)) + return; + int32_t feedback = this->_noise.lfsr << 13 ^ this->_noise.lfsr << 14; + + this->_noise.lfsr = feedback & 0x4000 ^ this->_noise.lfsr >> 1; } } \ No newline at end of file From 3f869f7929c06e0b40864e7d378782bc566ea2b6 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 12:14:38 +0100 Subject: [PATCH 09/26] Remove random testing --- sources/APU/DSP/Echo.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sources/APU/DSP/Echo.cpp b/sources/APU/DSP/Echo.cpp index d11a444..83c013b 100644 --- a/sources/APU/DSP/Echo.cpp +++ b/sources/APU/DSP/Echo.cpp @@ -95,9 +95,8 @@ namespace ComSquare::APU::DSP outputRight = 0; } - srand(time(NULL)); - this->_state.buffer[this->_state.bufferOffset] = outputLeft + (INT16_MIN + rand() % (INT16_MAX + 1 - INT16_MIN)); - this->_state.buffer[this->_state.bufferOffset + 1] = outputRight + (INT16_MIN + rand() % (INT16_MAX + 1 - INT16_MIN)); + this->_state.buffer[this->_state.bufferOffset] = outputLeft; + this->_state.buffer[this->_state.bufferOffset + 1] = outputRight; this->_state.bufferOffset += 2; if (this->_state.bufferOffset >= this->_state.bufferSize) this->_state.bufferOffset = 0; @@ -164,6 +163,6 @@ namespace ComSquare::APU::DSP return; int32_t feedback = this->_noise.lfsr << 13 ^ this->_noise.lfsr << 14; - this->_noise.lfsr = feedback & 0x4000 ^ this->_noise.lfsr >> 1; + this->_noise.lfsr = (feedback & 0x4000) ^ this->_noise.lfsr >> 1; } } \ No newline at end of file From 850f3b8ef21113923647155a8445f7d4703a0037 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 12:21:25 +0100 Subject: [PATCH 10/26] Fixing warning & fixing tab --- sources/APU/APU.cpp | 2 +- sources/APU/DSP/Voice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 84d28bb..0d26352 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -11,7 +11,7 @@ namespace ComSquare::APU { APU::APU(Renderer::IRenderer &renderer) : - _renderer(renderer), + _renderer(renderer), _map(new MemoryMap()), _soundBuffer(), _dsp(_soundBuffer, APU::bufferSize / 2, _map) diff --git a/sources/APU/DSP/Voice.cpp b/sources/APU/DSP/Voice.cpp index 197885b..324e07e 100644 --- a/sources/APU/DSP/Voice.cpp +++ b/sources/APU/DSP/Voice.cpp @@ -131,7 +131,7 @@ namespace ComSquare::APU::DSP voice.endx |= voice.loop; if (voice.konDelay == 5) - voice.endx &= ~voice.endx; + voice.endx = 0x00; } void DSP::voice6(Voice &) From 7555227e208f862c17f7eb74f887b5c37fd9af84 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 13:49:56 +0100 Subject: [PATCH 11/26] Fixing more tabs --- sources/APU/DSP/DSP.hpp | 125 ++----------------------- sources/Debugger/APUDebug.cpp | 10 +- sources/Renderer/IRenderer.hpp | 6 +- sources/Renderer/NoRenderer.cpp | 6 +- sources/Renderer/NoRenderer.hpp | 8 +- sources/Renderer/QtRenderer/QtSFML.cpp | 4 +- sources/Renderer/QtRenderer/QtSFML.hpp | 10 +- sources/Renderer/SFRenderer.cpp | 12 +-- sources/Renderer/SFRenderer.hpp | 8 +- 9 files changed, 40 insertions(+), 149 deletions(-) diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 6de6b07..284b8c8 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -203,123 +203,6 @@ namespace ComSquare::APU::DSP bool sample = true; }; - /*//! @brief All the registers of the DSP - struct Registers { - //! @brief Main Volume register - std::array mVol; //master.volume - - //! @brief Echo Volume register - std::array eVol; //echo.volume - - //! @brief Flags register - union { - struct { - uint8_t noiseClock : 5; //noise.frequency - bool ecen : 1; //echo.readonly - bool mute : 1; //master.mute - bool reset : 1; //master.reset - }; - uint8_t flg; - }; - - //! @brief Echo feedback register - uint8_t efb; //echo.feedback - - //! @brief Not used register - uint8_t unused; - - //! @brief Source Directory offset register - uint8_t dir; //brr.bank - - //! @brief Echo data start register - uint8_t esa; //echo.bank - //! @brief Echo delay size register - uint8_t edl; //echo.delay - }; - - struct BRR { - //! @brief BRR Header - union { - struct { - //! @brief Shift value range - unsigned range : 4; - //! @brief Decompression filter - unsigned filter : 2; - //! @brief Flag if the sample loops - bool loop : 1; - //! @brief Stop the sample (or restart from loop point) - bool end : 1; - }; - uint8_t head; - }; - //! @brief Sample data inside BRR - uint64_t block; - }; - - struct Voice { - //! @brief Volume register - std::array volume; //voice.volume - - union { - struct { - //! @brief Lower 8 bits of pitch register - uint8_t pitchL; - //! @brief Higher 8 bits of pitch register - uint8_t pitchH; - }; - uint16_t pitch; //voice.pitch - }; - - //! @brief Source number register - uint8_t srcn; //voice.source - - union { - struct { - //! @brief Envelope register - uint8_t adsr1; //voice.adsr0 - //! @brief Envelope controllers register - uint8_t adsr2; //voice.adsr1 - }; - uint16_t envelope; - }; - - //! @brief Gain register - uint8_t gain; //voice.gain - - //! @brief Envelope value register - uint8_t envx; //latch.envx - //! @brief Wave height register - uint8_t outx; //latch.outx - - //! @brief Key On register - bool kon : 1; //voice.keyon - //! @brief Key Off register - bool kof : 1; //voice.keyoff - bool keyLatch : 1; //voice._keylatch - - //! @brief Sample end register - bool endx : 1; //voice._end - //! @brief Noise enable register - bool non : 1; //voice.noise - //! @brief Echo enable register - bool eon : 1; //voice.echo - - //! @brief Pitch modulation register - bool pmon : 1; //voice.modulate - - //! @brief Echo FIR filter coefficients - uint8_t coeff; //echo.fir - - bool latchEon : 1; //voice._echo - }; - - struct Latch - { - uint8_t adsr0; - uint16_t pitch; - uint16_t output; - };*/ - class DSP { private: //! @brief Number of samples per counter event @@ -415,7 +298,9 @@ namespace ComSquare::APU::DSP void misc29(); void misc30(); + //! @brief Interpolate voice samples with gauss table int32_t interpolate(const Voice &voice); + //! @brief Modify voice samples with its envelope void runEnvelope(Voice &voice); int32_t loadFIR(bool channel, int fir); @@ -423,14 +308,20 @@ namespace ComSquare::APU::DSP int16_t outputEcho(bool channel); void writeEcho(bool channel); + //! @brief Remove one tick from timer void timerTick(); + //! @brief Check if timer value is equal to rate value bool timerPoll(uint32_t rate); + //! @brief Transform BRR value to samples void decodeBRR(Voice &voice); + //! @brief Whole APU RAM map std::weak_ptr _map; + //! @brief Read inside APU RAM uint8_t _readRAM(uint24_t addr); + //! @brief Write into APU RAM void _writeRAM(uint24_t addr, uint8_t data); public: DSP(int16_t *buffer, uint32_t size, std::weak_ptr map); diff --git a/sources/Debugger/APUDebug.cpp b/sources/Debugger/APUDebug.cpp index fa768b5..3222f8d 100644 --- a/sources/Debugger/APUDebug.cpp +++ b/sources/Debugger/APUDebug.cpp @@ -97,11 +97,11 @@ namespace ComSquare::Debugger this->_ui.evolRprogressBar->setValue(echo.volume[1]); this->_ui.echoprogressBar->setValue(echo.feedback); - uint8_t flg = 0; - flg += master.reset << 7; - flg += master.mute << 6; - flg += echo.enabled << 5; - flg += noise.clock; + uint8_t flg = 0; + flg += master.reset << 7; + flg += master.mute << 6; + flg += echo.enabled << 5; + flg += noise.clock; this->_ui.flagslineEdit->setText(Utility::to_binary(flg).c_str()); this->_ui.sourceDirectoryLineEdit->setText(Utility::to_hex(brr.offset).c_str()); this->_ui.echoBufferOffsetLineEdit->setText(Utility::to_hex(echo.data).c_str()); diff --git a/sources/Renderer/IRenderer.hpp b/sources/Renderer/IRenderer.hpp index 43b4aba..7ce97cb 100644 --- a/sources/Renderer/IRenderer.hpp +++ b/sources/Renderer/IRenderer.hpp @@ -31,9 +31,9 @@ namespace ComSquare //! @param maxFPS The number of FPS you aim to run on. virtual void createWindow(SNES &snes, int maxFPS) = 0; - //! @brief Playing all samples from buffer - //! @param samples Buffer containing samples - //! @param sampleCount number of samples inside buffer + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer virtual void playAudio(int16_t *samples, uint64_t sampleCount) = 0; }; } diff --git a/sources/Renderer/NoRenderer.cpp b/sources/Renderer/NoRenderer.cpp index 505ebcc..2ff3757 100644 --- a/sources/Renderer/NoRenderer.cpp +++ b/sources/Renderer/NoRenderer.cpp @@ -20,9 +20,9 @@ namespace ComSquare::Renderer (void)rgba; } - void NoRenderer::playAudio(int16_t *, uint64_t) - { - } + void NoRenderer::playAudio(int16_t *, uint64_t) + { + } void NoRenderer::getEvents() { } diff --git a/sources/Renderer/NoRenderer.hpp b/sources/Renderer/NoRenderer.hpp index 37fd940..149e92e 100644 --- a/sources/Renderer/NoRenderer.hpp +++ b/sources/Renderer/NoRenderer.hpp @@ -22,10 +22,10 @@ namespace ComSquare::Renderer //! @param Y vertical index. //! @param rgba The color of the pixel. void putPixel(unsigned y, unsigned x, uint32_t rgba) override; - //! @brief Playing all samples from buffer - //! @param samples Buffer containing samples - //! @param sampleCount number of samples inside buffer - void playAudio(int16_t *samples, uint64_t sampleCount) override; + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer + void playAudio(int16_t *samples, uint64_t sampleCount) override; //! @brief Get the inputs from the Window void getEvents(); //! @brief Use this function to create the window. diff --git a/sources/Renderer/QtRenderer/QtSFML.cpp b/sources/Renderer/QtRenderer/QtSFML.cpp index d7baf96..53d1e35 100644 --- a/sources/Renderer/QtRenderer/QtSFML.cpp +++ b/sources/Renderer/QtRenderer/QtSFML.cpp @@ -12,7 +12,7 @@ #ifdef Q_WS_X11 #include - #include + #include #endif namespace ComSquare::Renderer @@ -87,7 +87,7 @@ namespace ComSquare::Renderer void QtSFML::playAudio(int16_t *samples, uint64_t sampleCount) { - this->_sfWidget->playAudio(samples, sampleCount); + this->_sfWidget->playAudio(samples, sampleCount); } void QtSFML::drawScreen() { } diff --git a/sources/Renderer/QtRenderer/QtSFML.hpp b/sources/Renderer/QtRenderer/QtSFML.hpp index 7d1791a..204a046 100644 --- a/sources/Renderer/QtRenderer/QtSFML.hpp +++ b/sources/Renderer/QtRenderer/QtSFML.hpp @@ -65,11 +65,11 @@ namespace ComSquare::Renderer void putPixel(unsigned y, unsigned x, uint32_t rgba) override; //! @brief This function doesn't do anything because QT internally handle drawing to the screen. void drawScreen() override; - //! @brief Playing all samples from buffer - //! @param samples Buffer containing samples - //! @param sampleCount number of samples inside buffer - void playAudio(int16_t *samples, uint64_t sampleCount) override; - //! @brief Set a new name to the window, if there is already a name it will be overwrite. + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer + void playAudio(int16_t *samples, uint64_t sampleCount) override; + //! @brief Set a new name to the window, if there is already a name it will be overwrite. //! @param newWindowName new title for the window. void setWindowName(std::string &newWindowName) override; //! @brief Constructor that return a SFML renderer inside a QT window. diff --git a/sources/Renderer/SFRenderer.cpp b/sources/Renderer/SFRenderer.cpp index a7c99b3..faae54b 100644 --- a/sources/Renderer/SFRenderer.cpp +++ b/sources/Renderer/SFRenderer.cpp @@ -18,8 +18,8 @@ namespace ComSquare::Renderer this->_texture.create(width, height); this->_sprite.setTexture(this->_texture); this->_pixelBuffer = new sf::Color[height * width]; - this->_sound.setBuffer(this->_soundBuffer); - } + this->_sound.setBuffer(this->_soundBuffer); + } void SFRenderer::createWindow(SNES &snes, int maxFPS) { @@ -55,10 +55,10 @@ namespace ComSquare::Renderer } void SFRenderer::playAudio(int16_t *samples, uint64_t sampleCount) - { - this->_soundBuffer.loadFromSamples(samples, sampleCount, 2, 32040); - this->_sound.play(); - } + { + this->_soundBuffer.loadFromSamples(samples, sampleCount, 2, 32040); + this->_sound.play(); + } void SFRenderer::putPixel(unsigned y, unsigned x, uint32_t rgba) { diff --git a/sources/Renderer/SFRenderer.hpp b/sources/Renderer/SFRenderer.hpp index 9d902c8..8cceb3b 100644 --- a/sources/Renderer/SFRenderer.hpp +++ b/sources/Renderer/SFRenderer.hpp @@ -40,7 +40,7 @@ namespace ComSquare::Renderer //! @brief The buffer containing samples to be played sf::SoundBuffer _soundBuffer; //! @brief the sound played - sf::Sound _sound; + sf::Sound _sound; public: //! @brief Tells to the program if the window has been closed, and therefore if he should stop bool shouldExit = false; @@ -54,9 +54,9 @@ namespace ComSquare::Renderer //! @param Y vertical index. //! @param rgba The color of the pixel. void putPixel(unsigned y, unsigned x, uint32_t rgba) override; - //! @brief Playing all samples from buffer - //! @param samples Buffer containing samples - //! @param sampleCount number of samples inside buffer + //! @brief Playing all samples from buffer + //! @param samples Buffer containing samples + //! @param sampleCount number of samples inside buffer void playAudio(int16_t *samples, uint64_t sampleCount) override; //! @brief Get the inputs from the Window void getEvents(); From 8a32689a4cc7466e7460fbd5c8b66fc480ce7021 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 13:51:38 +0100 Subject: [PATCH 12/26] Tabs... --- sources/APU/APU.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index aaf273e..937ae86 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -144,12 +144,12 @@ namespace ComSquare::APU std::shared_ptr _map; //! @brief Total size of the buffer containing samples - static constexpr int32_t bufferSize = 0x10000; - //! @brief Buffer containing samples to be played + static constexpr int32_t bufferSize = 0x10000; + //! @brief Buffer containing samples to be played int16_t _soundBuffer[bufferSize]; - //! @brief The DSP component used to produce sound - DSP::DSP _dsp; + //! @brief The DSP component used to produce sound + DSP::DSP _dsp; //! @brief Read from the APU ram. //! @param addr The address to read from. The address 0x0000 should refer to the first byte of the register. From b976b16f439a3ea1ce30876b8325b7ca0b244b69 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 15:06:34 +0100 Subject: [PATCH 13/26] tabs --- sources/APU/APU.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 0d26352..b80c6e6 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -713,7 +713,7 @@ namespace ComSquare::APU void APU::update(unsigned cycles) { unsigned total = 0; - int32_t samples = 0; + int32_t samples = 0; if (this->_paddingCycles > cycles) { this->_paddingCycles -= cycles; @@ -726,9 +726,9 @@ namespace ComSquare::APU this->_paddingCycles = total - cycles; this->_dsp.update(); - samples = this->_dsp.getSamplesCount(); - if (samples > 0) - this->_renderer.playAudio(this->_soundBuffer, samples / 2); + samples = this->_dsp.getSamplesCount(); + if (samples > 0) + this->_renderer.playAudio(this->_soundBuffer, samples / 2); } void APU::_setNZflags(uint8_t value) @@ -741,6 +741,6 @@ namespace ComSquare::APU Page0(0x00F0, Apu, "APU's Page 0"), Page1(0x0100, Apu, "APU's Page 1"), Memory(0xFDC0, Apu, "APU's Ram"), - IPL(Apu, "IPL Rom") + IPL(Apu, "IPL Rom") { } } \ No newline at end of file From 18bf27c31813bd979c3c99da27a4e963e150962a Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 16:13:09 +0100 Subject: [PATCH 14/26] Using std::array instead of a raw pointer --- sources/APU/APU.cpp | 4 ++-- sources/APU/APU.hpp | 4 +--- sources/APU/DSP/DSP.cpp | 3 ++- sources/APU/DSP/DSP.hpp | 8 +++++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index b80c6e6..221af87 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -14,7 +14,7 @@ namespace ComSquare::APU _renderer(renderer), _map(new MemoryMap()), _soundBuffer(), - _dsp(_soundBuffer, APU::bufferSize / 2, _map) + _dsp(this->_soundBuffer, this->_soundBuffer.size() / 2, _map) { this->reset(); } @@ -728,7 +728,7 @@ namespace ComSquare::APU this->_dsp.update(); samples = this->_dsp.getSamplesCount(); if (samples > 0) - this->_renderer.playAudio(this->_soundBuffer, samples / 2); + this->_renderer.playAudio(this->_soundBuffer.data(), samples / 2); } void APU::_setNZflags(uint8_t value) diff --git a/sources/APU/APU.hpp b/sources/APU/APU.hpp index 937ae86..a56a0d6 100644 --- a/sources/APU/APU.hpp +++ b/sources/APU/APU.hpp @@ -143,10 +143,8 @@ namespace ComSquare::APU //! @brief Internal APU memory separated according to their utility std::shared_ptr _map; - //! @brief Total size of the buffer containing samples - static constexpr int32_t bufferSize = 0x10000; //! @brief Buffer containing samples to be played - int16_t _soundBuffer[bufferSize]; + std::array _soundBuffer; //! @brief The DSP component used to produce sound DSP::DSP _dsp; diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index a3036a0..fbc570a 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -8,7 +8,8 @@ namespace ComSquare::APU::DSP { - DSP::DSP(int16_t *buffer, uint32_t size, std::weak_ptr map) : _map(map) + DSP::DSP(std::array &buffer, uint32_t size, std::weak_ptr map) : + _state(buffer), _map(map) { this->_state.buffer = buffer; this->_state.bufferSize = size; diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index 284b8c8..e4f542d 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -186,10 +186,12 @@ namespace ComSquare::APU::DSP //! @brief Current state of the DSP struct State { + State(std::array &array) : buffer(array) {}; + //! @brief Current voice modification to do uint8_t voice = 0; //! @brief Current buffer of samples - int16_t *buffer; + std::array &buffer; //! @brief Size of buffer uint32_t bufferSize; //! @brief Current position in the buffer of samples @@ -268,7 +270,7 @@ namespace ComSquare::APU::DSP Noise _noise {}; BRR _brr {}; Latch _latch {}; - State _state {}; + State _state; Timer _timer {}; void voiceOutput(Voice &voice, bool channel); @@ -324,7 +326,7 @@ namespace ComSquare::APU::DSP //! @brief Write into APU RAM void _writeRAM(uint24_t addr, uint8_t data); public: - DSP(int16_t *buffer, uint32_t size, std::weak_ptr map); + DSP(std::array &buffer, uint32_t size, std::weak_ptr map); DSP(const DSP &) = default; DSP &operator=(const DSP &) = default; ~DSP() = default; From 6a063a40bf557af6f8738c86fcfb3b242ef515ce Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Wed, 10 Feb 2021 16:15:53 +0100 Subject: [PATCH 15/26] Fixing lock --- sources/APU/DSP/DSP.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index fbc570a..781684b 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -568,7 +568,10 @@ namespace ComSquare::APU::DSP throw InvalidAddress("DSP Registers write", addr); } } - uint8_t DSP::_readRAM(uint24_t addr) { + uint8_t DSP::_readRAM(uint24_t addr) + { + if (!this->_map.lock()) + throw InvalidAddress("DSP read", addr); switch (addr) { case 0x0000 ... 0x00EF: return this->_map.lock()->Page0.read(addr); @@ -583,7 +586,10 @@ namespace ComSquare::APU::DSP } } - void DSP::_writeRAM(uint24_t addr, uint8_t data) { + void DSP::_writeRAM(uint24_t addr, uint8_t data) + { + if (!this->_map.lock()) + throw InvalidAddress("DSP write", addr); switch (addr) { case 0x0000 ... 0x00EF: this->_map.lock()->Page0.write(addr, data); From ed188e0e63e844cb74031bb384ad39e09bdb5ed2 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 09:43:58 +0100 Subject: [PATCH 16/26] Update C++ to v20 Using span inside renderers --- CMakeLists.txt | 2 +- sources/APU/APU.cpp | 2 +- sources/CPU/Instruction.hpp | 5 ----- sources/Renderer/IRenderer.hpp | 3 ++- sources/Renderer/NoRenderer.cpp | 2 +- sources/Renderer/NoRenderer.hpp | 2 +- sources/Renderer/QtRenderer/QtSFML.cpp | 2 +- sources/Renderer/QtRenderer/QtSFML.hpp | 2 +- sources/Renderer/SFRenderer.cpp | 4 ++-- sources/Renderer/SFRenderer.hpp | 2 +- 10 files changed, 11 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28b1656..f38def3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.12) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) # set the project name project(ComSquare) diff --git a/sources/APU/APU.cpp b/sources/APU/APU.cpp index 221af87..8613883 100644 --- a/sources/APU/APU.cpp +++ b/sources/APU/APU.cpp @@ -728,7 +728,7 @@ namespace ComSquare::APU this->_dsp.update(); samples = this->_dsp.getSamplesCount(); if (samples > 0) - this->_renderer.playAudio(this->_soundBuffer.data(), samples / 2); + this->_renderer.playAudio(std::span{this->_soundBuffer}, samples / 2); } void APU::_setNZflags(uint8_t value) diff --git a/sources/CPU/Instruction.hpp b/sources/CPU/Instruction.hpp index f6ef811..59115c1 100644 --- a/sources/CPU/Instruction.hpp +++ b/sources/CPU/Instruction.hpp @@ -55,11 +55,6 @@ namespace ComSquare::CPU std::string name = ""; AddressingMode addressingMode = Implied; int size = 0; - - Instruction() = default; - Instruction(const Instruction &) = default; - Instruction &operator=(const Instruction &) = default; - ~Instruction() = default; }; } #endif //COMSQUARE_INSTRUCTION_HPP diff --git a/sources/Renderer/IRenderer.hpp b/sources/Renderer/IRenderer.hpp index 7ce97cb..a81a4ec 100644 --- a/sources/Renderer/IRenderer.hpp +++ b/sources/Renderer/IRenderer.hpp @@ -6,6 +6,7 @@ #define COMSQUARE_IRENDERER_HPP #include +#include namespace ComSquare { @@ -34,7 +35,7 @@ namespace ComSquare //! @brief Playing all samples from buffer //! @param samples Buffer containing samples //! @param sampleCount number of samples inside buffer - virtual void playAudio(int16_t *samples, uint64_t sampleCount) = 0; + virtual void playAudio(std::span samples, uint64_t sampleCount) = 0; }; } } diff --git a/sources/Renderer/NoRenderer.cpp b/sources/Renderer/NoRenderer.cpp index 2ff3757..3eec68b 100644 --- a/sources/Renderer/NoRenderer.cpp +++ b/sources/Renderer/NoRenderer.cpp @@ -20,7 +20,7 @@ namespace ComSquare::Renderer (void)rgba; } - void NoRenderer::playAudio(int16_t *, uint64_t) + void NoRenderer::playAudio(std::span, uint64_t) { } diff --git a/sources/Renderer/NoRenderer.hpp b/sources/Renderer/NoRenderer.hpp index 149e92e..e5a3d7f 100644 --- a/sources/Renderer/NoRenderer.hpp +++ b/sources/Renderer/NoRenderer.hpp @@ -25,7 +25,7 @@ namespace ComSquare::Renderer //! @brief Playing all samples from buffer //! @param samples Buffer containing samples //! @param sampleCount number of samples inside buffer - void playAudio(int16_t *samples, uint64_t sampleCount) override; + void playAudio(std::span samples, uint64_t sampleCount) override; //! @brief Get the inputs from the Window void getEvents(); //! @brief Use this function to create the window. diff --git a/sources/Renderer/QtRenderer/QtSFML.cpp b/sources/Renderer/QtRenderer/QtSFML.cpp index 53d1e35..950ca09 100644 --- a/sources/Renderer/QtRenderer/QtSFML.cpp +++ b/sources/Renderer/QtRenderer/QtSFML.cpp @@ -85,7 +85,7 @@ namespace ComSquare::Renderer this->_sfWidget->putPixel(y, x, rgba); } - void QtSFML::playAudio(int16_t *samples, uint64_t sampleCount) + void QtSFML::playAudio(std::span samples, uint64_t sampleCount) { this->_sfWidget->playAudio(samples, sampleCount); } diff --git a/sources/Renderer/QtRenderer/QtSFML.hpp b/sources/Renderer/QtRenderer/QtSFML.hpp index 204a046..2156052 100644 --- a/sources/Renderer/QtRenderer/QtSFML.hpp +++ b/sources/Renderer/QtRenderer/QtSFML.hpp @@ -68,7 +68,7 @@ namespace ComSquare::Renderer //! @brief Playing all samples from buffer //! @param samples Buffer containing samples //! @param sampleCount number of samples inside buffer - void playAudio(int16_t *samples, uint64_t sampleCount) override; + void playAudio(std::span samples, uint64_t sampleCount) override; //! @brief Set a new name to the window, if there is already a name it will be overwrite. //! @param newWindowName new title for the window. void setWindowName(std::string &newWindowName) override; diff --git a/sources/Renderer/SFRenderer.cpp b/sources/Renderer/SFRenderer.cpp index faae54b..b051ff7 100644 --- a/sources/Renderer/SFRenderer.cpp +++ b/sources/Renderer/SFRenderer.cpp @@ -54,9 +54,9 @@ namespace ComSquare::Renderer this->_window.display(); } - void SFRenderer::playAudio(int16_t *samples, uint64_t sampleCount) + void SFRenderer::playAudio(std::span samples, uint64_t sampleCount) { - this->_soundBuffer.loadFromSamples(samples, sampleCount, 2, 32040); + this->_soundBuffer.loadFromSamples(samples.data(), sampleCount, 2, 32040); this->_sound.play(); } diff --git a/sources/Renderer/SFRenderer.hpp b/sources/Renderer/SFRenderer.hpp index 8cceb3b..8221ea3 100644 --- a/sources/Renderer/SFRenderer.hpp +++ b/sources/Renderer/SFRenderer.hpp @@ -57,7 +57,7 @@ namespace ComSquare::Renderer //! @brief Playing all samples from buffer //! @param samples Buffer containing samples //! @param sampleCount number of samples inside buffer - void playAudio(int16_t *samples, uint64_t sampleCount) override; + void playAudio(std::span samples, uint64_t sampleCount) override; //! @brief Get the inputs from the Window void getEvents(); //! @brief Use this function to create the window. From a4744a40cde30066479e7594a1df2ef76fd7ad2f Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 10:29:55 +0100 Subject: [PATCH 17/26] Removing impossible test as every value is an instruction opcode --- tests/APU/testAPU.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/APU/testAPU.cpp b/tests/APU/testAPU.cpp index 2c54013..767beb5 100644 --- a/tests/APU/testAPU.cpp +++ b/tests/APU/testAPU.cpp @@ -203,15 +203,6 @@ Test(executeInstruction, Valid) cr_assert_eq(result, 2); } -Test(executeInstruction, Invalid) -{ - Init() - auto apu = snes.apu; - - apu->_internalRegisters.pc = 0xFFFF; - cr_assert_throw(apu->_executeInstruction(), InvalidOpcode); -} - /////////////////////// // // // APU::update tests // From e88db2e2d5b7b6d9dd2cff8414defa956dba3fe7 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 14:24:31 +0100 Subject: [PATCH 18/26] Throwing runtime error when MemoryMap is inaccessible instead of InvalidAddress --- sources/APU/DSP/DSP.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/APU/DSP/DSP.cpp b/sources/APU/DSP/DSP.cpp index 781684b..fb933c9 100644 --- a/sources/APU/DSP/DSP.cpp +++ b/sources/APU/DSP/DSP.cpp @@ -571,7 +571,7 @@ namespace ComSquare::APU::DSP uint8_t DSP::_readRAM(uint24_t addr) { if (!this->_map.lock()) - throw InvalidAddress("DSP read", addr); + throw std::runtime_error("DSP read : MemoryMap inaccessible"); switch (addr) { case 0x0000 ... 0x00EF: return this->_map.lock()->Page0.read(addr); @@ -589,7 +589,7 @@ namespace ComSquare::APU::DSP void DSP::_writeRAM(uint24_t addr, uint8_t data) { if (!this->_map.lock()) - throw InvalidAddress("DSP write", addr); + throw std::runtime_error("DSP write : MemoryMap inaccessible"); switch (addr) { case 0x0000 ... 0x00EF: this->_map.lock()->Page0.write(addr, data); From 4e10a4c1916b369541966b20b89b0f050e8511e3 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 14:31:07 +0100 Subject: [PATCH 19/26] Adding Envelope state documentation --- sources/APU/DSP/DSP.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sources/APU/DSP/DSP.hpp b/sources/APU/DSP/DSP.hpp index e4f542d..216df36 100644 --- a/sources/APU/DSP/DSP.hpp +++ b/sources/APU/DSP/DSP.hpp @@ -17,10 +17,15 @@ namespace ComSquare::APU namespace ComSquare::APU::DSP { + //! @brief The 4 states of volume envelope adjustment enum Envelope : uint { + //! @brief The voice is keyed off or a BRR end-without-loop block is reached Release, + //! @brief The voice is keyed on Attack, + //! @brief When the Envelope adjustment method bits exceeds 0x7ff Decay, + //! @brief When the upper 3 bits of Envelope adjustment method bits equal the Sustain Level Sustain }; From f840ab416bcb1302c5e60e3a1891539f871fe512 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:04:35 +0100 Subject: [PATCH 20/26] Testing compilation github action --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5de8a5e..c9fa3c6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ on: jobs: Testing: - runs-on: [ubuntu-latest] + runs-on: [ubuntu-18.04] steps: - uses: actions/checkout@v1 From 052c2adc9bdcfdb2657acb3628bf08d9a0cfcb36 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:20:59 +0100 Subject: [PATCH 21/26] Updating G++ --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c9fa3c6..030510b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,8 @@ jobs: sudo apt-get install --yes criterion-dev - name: Install Gcovr run: python -m pip install --upgrade pip gcovr + - name: Update G++ + run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10.1 100 - name: Build Makefile with CMake run: mkdir -p build && cd build && cmake .. - name: Build with Makefile From 75eaa92eee4d50497159edf0c7e369c81957e3ca Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:23:45 +0100 Subject: [PATCH 22/26] Updating G++ --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 030510b..4c6d79d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: - name: Install Gcovr run: python -m pip install --upgrade pip gcovr - name: Update G++ - run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10.1 100 + run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 - name: Build Makefile with CMake run: mkdir -p build && cd build && cmake .. - name: Build with Makefile From 2d18c0624e1b3a56ac8f1f68795fc152cb4d744f Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Thu, 11 Feb 2021 19:35:25 +0100 Subject: [PATCH 23/26] Updating G++ in build --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c8dd2a..5775650 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ on: jobs: Building: - runs-on: [ubuntu-latest] + runs-on: [ubuntu-18.04] steps: - uses: actions/checkout@v1 @@ -26,6 +26,8 @@ jobs: mkdir build cd build cmake .. && make -j 4 && sudo make install + - name: Update G++ + run: sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 - name: Build Makefile with CMake run: mkdir -p build && cd build && cmake .. - name: Build with Makefile From 7896218469f45375460cfe211c6a608e67663882 Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:29:04 +0100 Subject: [PATCH 24/26] Build Criterion --- .github/workflows/test.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4c6d79d..a1cfe7f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,9 +25,12 @@ jobs: run: sudo apt-get update && sudo apt-get install --yes libsfml-dev qt5-default - name: Install Criterion - run: sudo add-apt-repository ppa:snaipewastaken/ppa && - sudo apt-get update && - sudo apt-get install --yes criterion-dev + run: git clone --recursive https://github.com/Snaipe/Criterion && + cd Criterion && + sudo apt install --yes meson ninja && + meson build && + ninja -C build && + sudo ninja -C build install - name: Install Gcovr run: python -m pip install --upgrade pip gcovr - name: Update G++ From 91d7ddc313322a9594fd915cbdd3236f24a7d3ab Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:30:40 +0100 Subject: [PATCH 25/26] Install ninja --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1cfe7f..7371e8b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - name: Install Criterion run: git clone --recursive https://github.com/Snaipe/Criterion && cd Criterion && - sudo apt install --yes meson ninja && + sudo apt install --yes meson ninja-build && meson build && ninja -C build && sudo ninja -C build install From 1f3f118964fd6e9b0005c4e1035c93281b8113fc Mon Sep 17 00:00:00 2001 From: Melefo <42809472+Melefo@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:52:11 +0100 Subject: [PATCH 26/26] Build && install functional criterion --- .github/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7371e8b..52182cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,10 +27,12 @@ jobs: - name: Install Criterion run: git clone --recursive https://github.com/Snaipe/Criterion && cd Criterion && - sudo apt install --yes meson ninja-build && + sudo apt install --yes ninja-build && + pip3 install meson && meson build && ninja -C build && - sudo ninja -C build install + sudo ninja -C build install && + sudo cp -r /usr/local/lib/x86_64-linux-gnu/libcriterion* /usr/lib - name: Install Gcovr run: python -m pip install --upgrade pip gcovr - name: Update G++