// // Created by Melefo on 28/01/2020. // #ifndef COMSQUARE_DSP_HPP #define COMSQUARE_DSP_HPP #include #include #include "../../Memory/AMemory.hpp" namespace ComSquare::APU::DSP { 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 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 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 : public Memory::AMemory { private: //! @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 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; //! @brief Return all 8 voices from DSP 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. //! @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; //! @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; //! @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; }; } #endif //COMSQUARE_DSP_HPP