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
Gets the number of channels on a bus with bounds checking.
int NBuses(ERoute direction) const
Gets the number of buses for a given direction.
int GetTotalNChannels(ERoute direction) const
Get the total number of channels across all buses for this IOConfig.
const IBusInfo * GetBusInfo(ERoute direction, int index) const
Gets bus information for a specific bus.