xtHardware.cpp (6931B)
1 #include "xtHardware.h" 2 3 #include "synthLib/midiBufferParser.h" 4 #include "synthLib/deviceException.h" 5 6 #include <cstring> // memcpy 7 8 #include "xtRomLoader.h" 9 10 namespace xt 11 { 12 Rom initializeRom(const std::vector<uint8_t>& _romData, const std::string& _romName) 13 { 14 if(_romData.empty()) 15 return RomLoader::findROM(); 16 return Rom{_romName, _romData}; 17 } 18 19 Hardware::Hardware(const std::vector<uint8_t>& _romData, const std::string& _romName) 20 : wLib::Hardware(40000) 21 , m_rom(initializeRom(_romData, _romName)) 22 , m_uc(m_rom) 23 , m_dsps{DSP(*this, m_uc.getHdi08A().getHdi08(), 0)} 24 , m_midi(m_uc) 25 { 26 if(!m_rom.isValid()) 27 throw synthLib::DeviceException(synthLib::DeviceError::FirmwareMissing); 28 } 29 30 Hardware::~Hardware() 31 { 32 m_dsps.front().getPeriph().getEssi0().setCallback({}, 0); 33 } 34 35 void Hardware::process() 36 { 37 processUcCycle(); 38 } 39 40 void Hardware::resetMidiCounter() 41 { 42 // wait for DSP to enter blocking state 43 44 const auto& esai = m_dsps.front().getPeriph().getEssi0(); 45 46 auto& inputs = esai.getAudioInputs(); 47 auto& outputs = esai.getAudioOutputs(); 48 49 while(inputs.size() > 2 && !outputs.full()) 50 std::this_thread::yield(); 51 52 m_midiOffsetCounter = 0; 53 } 54 55 void Hardware::initVoiceExpansion() 56 { 57 if (m_dsps.size() < 3) 58 { 59 setupEsaiListener(); 60 return; 61 } 62 } 63 64 void Hardware::setupEsaiListener() 65 { 66 auto& esaiA = m_dsps.front().getPeriph().getEssi0(); 67 68 esaiA.setCallback([&](dsp56k::Audio*) 69 { 70 m_bootCompleted = true; 71 72 onEsaiCallback(esaiA); 73 }, 0); 74 } 75 76 void Hardware::processUcCycle() 77 { 78 syncUcToDSP(); 79 80 const auto deltaCycles = m_uc.exec(); 81 if(m_esaiFrameIndex > 0) 82 m_remainingUcCycles -= static_cast<int64_t>(deltaCycles); 83 84 for (auto& dsp : m_dsps) 85 dsp.transferHostFlagsUc2Dsdp(); 86 87 for (auto& dsp : m_dsps) 88 dsp.hdiTransferDSPtoUC(); 89 90 if(m_uc.requestDSPReset()) 91 { 92 for (auto& dsp : m_dsps) 93 { 94 if(dsp.haveSentTXToDSP()) 95 { 96 // m_uc.dumpMemory("DSPreset"); 97 assert(false && "DSP needs reset even though it got data already. Needs impl"); 98 } 99 } 100 m_uc.notifyDSPBooted(); 101 } 102 } 103 104 void Hardware::processAudio(uint32_t _frames, uint32_t _latency) 105 { 106 ensureBufferSize(_frames); 107 108 if(m_esaiFrameIndex == 0) 109 return; 110 111 m_midi.process(_frames); 112 113 m_processAudio = true; 114 115 auto& esai = m_dsps.front().getPeriph().getEssi0(); 116 117 const dsp56k::TWord* inputs[16]{nullptr}; 118 dsp56k::TWord* outputs[16]{nullptr}; 119 120 inputs[0] = &m_audioInputs[0].front(); 121 inputs[1] = &m_audioInputs[1].front(); 122 inputs[2] = m_dummyInput.data(); 123 inputs[3] = m_dummyInput.data(); 124 inputs[4] = m_dummyInput.data(); 125 inputs[5] = m_dummyInput.data(); 126 inputs[6] = m_dummyInput.data(); 127 inputs[7] = m_dummyInput.data(); 128 129 outputs[0] = &m_audioOutputs[0].front(); 130 outputs[1] = &m_audioOutputs[1].front(); 131 outputs[2] = &m_audioOutputs[2].front(); 132 outputs[3] = &m_audioOutputs[3].front(); 133 outputs[4] = m_dummyOutput.data(); 134 outputs[5] = m_dummyOutput.data(); 135 outputs[6] = m_dummyOutput.data(); 136 outputs[7] = m_dummyOutput.data(); 137 outputs[8] = m_dummyOutput.data(); 138 outputs[9] = m_dummyOutput.data(); 139 outputs[10] = m_dummyOutput.data(); 140 outputs[11] = m_dummyOutput.data(); 141 142 const auto totalFrames = _frames; 143 144 while (_frames) 145 { 146 const auto processCount = std::min(_frames, static_cast<uint32_t>(1024)); 147 _frames -= processCount; 148 /* 149 if constexpr (g_useVoiceExpansion) 150 { 151 auto& esaiA = m_dsps[0].getPeriph().getEsai(); 152 auto& esaiB = m_dsps[1].getPeriph().getEsai(); 153 auto& esaiC = m_dsps[2].getPeriph().getEsai(); 154 155 const auto tccrA = esaiA.getTccrAsString(); const auto rccrA = esaiA.getRccrAsString(); 156 const auto tcrA = esaiA.getTcrAsString(); const auto rcrA = esaiA.getRcrAsString(); 157 158 const auto tccrB = esaiB.getTccrAsString(); const auto rccrB = esaiB.getRccrAsString(); 159 const auto tcrB = esaiB.getTcrAsString(); const auto rcrB = esaiB.getRcrAsString(); 160 161 const auto tccrC = esaiC.getTccrAsString(); const auto rccrC = esaiC.getRccrAsString(); 162 const auto tcrC = esaiC.getTcrAsString(); const auto rcrC = esaiC.getRcrAsString(); 163 164 LOG("ESAI DSPmain:\n" << tccrA << '\n' << tcrA << '\n' << rccrA << '\n' << rcrA << '\n'); 165 LOG("ESAI VexpA:\n" << tccrB << '\n' << tcrB << '\n' << rccrB << '\n' << rcrB << '\n'); 166 LOG("ESAI VexpB:\n" << tccrC << '\n' << tcrC << '\n' << rccrC << '\n' << rcrC << '\n'); 167 168 // vexp1 only needs the audio input 169 esaiB.processAudioInputInterleaved(inputs, processCount); 170 171 // transfer output from vexp1 to vexp2 172 esaiB.processAudioOutputInterleaved(outputs, processCount); 173 174 const dsp56k::TWord* in[] = { outputs[0], outputs[1], outputs[2], outputs[3], outputs[4], outputs[5], nullptr, nullptr }; 175 esaiC.processAudioInputInterleaved(in, processCount); 176 177 // read output of vexp2 and send to main 178 esaiC.processAudioOutputInterleaved(outputs, processCount); 179 180 // RX1/2 = vexp2 output TX1/TX2 181 const dsp56k::TWord* inA[] = { inputs[1], inputs[0], outputs[2], outputs[3], outputs[4], outputs[5], nullptr, nullptr }; 182 esaiA.processAudioInputInterleaved(inA, processCount); 183 184 // final output 0,1,2 = audio outs below 185 } 186 else 187 */ { 188 esai.processAudioInputInterleaved(inputs, processCount, _latency); 189 } 190 191 const auto requiredSize = processCount > 8 ? processCount - 8 : 0; 192 193 if(esai.getAudioOutputs().size() < requiredSize) 194 { 195 // reduce thread contention by waiting for output buffer to be full enough to let us grab the data without entering the read mutex too often 196 197 std::unique_lock uLock(m_requestedFramesAvailableMutex); 198 m_requestedFrames = requiredSize; 199 m_requestedFramesAvailableCv.wait(uLock, [&]() 200 { 201 if(esai.getAudioOutputs().size() < requiredSize) 202 return false; 203 m_requestedFrames = 0; 204 return true; 205 }); 206 } 207 208 esai.processAudioOutputInterleaved(outputs, processCount); 209 /* 210 if constexpr (g_useVoiceExpansion) 211 { 212 for (uint32_t i = 1; i < 3; ++i) 213 { 214 auto& e = m_dsps[i].getPeriph().getEsai(); 215 216 dsp56k::TWord* outs[16]{ nullptr }; 217 if (e.getAudioOutputs().size() >= 512) 218 e.processAudioOutputInterleaved(outs, static_cast<uint32_t>(e.getAudioOutputs().size() >> 1)); 219 } 220 } 221 */ 222 inputs[0] += processCount; 223 inputs[1] += processCount; 224 225 outputs[0] += processCount; 226 outputs[1] += processCount; 227 outputs[2] += processCount; 228 outputs[3] += processCount; 229 outputs[4] += processCount; 230 outputs[5] += processCount; 231 } 232 233 m_processAudio = false; 234 } 235 236 void Hardware::ensureBufferSize(const uint32_t _frames) 237 { 238 if(m_audioInputs.front().size() < _frames) 239 { 240 for (auto& input : m_audioInputs) 241 input.resize(_frames); 242 } 243 244 if(m_audioOutputs.front().size() < _frames) 245 { 246 for (auto& output : m_audioOutputs) 247 output.resize(_frames); 248 } 249 250 if(m_dummyInput.size() < _frames) 251 m_dummyInput.resize(_frames); 252 if(m_dummyOutput.size() < _frames) 253 m_dummyOutput.resize(_frames); 254 } 255 }