gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit aaeab7f97b0729936ac21a8b60ec3fe3ee2d8c51
parent 5957419201b85a704b8336d720874c1e036d7cba
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Mon, 10 Mar 2025 21:12:02 +0100

use empty space in rom for additional user tables as we require contiguous memory for speech to work (this will not work on hardware!)

Diffstat:
Msource/hardwareLib/sciMidi.h | 5++---
Msource/xtLib/CMakeLists.txt | 2++
Msource/xtLib/xtHardware.cpp | 2+-
Msource/xtLib/xtHardware.h | 3++-
Asource/xtLib/xtMidi.cpp | 27+++++++++++++++++++++++++++
Asource/xtLib/xtMidi.h | 20++++++++++++++++++++
Msource/xtLib/xtMidiTypes.h | 5+++++
Asource/xtLib/xtRomWaves.cpp | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/xtLib/xtRomWaves.h | 26++++++++++++++++++++++++++
Msource/xtLib/xtUc.h | 2++
10 files changed, 177 insertions(+), 5 deletions(-)

diff --git a/source/hardwareLib/sciMidi.h b/source/hardwareLib/sciMidi.h @@ -35,10 +35,9 @@ namespace hwLib for (const uint8_t byte : _bytes) write(byte); } - void write(const synthLib::SMidiEvent& _e); + virtual void write(const synthLib::SMidiEvent& _e); - - void read(std::vector<uint8_t>& _result); + virtual void read(std::vector<uint8_t>& _result); void setSysexDelay(const float _seconds, const uint32_t _size); diff --git a/source/xtLib/CMakeLists.txt b/source/xtLib/CMakeLists.txt @@ -13,10 +13,12 @@ set(SOURCES xtId.cpp xtId.h xtLcd.cpp xtLcd.h xtLeds.cpp xtLeds.h + xtMidi.cpp xtMidi.h xtMidiTypes.h xtPic.cpp xtPic.h xtRom.cpp xtRom.h xtRomLoader.cpp xtRomLoader.h + xtRomWaves.cpp xtRomWaves.h xtState.cpp xtState.h xtSysexRemoteControl.cpp xtSysexRemoteControl.h xtTypes.h diff --git a/source/xtLib/xtHardware.cpp b/source/xtLib/xtHardware.cpp @@ -21,7 +21,7 @@ namespace xt , m_rom(initializeRom(_romData, _romName)) , m_uc(m_rom) , m_dsps{DSP(*this, m_uc.getHdi08A().getHdi08(), 0)} - , m_midi(m_uc.getQSM(), 40000) + , m_midi(m_uc) { if(!m_rom.isValid()) throw synthLib::DeviceException(synthLib::DeviceError::FirmwareMissing); diff --git a/source/xtLib/xtHardware.h b/source/xtLib/xtHardware.h @@ -3,6 +3,7 @@ #include "xtDSP.h" #include "xtRom.h" #include "xtUc.h" +#include "xtMidi.h" #include "dsp56kEmu/dspthread.h" @@ -69,6 +70,6 @@ namespace xt TAudioInputs m_audioInputs; TAudioOutputs m_audioOutputs; std::array<DSP,g_dspCount> m_dsps; - hwLib::SciMidi m_midi; + SciMidi m_midi; }; } diff --git a/source/xtLib/xtMidi.cpp b/source/xtLib/xtMidi.cpp @@ -0,0 +1,27 @@ +#include "xtMidi.h" + +#include "synthLib/midiTypes.h" + +namespace xt +{ + SciMidi::SciMidi(XtUc& _uc) : hwLib::SciMidi(_uc.getQSM(), 40000), m_romWaves(_uc) + { + } + + void SciMidi::write(const synthLib::SMidiEvent& _e) + { + if (m_romWaves.receiveSysEx(m_results, _e.sysex)) + return; + + hwLib::SciMidi::write(_e); + } + + void SciMidi::read(std::vector<uint8_t>& _result) + { + hwLib::SciMidi::read(_result); + + for (const auto& result : m_results) + _result.insert(_result.end(), result.begin(), result.end()); + m_results.clear(); + } +} diff --git a/source/xtLib/xtMidi.h b/source/xtLib/xtMidi.h @@ -0,0 +1,20 @@ +#pragma once + +#include "xtRomWaves.h" +#include "hardwareLib/sciMidi.h" + +namespace xt +{ + class SciMidi : public hwLib::SciMidi + { + public: + SciMidi(XtUc& _uc); + + void write(const synthLib::SMidiEvent& _e) override; + void read(std::vector<uint8_t>& _result) override; + + private: + RomWaves m_romWaves; + std::vector<SysEx> m_results; + }; +} diff --git a/source/xtLib/xtMidiTypes.h b/source/xtLib/xtMidiTypes.h @@ -219,6 +219,7 @@ namespace xt static constexpr uint16_t g_romWaveCount = 506; static constexpr uint16_t g_ramWaveCount = 250; static constexpr uint16_t g_firstRamWaveIndex = 1000; + static constexpr uint16_t g_firstRwRomWaveIndex = 452; // these are zeroed in the rom, we can write to them to make them useable static constexpr uint16_t g_tableCount = 128; static constexpr uint16_t g_wavesPerTable = 64; @@ -269,6 +270,10 @@ namespace xt { if(!_waveId.isValid()) return true; + if (_waveId.rawId() < g_firstRwRomWaveIndex) + return true; + if (_waveId.rawId() < g_romWaveCount) + return false; return _waveId.rawId() < g_firstRamWaveIndex; } diff --git a/source/xtLib/xtRomWaves.cpp b/source/xtLib/xtRomWaves.cpp @@ -0,0 +1,90 @@ +#include "xtRomWaves.h" + +#include <cstdint> + +#include "xtState.h" + +namespace xt +{ + constexpr uint32_t g_rwRomWaveStartAddr = 0x26501; + + namespace + { + bool isValidRwRomWave(const WaveId _id) + { + return _id.rawId() >= wave::g_firstRwRomWaveIndex && _id.rawId() < wave::g_romWaveCount; + } + uint32_t getWaveAddr(const WaveId _id) + { + return g_rwRomWaveStartAddr + (_id.rawId() - wave::g_firstRwRomWaveIndex) * 128; + } + } + + bool RomWaves::receiveSysEx(std::vector<SysEx>& _results, const SysEx& _data) const + { + switch (State::getCommand(_data)) + { + case SysexCommand::WaveRequest: + { + auto waveId = State::getWaveId(_data); + if (!isValidRwRomWave(waveId)) + return false; + WaveData waveData; + if (!readFromRom(waveData, waveId)) + return false; + auto response = State::createWaveData(waveData, waveId.rawId(), false); + _results.emplace_back(std::move(response)); + } + return true; + case SysexCommand::WaveDump: + { + auto waveId = State::getWaveId(_data); + if (!isValidRwRomWave(waveId)) + return false; + + WaveData d; + if (!State::parseWaveData(d, _data)) + return false; + + writeToRom(waveId, d); + } + return true; + default: + return false; + } + } + + bool RomWaves::writeToRom(const WaveId _id, const WaveData& _waveData) const + { + if (!isValidRwRomWave(_id)) + return false; + + const auto addr = getWaveAddr(_id); + + for (size_t i=0; i<64; ++i) + { + const auto idx = i << 1; + const auto sample = static_cast<uint8_t>(_waveData[i] ^ 0x80); + + m_uc.getRomRuntimeData()[addr + idx] = sample; + } + + return true; + } + + bool RomWaves::readFromRom(WaveData& _waveData, const WaveId _id) const + { + if (!isValidRwRomWave(_id)) + return false; + + const auto addr = getWaveAddr(_id); + for (size_t i = 0; i < 64; ++i) + { + const auto idx = i << 1; + const auto sample = m_uc.getRomRuntimeData()[addr + idx] ^ 0x80; + _waveData[i] = static_cast<int8_t>(sample); + _waveData[127-i] = static_cast<int8_t>(-sample); + } + return true; + } +} diff --git a/source/xtLib/xtRomWaves.h b/source/xtLib/xtRomWaves.h @@ -0,0 +1,26 @@ +#pragma once + +#include <cstdint> +#include <vector> + +#include "xtId.h" +#include "xtTypes.h" +#include "xtUc.h" + +namespace xt +{ + using SysEx = std::vector<uint8_t>; + + class RomWaves + { + public: + RomWaves(XtUc& _uc) : m_uc(_uc) {} + bool receiveSysEx(std::vector<SysEx>& _results, const SysEx& _data) const; + + private: + bool writeToRom(WaveId _id, const WaveData& _waveData) const; + bool readFromRom(WaveData& _waveData, WaveId _id) const; + + XtUc& m_uc; + }; +} diff --git a/source/xtLib/xtUc.h b/source/xtLib/xtUc.h @@ -45,6 +45,8 @@ namespace xt bool getLedState(LedType _led) const; bool getButton(ButtonType _button) const; + auto& getRomRuntimeData() { return m_romRuntimeData; } + private: std::array<uint8_t, g_ramSize> m_memory; std::array<uint8_t, g_romSize> m_romRuntimeData;