iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugProcessor.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9 */
10
16#include "IPlugProcessor.h"
17
18#ifdef OS_WIN
19#define strtok_r strtok_s
20#endif
21
22using namespace iplug;
23
24IPlugProcessor::IPlugProcessor(const Config& config, EAPI plugAPI)
25: mPlugType((EIPlugPluginType) config.plugType)
26, mDoesMIDIIn(config.plugDoesMidiIn)
27, mDoesMIDIOut(config.plugDoesMidiOut)
28, mDoesMPE(config.plugDoesMPE)
29, mLatency(config.latency)
30{
31 int totalNInBuses, totalNOutBuses;
32 int totalNInChans, totalNOutChans;
33
34 ParseChannelIOStr(config.channelIOStr, mIOConfigs, totalNInChans, totalNOutChans, totalNInBuses, totalNOutBuses);
35
36 mScratchData[ERoute::kInput].Resize(totalNInChans);
37 mScratchData[ERoute::kOutput].Resize(totalNOutChans);
38
39 sample** ppInData = mScratchData[ERoute::kInput].Get();
40
41 for (auto i = 0; i < totalNInChans; ++i, ++ppInData)
42 {
43 IChannelData<>* pInChannel = new IChannelData<>;
44 pInChannel->mConnected = false;
45 pInChannel->mData = ppInData;
46 mChannelData[ERoute::kInput].Add(pInChannel);
47 }
48
49 sample** ppOutData = mScratchData[ERoute::kOutput].Get();
50
51 for (auto i = 0; i < totalNOutChans; ++i, ++ppOutData)
52 {
53 IChannelData<>* pOutChannel = new IChannelData<>;
54 pOutChannel->mConnected = false;
55 pOutChannel->mData = ppOutData;
56 pOutChannel->mIncomingData = nullptr;
57 mChannelData[ERoute::kOutput].Add(pOutChannel);
58 }
59}
60
61IPlugProcessor::~IPlugProcessor()
62{
63 TRACE
64
65 mChannelData[ERoute::kInput].Empty(true);
66 mChannelData[ERoute::kOutput].Empty(true);
67 mIOConfigs.Empty(true);
68}
69
70void IPlugProcessor::ProcessBlock(sample** inputs, sample** outputs, int nFrames)
71{
72 const int nIn = mChannelData[ERoute::kInput].GetSize();
73 const int nOut = mChannelData[ERoute::kOutput].GetSize();
74
75 int j = 0;
76 for (int i = 0; i < nOut; ++i)
77 {
78 if (i < nIn)
79 {
80 memcpy(outputs[i], inputs[i], nFrames * sizeof(sample));
81 j++;
82 }
83 }
84 // zero remaining outs
85 for (/* same j */; j < nOut; ++j)
86 {
87 memset(outputs[j], 0, nFrames * sizeof(sample));
88 }
89}
90
92{
93 SendMidiMsg(msg);
94}
95
96bool IPlugProcessor::SendMidiMsgs(WDL_TypedBuf<IMidiMsg>& msgs)
97{
98 bool rc = true;
99 int n = msgs.GetSize();
100
101 for (auto i = 0; i < n; ++i)
102 rc &= SendMidiMsg(msgs.Get()[i]);
103
104 return rc;
105}
106
108{
109 const double tempo = GetTempo();
110
111 if (tempo > 0.0)
112 return GetSampleRate() * 60.0 / tempo;
113
114 return 0.0;
115}
116
117#pragma mark -
118
119void IPlugProcessor::GetBusName(ERoute direction, int busIdx, int nBuses, WDL_String& str) const
120{
121 if(direction == ERoute::kInput)
122 {
123 if(nBuses == 1)
124 {
125 str.Set("Input");
126 }
127 else if(nBuses == 2)
128 {
129 if(busIdx == 0)
130 str.Set("Main");
131 else
132 str.Set("Aux");
133 }
134 else
135 {
136 str.SetFormatted(MAX_BUS_NAME_LEN, "Input %i", busIdx);
137 }
138 }
139 else
140 {
141 if(nBuses == 1)
142 {
143 str.Set("Output");
144 }
145 else
146 {
147 str.SetFormatted(MAX_BUS_NAME_LEN, "Output %i", busIdx);
148 }
149 }
150}
151
152int IPlugProcessor::MaxNBuses(ERoute direction, int* pConfigIdxWithTheMostBuses) const
153{
154 int maxNBuses = 0;
155 int configWithMostBuses = 0;
156
157 for (auto configIdx = 0; configIdx < NIOConfigs(); configIdx++)
158 {
159 IOConfig* pIConfig = mIOConfigs.Get(configIdx);
160 int nBuses = pIConfig->NBuses(direction);
161
162 if(nBuses >= maxNBuses)
163 {
164 maxNBuses = nBuses;
165 configWithMostBuses = configIdx;
166 }
167 }
168
169 if(pConfigIdxWithTheMostBuses)
170 *pConfigIdxWithTheMostBuses = configWithMostBuses;
171
172 return maxNBuses;
173}
174
175int IPlugProcessor::GetIOConfigWithChanCounts(std::vector<int>& inputBuses, std::vector<int>& outputBuses)
176{
177 int nInputBuses = static_cast<int>(inputBuses.size());
178 int nOutputBuses = static_cast<int>(outputBuses.size());
179
180 for (auto configIdx = 0; configIdx < NIOConfigs(); configIdx++)
181 {
182 const IOConfig* pConfig = GetIOConfig(configIdx);
183
184 if(pConfig->NBuses(ERoute::kInput) == nInputBuses && pConfig->NBuses(ERoute::kOutput) == nOutputBuses)
185 {
186 bool match = true;
187
188 for (int inputBusIdx = 0; inputBusIdx < nInputBuses; inputBusIdx++)
189 {
190 match &= inputBuses[inputBusIdx] == pConfig->GetBusInfo(ERoute::kInput, inputBusIdx)->NChans();
191 }
192
193 if(match)
194 {
195 for (int outputBusIdx = 0; outputBusIdx < nOutputBuses; outputBusIdx++)
196 {
197 match &= outputBuses[outputBusIdx] == pConfig->GetBusInfo(ERoute::kOutput, outputBusIdx)->NChans();
198 }
199 }
200
201 if(match)
202 return configIdx;
203 }
204 }
205
206 return -1;
207}
208
209int IPlugProcessor::MaxNChannelsForBus(ERoute direction, int busIdx) const
210{
211 if(HasWildcardBus(direction))
212 return -1;
213
214 const int maxNBuses = MaxNBuses(direction);
215 std::vector<int> maxChansOnBuses;
216 maxChansOnBuses.resize(maxNBuses);
217
218 //find the maximum channel count for each input or output bus
219 for (auto configIdx = 0; configIdx < NIOConfigs(); configIdx++)
220 {
221 const IOConfig* pIOConfig = GetIOConfig(configIdx);
222
223 for (int bus = 0; bus < maxNBuses; bus++)
224 maxChansOnBuses[bus] = std::max(pIOConfig->NChansOnBusSAFE(direction, bus), maxChansOnBuses[bus]);
225 }
226
227 return maxChansOnBuses.size() > 0 ? maxChansOnBuses[busIdx] : 0;
228}
229
231{
232 const WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
233
234 int count = 0;
235 for (auto i = 0; i<channelData.GetSize(); i++)
236 {
237 count += (int) IsChannelConnected(direction, i);
238 }
239
240 return count;
241}
242
243bool IPlugProcessor::LegalIO(int NInputChans, int NOutputChans) const
244{
245 bool legal = false;
246
247 for (auto i = 0; i < NIOConfigs() && !legal; ++i)
248 {
249 const IOConfig* pIO = GetIOConfig(i);
250 legal = ((NInputChans < 0 || NInputChans == pIO->GetTotalNChannels(ERoute::kInput)) && (NOutputChans < 0 || NOutputChans == pIO->GetTotalNChannels(ERoute::kOutput)));
251 }
252
253 Trace(TRACELOC, "%d:%d:%s", NInputChans, NOutputChans, (legal ? "legal" : "illegal"));
254 return legal;
255}
256
258{
259 if (MaxNChannels(ERoute::kInput) > 2)
260 SetChannelConnections(ERoute::kInput, 2, MaxNChannels(ERoute::kInput) - 2, false);
261
262 if (MaxNChannels(ERoute::kOutput) > 2)
263 SetChannelConnections(ERoute::kOutput, 2, MaxNChannels(ERoute::kOutput) - 2, true);
264}
265
266void IPlugProcessor::SetChannelLabel(ERoute direction, int idx, const char* formatStr, bool zeroBased)
267{
268 if (idx >= 0 && idx < MaxNChannels(direction))
269 mChannelData[direction].Get(idx)->mLabel.SetFormatted(MAX_CHAN_NAME_LEN, formatStr, idx+(!zeroBased));
270}
271
273{
274 mLatency = samples;
275
276 if (mLatencyDelay)
277 mLatencyDelay->SetDelayTime(mLatency);
278}
279
280//static
281int IPlugProcessor::ParseChannelIOStr(const char* IOStr, WDL_PtrList<IOConfig>& channelIOList, int& totalNInChans, int& totalNOutChans, int& totalNInBuses, int& totalNOutBuses)
282{
283 bool foundAWildcard = false;
284 int IOConfigIndex = 0;
285
286 DBGMSG("\nBEGIN IPLUG CHANNEL IO PARSER --------------------------------------------------\n");
287 // lamda function to iterate through the period separated buses and check that none have 0 channel count
288 auto ParseBusToken = [&foundAWildcard, &IOConfigIndex](ERoute busDir, char* pBusStr, char* pBusStrEnd, int& NBuses, int& NChans, IOConfig* pConfig)
289 {
290 while (pBusStr != NULL)
291 {
292 auto NChanOnBus = 0;
293
294 if(strcmp(pBusStr, "*") == 0)
295 {
296 foundAWildcard = true;
297 NChanOnBus = -MAX_BUS_CHANS; // we put a negative number in here which will be picked up in the api classes in order to deal with NxN or NxM routings
298 }
299 else if (sscanf(pBusStr, "%d", &NChanOnBus) == 1)
300 ; //don't do anything
301 else
302 {
303 DBGMSG("Error: something wrong in the %s part of this io string: %s.\n", RoutingDirStrs[busDir], pBusStr);
304 assert(0);
305 }
306 NChans += NChanOnBus;
307
308 pBusStr = strtok_r(NULL, ".", &pBusStrEnd);
309
310 if(NChanOnBus)
311 {
312 pConfig->AddBusInfo(busDir, NChanOnBus);
313 NBuses++;
314 }
315 else if(NBuses > 0)
316 {
317 DBGMSG("Error: with multiple %s buses you can't define one with no channels!\n", RoutingDirStrs[busDir]);
318 assert(NChanOnBus > 0);
319 }
320 }
321 };
322
323 totalNInChans = 0; totalNOutChans = 0;
324 totalNInBuses = 0; totalNOutBuses = 0;
325
326 char* pChannelIOStr = strdup(IOStr);
327
328 char* pIOStrEnd;
329 char* pIOStr = strtok_r(pChannelIOStr, " ", &pIOStrEnd); // a single IO string
330
331 WDL_PtrList<WDL_String> IOStrlist;
332
333 // iterate through the space separated IO configs
334 while (pIOStr != NULL)
335 {
336 IOConfig* pConfig = new IOConfig();
337
338 int NInChans = 0, NOutChans = 0;
339 int NInBuses = 0, NOutBuses = 0;
340
341 char* pIStr = strtok(pIOStr, "-"); // Input buses part of string
342 char* pOStr = strtok(NULL, "-"); // Output buses part of string
343
344 WDL_String* thisIOStr = new WDL_String();
345 thisIOStr->SetFormatted(256, "%s-%s", pIStr, pOStr);
346
347 for (auto str = 0; str < IOStrlist.GetSize(); str++)
348 {
349 if(strcmp(IOStrlist.Get(str)->Get(), thisIOStr->Get()) == 0)
350 {
351 DBGMSG("Error: Duplicate IO string. %s\n", thisIOStr->Get());
352 assert(0);
353 }
354 }
355
356 IOStrlist.Add(thisIOStr);
357
358 char* pIBusStrEnd;
359 char* pIBusStr = strtok_r(pIStr, ".", &pIBusStrEnd); // a single input bus
360
361 ParseBusToken(ERoute::kInput, pIBusStr, pIBusStrEnd, NInBuses, NInChans, pConfig);
362
363 char* pOBusStrEnd;
364 char* pOBusStr = strtok_r(pOStr, ".", &pOBusStrEnd);
365
366 ParseBusToken(ERoute::kOutput, pOBusStr, pOBusStrEnd, NOutBuses, NOutChans, pConfig);
367
368 if(foundAWildcard == true && IOConfigIndex > 0)
369 {
370 DBGMSG("Error: You can only have a single IO config when using wild cards.\n");
371 assert(0);
372 }
373
374 DBGMSG("Channel I/O #%i - %s\n", IOConfigIndex + 1, thisIOStr->Get());
375 DBGMSG(" - input bus count: %i, output bus count %i\n", NInBuses, NOutBuses);
376 for (auto i = 0; i < NInBuses; i++)
377 DBGMSG(" - channel count on input bus %i: %i\n", i + 1, pConfig->NChansOnBusSAFE(ERoute::kInput, i));
378 for (auto i = 0; i < NOutBuses; i++)
379 DBGMSG(" - channel count on output bus %i: %i\n", i + 1, pConfig->NChansOnBusSAFE(ERoute::kOutput, i));
380 DBGMSG(" - input channel count across all buses: %i, output channel count across all buses %i\n\n", NInChans, NOutChans);
381
382 totalNInChans = std::max(totalNInChans, NInChans);
383 totalNOutChans = std::max(totalNOutChans, NOutChans);
384 totalNInBuses = std::max(totalNInBuses, NInBuses);
385 totalNOutBuses = std::max(totalNOutBuses, NOutBuses);
386
387 channelIOList.Add(pConfig);
388
389 IOConfigIndex++;
390
391 pIOStr = strtok_r(NULL, " ", &pIOStrEnd); // go to next io string
392 }
393
394 free(pChannelIOStr);
395 IOStrlist.Empty(true);
396 DBGMSG("%i I/O configs detected\n", IOConfigIndex);
397 DBGMSG("Total # in chans: %i, Total # out chans: %i \n\n", totalNInChans, totalNOutChans);
398 DBGMSG("END IPLUG CHANNEL IO PARSER --------------------------------------------------\n");
399
400 return IOConfigIndex;
401}
402
404{
405 if (mPlugType == EIPlugPluginType::kEffect)
406 {
407 if (DoesMIDIIn())
408 return 'aumf';
409 else
410 return 'aufx';
411 }
412 else if (mPlugType == EIPlugPluginType::kInstrument)
413 {
414 return 'aumu';
415 }
416 else if (mPlugType == EIPlugPluginType::kMIDIEffect)
417 {
418 return 'aumi';
419 }
420 else
421 return 'aufx';
422}
423
424#pragma mark -
425
426void IPlugProcessor::SetChannelConnections(ERoute direction, int idx, int n, bool connected)
427{
428 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
429
430 const auto endIdx = std::min(idx + n, channelData.GetSize());
431
432 for (auto i = idx; i < endIdx; ++i)
433 {
434 IChannelData<>* pChannel = channelData.Get(i);
435 pChannel->mConnected = connected;
436
437 if (!connected)
438 *(pChannel->mData) = pChannel->mScratchBuf.Get();
439 }
440}
441
442void IPlugProcessor::InitLatencyDelay()
443{
444 if (MaxNChannels(ERoute::kInput))
445 {
446 mLatencyDelay = std::unique_ptr<NChanDelayLine<PLUG_SAMPLE_DST>>(new NChanDelayLine<PLUG_SAMPLE_DST>(MaxNChannels(ERoute::kInput), MaxNChannels(ERoute::kOutput)));
447 mLatencyDelay->SetDelayTime(GetLatency());
448 }
449}
450
451void IPlugProcessor::AttachBuffers(ERoute direction, int idx, int n, PLUG_SAMPLE_DST** ppData, int)
452{
453 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
454
455 const auto endIdx = std::min(idx + n, channelData.GetSize());
456
457 for (auto i = idx; i < endIdx; ++i)
458 {
459 IChannelData<>* pChannel = channelData.Get(i);
460
461 if (pChannel->mConnected)
462 *(pChannel->mData) = *(ppData++);
463 }
464}
465
466void IPlugProcessor::AttachBuffers(ERoute direction, int idx, int n, PLUG_SAMPLE_SRC** ppData, int nFrames)
467{
468 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
469
470 const auto endIdx = std::min(idx + n, channelData.GetSize());
471
472 for (auto i = idx; i < endIdx; ++i)
473 {
474 IChannelData<>* pChannel = channelData.Get(i);
475
476 if (pChannel->mConnected)
477 {
478 if (direction == ERoute::kInput)
479 {
480 PLUG_SAMPLE_DST* pScratch = pChannel->mScratchBuf.Get();
481 CastCopy(pScratch, *(ppData++), nFrames);
482 *(pChannel->mData) = pScratch;
483 }
484 else // output
485 {
486 *(pChannel->mData) = pChannel->mScratchBuf.Get();
487 pChannel->mIncomingData = *(ppData++);
488 }
489 }
490 }
491}
492
493void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_DST type, int nFrames)
494{
495 if (mLatency && mLatencyDelay)
496 mLatencyDelay->ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
497 else
498 IPlugProcessor::ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
499}
500
501void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_SRC type, int nFrames)
502{
503 // for PLUG_SAMPLE_SRC bit buffers, first run the delay (if mLatency) on the PLUG_SAMPLE_DST IPlug buffers
504 PassThroughBuffers(PLUG_SAMPLE_DST(0.), nFrames);
505
506 int i, n = MaxNChannels(ERoute::kOutput);
507 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
508
509 for (i = 0; i < n; ++i, ++ppOutChannel)
510 {
511 IChannelData<>* pOutChannel = *ppOutChannel;
512 if (pOutChannel->mConnected)
513 {
514 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
515 }
516 }
517}
518
519void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_DST type, int nFrames)
520{
521 ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
522}
523
524void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_SRC type, int nFrames)
525{
526 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
527 int i, n = MaxNChannels(ERoute::kOutput);
528 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
529
530 for (i = 0; i < n; ++i, ++ppOutChannel)
531 {
532 IChannelData<>* pOutChannel = *ppOutChannel;
533
534 if (pOutChannel->mConnected)
535 {
536 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
537 }
538 }
539}
540
541void IPlugProcessor::ProcessBuffersAccumulating(int nFrames)
542{
543 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
544 int i, n = MaxNChannels(ERoute::kOutput);
545 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
546
547 for (i = 0; i < n; ++i, ++ppOutChannel)
548 {
549 IChannelData<>* pOutChannel = *ppOutChannel;
550 if (pOutChannel->mConnected)
551 {
552 PLUG_SAMPLE_SRC* pDest = pOutChannel->mIncomingData;
553 PLUG_SAMPLE_DST* pSrc = *(pOutChannel->mData); // TODO : check this: PLUG_SAMPLE_DST will allways be float, because this is only for VST2 accumulating
554 for (int j = 0; j < nFrames; ++j, ++pDest, ++pSrc)
555 {
556 *pDest += (PLUG_SAMPLE_SRC) *pSrc;
557 }
558 }
559 }
560}
561
562void IPlugProcessor::ZeroScratchBuffers()
563{
564 int i, nIn = MaxNChannels(ERoute::kInput), nOut = MaxNChannels(ERoute::kOutput);
565
566 for (i = 0; i < nIn; ++i)
567 {
568 IChannelData<>* pInChannel = mChannelData[ERoute::kInput].Get(i);
569 memset(pInChannel->mScratchBuf.Get(), 0, mBlockSize * sizeof(PLUG_SAMPLE_DST));
570 }
571
572 for (i = 0; i < nOut; ++i)
573 {
574 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
575 memset(pOutChannel->mScratchBuf.Get(), 0, mBlockSize * sizeof(PLUG_SAMPLE_DST));
576 }
577}
578
579void IPlugProcessor::SetBlockSize(int blockSize)
580{
581 if (blockSize != mBlockSize)
582 {
583 int i, nIn = MaxNChannels(ERoute::kInput), nOut = MaxNChannels(ERoute::kOutput);
584
585 for (i = 0; i < nIn; ++i)
586 {
587 IChannelData<>* pInChannel = mChannelData[ERoute::kInput].Get(i);
588 pInChannel->mScratchBuf.Resize(blockSize);
589 memset(pInChannel->mScratchBuf.Get(), 0, blockSize * sizeof(PLUG_SAMPLE_DST));
590 }
591
592 for (i = 0; i < nOut; ++i)
593 {
594 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
595 pOutChannel->mScratchBuf.Resize(blockSize);
596 memset(pOutChannel->mScratchBuf.Get(), 0, blockSize * sizeof(PLUG_SAMPLE_DST));
597 }
598
599 mBlockSize = blockSize;
600 }
601}
virtual bool SendMidiMsgs(WDL_TypedBuf< IMidiMsg > &msgs)
Send a collection of MIDI messages // TODO: info about what thread should this be called on or not ca...
const IOConfig * GetIOConfig(int idx) const
virtual void ProcessMidiMsg(const IMidiMsg &msg)
Override this method to handle incoming MIDI messages.
bool LegalIO(int NInputChans, int NOutputChans) const
Check if a certain configuration of input channels and output channels is allowed based on the channe...
virtual void GetBusName(ERoute direction, int busIdx, int nBuses, WDL_String &str) const
Get the name for a particular bus.
virtual void SetLatency(int latency)
Call this if the latency of your plug-in changes after initialization (perhaps from OnReset() ) This ...
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...
virtual bool SendMidiMsg(const IMidiMsg &msg)=0
Send a single MIDI message // TODO: info about what thread should this be called on or not called on!
void SetChannelLabel(ERoute direction, int idx, const char *formatStr, bool zeroBased=false)
This allows you to label input/output channels in supporting VST2 hosts.
int GetAUPluginType() const
IPlugProcessor(const Config &config, EAPI plugAPI)
IPlugProcessor constructor.
bool DoesMIDIIn() const
int NChannelsConnected(ERoute direction) const
double GetSampleRate() const
bool IsChannelConnected(ERoute direction, int chIdx) const
double GetTempo() const
int GetIOConfigWithChanCounts(std::vector< int > &inputBuses, std::vector< int > &outputBuses)
int MaxNChannelsForBus(ERoute direction, int busIdx) const
For a given input or output bus what is the maximum possible number of channels.
int NIOConfigs() const
bool HasWildcardBus(ERoute direction) const
Check if we have any wildcard characters in the channel I/O configs.
int MaxNChannels(ERoute direction) const
void LimitToStereoIO()
This is called by IPlugVST in order to limit a plug-in to stereo I/O for certain picky hosts.
int GetLatency() const
static int ParseChannelIOStr(const char *IOStr, WDL_PtrList< IOConfig > &channelIOList, int &totalNInChans, int &totalNOutChans, int &totalNInBuses, int &totalNOutBuses)
A static method to parse the config.h channel I/O string.
virtual void ProcessBlock(sample **inputs, sample **outputs, int nFrames)
Override in your plug-in class to process audio In ProcessBlock you are always guaranteed to get vali...
double GetSamplesPerBeat() const
ERoute
Used to identify whether a bus/channel connection is an input or an output.
Used to manage scratch buffers for each channel of I/O, which may involve converting from single to d...
Definition: IPlugStructs.h:475
void CastCopy(DEST *pDest, SRC *pSrc, int n)
Helper function to loop through a buffer of samples copying and casting from e.g float to double.
Encapsulates a MIDI message and provides helper functions.
Definition: IPlugMidi.h:31
An IOConfig is used to store bus info for each input/output configuration defined in the channel io s...
Definition: IPlugStructs.h:504
int NChansOnBusSAFE(ERoute direction, int index) const
Definition: IPlugStructs.h:536
int NBuses(ERoute direction) const
Definition: IPlugStructs.h:549
int GetTotalNChannels(ERoute direction) const
Get the total number of channels across all direction buses for this IOConfig.
Definition: IPlugStructs.h:557
const IBusInfo * GetBusInfo(ERoute direction, int index) const
Definition: IPlugStructs.h:526