plugin.cpp (7509B)
1 #include "plugin.h" 2 #include "device.h" 3 4 #include <cmath> 5 6 #include "os.h" 7 8 using namespace synthLib; 9 10 namespace synthLib 11 { 12 constexpr uint8_t g_stateVersion = 1; 13 14 Plugin::Plugin(Device* _device, CallbackDeviceInvalid _callbackDeviceInvalid) 15 : m_resampler(_device->getChannelCountIn(), _device->getChannelCountOut()) 16 , m_device(_device) 17 , m_midiClock(*this) 18 , m_deviceSamplerate(_device->getSamplerate()) 19 , m_callbackDeviceInvalid(std::move(_callbackDeviceInvalid)) 20 { 21 } 22 23 void Plugin::addMidiEvent(const SMidiEvent& _ev) 24 { 25 std::lock_guard lock(m_lockAddMidiEvent); 26 27 if(m_midiInRingBuffer.full()) 28 { 29 std::lock_guard l(m_lock); 30 processMidiInEvent(m_midiInRingBuffer.pop_front()); 31 } 32 m_midiInRingBuffer.push_back(_ev); 33 } 34 35 bool Plugin::setPreferredDeviceSamplerate(const float _samplerate) 36 { 37 std::lock_guard lock(m_lock); 38 39 const auto sr = m_device->getDeviceSamplerate(_samplerate, m_hostSamplerate); 40 41 if(sr == m_deviceSamplerate) // NOLINT(clang-diagnostic-float-equal) 42 return true; 43 44 if(!m_device->setSamplerate(sr)) 45 return false; 46 47 m_deviceSamplerate = sr; 48 m_resampler.setSamplerates(m_hostSamplerate, m_deviceSamplerate); 49 50 updateDeviceLatency(); 51 return true; 52 } 53 54 void Plugin::setHostSamplerate(const float _hostSamplerate, const float _preferredDeviceSamplerate) 55 { 56 std::lock_guard lock(m_lock); 57 58 m_deviceSamplerate = m_device->getDeviceSamplerate(_preferredDeviceSamplerate, _hostSamplerate); 59 m_device->setSamplerate(m_deviceSamplerate); 60 m_resampler.setSamplerates(_hostSamplerate, m_deviceSamplerate); 61 62 m_hostSamplerate = _hostSamplerate; 63 m_hostSamplerateInv = _hostSamplerate > 0 ? 1.0f / _hostSamplerate : 0.0f; 64 65 updateDeviceLatency(); 66 } 67 68 void Plugin::process(const TAudioInputs& _inputs, const TAudioOutputs& _outputs, size_t _count, const float _bpm, const float _ppqPos, const bool _isPlaying) 69 { 70 setFlushDenormalsToZero(); 71 72 TAudioInputs inputs(_inputs); 73 TAudioOutputs outputs(_outputs); 74 75 for(size_t i=0; i<inputs.size(); ++i) 76 inputs[i] = _inputs[i] ? _inputs[i] : getDummyBuffer(_count); 77 78 for(size_t i=0; i<outputs.size(); ++i) 79 outputs[i] = _outputs[i] ? _outputs[i] : getDummyBuffer(_count); 80 81 std::lock_guard lock(m_lock); 82 83 if(!m_device->isValid()) 84 { 85 m_device = m_callbackDeviceInvalid(m_device); 86 87 if(!m_device || !m_device->isValid()) 88 return; 89 } 90 91 processMidiInEvents(); 92 processMidiClock(_bpm, _ppqPos, _isPlaying, _count); 93 94 m_resampler.process(inputs, outputs, m_midiIn, m_midiOut, static_cast<uint32_t>(_count), 95 [&](const TAudioInputs& _ins, const TAudioOutputs& _outs, size_t _c, const ResamplerInOut::TMidiVec& _midiIn, ResamplerInOut::TMidiVec& _midiOut) 96 { 97 m_device->process(_ins, _outs, _c, _midiIn, _midiOut); 98 }); 99 100 m_midiIn.clear(); 101 } 102 103 void Plugin::getMidiOut(std::vector<SMidiEvent>& _midiOut) 104 { 105 std::swap(_midiOut, m_midiOut); 106 m_midiOut.clear(); 107 } 108 109 bool Plugin::isValid() const 110 { 111 return m_device->isValid(); 112 } 113 114 void Plugin::setDevice(Device* _device) 115 { 116 if(!_device) 117 return; 118 119 std::lock_guard lock(m_lock); 120 121 std::vector<uint8_t> deviceState; 122 getState(deviceState, StateTypeGlobal); 123 124 delete m_device; 125 126 m_device = _device; 127 128 m_device->setSamplerate(m_deviceSamplerate); 129 if(!deviceState.empty()) 130 setState(deviceState); 131 132 // MIDI clock has to send the start event again, some device find it confusing and do strange things if there isn't any 133 m_midiClock.restart(); 134 135 updateDeviceLatency(); 136 } 137 138 #if !SYNTHLIB_DEMO_MODE 139 bool Plugin::getState(std::vector<uint8_t>& _state, StateType _type) const 140 { 141 if(!m_device) 142 return false; 143 144 _state.push_back(g_stateVersion); 145 _state.push_back(_type); 146 147 return m_device->getState(_state, _type); 148 } 149 150 bool Plugin::setState(const std::vector<uint8_t>& _state) const 151 { 152 if(!m_device) 153 return false; 154 155 if(_state.empty()) 156 return false; 157 158 if(_state.size() < 2) 159 return m_device->setStateFromUnknownCustomData(_state); 160 161 const auto version = _state[0]; 162 163 if(version != g_stateVersion) 164 return m_device->setStateFromUnknownCustomData(_state); 165 166 const auto stateType = static_cast<StateType>(_state[1]); 167 168 auto state = _state; 169 state.erase(state.begin(), state.begin() + 2); 170 171 return m_device->setState(state, stateType); 172 } 173 #endif 174 void Plugin::insertMidiEvent(const SMidiEvent& _ev) 175 { 176 if(m_midiIn.empty() || m_midiIn.back().offset <= _ev.offset) 177 { 178 m_midiIn.push_back(_ev); 179 return; 180 } 181 182 for (auto it = m_midiIn.begin(); it != m_midiIn.end(); ++it) 183 { 184 if (it->offset > _ev.offset) 185 { 186 m_midiIn.insert(it, _ev); 187 return; 188 } 189 } 190 191 m_midiIn.push_back(_ev); 192 } 193 194 bool Plugin::setLatencyBlocks(uint32_t _latencyBlocks) 195 { 196 std::lock_guard lock(m_lock); 197 198 if(m_extraLatencyBlocks == _latencyBlocks) 199 return false; 200 201 m_extraLatencyBlocks = _latencyBlocks; 202 updateDeviceLatency(); 203 return true; 204 } 205 206 void Plugin::processMidiClock(const float _bpm, const float _ppqPos, const bool _isPlaying, const size_t _sampleCount) 207 { 208 m_midiClock.process(_bpm, _ppqPos, _isPlaying, _sampleCount); 209 } 210 211 float* Plugin::getDummyBuffer(size_t _minimumSize) 212 { 213 if(m_dummyBuffer.size() < _minimumSize) 214 m_dummyBuffer.resize(_minimumSize); 215 216 return m_dummyBuffer.data(); 217 } 218 219 void Plugin::updateDeviceLatency() 220 { 221 if(m_blockSize <= 0 || m_hostSamplerate <= 0) 222 return; 223 224 const auto latency = static_cast<uint32_t>(std::ceil(static_cast<float>(m_blockSize * m_extraLatencyBlocks) * m_device->getSamplerate() * m_hostSamplerateInv)); 225 m_device->setExtraLatencySamples(latency); 226 227 m_deviceLatencyMidiToOutput = static_cast<uint32_t>(static_cast<float>(m_device->getInternalLatencyMidiToOutput()) * m_hostSamplerate / m_device->getSamplerate()); 228 m_deviceLatencyInputToOutput = static_cast<uint32_t>(static_cast<float>(m_device->getInternalLatencyInputToOutput()) * m_hostSamplerate / m_device->getSamplerate()); 229 } 230 231 void Plugin::processMidiInEvents() 232 { 233 while (!m_midiInRingBuffer.empty()) 234 { 235 const auto ev = m_midiInRingBuffer.pop_front(); 236 237 processMidiInEvent(ev); 238 } 239 } 240 241 void Plugin::processMidiInEvent(const SMidiEvent& _ev) 242 { 243 // sysex might be sent in multiple chunks. Happens if coming from hardware 244 if (!_ev.sysex.empty()) 245 { 246 const bool isComplete = _ev.sysex.front() == M_STARTOFSYSEX && _ev.sysex.back() == M_ENDOFSYSEX; 247 248 if (isComplete) 249 { 250 m_midiIn.push_back(_ev); 251 return; 252 } 253 254 const bool isStart = _ev.sysex.front() == M_STARTOFSYSEX && _ev.sysex.back() != M_ENDOFSYSEX; 255 const bool isEnd = _ev.sysex.front() != M_STARTOFSYSEX && _ev.sysex.back() == M_ENDOFSYSEX; 256 257 if (isStart) 258 { 259 m_pendingSysexInput = _ev; 260 return; 261 } 262 263 if (!m_pendingSysexInput.sysex.empty()) 264 { 265 m_pendingSysexInput.sysex.insert(m_pendingSysexInput.sysex.end(), _ev.sysex.begin(), _ev.sysex.end()); 266 267 if (isEnd) 268 { 269 m_midiIn.push_back(m_pendingSysexInput); 270 m_pendingSysexInput.sysex.clear(); 271 } 272 } 273 } 274 275 m_midiIn.push_back(_ev); 276 } 277 278 void Plugin::setBlockSize(const uint32_t _blockSize) 279 { 280 std::lock_guard lock(m_lock); 281 m_blockSize = _blockSize; 282 updateDeviceLatency(); 283 } 284 285 uint32_t Plugin::getLatencyMidiToOutput() const 286 { 287 std::lock_guard lock(m_lock); 288 return m_blockSize * m_extraLatencyBlocks + m_deviceLatencyMidiToOutput + m_resampler.getOutputLatency(); 289 } 290 291 uint32_t Plugin::getLatencyInputToOutput() const 292 { 293 std::lock_guard lock(m_lock); 294 return m_blockSize * m_extraLatencyBlocks + m_deviceLatencyInputToOutput + m_resampler.getOutputLatency() + m_resampler.getInputLatency(); 295 } 296 }