virtual void audioDeviceIOCallback()

in pedalboard/io/AudioStream.h [295:391]


  virtual void audioDeviceIOCallback(const float **inputChannelData,
                                     int numInputChannels,
                                     float **outputChannelData,
                                     int numOutputChannels, int numSamples) {
    // Live processing mode: run the input audio through a Pedalboard object.
    if (playBufferFifo && recordBufferFifo) {
      for (int i = 0; i < numOutputChannels; i++) {
        const float *inputChannel = inputChannelData[i % numInputChannels];
        std::memcpy((char *)outputChannelData[i], (char *)inputChannel,
                    numSamples * sizeof(float));
      }

      auto ioBlock = juce::dsp::AudioBlock<float>(
          outputChannelData, numOutputChannels, 0, numSamples);
      juce::dsp::ProcessContextReplacing<float> context(ioBlock);

      juce::SpinLock::ScopedTryLockType tryLock(livePedalboardMutex);
      if (tryLock.isLocked()) {
        for (auto plugin : livePedalboard.getPlugins()) {
          std::unique_lock<std::mutex> lock(pedalboard->mutex,
                                            std::try_to_lock);
          // If someone's running audio through this plugin in parallel
          // (offline, or in a different AudioStream object) then don't corrupt
          // its state by calling it here too; instead, just skip it:
          if (lock.owns_lock()) {
            plugin->process(context);
          }
        }
      }
    } else if (recordBufferFifo) {
      // If Python wants audio input, then copy the audio into the record
      // buffer:
      for (int attempt = 0; attempt < 2; attempt++) {
        int samplesWritten = 0;
        {
          const auto scope = recordBufferFifo->write(numSamples);

          if (scope.blockSize1 > 0)
            for (int i = 0; i < numInputChannels; i++) {
              std::memcpy(
                  (char *)recordBuffer->getWritePointer(i, scope.startIndex1),
                  (char *)inputChannelData[i],
                  scope.blockSize1 * sizeof(float));
            }

          if (scope.blockSize2 > 0)
            for (int i = 0; i < numInputChannels; i++) {
              std::memcpy(
                  (char *)recordBuffer->getWritePointer(i, scope.startIndex2),
                  (char *)(inputChannelData[i] + scope.blockSize1),
                  scope.blockSize2 * sizeof(float));
            }

          samplesWritten = scope.blockSize1 + scope.blockSize2;
        }

        if (samplesWritten < numSamples) {
          numDroppedInputFrames += numSamples - samplesWritten;
          // We've dropped some frames during recording; not great.
          // Favour capturing more recent audio instead, so clear out enough
          // space in the buffer to keep up and retry:
          const auto scope = recordBufferFifo->read(numSamples);

          // Do nothing here; as soon as `scope` goes out of scope,
          // the buffer will now allow us to append `numSamples`.
        } else {
          break;
        }
      }
    } else if (playBufferFifo) {
      for (int i = 0; i < numOutputChannels; i++) {
        std::memset((char *)outputChannelData[i], 0,
                    numSamples * sizeof(float));
      }

      const auto scope = playBufferFifo->read(numSamples);

      if (scope.blockSize1 > 0)
        for (int i = 0; i < numOutputChannels; i++) {
          std::memcpy((char *)outputChannelData[i],
                      (char *)playBuffer->getReadPointer(i, scope.startIndex1),
                      scope.blockSize1 * sizeof(float));
        }

      if (scope.blockSize2 > 0)
        for (int i = 0; i < numOutputChannels; i++) {
          std::memcpy((char *)(outputChannelData[i] + scope.blockSize1),
                      (char *)playBuffer->getReadPointer(i, scope.startIndex2),
                      scope.blockSize2 * sizeof(float));
        }
    } else {
      for (int i = 0; i < numOutputChannels; i++) {
        std::memset((char *)outputChannelData[i], 0,
                    numSamples * sizeof(float));
      }
    }
  }