| 287 | dsp::Timer rateLimiterTimer; |
| 288 | PORTMODE_t portModes[NUM_INPUTS] = {}; |
| 289 | void process(const ProcessArgs& args) override { |
| 290 | |
| 291 | if (buttonTrigger.process(params[REFRESH_PARAM].getValue())) { |
| 292 | doSync(); |
| 293 | } |
| 294 | |
| 295 | // disabled for now, but this is how VCV would read SysEx coming from the hardware (if requested above) |
| 296 | if (parseSysExMessagesFromHardware) { |
| 297 | midi::Message msg; |
| 298 | uint8_t outData[32] = {}; |
| 299 | while (inputQueue.tryPop(&msg, args.frame)) { |
| 300 | |
| 301 | uint8_t outLen = decodeSysEx(&msg.bytes[0], outData, msg.bytes.size(), false); |
| 302 | if (outLen > 3) { |
| 303 | |
| 304 | int channel = (outData[2] & 0x0f) >> 0; |
| 305 | |
| 306 | if (channel >= 0 && channel < NUM_INPUTS) { |
| 307 | if (outData[outLen - 1] < LASTPORTMODE) { |
| 308 | portModes[channel] = (PORTMODE_t) outData[outLen - 1]; |
| 309 | } |
| 310 | } |
| 311 | } |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | std::vector<int> activeChannels; |
| 316 | for (int c = 0; c < NUM_INPUTS; ++c) { |
| 317 | if (inputs[A1_INPUT + c].isConnected()) { |
| 318 | activeChannels.push_back(c); |
| 319 | } |
| 320 | } |
| 321 | numActiveChannels = activeChannels.size(); |
| 322 | // we're done if no channels are active |
| 323 | if (numActiveChannels == 0) { |
| 324 | return; |
| 325 | } |
| 326 | |
| 327 | //DEBUG("updateRateIdx: %d", updateRateIdx); |
| 328 | const float updateRateHz = updateRates[updateRateIdx]; |
| 329 | //DEBUG("updateRateHz: %f", updateRateHz); |
| 330 | const int maxCCMessagesPerSecondPerChannel = updateRateHz / numActiveChannels; |
| 331 | |
| 332 | // MIDI baud rate is 31250 b/s, or 3125 B/s. |
| 333 | // CC messages are 3 bytes, so we can send a maximum of 1041 CC messages per second. |
| 334 | // The refresh rate period (i.e. how often we can send X channels of data is: |
| 335 | const float rateLimiterPeriod = 1.f / maxCCMessagesPerSecondPerChannel; |
| 336 | |
| 337 | // this returns -1 if no channel should be updated, or the index of the channel that should be updated |
| 338 | // it distributes update times in a round robin fashion |
| 339 | int channelIdxToUpdate = roundRobinProcessor.process(args.sampleTime, rateLimiterPeriod, numActiveChannels); |
| 340 | |
| 341 | if (channelIdxToUpdate >= 0 && channelIdxToUpdate < numActiveChannels) { |
| 342 | int c = activeChannels[channelIdxToUpdate]; |
| 343 | |
| 344 | const float channelVoltage = inputs[A1_INPUT + c].getVoltage(); |
| 345 | uint16_t pw = rescaleVoltageForChannel(c, channelVoltage); |
| 346 | isClipping[c] = !checkIsVoltageWithinRange(c, channelVoltage); |
nothing calls this directly
no test coverage detected