19#define strtok_r strtok_s
25: mPlugType((EIPlugPluginType) config.plugType)
26, mDoesMIDIIn(config.plugDoesMidiIn)
27, mDoesMIDIOut(config.plugDoesMidiOut)
28, mDoesMPE(config.plugDoesMPE)
29, mLatency(config.latency)
31 int totalNInBuses, totalNOutBuses;
32 int totalNInChans, totalNOutChans;
34 ParseChannelIOStr(config.channelIOStr, mIOConfigs, totalNInChans, totalNOutChans, totalNInBuses, totalNOutBuses);
36 mScratchData[ERoute::kInput].Resize(totalNInChans);
37 mScratchData[ERoute::kOutput].Resize(totalNOutChans);
39 sample** ppInData = mScratchData[ERoute::kInput].Get();
41 for (
auto i = 0; i < totalNInChans; ++i, ++ppInData)
44 pInChannel->mConnected =
false;
45 pInChannel->mData = ppInData;
46 mChannelData[ERoute::kInput].Add(pInChannel);
49 sample** ppOutData = mScratchData[ERoute::kOutput].Get();
51 for (
auto i = 0; i < totalNOutChans; ++i, ++ppOutData)
54 pOutChannel->mConnected =
false;
55 pOutChannel->mData = ppOutData;
56 pOutChannel->mIncomingData =
nullptr;
57 mChannelData[ERoute::kOutput].Add(pOutChannel);
61IPlugProcessor::~IPlugProcessor()
65 mChannelData[ERoute::kInput].Empty(
true);
66 mChannelData[ERoute::kOutput].Empty(
true);
67 mIOConfigs.Empty(
true);
72 const int nIn = mChannelData[ERoute::kInput].GetSize();
73 const int nOut = mChannelData[ERoute::kOutput].GetSize();
76 for (
int i = 0; i < nOut; ++i)
80 memcpy(outputs[i], inputs[i], nFrames *
sizeof(sample));
87 memset(outputs[j], 0, nFrames *
sizeof(sample));
99 int n = msgs.GetSize();
101 for (
auto i = 0; i < n; ++i)
121 if(direction == ERoute::kInput)
136 str.SetFormatted(MAX_BUS_NAME_LEN,
"Input %i", busIdx);
147 str.SetFormatted(MAX_BUS_NAME_LEN,
"Output %i", busIdx);
155 int configWithMostBuses = 0;
157 for (
auto configIdx = 0; configIdx <
NIOConfigs(); configIdx++)
159 IOConfig* pIConfig = mIOConfigs.Get(configIdx);
160 int nBuses = pIConfig->
NBuses(direction);
162 if(nBuses >= maxNBuses)
165 configWithMostBuses = configIdx;
169 if(pConfigIdxWithTheMostBuses)
170 *pConfigIdxWithTheMostBuses = configWithMostBuses;
177 int nInputBuses =
static_cast<int>(inputBuses.size());
178 int nOutputBuses =
static_cast<int>(outputBuses.size());
180 for (
auto configIdx = 0; configIdx <
NIOConfigs(); configIdx++)
184 if(pConfig->
NBuses(ERoute::kInput) == nInputBuses && pConfig->
NBuses(ERoute::kOutput) == nOutputBuses)
188 for (
int inputBusIdx = 0; inputBusIdx < nInputBuses; inputBusIdx++)
190 match &= inputBuses[inputBusIdx] == pConfig->
GetBusInfo(ERoute::kInput, inputBusIdx)->NChans();
195 for (
int outputBusIdx = 0; outputBusIdx < nOutputBuses; outputBusIdx++)
197 match &= outputBuses[outputBusIdx] == pConfig->
GetBusInfo(ERoute::kOutput, outputBusIdx)->NChans();
214 const int maxNBuses =
MaxNBuses(direction);
215 std::vector<int> maxChansOnBuses;
216 maxChansOnBuses.resize(maxNBuses);
219 for (
auto configIdx = 0; configIdx <
NIOConfigs(); configIdx++)
223 for (
int bus = 0; bus < maxNBuses; bus++)
224 maxChansOnBuses[bus] = std::max(pIOConfig->
NChansOnBusSAFE(direction, bus), maxChansOnBuses[bus]);
227 return maxChansOnBuses.size() > 0 ? maxChansOnBuses[busIdx] : 0;
232 const WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
235 for (
auto i = 0; i<channelData.GetSize(); i++)
247 for (
auto i = 0; i <
NIOConfigs() && !legal; ++i)
250 legal = ((NInputChans < 0 || NInputChans == pIO->
GetTotalNChannels(ERoute::kInput)) && (NOutputChans < 0 || NOutputChans == pIO->GetTotalNChannels(ERoute::kOutput)));
253 Trace(TRACELOC,
"%d:%d:%s", NInputChans, NOutputChans, (legal ?
"legal" :
"illegal"));
260 SetChannelConnections(ERoute::kInput, 2,
MaxNChannels(ERoute::kInput) - 2,
false);
263 SetChannelConnections(ERoute::kOutput, 2,
MaxNChannels(ERoute::kOutput) - 2,
true);
269 mChannelData[direction].Get(idx)->mLabel.SetFormatted(MAX_CHAN_NAME_LEN, formatStr, idx+(!zeroBased));
277 mLatencyDelay->SetDelayTime(mLatency);
283 bool foundAWildcard =
false;
284 int IOConfigIndex = 0;
286 DBGMSG(
"\nBEGIN IPLUG CHANNEL IO PARSER --------------------------------------------------\n");
288 auto ParseBusToken = [&foundAWildcard, &IOConfigIndex](
ERoute busDir,
char* pBusStr,
char* pBusStrEnd,
int& NBuses,
int& NChans,
IOConfig* pConfig)
290 while (pBusStr != NULL)
294 if(strcmp(pBusStr,
"*") == 0)
296 foundAWildcard =
true;
297 NChanOnBus = -MAX_BUS_CHANS;
299 else if (sscanf(pBusStr,
"%d", &NChanOnBus) == 1)
303 DBGMSG(
"Error: something wrong in the %s part of this io string: %s.\n", RoutingDirStrs[busDir], pBusStr);
306 NChans += NChanOnBus;
308 pBusStr = strtok_r(NULL,
".", &pBusStrEnd);
312 pConfig->AddBusInfo(busDir, NChanOnBus);
317 DBGMSG(
"Error: with multiple %s buses you can't define one with no channels!\n", RoutingDirStrs[busDir]);
318 assert(NChanOnBus > 0);
323 totalNInChans = 0; totalNOutChans = 0;
324 totalNInBuses = 0; totalNOutBuses = 0;
326 char* pChannelIOStr = strdup(IOStr);
329 char* pIOStr = strtok_r(pChannelIOStr,
" ", &pIOStrEnd);
331 WDL_PtrList<WDL_String> IOStrlist;
334 while (pIOStr != NULL)
338 int NInChans = 0, NOutChans = 0;
339 int NInBuses = 0, NOutBuses = 0;
341 char* pIStr = strtok(pIOStr,
"-");
342 char* pOStr = strtok(NULL,
"-");
344 WDL_String* thisIOStr =
new WDL_String();
345 thisIOStr->SetFormatted(256,
"%s-%s", pIStr, pOStr);
347 for (
auto str = 0; str < IOStrlist.GetSize(); str++)
349 if(strcmp(IOStrlist.Get(str)->Get(), thisIOStr->Get()) == 0)
351 DBGMSG(
"Error: Duplicate IO string. %s\n", thisIOStr->Get());
356 IOStrlist.Add(thisIOStr);
359 char* pIBusStr = strtok_r(pIStr,
".", &pIBusStrEnd);
361 ParseBusToken(ERoute::kInput, pIBusStr, pIBusStrEnd, NInBuses, NInChans, pConfig);
364 char* pOBusStr = strtok_r(pOStr,
".", &pOBusStrEnd);
366 ParseBusToken(ERoute::kOutput, pOBusStr, pOBusStrEnd, NOutBuses, NOutChans, pConfig);
368 if(foundAWildcard ==
true && IOConfigIndex > 0)
370 DBGMSG(
"Error: You can only have a single IO config when using wild cards.\n");
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);
382 totalNInChans = std::max(totalNInChans, NInChans);
383 totalNOutChans = std::max(totalNOutChans, NOutChans);
384 totalNInBuses = std::max(totalNInBuses, NInBuses);
385 totalNOutBuses = std::max(totalNOutBuses, NOutBuses);
387 channelIOList.Add(pConfig);
391 pIOStr = strtok_r(NULL,
" ", &pIOStrEnd);
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");
400 return IOConfigIndex;
405 if (mPlugType == EIPlugPluginType::kEffect)
412 else if (mPlugType == EIPlugPluginType::kInstrument)
416 else if (mPlugType == EIPlugPluginType::kMIDIEffect)
420 else if (mPlugType == EIPlugPluginType::kGenerator)
430void IPlugProcessor::SetChannelConnections(
ERoute direction,
int idx,
int n,
bool connected)
432 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
434 const auto endIdx = std::min(idx + n, channelData.GetSize());
436 for (
auto i = idx; i < endIdx; ++i)
439 pChannel->mConnected = connected;
442 *(pChannel->mData) = pChannel->mScratchBuf.Get();
446void IPlugProcessor::InitLatencyDelay()
450 mLatencyDelay = std::unique_ptr<NChanDelayLine<PLUG_SAMPLE_DST>>(
new NChanDelayLine<PLUG_SAMPLE_DST>(
MaxNChannels(ERoute::kInput),
MaxNChannels(ERoute::kOutput)));
455void IPlugProcessor::AttachBuffers(
ERoute direction,
int idx,
int n, PLUG_SAMPLE_DST** ppData,
int)
457 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
459 const auto endIdx = std::min(idx + n, channelData.GetSize());
461 for (
auto i = idx; i < endIdx; ++i)
465 if (pChannel->mConnected)
466 *(pChannel->mData) = *(ppData++);
470void IPlugProcessor::AttachBuffers(
ERoute direction,
int idx,
int n, PLUG_SAMPLE_SRC** ppData,
int nFrames)
472 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
474 const auto endIdx = std::min(idx + n, channelData.GetSize());
476 for (
auto i = idx; i < endIdx; ++i)
480 if (pChannel->mConnected)
482 if (direction == ERoute::kInput)
484 PLUG_SAMPLE_DST* pScratch = pChannel->mScratchBuf.Get();
485 CastCopy(pScratch, *(ppData++), nFrames);
486 *(pChannel->mData) = pScratch;
490 *(pChannel->mData) = pChannel->mScratchBuf.Get();
491 pChannel->mIncomingData = *(ppData++);
497void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_DST type,
int nFrames)
499 if (mLatency && mLatencyDelay)
500 mLatencyDelay->ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
505void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_SRC type,
int nFrames)
508 PassThroughBuffers(PLUG_SAMPLE_DST(0.), nFrames);
511 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
513 for (i = 0; i < n; ++i, ++ppOutChannel)
516 if (pOutChannel->mConnected)
518 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
523void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_DST type,
int nFrames)
525 ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
528void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_SRC type,
int nFrames)
530 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
532 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
534 for (i = 0; i < n; ++i, ++ppOutChannel)
538 if (pOutChannel->mConnected)
540 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
545void IPlugProcessor::ProcessBuffersAccumulating(
int nFrames)
547 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
549 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
551 for (i = 0; i < n; ++i, ++ppOutChannel)
554 if (pOutChannel->mConnected)
556 PLUG_SAMPLE_SRC* pDest = pOutChannel->mIncomingData;
557 PLUG_SAMPLE_DST* pSrc = *(pOutChannel->mData);
558 for (
int j = 0; j < nFrames; ++j, ++pDest, ++pSrc)
560 *pDest += (PLUG_SAMPLE_SRC) *pSrc;
566void IPlugProcessor::ZeroScratchBuffers()
570 for (i = 0; i < nIn; ++i)
573 memset(pInChannel->mScratchBuf.Get(), 0, mBlockSize *
sizeof(PLUG_SAMPLE_DST));
576 for (i = 0; i < nOut; ++i)
578 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
579 memset(pOutChannel->mScratchBuf.Get(), 0, mBlockSize *
sizeof(PLUG_SAMPLE_DST));
583void IPlugProcessor::SetBlockSize(
int blockSize)
585 if (blockSize != mBlockSize)
589 for (i = 0; i < nIn; ++i)
592 pInChannel->mScratchBuf.Resize(blockSize);
593 memset(pInChannel->mScratchBuf.Get(), 0, blockSize *
sizeof(PLUG_SAMPLE_DST));
596 for (i = 0; i < nOut; ++i)
598 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
599 pOutChannel->mScratchBuf.Resize(blockSize);
600 memset(pOutChannel->mScratchBuf.Get(), 0, blockSize *
sizeof(PLUG_SAMPLE_DST));
603 mBlockSize = blockSize;
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.
int NChannelsConnected(ERoute direction) const
double GetSampleRate() const
bool IsChannelConnected(ERoute direction, int chIdx) 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.
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.
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...
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.
An IOConfig is used to store bus info for each input/output configuration defined in the channel io s...
int NChansOnBusSAFE(ERoute direction, int index) const
int NBuses(ERoute direction) const
int GetTotalNChannels(ERoute direction) const
Get the total number of channels across all direction buses for this IOConfig.
const IBusInfo * GetBusInfo(ERoute direction, int index) const