LCOV - code coverage report
Current view: top level - muse/framework/vst/internal - vstaudioclient.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 330 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2025 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "vstaudioclient.h"
      23              : 
      24              : #include "log.h"
      25              : 
      26              : using namespace muse;
      27              : using namespace muse::vst;
      28              : using namespace muse::mpe;
      29              : using namespace muse::audio;
      30              : using namespace muse::audio::engine;
      31              : using namespace muse::audioplugins;
      32              : using namespace muse::midiremote;
      33              : 
      34            0 : static size_t noteEventKey(int pitch, int channel)
      35              : {
      36            0 :     std::size_t h1 = std::hash<int> {}(pitch);
      37            0 :     std::size_t h2 = std::hash<int> {}(channel);
      38            0 :     return h1 ^ (h2 << 1);
      39              : }
      40              : 
      41            0 : static std::optional<TransportEvent> mmcToTransportEvent(const IMMCDecoderPtr& decoder, const MMCMessage& msg)
      42              : {
      43            0 :     switch (msg.command) {
      44            0 :     case MMCCommand::Play:
      45            0 :         return TransportEvent::play();
      46            0 :     case MMCCommand::Pause:
      47            0 :         return TransportEvent::pause();
      48            0 :     case MMCCommand::Stop:
      49            0 :         return TransportEvent::stop();
      50            0 :     case MMCCommand::Locate: {
      51            0 :         const std::optional<double> pos = decoder->locateToSeconds(msg);
      52            0 :         if (pos.has_value()) {
      53            0 :             return TransportEvent::seek(pos.value());
      54              :         }
      55            0 :     } break;
      56            0 :     default: break;
      57              :     }
      58              : 
      59            0 :     return std::nullopt;
      60              : }
      61              : 
      62            0 : VstAudioClient::VstAudioClient()
      63              : {
      64            0 :     m_processContext.state = 0;
      65            0 : }
      66              : 
      67            0 : VstAudioClient::~VstAudioClient()
      68              : {
      69              :     // Do not call setActive(false) or terminate() here.
      70              :     // The component lifecycle is managed by VstPluginInstance,
      71              :     // which defers cleanup to the main thread so that any open
      72              :     // editor view is destroyed first (required by ZENOLOGY).
      73            0 : }
      74              : 
      75            0 : void VstAudioClient::init(PluginType type, IVstPluginInstancePtr instance)
      76              : {
      77            0 :     IF_ASSERT_FAILED(instance && type != PluginType::Undefined) {
      78            0 :         return;
      79              :     }
      80              : 
      81            0 :     m_type = type;
      82            0 :     m_pluginPtr = std::move(instance);
      83              : 
      84            0 :     if (mmcDecoderFactory()) {
      85            0 :         m_mmcDecoder = mmcDecoderFactory()->makeDecoder();
      86              :     }
      87              : 
      88            0 :     transportEventsDispatcher(); // Force resolution outside audio callback
      89              : }
      90              : 
      91            0 : void VstAudioClient::loadSupportedParams()
      92              : {
      93            0 :     TRACEFUNC;
      94              : 
      95            0 :     IF_ASSERT_FAILED(m_pluginPtr) {
      96            0 :         return;
      97              :     }
      98              : 
      99            0 :     PluginControllerPtr controller = m_pluginPtr->controller();
     100            0 :     IF_ASSERT_FAILED(controller) {
     101            0 :         return;
     102              :     }
     103              : 
     104            0 :     const int paramCount = controller->getParameterCount();
     105            0 :     m_pluginParamInfoMap.reserve(static_cast<size_t>(paramCount));
     106              : 
     107            0 :     for (int i = 0; i < paramCount; ++i) {
     108              :         PluginParamInfo info;
     109            0 :         controller->getParameterInfo(i, info);
     110            0 :         m_pluginParamInfoMap.emplace(info.id, std::move(info));
     111              :     }
     112            0 : }
     113              : 
     114            0 : void VstAudioClient::setIsActive(const bool isActive)
     115              : {
     116            0 :     flushSound();
     117              : 
     118            0 :     if (isActive) {
     119            0 :         ensureActivity();
     120              :     } else {
     121            0 :         disableActivity();
     122              :     }
     123            0 : }
     124              : 
     125            0 : void VstAudioClient::setIsPlaying(const bool newPlaying)
     126              : {
     127            0 :     constexpr uint32_t playingFlag = static_cast<uint32_t>(VstProcessContext::kPlaying);
     128            0 :     const bool playing = (m_processContext.state & playingFlag) != 0;
     129            0 :     if (playing == newPlaying) {
     130            0 :         return;
     131              :     }
     132              : 
     133            0 :     if (newPlaying) {
     134            0 :         m_processContext.state |= playingFlag;
     135              :     } else {
     136            0 :         m_processContext.state &= ~playingFlag;
     137              :     }
     138              : 
     139            0 :     m_needUpdateState = m_isActive;
     140              : }
     141              : 
     142            0 : void VstAudioClient::setOutputSpec(const audio::OutputSpec& spec)
     143              : {
     144            0 :     if (m_outputSpec == spec) {
     145            0 :         return;
     146              :     }
     147              : 
     148            0 :     m_processData.numSamples = static_cast<Steinberg::int32>(spec.samplesPerChannel);
     149            0 :     m_outputSpec = spec;
     150            0 :     m_needUnprepareProcessData = true;
     151            0 :     m_needUpdateState = false;
     152              : 
     153            0 :     updateProcessSetup();
     154              : }
     155              : 
     156            0 : void VstAudioClient::setProcessMode(VstProcessMode mode)
     157              : {
     158            0 :     if (m_processMode == mode) {
     159            0 :         return;
     160              :     }
     161              : 
     162            0 :     m_processMode = mode;
     163            0 :     m_needUnprepareProcessData = true;
     164            0 :     m_needUpdateState = false;
     165              : 
     166            0 :     updateProcessSetup();
     167              : }
     168              : 
     169            0 : void VstAudioClient::setVolumeGain(const muse::audio::gain_t newVolumeGain)
     170              : {
     171            0 :     m_volumeGain = newVolumeGain;
     172            0 : }
     173              : 
     174            0 : bool VstAudioClient::handleEvent(const VstEvent& event)
     175              : {
     176            0 :     ensureActivity();
     177              : 
     178            0 :     if (event.type == VstEvent::kNoteOnEvent) {
     179            0 :         size_t key = noteEventKey(event.noteOn.pitch, event.noteOn.channel);
     180            0 :         m_playingNotes.insert_or_assign(key, event);
     181            0 :     } else if (event.type == VstEvent::kNoteOffEvent) {
     182            0 :         size_t key = noteEventKey(event.noteOff.pitch, event.noteOff.channel);
     183            0 :         m_playingNotes.erase(key);
     184              :     }
     185              : 
     186            0 :     if (m_inputEvents.addEvent(const_cast<VstEvent&>(event)) == Steinberg::kResultTrue) {
     187            0 :         return true;
     188              :     }
     189              : 
     190            0 :     return false;
     191              : }
     192              : 
     193            0 : bool VstAudioClient::handleParamChange(const ParamChangeEvent& param)
     194              : {
     195            0 :     ensureActivity();
     196            0 :     addParamChange(param);
     197              : 
     198            0 :     m_playingParams.push_back(param.paramId);
     199              : 
     200            0 :     return true;
     201              : }
     202              : 
     203            0 : void VstAudioClient::flushSound()
     204              : {
     205            0 :     if (m_playingNotes.empty() && m_playingParams.empty()) {
     206            0 :         return;
     207              :     }
     208              : 
     209            0 :     flushBuffers();
     210              : 
     211            0 :     m_inputEvents.clear();
     212            0 :     m_inputParamChanges.clearQueue();
     213              : 
     214            0 :     for (const auto& pair : m_playingNotes) {
     215            0 :         const VstEvent& noteOn = pair.second;
     216              : 
     217              :         VstEvent noteOff;
     218            0 :         noteOff.type = VstEvent::kNoteOffEvent;
     219            0 :         noteOff.ppqPosition = 0;
     220            0 :         noteOff.sampleOffset = 0;
     221            0 :         noteOff.busIndex = noteOn.busIndex;
     222            0 :         noteOff.flags = noteOn.flags;
     223            0 :         noteOff.noteOff.noteId = noteOn.noteOn.noteId;
     224            0 :         noteOff.noteOff.channel = noteOn.noteOn.channel;
     225            0 :         noteOff.noteOff.pitch = noteOn.noteOn.pitch;
     226            0 :         noteOff.noteOff.tuning = noteOn.noteOn.tuning;
     227            0 :         noteOff.noteOff.velocity = noteOn.noteOn.velocity;
     228              : 
     229            0 :         m_inputEvents.addEvent(noteOff);
     230              :     }
     231              : 
     232            0 :     for (PluginParamId id : m_playingParams) {
     233            0 :         auto infoIt = m_pluginParamInfoMap.find(id);
     234            0 :         if (infoIt == m_pluginParamInfoMap.end()) {
     235            0 :             continue;
     236              :         }
     237              : 
     238            0 :         ParamChangeEvent paramOff;
     239            0 :         paramOff.paramId = id;
     240            0 :         paramOff.value = infoIt->second.defaultNormalizedValue;
     241              : 
     242            0 :         addParamChange(paramOff);
     243              :     }
     244              : 
     245            0 :     m_playingNotes.clear();
     246            0 :     m_playingParams.clear();
     247              : }
     248              : 
     249            0 : audio::samples_t VstAudioClient::process(float* output, samples_t samplesPerChannel,
     250              :                                          samples_t playbackPositionSamples)
     251              : {
     252            0 :     IAudioProcessorPtr processor = pluginProcessor();
     253            0 :     if (!processor || !output) {
     254            0 :         return 0;
     255              :     }
     256              : 
     257            0 :     if (!m_isActive) {
     258            0 :         return 0;
     259              :     }
     260              : 
     261              :     //! NOTE: From the VST3 documentation:
     262              :     //!
     263              :     //! Note that the ProcessData->numSamples
     264              :     //! which indicates how many samples are used in a process call can change from call to call,
     265              :     //! but never bigger than the maxSamplesPerBlock
     266            0 :     m_processData.numSamples = samplesPerChannel;
     267              : 
     268            0 :     m_processContext.projectTimeSamples = playbackPositionSamples;
     269              : 
     270            0 :     if (samplesPerChannel > m_outputSpec.samplesPerChannel) {
     271            0 :         OutputSpec newSpec = m_outputSpec;
     272            0 :         newSpec.samplesPerChannel = samplesPerChannel;
     273            0 :         setOutputSpec(newSpec);
     274              :     }
     275              : 
     276            0 :     if (m_type == PluginType::Fx) {
     277            0 :         extractInputSamples(samplesPerChannel, output);
     278              :     }
     279              : 
     280            0 :     if (processor->process(m_processData) != Steinberg::kResultOk) {
     281            0 :         return 0;
     282              :     }
     283              : 
     284            0 :     m_needUpdateState = false;
     285              : 
     286            0 :     if (m_type == PluginType::Instrument) {
     287            0 :         m_inputEvents.clear();
     288            0 :         m_inputParamChanges.clearQueue();
     289              : 
     290            0 :         fillOutputBufferInstrument(samplesPerChannel, output);
     291              :     } else {
     292            0 :         fillOutputBufferFx(samplesPerChannel, output);
     293              :     }
     294              : 
     295            0 :     processOutputEvents();
     296              : 
     297            0 :     return samplesPerChannel;
     298            0 : }
     299              : 
     300            0 : ParamsMapping VstAudioClient::paramsMapping(const std::set<Steinberg::Vst::CtrlNumber>& controllers) const
     301              : {
     302            0 :     ParamsMapping result;
     303              : 
     304            0 :     if (!m_pluginPtr) {
     305            0 :         return result;
     306              :     }
     307              : 
     308            0 :     PluginMidiMappingPtr midiMapping = m_pluginPtr->midiMapping();
     309            0 :     if (!midiMapping) {
     310            0 :         return result;
     311              :     }
     312              : 
     313            0 :     for (const int busIdx : m_activeInputBusses) {
     314            0 :         for (const auto& ctrlNum : controllers) {
     315            0 :             PluginParamId id = 0;
     316              : 
     317            0 :             if (midiMapping->getMidiControllerAssignment(busIdx, 0, ctrlNum, id) != Steinberg::kResultOk) {
     318            0 :                 continue;
     319              :             }
     320              : 
     321            0 :             result.emplace(ctrlNum, id);
     322              :         }
     323              :     }
     324              : 
     325            0 :     return result;
     326            0 : }
     327              : 
     328            0 : IAudioProcessorPtr VstAudioClient::pluginProcessor() const
     329              : {
     330            0 :     return static_cast<IAudioProcessorPtr>(pluginComponent());
     331              : }
     332              : 
     333            0 : PluginComponentPtr VstAudioClient::pluginComponent() const
     334              : {
     335            0 :     if (!m_pluginComponent) {
     336            0 :         if (!m_pluginPtr) {
     337            0 :             return nullptr;
     338              :         }
     339              : 
     340            0 :         m_pluginComponent = m_pluginPtr->component();
     341              :     }
     342              : 
     343            0 :     return m_pluginComponent;
     344              : }
     345              : 
     346            0 : void VstAudioClient::setUpProcessData()
     347              : {
     348            0 :     PluginComponentPtr component = pluginComponent();
     349            0 :     if (!component) {
     350            0 :         return;
     351              :     }
     352              : 
     353            0 :     m_processContext.sampleRate = m_outputSpec.sampleRate;
     354            0 :     m_processData.inputEvents = &m_inputEvents;
     355            0 :     m_processData.inputParameterChanges = &m_inputParamChanges;
     356            0 :     m_processData.outputEvents = &m_outputEvents;
     357            0 :     m_processData.processContext = &m_processContext;
     358              : 
     359            0 :     if (m_needUnprepareProcessData) {
     360            0 :         m_processData.unprepare();
     361            0 :         m_needUnprepareProcessData = false;
     362              :     }
     363              : 
     364            0 :     if (!m_processData.outputs || !m_processData.inputs) {
     365            0 :         m_processData.prepare(*component, m_outputSpec.samplesPerChannel, Steinberg::Vst::kSample32);
     366              :     }
     367              : 
     368            0 :     if (!m_activeOutputBusses.empty() && !m_activeInputBusses.empty()) {
     369            0 :         return;
     370              :     }
     371              : 
     372              :     BusInfo busInfo;
     373              : 
     374            0 :     for (int busIndex = 0; busIndex < m_processData.numInputs; ++busIndex) {
     375            0 :         component->getBusInfo(BusMediaType::kAudio, BusDirection::kInput, busIndex, busInfo);
     376              : 
     377            0 :         if (busInfo.busType == BusType::kMain && (busInfo.flags & BusInfo::kDefaultActive)) {
     378            0 :             component->activateBus(BusMediaType::kAudio, BusDirection::kInput, busIndex, true);
     379            0 :             m_activeInputBusses.emplace_back(busIndex);
     380              :         }
     381              :     }
     382              : 
     383            0 :     for (int busIndex = 0; busIndex < m_processData.numOutputs; ++busIndex) {
     384            0 :         component->getBusInfo(BusMediaType::kAudio, BusDirection::kOutput, busIndex, busInfo);
     385              : 
     386            0 :         if (busInfo.busType == BusType::kMain && (busInfo.flags & BusInfo::kDefaultActive)) {
     387            0 :             component->activateBus(BusMediaType::kAudio, BusDirection::kOutput, busIndex, true);
     388            0 :             m_activeOutputBusses.emplace_back(busIndex);
     389              :         }
     390              : 
     391            0 :         LOGI() << "BusIndex: " << busIndex;
     392              : 
     393            0 :         if (busInfo.busType == BusType::kMain) {
     394            0 :             LOGI() << "BusType: Main";
     395              :         } else {
     396            0 :             LOGI() << "BusType: Aux";
     397              :         }
     398              : 
     399            0 :         if (busInfo.flags & BusInfo::kDefaultActive) {
     400            0 :             LOGI() << "BusFlag: DefaultActive";
     401              :         } else {
     402            0 :             LOGI() << "BusFlag: ControlVoltage";
     403              :         }
     404              :     }
     405              : 
     406            0 :     if (m_activeInputBusses.empty()) {
     407            0 :         LOGI() << "0 active input buses, activating default bus";
     408            0 :         component->activateBus(BusMediaType::kAudio, BusDirection::kInput, 0, true);
     409            0 :         m_activeInputBusses.emplace_back(0);
     410              :     }
     411              : 
     412            0 :     if (m_activeOutputBusses.empty()) {
     413            0 :         LOGI() << "0 active output buses, activating default bus";
     414            0 :         component->activateBus(BusMediaType::kAudio, BusDirection::kOutput, 0, true);
     415            0 :         m_activeOutputBusses.emplace_back(0);
     416              :     }
     417            0 : }
     418              : 
     419            0 : void VstAudioClient::updateProcessSetup()
     420              : {
     421            0 :     if (!m_outputSpec.isValid()) {
     422            0 :         return;
     423              :     }
     424              : 
     425            0 :     IAudioProcessorPtr processor = pluginProcessor();
     426            0 :     if (!processor) {
     427            0 :         return;
     428              :     }
     429              : 
     430            0 :     disableActivity();
     431              : 
     432              :     VstProcessSetup setup;
     433            0 :     setup.processMode = m_processMode;
     434            0 :     setup.symbolicSampleSize = Steinberg::Vst::kSample32;
     435            0 :     setup.maxSamplesPerBlock = m_outputSpec.samplesPerChannel;
     436            0 :     setup.sampleRate = m_outputSpec.sampleRate;
     437              : 
     438            0 :     if (processor->setupProcessing(setup) != Steinberg::kResultOk) {
     439            0 :         return;
     440              :     }
     441              : 
     442            0 :     setUpProcessData();
     443            0 :     flushBuffers();
     444              : 
     445            0 :     ensureActivity();
     446            0 : }
     447              : 
     448            0 : void VstAudioClient::extractInputSamples(samples_t sampleCount, const float* sourceBuffer)
     449              : {
     450            0 :     if (!m_processData.inputs || !sourceBuffer) {
     451            0 :         return;
     452              :     }
     453              : 
     454            0 :     Steinberg::Vst::AudioBusBuffers& bus = m_processData.inputs[0];
     455              : 
     456            0 :     for (samples_t sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex) {
     457            0 :         size_t offset = sampleIndex * m_outputSpec.audioChannelCount;
     458              : 
     459            0 :         for (audioch_t audioChannelIndex = 0; audioChannelIndex < bus.numChannels; ++audioChannelIndex) {
     460            0 :             bus.channelBuffers32[audioChannelIndex][sampleIndex] = sourceBuffer[offset + audioChannelIndex];
     461              :         }
     462              :     }
     463              : }
     464              : 
     465            0 : void VstAudioClient::fillOutputBufferInstrument(samples_t sampleCount, float* output)
     466              : {
     467            0 :     if (!m_processData.outputs) {
     468            0 :         return;
     469              :     }
     470              : 
     471            0 :     for (const int busIndex : m_activeOutputBusses) {
     472            0 :         Steinberg::Vst::AudioBusBuffers bus = m_processData.outputs[busIndex];
     473              : 
     474            0 :         for (samples_t sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex) {
     475            0 :             size_t offset = sampleIndex * m_outputSpec.audioChannelCount;
     476              : 
     477            0 :             for (audioch_t audioChannelIndex = 0; audioChannelIndex < bus.numChannels; ++audioChannelIndex) {
     478            0 :                 float sample = bus.channelBuffers32[audioChannelIndex][sampleIndex];
     479            0 :                 output[offset + audioChannelIndex] += sample * m_volumeGain;
     480              :             }
     481              :         }
     482              :     }
     483              : }
     484              : 
     485            0 : void VstAudioClient::fillOutputBufferFx(samples_t sampleCount, float* output)
     486              : {
     487            0 :     if (!m_processData.outputs) {
     488            0 :         return;
     489              :     }
     490              : 
     491            0 :     for (const int busIndex : m_activeOutputBusses) {
     492            0 :         Steinberg::Vst::AudioBusBuffers bus = m_processData.outputs[busIndex];
     493              : 
     494            0 :         for (samples_t sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex) {
     495            0 :             size_t offset = sampleIndex * m_outputSpec.audioChannelCount;
     496              : 
     497            0 :             for (audioch_t audioChannelIndex = 0; audioChannelIndex < bus.numChannels; ++audioChannelIndex) {
     498            0 :                 float sample = bus.channelBuffers32[audioChannelIndex][sampleIndex];
     499            0 :                 output[offset + audioChannelIndex] = sample * m_volumeGain;
     500              :             }
     501              :         }
     502              :     }
     503              : }
     504              : 
     505            0 : void VstAudioClient::processOutputEvents()
     506              : {
     507            0 :     const int32_t count = m_outputEvents.getEventCount();
     508            0 :     if (count == 0) {
     509            0 :         return;
     510              :     }
     511              : 
     512            0 :     if (!m_mmcDecoder || !transportEventsDispatcher()) {
     513            0 :         m_outputEvents.clear();
     514            0 :         return;
     515              :     }
     516              : 
     517            0 :     TransportEvents events;
     518              : 
     519            0 :     for (int32_t i = 0; i < count; ++i) {
     520              :         VstEvent vstEvent;
     521            0 :         if (m_outputEvents.getEvent(i, vstEvent) != Steinberg::kResultOk) {
     522            0 :             continue;
     523              :         }
     524              : 
     525            0 :         if (vstEvent.type != Steinberg::Vst::Event::kDataEvent
     526            0 :             || vstEvent.data.type != Steinberg::Vst::DataEvent::kMidiSysEx) {
     527            0 :             continue;
     528              :         }
     529              : 
     530            0 :         std::optional<MMCMessage> msg = m_mmcDecoder->decode(vstEvent.data.bytes, vstEvent.data.size);
     531            0 :         if (!msg.has_value()) {
     532            0 :             continue;
     533              :         }
     534              : 
     535            0 :         std::optional<TransportEvent> event = mmcToTransportEvent(m_mmcDecoder, msg.value());
     536            0 :         if (event.has_value()) {
     537            0 :             events.push_back(event.value());
     538              :         }
     539            0 :     }
     540              : 
     541            0 :     m_outputEvents.clear();
     542              : 
     543            0 :     if (!events.empty()) {
     544            0 :         transportEventsDispatcher()->dispatch(events);
     545              :     }
     546            0 : }
     547              : 
     548            0 : void VstAudioClient::ensureActivity()
     549              : {
     550            0 :     if (m_isActive) {
     551            0 :         return;
     552              :     }
     553              : 
     554            0 :     IAudioProcessorPtr processor = pluginProcessor();
     555            0 :     if (!processor) {
     556            0 :         return;
     557              :     }
     558              : 
     559            0 :     PluginComponentPtr component = pluginComponent();
     560            0 :     if (!component) {
     561            0 :         return;
     562              :     }
     563              : 
     564            0 :     component->setActive(true);
     565            0 :     processor->setProcessing(true);
     566              : 
     567            0 :     m_isActive = true;
     568            0 : }
     569              : 
     570            0 : void VstAudioClient::disableActivity()
     571              : {
     572            0 :     if (!m_isActive) {
     573            0 :         return;
     574              :     }
     575              : 
     576            0 :     IAudioProcessorPtr processor = pluginProcessor();
     577            0 :     if (!processor) {
     578            0 :         return;
     579              :     }
     580              : 
     581            0 :     PluginComponentPtr component = pluginComponent();
     582            0 :     if (!component) {
     583            0 :         return;
     584              :     }
     585              : 
     586            0 :     if (m_needUpdateState) {
     587            0 :         processor->process(m_processData);
     588            0 :         m_needUpdateState = false;
     589              :     }
     590              : 
     591            0 :     processor->setProcessing(false);
     592            0 :     component->setActive(false);
     593              : 
     594            0 :     m_isActive = false;
     595            0 : }
     596              : 
     597            0 : void VstAudioClient::flushBuffers()
     598              : {
     599            0 :     for (int inputsNumber = 0; inputsNumber < m_processData.numInputs; ++inputsNumber) {
     600            0 :         Steinberg::Vst::AudioBusBuffers input = m_processData.inputs[inputsNumber];
     601              : 
     602            0 :         for (int i = 0; i < m_processData.numSamples; ++i) {
     603            0 :             for (int audioChannel = 0; audioChannel < input.numChannels; ++audioChannel) {
     604            0 :                 input.channelBuffers32[audioChannel][i] = 0.f;
     605              :             }
     606              :         }
     607              :     }
     608              : 
     609            0 :     for (int outputsNumber = 0; outputsNumber < m_processData.numOutputs; ++outputsNumber) {
     610            0 :         Steinberg::Vst::AudioBusBuffers output = m_processData.outputs[outputsNumber];
     611              : 
     612            0 :         for (int i = 0; i < m_processData.numSamples; ++i) {
     613            0 :             for (int audioChannel = 0; audioChannel < output.numChannels; ++audioChannel) {
     614            0 :                 output.channelBuffers32[audioChannel][i] = 0.f;
     615              :             }
     616              :         }
     617              :     }
     618            0 : }
     619              : 
     620            0 : void VstAudioClient::addParamChange(const ParamChangeEvent& param)
     621              : {
     622            0 :     Steinberg::int32 dummyIdx = 0;
     623            0 :     Steinberg::Vst::IParamValueQueue* queue = m_inputParamChanges.addParameterData(param.paramId, dummyIdx);
     624            0 :     if (queue) {
     625            0 :         queue->addPoint(0, param.value, dummyIdx);
     626              :     }
     627            0 : }
        

Generated by: LCOV version 2.0-1