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
61void IPlugCLAP::FlushParamsIfNeeded()
64 runOnMainThread([&](){
if (!isBeingDestroyed()) GetClapHost().paramsRequestFlush(); });
69 mParamValuesToHost.
PushFromArgs(ParamToHost::Type::Begin, idx, 0.0);
70 FlushParamsIfNeeded();
75 const IParam* pParam = GetParam(idx);
76 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
77 const double value = isDoubleType ? normalizedValue : pParam->
FromNormalized(normalizedValue);
79 mParamValuesToHost.
PushFromArgs(ParamToHost::Type::Value, idx, value);
80 FlushParamsIfNeeded();
85 mParamValuesToHost.
PushFromArgs(ParamToHost::Type::End, idx, 0.0);
86 FlushParamsIfNeeded();
93 if (viewWidth != GetEditorWidth() || viewHeight != GetEditorHeight())
95 GetClapHost().guiRequestResize(viewWidth, viewHeight);
98 SetEditorSize(viewWidth, viewHeight);
109 if (GetClapHost().canUseTail())
117 if (GetClapHost().canUseLatency())
122 mLatencyUpdate =
true;
123 runOnMainThread([&](){
if (!isBeingDestroyed()) GetClapHost().requestRestart(); });
127 runOnMainThread([&](){
if (!isBeingDestroyed()) GetClapHost().latencyChanged(); });
134 mMidiToHost.Add(msg);
141 SysExData data(msg.mOffset, msg.mSize, msg.mData);
142 mSysExToHost.Add(data);
147bool IPlugCLAP::init() noexcept
154bool IPlugCLAP::activate(
double sampleRate, uint32_t minFrameCount, uint32_t maxFrameCount)
noexcept
156 SetBlockSize(maxFrameCount);
157 SetSampleRate(sampleRate);
159 OnParamReset(kReset);
162 mHostHasTail = GetClapHost().canUseTail();
168void IPlugCLAP::deactivate() noexcept
174 GetClapHost().latencyChanged();
175 mLatencyUpdate =
false;
182const T* ClapEventCast(
const clap_event_header_t* event)
184 return reinterpret_cast<const T*
>(event);
188bool InputIsSilent(
const T* data,
int nFrames)
191 auto isZero = [](T x) {
return x == T(0); };
193 return std::find_if_not(data, data + nFrames, isZero) == (data + nFrames);
196clap_process_status IPlugCLAP::process(
const clap_process* pProcess)
noexcept
202 if (pProcess->transport)
206 auto pTransport = pProcess->transport;
208 constexpr double beatFactor =
static_cast<double>(CLAP_BEATTIME_FACTOR);
209 constexpr double secFactor =
static_cast<double>(CLAP_SECTIME_FACTOR);
211 if (pTransport->flags & CLAP_TRANSPORT_HAS_TEMPO)
212 timeInfo.mTempo = pTransport->tempo;
215 if (pTransport->flags & CLAP_TRANSPORT_HAS_SECONDS_TIMELINE)
216 timeInfo.mSamplePos = (GetSampleRate() *
static_cast<double>(pTransport->song_pos_seconds) / secFactor);
218 if (pTransport->flags & CLAP_TRANSPORT_HAS_BEATS_TIMELINE)
220 timeInfo.mPPQPos =
static_cast<double>(pTransport->song_pos_beats) / beatFactor;
221 timeInfo.mLastBar =
static_cast<double>(pTransport->bar_start) / beatFactor;
222 timeInfo.mCycleStart =
static_cast<double>(pTransport->loop_start_beats) / beatFactor;
223 timeInfo.mCycleEnd =
static_cast<double>(pTransport->loop_end_beats) / beatFactor;
226 if (pTransport->flags & CLAP_TRANSPORT_HAS_TIME_SIGNATURE)
228 timeInfo.mNumerator =
static_cast<int>(pTransport->tsig_num);
229 timeInfo.mDenominator =
static_cast<int>(pTransport->tsig_denom);
232 timeInfo.mTransportIsRunning = pTransport->flags & CLAP_TRANSPORT_IS_PLAYING;
233 timeInfo.mTransportLoopEnabled = pTransport->flags & CLAP_TRANSPORT_IS_LOOP_ACTIVE;
235 SetTimeInfo(timeInfo);
239 ProcessInputEvents(pProcess->in_events);
241 while (mMidiMsgsFromEditor.Pop(msg))
246 while (mSysExDataFromEditor.Pop(sysEx))
248 SendSysEx(
ISysEx(sysEx.mOffset, sysEx.mData, sysEx.mSize));
254 int nFrames = pProcess->frames_count;
257 bool localTail = !mHostHasTail && !GetTailIsInfinite() && GetTailSize();
258 bool insQuiet =
true;
261 for (uint32_t i = 0; i < pProcess->audio_inputs_count; i++)
262 nIns +=
static_cast<int>(pProcess->audio_inputs[i].channel_count);
264 for (uint32_t i = 0; i < pProcess->audio_outputs_count; i++)
265 nOuts +=
static_cast<int>(pProcess->audio_outputs[i].channel_count);
268 bool format64 =
false;
270 if (pProcess->audio_inputs_count && pProcess->audio_inputs && pProcess->audio_inputs[0].channel_count)
271 format64 = pProcess->audio_inputs[0].data64;
272 else if (pProcess->audio_outputs_count && pProcess->audio_outputs && pProcess->audio_outputs[0].channel_count)
273 format64 = pProcess->audio_outputs[0].data64;
277 for (uint32_t i = 0; i < pProcess->audio_inputs_count; i++)
279 auto bus = pProcess->audio_inputs[i];
280 assert(!bus.channel_count || format64 ==
static_cast<bool>(bus.data64));
283 for (uint32_t i = 0; i < pProcess->audio_outputs_count; i++)
285 auto bus = pProcess->audio_outputs[i];
286 assert(!bus.channel_count || format64 ==
static_cast<bool>(bus.data64));
290 SetChannelConnections(ERoute::kInput, 0, MaxNChannels(ERoute::kInput),
false);
291 SetChannelConnections(ERoute::kInput, 0, nIns,
true);
298 for (uint32_t i = 0, k = 0; i < pProcess->audio_inputs_count; i++)
300 auto bus = pProcess->audio_inputs[i];
302 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
304 mAudioIO64.Get()[k] = bus.data64[j];
308 if (localTail && insQuiet)
309 insQuiet = InputIsSilent(bus.data64[j], nFrames);
313 AttachBuffers(ERoute::kInput, 0, nIns, mAudioIO64.Get(), nFrames);
317 for (uint32_t i = 0, k = 0; i < pProcess->audio_inputs_count; i++)
319 auto bus = pProcess->audio_inputs[i];
321 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
323 mAudioIO32.Get()[k] = bus.data32[j];
326 if (localTail && insQuiet)
327 insQuiet = InputIsSilent(bus.data32[j], nFrames);
331 AttachBuffers(ERoute::kInput, 0, nIns, mAudioIO32.Get(), nFrames);
335 SetChannelConnections(ERoute::kOutput, 0, MaxNChannels(ERoute::kOutput),
false);
336 SetChannelConnections(ERoute::kOutput, 0, nOuts,
true);
343 for (uint32_t i = 0, k = 0; i < pProcess->audio_outputs_count; i++)
345 auto bus = pProcess->audio_outputs[i];
346 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
347 mAudioIO64.Get()[k] = bus.data64[j];
350 AttachBuffers(ERoute::kOutput, 0, nOuts, mAudioIO64.Get(), nFrames);
354 for (uint32_t i = 0, k = 0; i < pProcess->audio_outputs_count; i++)
356 auto bus = pProcess->audio_outputs[i];
357 for (uint32_t j = 0; j < bus.channel_count; j++, k++)
358 mAudioIO32.Get()[k] = bus.data32[j];
361 AttachBuffers(ERoute::kOutput, 0, nOuts, mAudioIO32.Get(), nFrames);
366 ProcessBuffers(0.0, nFrames);
368 ProcessBuffers(0.f, nFrames);
371 ProcessOutputEvents(pProcess->out_events, nFrames);
376 GetClapHost().tailChanged();
382 return CLAP_PROCESS_TAIL;
387 return CLAP_PROCESS_CONTINUE_IF_NOT_QUIET;
390 if (GetTailIsInfinite())
391 return CLAP_PROCESS_CONTINUE;
394 mTailCount = insQuiet ? std::min(mTailCount + nFrames, GetTailSize()) : 0;
396 return mTailCount < GetTailSize() ? CLAP_PROCESS_CONTINUE : CLAP_PROCESS_SLEEP;
399 return CLAP_PROCESS_CONTINUE;
404bool IPlugCLAP::renderSetMode(clap_plugin_render_mode mode)
noexcept
406 SetRenderingOffline(mode == CLAP_RENDER_OFFLINE);
411bool IPlugCLAP::stateSave(
const clap_ostream* pStream)
noexcept
415 if (!SerializeState(chunk))
418 return pStream->write(pStream, chunk.
GetData(), chunk.
Size()) == chunk.
Size();
421bool IPlugCLAP::stateLoad(
const clap_istream* pStream)
noexcept
423 constexpr int bytesPerBlock = 256;
424 char buffer[bytesPerBlock];
425 int64_t bytesRead = 0;
429 while ((bytesRead = pStream->read(pStream, buffer, bytesPerBlock)) > 0)
430 chunk.
PutBytes(buffer,
static_cast<int>(bytesRead));
435 bool restoredOK = UnserializeState(chunk, 0) >= 0;
444bool IPlugCLAP::paramsInfo(uint32_t paramIdx, clap_param_info* pInfo)
const noexcept
446 assert(MAX_PARAM_NAME_LEN <= CLAP_NAME_SIZE &&
"iPlug parameter name size exceeds CLAP maximum");
447 assert(MAX_PARAM_GROUP_LEN <= CLAP_PATH_SIZE &&
"iPlug group name size exceeds CLAP maximum");
449 const IParam* pParam = GetParam(paramIdx);
450 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
452 clap_param_info_flags flags = CLAP_PARAM_REQUIRES_PROCESS;
455 flags |= CLAP_PARAM_IS_STEPPED;
457 flags |= CLAP_PARAM_IS_AUTOMATABLE;
459 pInfo->id = paramIdx;
460 pInfo->flags = flags;
461 pInfo->cookie =
nullptr;
463 strcpy(pInfo->name, pParam->
GetName());
464 strcpy(pInfo->module, pParam->
GetGroup());
467 pInfo->min_value = isDoubleType ? 0.0 : pParam->
GetMin();
468 pInfo->max_value = isDoubleType ? 1.0 : pParam->
GetMax();
469 pInfo->default_value = pParam->
GetDefault(isDoubleType);
474bool IPlugCLAP::paramsValue(clap_id paramIdx,
double* pValue)
noexcept
476 const IParam* pParam = GetParam(paramIdx);
477 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
482bool IPlugCLAP::paramsValueToText(clap_id paramIdx,
double value,
char* display, uint32_t size)
noexcept
484 const IParam* pParam = GetParam(paramIdx);
485 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
492 if (CStringHasContents(pParam->
GetLabel()))
498 if (size < str.GetLength())
501 strcpy(display, str.Get());
505bool IPlugCLAP::paramsTextToValue(clap_id paramIdx,
const char* display,
double* pValue)
noexcept
507 const IParam* pParam = GetParam(paramIdx);
508 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
511 *pValue = isDoubleType ? pParam->
ToNormalized(paramValue) : paramValue;
515void IPlugCLAP::paramsFlush(
const clap_input_events* pInputParamChanges,
const clap_output_events* pOutputParamChanges)
noexcept
517 ProcessInputEvents(pInputParamChanges);
518 ProcessOutputParams(pOutputParamChanges);
521void IPlugCLAP::ProcessInputEvents(
const clap_input_events* pInputEvents)
noexcept
527 for (
int i = 0; i < pInputEvents->size(pInputEvents); i++)
529 auto pEvent = pInputEvents->get(pInputEvents, i);
531 if (pEvent->space_id != CLAP_CORE_EVENT_SPACE_ID)
534 switch (pEvent->type)
536 case CLAP_EVENT_NOTE_ON:
539 auto pNote = ClapEventCast<clap_event_note>(pEvent);
540 auto velocity =
static_cast<int>(std::round(pNote->velocity * 127.0));
541 msg.
MakeNoteOnMsg(pNote->key, velocity, pEvent->time, pNote->channel);
543 mMidiMsgsFromProcessor.Push(msg);
547 case CLAP_EVENT_NOTE_OFF:
549 auto pNote = ClapEventCast<clap_event_note>(pEvent);
552 mMidiMsgsFromProcessor.Push(msg);
556 case CLAP_EVENT_MIDI:
558 auto pMidiEvent = ClapEventCast<clap_event_midi>(pEvent);
559 msg =
IMidiMsg(pEvent->time, pMidiEvent->data[0], pMidiEvent->data[1], pMidiEvent->data[2]);
561 mMidiMsgsFromProcessor.Push(msg);
565 case CLAP_EVENT_MIDI_SYSEX:
567 auto pSysexEvent = ClapEventCast<clap_event_midi_sysex>(pEvent);
568 ISysEx sysEx(pEvent->time, pSysexEvent->buffer, pSysexEvent->size);
570 mSysExDataFromProcessor.PushFromArgs(sysEx.mOffset, sysEx.mSize, sysEx.mData);
574 case CLAP_EVENT_PARAM_VALUE:
576 auto pParamValue = ClapEventCast<clap_event_param_value>(pEvent);
578 int paramIdx = pParamValue->param_id;
579 double value = pParamValue->value;
581 IParam* pParam = GetParam(paramIdx);
582 const bool isDoubleType = pParam->
Type() == IParam::kTypeDouble;
589 SendParameterValueFromAPI(paramIdx, value, isDoubleType);
590 OnParamChange(paramIdx, EParamSource::kHost, pEvent->time);
601void IPlugCLAP::ProcessOutputParams(
const clap_output_events* pOutputParamChanges)
noexcept
605 while (mParamValuesToHost.Pop(change))
608 bool isValue = change.type() == CLAP_EVENT_PARAM_VALUE;
610 clap_event_header_t header;
615 header.size = isValue ?
sizeof(clap_event_param_value) :
sizeof(clap_event_param_gesture);
617 header.space_id = CLAP_CORE_EVENT_SPACE_ID;
618 header.type = change.type();
623 clap_event_param_value
event { header, change.idx(),
nullptr, -1, -1, -1, -1, change.value() };
624 pOutputParamChanges->try_push(pOutputParamChanges, &event.header);
628 clap_event_param_gesture
event { header, change.idx() };
629 pOutputParamChanges->try_push(pOutputParamChanges, &event.header);
634void IPlugCLAP::ProcessOutputEvents(
const clap_output_events* pOutputEvents,
int nFrames)
noexcept
640 ProcessOutputParams(pOutputEvents);
644 clap_event_header_t header;
646 while (mMidiToHost.ToDo() || mSysExToHost.ToDo())
648 int midiMsgOffset = nFrames;
649 int sysExOffset = nFrames;
652 if (mMidiToHost.ToDo())
653 midiMsgOffset = mMidiToHost.Peek().mOffset;
655 if (mSysExToHost.ToDo())
656 sysExOffset = mSysExToHost.Peek().mOffset;
659 if (std::min(midiMsgOffset, sysExOffset) >= nFrames)
662 if (sysExOffset <= midiMsgOffset)
664 auto data = mSysExToHost.Peek();
666 uint32_t dataSize =
static_cast<uint32_t
>(data.mSize);
668 header.size =
sizeof(clap_event_midi_sysex);
669 header.time = data.mOffset;
670 header.space_id = CLAP_CORE_EVENT_SPACE_ID;
671 header.type = CLAP_EVENT_MIDI_SYSEX;
674 clap_event_midi_sysex sysex_event { header, 0, data.mData, dataSize };
676 pOutputEvents->try_push(pOutputEvents, &sysex_event.header);
678 mSysExToHost.Remove();
682 auto msg = mMidiToHost.Peek();
683 auto status = msg.mStatus;
686 header.size =
sizeof(clap_event_param_value);
687 header.time = msg.mOffset;
688 header.space_id = CLAP_CORE_EVENT_SPACE_ID;
689 header.type = CLAP_EVENT_MIDI;
692 if (msg.
StatusMsg() == IMidiMsg::kNoteOn)
693 header.type = CLAP_EVENT_NOTE_ON;
695 if (msg.
StatusMsg() == IMidiMsg::kNoteOff)
696 header.type = CLAP_EVENT_NOTE_OFF;
698 if (header.type == CLAP_EVENT_NOTE_ON || header.type == CLAP_EVENT_NOTE_OFF)
700 int16_t channel =
static_cast<int16_t
>(msg.
Channel());
701 clap_event_note note_event { header, -1, 0, channel, msg.mData1,
static_cast<double>(msg.mData2) / 127.0};
702 pOutputEvents->try_push(pOutputEvents, ¬e_event.header);
706 clap_event_midi midi_event { header, 0, { status, msg.mData1, msg.mData2 } };
707 pOutputEvents->try_push(pOutputEvents, &midi_event.header);
710 mMidiToHost.Remove();
714 mMidiToHost.Flush(nFrames);
715 mSysExToHost.Flush(nFrames);
719const char* ClapPortType(uint32_t nChans)
722 return nChans == 2 ? CLAP_PORT_STEREO : (nChans == 1 ? CLAP_PORT_MONO :
nullptr);
725bool IPlugCLAP::implementsAudioPorts() const noexcept
730uint32_t IPlugCLAP::audioPortsCount(
bool isInput)
const noexcept
732 return NBuses(isInput ? ERoute::kInput : ERoute::kOutput);
735bool IPlugCLAP::audioPortsInfo(uint32_t index,
bool isInput, clap_audio_port_info* pInfo)
const noexcept
740 const auto direction = isInput ? ERoute::kInput : ERoute::kOutput;
741 const auto nBuses = NBuses(direction);
742 const auto nChans = NChannels(direction, index);
744 GetBusName(direction, index, nBuses, busName);
746 constexpr uint32_t bitFlags = CLAP_AUDIO_PORT_SUPPORTS_64BITS
747 | CLAP_AUDIO_PORT_PREFERS_64BITS
748 | CLAP_AUDIO_PORT_REQUIRES_COMMON_SAMPLE_SIZE;
751 ClapNameCopy(pInfo->name, busName.Get());
752 pInfo->flags = !index ? bitFlags | CLAP_AUDIO_PORT_IS_MAIN : bitFlags;
753 pInfo->channel_count = nChans;
754 pInfo->port_type = ClapPortType(pInfo->channel_count);
755 pInfo->in_place_pair = CLAP_INVALID_ID;
759bool IPlugCLAP::implementsAudioPortsConfig() const noexcept
761 return audioPortsConfigCount();
764uint32_t IPlugCLAP::audioPortsConfigCount() const noexcept
769bool IPlugCLAP::audioPortsGetConfig(uint32_t index, clap_audio_ports_config* pConfig)
const noexcept
771 if (index >= audioPortsConfigCount())
774 WDL_String configName;
777 auto getNChans = [&](
ERoute direction,
int bus)
779 return static_cast<uint32_t
>(NChannels(direction,
static_cast<uint32_t
>(bus), index));
782 auto getDirectionName = [&](
ERoute direction)
785 configName.AppendFormatted(CLAP_NAME_SIZE,
"%d", getNChans(direction, 0));
787 for (
int i = 0; i < NBuses(direction, index); i++)
788 configName.AppendFormatted(CLAP_NAME_SIZE,
".%d", getNChans(direction, i));
791 getDirectionName(kInput);
792 configName.Append(
"-");
793 getDirectionName(kOutput);
796 ClapNameCopy(pConfig->name, configName.Get());
798 pConfig->input_port_count =
static_cast<uint32_t
>(NBuses(kInput, index));
799 pConfig->output_port_count =
static_cast<uint32_t
>(NBuses(kOutput, index));
801 pConfig->has_main_input = pConfig->input_port_count > 1;
802 pConfig->main_input_channel_count = pConfig->has_main_input ? getNChans(kInput, 0) : 0;
803 pConfig->main_input_port_type = ClapPortType(pConfig->main_input_channel_count);
805 pConfig->has_main_output = pConfig->output_port_count > 1;
806 pConfig->main_output_channel_count = pConfig->has_main_input ? getNChans(kOutput, 0) : 0;
807 pConfig->main_output_port_type = ClapPortType(pConfig->main_output_channel_count);
812bool IPlugCLAP::audioPortsSetConfig(clap_id configIdx)
noexcept
814 if (configIdx >= audioPortsConfigCount())
817 mConfigIdx =
static_cast<int>(configIdx);
822uint32_t IPlugCLAP::notePortsCount(
bool isInput)
const noexcept
825 return PLUG_DOES_MIDI_IN ? 1 : 0;
827 return PLUG_DOES_MIDI_OUT ? 1 : 0;
830bool IPlugCLAP::notePortsInfo(uint32_t index,
bool isInput, clap_note_port_info* pInfo)
const noexcept
835 pInfo->supported_dialects = CLAP_NOTE_DIALECT_MIDI;
836 pInfo->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
837 ClapNameCopy(pInfo->name,
"MIDI Input");
842 pInfo->supported_dialects = CLAP_NOTE_DIALECT_MIDI;
843 pInfo->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
844 ClapNameCopy(pInfo->name,
"MIDI Output");
850bool IPlugCLAP::guiIsApiSupported(
const char* api,
bool isFloating)
noexcept
853 return !isFloating && !strcmp(api, CLAP_WINDOW_API_COCOA);
855 return !isFloating && !strcmp(api, CLAP_WINDOW_API_WIN32);
857#error Not Implemented!
861bool IPlugCLAP::guiSetParent(
const clap_window* pWindow)
noexcept
864 return GUIWindowAttach(pWindow->cocoa);
866 return GUIWindowAttach(pWindow->win32);
868#error Not Implemented!
872bool IPlugCLAP::implementsGui() const noexcept
877bool IPlugCLAP::guiCreate(
const char* api,
bool isFloating)
noexcept
882void IPlugCLAP::guiDestroy() noexcept
889bool IPlugCLAP::guiShow() noexcept
891 if (
HasUI() && !mGUIOpen)
902bool IPlugCLAP::guiHide() noexcept
916bool IPlugCLAP::guiCanResize() const noexcept
921bool IPlugCLAP::guiSetScale(
double scale)
noexcept
925 SetScreenScale(
static_cast<float>(scale));
934bool IPlugCLAP::guiGetSize(uint32_t* pWidth, uint32_t* pHeight)
noexcept
940 *pWidth = GetEditorWidth();
941 *pHeight = GetEditorHeight();
951bool IPlugCLAP::GUIWindowAttach(
void* pWindow)
noexcept
966bool IPlugCLAP::guiAdjustSize(uint32_t* pWidth, uint32_t* pHeight)
noexcept
968 Trace(TRACELOC,
"width:%i height:%i\n", *pWidth, *pHeight);
974 ConstrainEditorResize(w, h);
986bool IPlugCLAP::guiSetSize(uint32_t width, uint32_t height)
noexcept
988 Trace(TRACELOC,
"width:%i height:%i\n", width, height);
992 OnParentWindowResize(width, height);
1002void IPlugCLAP::SetDefaultConfig()
1004 auto isMatch = [&](
int idx,
int chans)
1006 if (NBuses(ERoute::kOutput, idx) >= 1 && NChannels(ERoute::kOutput, 0, idx) == chans)
1008 int numBuses = NBuses(ERoute::kInput, idx);
1011 if (
IsInstrument() && (numBuses == 0 || NChannels(ERoute::kInput, 0, idx) == 0))
1015 return numBuses >= 1 && NChannels(ERoute::kInput, 0, idx) == chans;
1021 auto testMatches = [&](
int chans)
1023 bool matched =
false;
1024 int configNBusesI = 0;
1025 int configNBusesO = 0;
1027 for (
int i = 0; i < static_cast<int>(audioPortsConfigCount()); i++)
1029 if (isMatch(i, chans))
1031 const int nBusesI = NBuses(ERoute::kInput, i);
1032 const int nBusesO = NBuses(ERoute::kOutput, i);
1034 const bool preferInput = nBusesO < configNBusesI;
1035 const bool preferOutput = nBusesI < configNBusesO;
1037 if (!matched || preferOutput || (nBusesO == configNBusesO && preferInput))
1041 configNBusesI = NBuses(ERoute::kInput, i);
1042 configNBusesO = NBuses(ERoute::kOutput, i);
1053 if (GetClapHost().canUseTrackInfo())
1055 clap_track_info info;
1056 GetClapHost().trackInfoGet(&info);
1058 if (testMatches(info.audio_channel_count) || info.audio_channel_count == 2)
1066int IPlugCLAP::RequiredChannels()
const
1071uint32_t IPlugCLAP::NBuses(
ERoute direction,
int configIdx)
const
1076uint32_t IPlugCLAP::NChannels(
ERoute direction, uint32_t bus,
int configIdx)
const
1081uint32_t IPlugCLAP::NBuses(
ERoute direction)
const
1083 return NBuses(direction, mConfigIdx);
1086uint32_t IPlugCLAP::NChannels(
ERoute direction, uint32_t bus)
const
1088 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.