17#include "host-proxy.hxx"
24void ClapNameCopy(
char* destination,
const char* source)
26 strncpy(destination, source, CLAP_NAME_SIZE);
27 destination[CLAP_NAME_SIZE - 1] = 0;
30IPlugCLAP::IPlugCLAP(
const InstanceInfo& info,
const Config& config)
33 , ClapPluginHelper(info.mDesc, info.mHost)
35 Trace(TRACELOC,
"%s", config.pluginName);
39 if (CStringHasContents(info.mHost->version))
43 sscanf(info.mHost->version,
"%d.%d.%d", &ver, &rmaj, &rmin);
44 version = (ver << 16) + (rmaj << 8) + rmin;
48 int nChans = RequiredChannels();
49 mAudioIO32.Resize(nChans);
50 mAudioIO64.Resize(nChans);
52 SetHost(info.mHost->name, version);
56uint32_t IPlugCLAP::tailGet() const noexcept
63 mParamValuesToHost.
PushFromArgs(ParamToHost::Type::Begin, idx, 0.0);
68 const IParam* pParam = GetParam(idx);
69 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
70 const double value = isDoubleType ? normalizedValue : pParam->
FromNormalized(normalizedValue);
72 mParamValuesToHost.
PushFromArgs(ParamToHost::Type::Value, idx, value);
77 mParamValuesToHost.
PushFromArgs(ParamToHost::Type::End, idx, 0.0);
84 if (viewWidth != GetEditorWidth() || viewHeight != GetEditorHeight())
86 GetClapHost().guiRequestResize(viewWidth, viewHeight);
89 SetEditorSize(viewWidth, viewHeight);
100 if (GetClapHost().canUseTail())
108 if (GetClapHost().canUseLatency())
113 mLatencyUpdate =
true;
114 runOnMainThread([&](){
if (!isBeingDestroyed()) GetClapHost().requestRestart(); });
118 runOnMainThread([&](){
if (!isBeingDestroyed()) GetClapHost().latencyChanged(); });
125 mMidiToHost.Add(msg);
132 SysExData data(msg.mOffset, msg.mSize, msg.mData);
133 mSysExToHost.Add(data);
138bool IPlugCLAP::init() noexcept
145bool IPlugCLAP::activate(
double sampleRate, uint32_t minFrameCount, uint32_t maxFrameCount)
noexcept
147 SetBlockSize(maxFrameCount);
148 SetSampleRate(sampleRate);
150 OnParamReset(kReset);
153 mHostHasTail = GetClapHost().canUseTail();
159void IPlugCLAP::deactivate() noexcept
165 GetClapHost().latencyChanged();
166 mLatencyUpdate =
false;
173const T* ClapEventCast(
const clap_event_header_t* event)
175 return reinterpret_cast<const T*
>(event);
179bool InputIsSilent(
const T* data,
int nFrames)
182 auto isZero = [](T x) {
return x == T(0); };
184 return std::find_if_not(data, data + nFrames, isZero) == (data + nFrames);
187clap_process_status IPlugCLAP::process(
const clap_process* pProcess)
noexcept
193 if (pProcess->transport)
197 auto pTransport = pProcess->transport;
199 constexpr double beatFactor =
static_cast<double>(CLAP_BEATTIME_FACTOR);
200 constexpr double secFactor =
static_cast<double>(CLAP_SECTIME_FACTOR);
202 if (pTransport->flags & CLAP_TRANSPORT_HAS_TEMPO)
203 timeInfo.mTempo = pTransport->tempo;
206 if (pTransport->flags & CLAP_TRANSPORT_HAS_SECONDS_TIMELINE)
207 timeInfo.mSamplePos = (GetSampleRate() *
static_cast<double>(pTransport->song_pos_seconds) / secFactor);
209 if (pTransport->flags & CLAP_TRANSPORT_HAS_BEATS_TIMELINE)
211 timeInfo.mPPQPos =
static_cast<double>(pTransport->song_pos_beats) / beatFactor;
212 timeInfo.mLastBar =
static_cast<double>(pTransport->bar_start) / beatFactor;
213 timeInfo.mCycleStart =
static_cast<double>(pTransport->loop_start_beats) / beatFactor;
214 timeInfo.mCycleEnd =
static_cast<double>(pTransport->loop_end_beats) / beatFactor;
217 if (pTransport->flags & CLAP_TRANSPORT_HAS_TIME_SIGNATURE)
219 timeInfo.mNumerator =
static_cast<int>(pTransport->tsig_num);
220 timeInfo.mDenominator =
static_cast<int>(pTransport->tsig_denom);
223 timeInfo.mTransportIsRunning = pTransport->flags & CLAP_TRANSPORT_IS_PLAYING;
224 timeInfo.mTransportLoopEnabled = pTransport->flags & CLAP_TRANSPORT_IS_LOOP_ACTIVE;
226 SetTimeInfo(timeInfo);
230 ProcessInputEvents(pProcess->in_events);
232 while (mMidiMsgsFromEditor.Pop(msg))
237 while (mSysExDataFromEditor.Pop(sysEx))
239 SendSysEx(
ISysEx(sysEx.mOffset, sysEx.mData, sysEx.mSize));
245 int nFrames = pProcess->frames_count;
248 bool localTail = !mHostHasTail && !GetTailIsInfinite() && GetTailSize();
249 bool insQuiet =
true;
252 for (uint32_t i = 0; i < pProcess->audio_inputs_count; i++)
253 nIns +=
static_cast<int>(pProcess->audio_inputs[i].channel_count);
255 for (uint32_t i = 0; i < pProcess->audio_outputs_count; i++)
256 nOuts +=
static_cast<int>(pProcess->audio_outputs[i].channel_count);
259 bool format64 =
false;
261 if (pProcess->audio_inputs_count && pProcess->audio_inputs && pProcess->audio_inputs[0].channel_count)
262 format64 = pProcess->audio_inputs[0].data64;
263 else if (pProcess->audio_outputs_count && pProcess->audio_outputs && pProcess->audio_outputs[0].channel_count)
264 format64 = pProcess->audio_outputs[0].data64;
268 for (uint32_t i = 0; i < pProcess->audio_inputs_count; i++)
270 auto bus = pProcess->audio_inputs[i];
271 assert(!bus.channel_count || format64 ==
static_cast<bool>(bus.data64));
274 for (uint32_t i = 0; i < pProcess->audio_outputs_count; i++)
276 auto bus = pProcess->audio_outputs[i];
277 assert(!bus.channel_count || format64 ==
static_cast<bool>(bus.data64));
281 SetChannelConnections(ERoute::kInput, 0, MaxNChannels(ERoute::kInput),
false);
282 SetChannelConnections(ERoute::kInput, 0, nIns,
true);
289 for (uint32_t i = 0, k = 0; i < pProcess->audio_inputs_count; i++)
291 auto bus = pProcess->audio_inputs[i];
293 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
295 mAudioIO64.Get()[k] = bus.data64[j];
299 if (localTail && insQuiet)
300 insQuiet = InputIsSilent(bus.data64[j], nFrames);
304 AttachBuffers(ERoute::kInput, 0, nIns, mAudioIO64.Get(), nFrames);
308 for (uint32_t i = 0, k = 0; i < pProcess->audio_inputs_count; i++)
310 auto bus = pProcess->audio_inputs[i];
312 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
314 mAudioIO32.Get()[k] = bus.data32[j];
317 if (localTail && insQuiet)
318 insQuiet = InputIsSilent(bus.data32[j], nFrames);
322 AttachBuffers(ERoute::kInput, 0, nIns, mAudioIO32.Get(), nFrames);
326 SetChannelConnections(ERoute::kOutput, 0, MaxNChannels(ERoute::kOutput),
false);
327 SetChannelConnections(ERoute::kOutput, 0, nOuts,
true);
334 for (uint32_t i = 0, k = 0; i < pProcess->audio_outputs_count; i++)
336 auto bus = pProcess->audio_outputs[i];
337 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
338 mAudioIO64.Get()[k] = bus.data64[j];
341 AttachBuffers(ERoute::kOutput, 0, nOuts, mAudioIO64.Get(), nFrames);
345 for (uint32_t i = 0, k = 0; i < pProcess->audio_outputs_count; i++)
347 auto bus = pProcess->audio_outputs[i];
348 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
349 mAudioIO32.Get()[k] = bus.data32[j];
352 AttachBuffers(ERoute::kOutput, 0, nOuts, mAudioIO32.Get(), nFrames);
357 ProcessBuffers(0.0, nFrames);
359 ProcessBuffers(0.f, nFrames);
362 ProcessOutputEvents(pProcess->out_events, nFrames);
367 GetClapHost().tailChanged();
373 return CLAP_PROCESS_TAIL;
378 return CLAP_PROCESS_CONTINUE_IF_NOT_QUIET;
381 if (GetTailIsInfinite())
382 return CLAP_PROCESS_CONTINUE;
385 mTailCount = insQuiet ? std::min(mTailCount + nFrames, GetTailSize()) : 0;
387 return mTailCount < GetTailSize() ? CLAP_PROCESS_CONTINUE : CLAP_PROCESS_SLEEP;
390 return CLAP_PROCESS_CONTINUE;
395bool IPlugCLAP::renderSetMode(clap_plugin_render_mode mode)
noexcept
397 SetRenderingOffline(mode == CLAP_RENDER_OFFLINE);
402bool IPlugCLAP::stateSave(
const clap_ostream* pStream)
noexcept
406 if (!SerializeState(chunk))
409 return pStream->write(pStream, chunk.
GetData(), chunk.
Size()) == chunk.
Size();
412bool IPlugCLAP::stateLoad(
const clap_istream* pStream)
noexcept
414 constexpr int bytesPerBlock = 256;
415 char buffer[bytesPerBlock];
416 int64_t bytesRead = 0;
420 while ((bytesRead = pStream->read(pStream, buffer, bytesPerBlock)) > 0)
421 chunk.
PutBytes(buffer,
static_cast<int>(bytesRead));
426 bool restoredOK = UnserializeState(chunk, 0) >= 0;
435bool IPlugCLAP::paramsInfo(uint32_t paramIdx, clap_param_info* pInfo)
const noexcept
437 assert(MAX_PARAM_NAME_LEN <= CLAP_NAME_SIZE &&
"iPlug parameter name size exceeds CLAP maximum");
438 assert(MAX_PARAM_GROUP_LEN <= CLAP_PATH_SIZE &&
"iPlug group name size exceeds CLAP maximum");
440 const IParam* pParam = GetParam(paramIdx);
441 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
443 clap_param_info_flags flags = CLAP_PARAM_REQUIRES_PROCESS;
446 flags |= CLAP_PARAM_IS_STEPPED;
448 flags |= CLAP_PARAM_IS_AUTOMATABLE;
450 pInfo->id = paramIdx;
451 pInfo->flags = flags;
452 pInfo->cookie =
nullptr;
454 strcpy(pInfo->name, pParam->
GetName());
455 strcpy(pInfo->module, pParam->
GetGroup());
458 pInfo->min_value = isDoubleType ? 0.0 : pParam->
GetMin();
459 pInfo->max_value = isDoubleType ? 1.0 : pParam->
GetMax();
460 pInfo->default_value = pParam->
GetDefault(isDoubleType);
465bool IPlugCLAP::paramsValue(clap_id paramIdx,
double* pValue)
noexcept
467 const IParam* pParam = GetParam(paramIdx);
468 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
473bool IPlugCLAP::paramsValueToText(clap_id paramIdx,
double value,
char* display, uint32_t size)
noexcept
475 const IParam* pParam = GetParam(paramIdx);
476 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
483 if (CStringHasContents(pParam->
GetLabel()))
489 if (size < str.GetLength())
492 strcpy(display, str.Get());
496bool IPlugCLAP::paramsTextToValue(clap_id paramIdx,
const char* display,
double* pValue)
noexcept
498 const IParam* pParam = GetParam(paramIdx);
499 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
502 *pValue = isDoubleType ? pParam->
ToNormalized(paramValue) : paramValue;
506void IPlugCLAP::paramsFlush(
const clap_input_events* pInputParamChanges,
const clap_output_events* pOutputParamChanges)
noexcept
508 ProcessInputEvents(pInputParamChanges);
509 ProcessOutputParams(pOutputParamChanges);
512void IPlugCLAP::ProcessInputEvents(
const clap_input_events* pInputEvents)
noexcept
518 for (
int i = 0; i < pInputEvents->size(pInputEvents); i++)
520 auto pEvent = pInputEvents->get(pInputEvents, i);
522 if (pEvent->space_id != CLAP_CORE_EVENT_SPACE_ID)
525 switch (pEvent->type)
527 case CLAP_EVENT_NOTE_ON:
530 auto pNote = ClapEventCast<clap_event_note>(pEvent);
531 auto velocity =
static_cast<int>(std::round(pNote->velocity * 127.0));
532 msg.
MakeNoteOnMsg(pNote->key, velocity, pEvent->time, pNote->channel);
534 mMidiMsgsFromProcessor.Push(msg);
538 case CLAP_EVENT_NOTE_OFF:
540 auto pNote = ClapEventCast<clap_event_note>(pEvent);
543 mMidiMsgsFromProcessor.Push(msg);
547 case CLAP_EVENT_MIDI:
549 auto pMidiEvent = ClapEventCast<clap_event_midi>(pEvent);
550 msg =
IMidiMsg(pEvent->time, pMidiEvent->data[0], pMidiEvent->data[1], pMidiEvent->data[2]);
552 mMidiMsgsFromProcessor.Push(msg);
556 case CLAP_EVENT_MIDI_SYSEX:
558 auto pSysexEvent = ClapEventCast<clap_event_midi_sysex>(pEvent);
559 ISysEx sysEx(pEvent->time, pSysexEvent->buffer, pSysexEvent->size);
561 mSysExDataFromProcessor.PushFromArgs(sysEx.mOffset, sysEx.mSize, sysEx.mData);
565 case CLAP_EVENT_PARAM_VALUE:
567 auto pParamValue = ClapEventCast<clap_event_param_value>(pEvent);
569 int paramIdx = pParamValue->param_id;
570 double value = pParamValue->value;
572 IParam* pParam = GetParam(paramIdx);
573 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
580 SendParameterValueFromAPI(paramIdx, value, isDoubleType);
581 OnParamChange(paramIdx, EParamSource::kHost, pEvent->time);
592void IPlugCLAP::ProcessOutputParams(
const clap_output_events* pOutputParamChanges)
noexcept
596 while (mParamValuesToHost.Pop(change))
599 bool isValue = change.type() == CLAP_EVENT_PARAM_VALUE;
601 clap_event_header_t header;
606 header.size = isValue ?
sizeof(clap_event_param_value) :
sizeof(clap_event_param_gesture);
608 header.space_id = CLAP_CORE_EVENT_SPACE_ID;
609 header.type = change.type();
614 clap_event_param_value
event { header, change.idx(),
nullptr, -1, -1, -1, -1, change.value() };
615 pOutputParamChanges->try_push(pOutputParamChanges, &event.header);
619 clap_event_param_gesture
event { header, change.idx() };
620 pOutputParamChanges->try_push(pOutputParamChanges, &event.header);
625void IPlugCLAP::ProcessOutputEvents(
const clap_output_events* pOutputEvents,
int nFrames)
noexcept
631 ProcessOutputParams(pOutputEvents);
635 clap_event_header_t header;
637 while (mMidiToHost.ToDo() || mSysExToHost.ToDo())
639 int midiMsgOffset = nFrames;
640 int sysExOffset = nFrames;
643 if (mMidiToHost.ToDo())
644 midiMsgOffset = mMidiToHost.Peek().mOffset;
646 if (mSysExToHost.ToDo())
647 sysExOffset = mSysExToHost.Peek().mOffset;
650 if (std::min(midiMsgOffset, sysExOffset) >= nFrames)
653 if (sysExOffset <= midiMsgOffset)
655 auto data = mSysExToHost.Peek();
657 uint32_t dataSize =
static_cast<uint32_t
>(data.mSize);
659 header.size =
sizeof(clap_event_midi_sysex);
660 header.time = data.mOffset;
661 header.space_id = CLAP_CORE_EVENT_SPACE_ID;
662 header.type = CLAP_EVENT_MIDI_SYSEX;
665 clap_event_midi_sysex sysex_event { header, 0, data.mData, dataSize };
667 pOutputEvents->try_push(pOutputEvents, &sysex_event.header);
669 mSysExToHost.Remove();
673 auto msg = mMidiToHost.Peek();
674 auto status = msg.mStatus;
677 header.size =
sizeof(clap_event_param_value);
678 header.time = msg.mOffset;
679 header.space_id = CLAP_CORE_EVENT_SPACE_ID;
680 header.type = CLAP_EVENT_MIDI;
683 if (msg.
StatusMsg() == IMidiMsg::kNoteOn)
684 header.type = CLAP_EVENT_NOTE_ON;
686 if (msg.
StatusMsg() == IMidiMsg::kNoteOff)
687 header.type = CLAP_EVENT_NOTE_OFF;
689 if (header.type == CLAP_EVENT_NOTE_ON || header.type == CLAP_EVENT_NOTE_OFF)
691 int16_t channel =
static_cast<int16_t
>(msg.
Channel());
692 clap_event_note note_event { header, -1, 0, channel, msg.mData1,
static_cast<double>(msg.mData2) / 127.0};
693 pOutputEvents->try_push(pOutputEvents, ¬e_event.header);
697 clap_event_midi midi_event { header, 0, { status, msg.mData1, msg.mData2 } };
698 pOutputEvents->try_push(pOutputEvents, &midi_event.header);
701 mMidiToHost.Remove();
705 mMidiToHost.Flush(nFrames);
706 mSysExToHost.Flush(nFrames);
710const char* ClapPortType(uint32_t nChans)
713 return nChans == 2 ? CLAP_PORT_STEREO : (nChans == 1 ? CLAP_PORT_MONO :
nullptr);
716bool IPlugCLAP::implementsAudioPorts() const noexcept
721uint32_t IPlugCLAP::audioPortsCount(
bool isInput)
const noexcept
723 return NBuses(isInput ? ERoute::kInput : ERoute::kOutput);
726bool IPlugCLAP::audioPortsInfo(uint32_t index,
bool isInput, clap_audio_port_info* pInfo)
const noexcept
731 const auto direction = isInput ? ERoute::kInput : ERoute::kOutput;
732 const auto nBuses = NBuses(direction);
733 const auto nChans = NChannels(direction, index);
735 GetBusName(direction, index, nBuses, busName);
737 constexpr uint32_t bitFlags = CLAP_AUDIO_PORT_SUPPORTS_64BITS
738 | CLAP_AUDIO_PORT_PREFERS_64BITS
739 | CLAP_AUDIO_PORT_REQUIRES_COMMON_SAMPLE_SIZE;
742 ClapNameCopy(pInfo->name, busName.Get());
743 pInfo->flags = !index ? bitFlags | CLAP_AUDIO_PORT_IS_MAIN : bitFlags;
744 pInfo->channel_count = nChans;
745 pInfo->port_type = ClapPortType(pInfo->channel_count);
746 pInfo->in_place_pair = CLAP_INVALID_ID;
750bool IPlugCLAP::implementsAudioPortsConfig() const noexcept
752 return audioPortsConfigCount();
755uint32_t IPlugCLAP::audioPortsConfigCount() const noexcept
760bool IPlugCLAP::audioPortsGetConfig(uint32_t index, clap_audio_ports_config* pConfig)
const noexcept
762 if (index >= audioPortsConfigCount())
765 WDL_String configName;
768 auto getNChans = [&](
ERoute direction,
int bus)
770 return static_cast<uint32_t
>(NChannels(direction,
static_cast<uint32_t
>(bus), index));
773 auto getDirectionName = [&](
ERoute direction)
776 configName.AppendFormatted(CLAP_NAME_SIZE,
"%d", getNChans(direction, 0));
778 for (
int i = 0; i < NBuses(direction, index); i++)
779 configName.AppendFormatted(CLAP_NAME_SIZE,
".%d", getNChans(direction, i));
782 getDirectionName(kInput);
783 configName.Append(
"-");
784 getDirectionName(kOutput);
787 ClapNameCopy(pConfig->name, configName.Get());
789 pConfig->input_port_count =
static_cast<uint32_t
>(NBuses(kInput, index));
790 pConfig->output_port_count =
static_cast<uint32_t
>(NBuses(kOutput, index));
792 pConfig->has_main_input = pConfig->input_port_count > 1;
793 pConfig->main_input_channel_count = pConfig->has_main_input ? getNChans(kInput, 0) : 0;
794 pConfig->main_input_port_type = ClapPortType(pConfig->main_input_channel_count);
796 pConfig->has_main_output = pConfig->output_port_count > 1;
797 pConfig->main_output_channel_count = pConfig->has_main_input ? getNChans(kOutput, 0) : 0;
798 pConfig->main_output_port_type = ClapPortType(pConfig->main_output_channel_count);
803bool IPlugCLAP::audioPortsSetConfig(clap_id configIdx)
noexcept
805 if (configIdx >= audioPortsConfigCount())
808 mConfigIdx =
static_cast<int>(configIdx);
813uint32_t IPlugCLAP::notePortsCount(
bool isInput)
const noexcept
816 return PLUG_DOES_MIDI_IN ? 1 : 0;
818 return PLUG_DOES_MIDI_OUT ? 1 : 0;
821bool IPlugCLAP::notePortsInfo(uint32_t index,
bool isInput, clap_note_port_info* pInfo)
const noexcept
826 pInfo->supported_dialects = CLAP_NOTE_DIALECT_MIDI;
827 pInfo->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
828 ClapNameCopy(pInfo->name,
"MIDI Input");
833 pInfo->supported_dialects = CLAP_NOTE_DIALECT_MIDI;
834 pInfo->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
835 ClapNameCopy(pInfo->name,
"MIDI Output");
841bool IPlugCLAP::guiIsApiSupported(
const char* api,
bool isFloating)
noexcept
844 return !isFloating && !strcmp(api, CLAP_WINDOW_API_COCOA);
846 return !isFloating && !strcmp(api, CLAP_WINDOW_API_WIN32);
848#error Not Implemented!
852bool IPlugCLAP::guiSetParent(
const clap_window* pWindow)
noexcept
855 return GUIWindowAttach(pWindow->cocoa);
857 return GUIWindowAttach(pWindow->win32);
859#error Not Implemented!
863bool IPlugCLAP::implementsGui() const noexcept
868bool IPlugCLAP::guiCreate(
const char* api,
bool isFloating)
noexcept
873void IPlugCLAP::guiDestroy() noexcept
880bool IPlugCLAP::guiShow() noexcept
882 if (
HasUI() && !mGUIOpen)
893bool IPlugCLAP::guiHide() noexcept
907bool IPlugCLAP::guiCanResize() const noexcept
912bool IPlugCLAP::guiSetScale(
double scale)
noexcept
916 SetScreenScale(
static_cast<float>(scale));
925bool IPlugCLAP::guiGetSize(uint32_t* pWidth, uint32_t* pHeight)
noexcept
931 *pWidth = GetEditorWidth();
932 *pHeight = GetEditorHeight();
942bool IPlugCLAP::GUIWindowAttach(
void* pWindow)
noexcept
957bool IPlugCLAP::guiAdjustSize(uint32_t* pWidth, uint32_t* pHeight)
noexcept
959 Trace(TRACELOC,
"width:%i height:%i\n", *pWidth, *pHeight);
965 ConstrainEditorResize(w, h);
977bool IPlugCLAP::guiSetSize(uint32_t width, uint32_t height)
noexcept
979 Trace(TRACELOC,
"width:%i height:%i\n", width, height);
983 OnParentWindowResize(width, height);
993void IPlugCLAP::SetDefaultConfig()
995 auto isMatch = [&](
int idx,
int chans)
997 if (NBuses(ERoute::kOutput, idx) >= 1 && NChannels(ERoute::kOutput, 0, idx) == chans)
999 int numBuses = NBuses(ERoute::kInput, idx);
1002 if (
IsInstrument() && (numBuses == 0 || NChannels(ERoute::kInput, 0, idx) == 0))
1006 return numBuses >= 1 && NChannels(ERoute::kInput, 0, idx) == chans;
1012 auto testMatches = [&](
int chans)
1014 bool matched =
false;
1015 int configNBusesI = 0;
1016 int configNBusesO = 0;
1018 for (
int i = 0; i < static_cast<int>(audioPortsConfigCount()); i++)
1020 if (isMatch(i, chans))
1022 const int nBusesI = NBuses(ERoute::kInput, i);
1023 const int nBusesO = NBuses(ERoute::kOutput, i);
1025 const bool preferInput = nBusesO < configNBusesI;
1026 const bool preferOutput = nBusesI < configNBusesO;
1028 if (!matched || preferOutput || (nBusesO == configNBusesO && preferInput))
1032 configNBusesI = NBuses(ERoute::kInput, i);
1033 configNBusesO = NBuses(ERoute::kOutput, i);
1044 if (GetClapHost().canUseTrackInfo())
1046 clap_track_info info;
1047 GetClapHost().trackInfoGet(&info);
1049 if (testMatches(info.audio_channel_count) || info.audio_channel_count == 2)
1057int IPlugCLAP::RequiredChannels()
const
1062uint32_t IPlugCLAP::NBuses(
ERoute direction,
int configIdx)
const
1067uint32_t IPlugCLAP::NChannels(
ERoute direction, uint32_t bus,
int configIdx)
const
1072uint32_t IPlugCLAP::NBuses(
ERoute direction)
const
1074 return NBuses(direction, mConfigIdx);
1077uint32_t IPlugCLAP::NChannels(
ERoute direction, uint32_t bus)
const
1079 return NChannels(direction, bus, mConfigIdx);
Manages a block of memory, for plug-in settings store/recall.
int PutBytes(const void *pSrc, int nBytesToCopy)
Copies data into the chunk, placing it at the end, resizing if necessary.
uint8_t * GetData()
Gets a ptr to the chunk data.
int Size() const
Returns the current size of the chunk.
double GetDefault(bool normalized=false) const
Returns the parameter's default value.
EParamType Type() const
Get the parameter's type.
double ToNormalized(double nonNormalizedValue) const
Convert a real value to normalized value for this parameter.
bool GetCanAutomate() const
void GetDisplay(WDL_String &display, bool withDisplayText=true) const
Get the current textual display for the current parameter value.
double GetMin() const
Returns the parameter's minimum value.
void Set(double value)
Sets the parameter value.
const char * GetLabel() const
Returns the parameter's label.
double StringToValue(const char *str) const
Convert a textual representation of the parameter value to a double (real value)
void SetNormalized(double normalizedValue)
Sets the parameter value from a normalized range (usually coming from the linked IControl)
const char * GetName() const
Returns the parameter's name.
double FromNormalized(double normalizedValue) const
Convert a normalized value to real value for this parameter.
double GetNormalized() const
Returns the parameter's normalized value.
const char * GetGroup() const
Returns the parameter's group.
double Value() const
Gets a readable value of the parameter.
double GetMax() const
Returns the parameter's maximum value.
The base class of an IPlug plug-in, which interacts with the different plug-in APIs.
bool SendSysEx(const ISysEx &msg) override
Send a single MIDI System Exclusive (SysEx) message // TODO: info about what thread should this be ca...
void InformHostOfParamChange(int idx, double normalizedValue) override
Implemented by the API class, called by the UI via SetParameterValue() with the value of a parameter ...
void SetTailSize(int tailSize) override
Call this method if you need to update the tail size at runtime, for example if the decay time of you...
void SetLatency(int samples) override
Call this if the latency of your plug-in changes after initialization (perhaps from OnReset() ) This ...
bool EditorResize(int viewWidth, int viewHeight) override
Implementations call into the APIs resize hooks returns a bool to indicate whether the DAW or plugin ...
void BeginInformHostOfParamChange(int idx) override
Implemented by the API class, called by the UI (or by a delegate) at the beginning of a parameter cha...
bool SendMidiMsg(const IMidiMsg &msg) override
Send a single MIDI message // TODO: info about what thread should this be called on or not called on!
void EndInformHostOfParamChange(int idx) override
Implemented by the API class, called by the UI (or by a delegate) at the end of a parameter change ge...
The base class for IPlug Audio Processing.
bool GetTailIsInfinite() const
const IOConfig * GetIOConfig(int idx) const
virtual void SetTailSize(int tailSize)
Call this method if you need to update the tail size at runtime, for example if the decay time of you...
virtual void SetLatency(int latency)
Call this if the latency of your plug-in changes after initialization (perhaps from OnReset() ) This ...
bool IsInstrument() const
int MaxNBuses(ERoute direction, int *pConfigIdxWithTheMostBuses=nullptr) const
Used to determine the maximum number of input or output buses based on what was specified in the chan...
int MaxNChannels(ERoute direction) const
virtual void OnActivate(bool active)
Override OnActivate() which should be called by the API class when a plug-in is "switched on" by the ...
bool PushFromArgs(Args ...args)
bool GetHostResizeEnabled() const
ERoute
Used to identify whether a bus/channel connection is an input or an output.
Encapsulates information about the host transport state.
Encapsulates a MIDI message and provides helper functions.
void MakeNoteOnMsg(int noteNumber, int velocity, int offset, int channel=0)
Make a Note On message.
int Channel() const
Gets the channel of a MIDI message.
void MakeNoteOffMsg(int noteNumber, int offset, int channel=0)
Make a Note Off message.
EStatusMsg StatusMsg() const
Gets the MIDI Status message.
int NChansOnBusSAFE(ERoute direction, int index) const
int NBuses(ERoute direction) const
A struct for dealing with SysEx messages.
This structure is used when queueing Sysex messages.