19 #define strtok_r strtok_s 22 using namespace iplug;
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);
61 IPlugProcessor::~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));
281 int IPlugProcessor::ParseChannelIOStr(
const char* IOStr, WDL_PtrList<IOConfig>& channelIOList,
int& totalNInChans,
int& totalNOutChans,
int& totalNInBuses,
int& totalNOutBuses)
283 bool foundAWildcard =
false;
284 int IOConfigIndex = 0;
286 DBGMSG(
"BEGIN 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)
426 void IPlugProcessor::SetChannelConnections(
ERoute direction,
int idx,
int n,
bool connected)
428 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
430 const auto endIdx = std::min(idx + n, channelData.GetSize());
432 for (
auto i = idx; i < endIdx; ++i)
435 pChannel->mConnected = connected;
438 *(pChannel->mData) = pChannel->mScratchBuf.Get();
442 void IPlugProcessor::AttachBuffers(
ERoute direction,
int idx,
int n, PLUG_SAMPLE_DST** ppData,
int)
444 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
446 const auto endIdx = std::min(idx + n, channelData.GetSize());
448 for (
auto i = idx; i < endIdx; ++i)
452 if (pChannel->mConnected)
453 *(pChannel->mData) = *(ppData++);
457 void IPlugProcessor::AttachBuffers(
ERoute direction,
int idx,
int n, PLUG_SAMPLE_SRC** ppData,
int nFrames)
459 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
461 const auto endIdx = std::min(idx + n, channelData.GetSize());
463 for (
auto i = idx; i < endIdx; ++i)
467 if (pChannel->mConnected)
469 if (direction == ERoute::kInput)
471 PLUG_SAMPLE_DST* pScratch = pChannel->mScratchBuf.Get();
472 CastCopy(pScratch, *(ppData++), nFrames);
473 *(pChannel->mData) = pScratch;
477 *(pChannel->mData) = pChannel->mScratchBuf.Get();
478 pChannel->mIncomingData = *(ppData++);
484 void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_DST type,
int nFrames)
487 mLatencyDelay->ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
492 void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_SRC type,
int nFrames)
495 PassThroughBuffers(PLUG_SAMPLE_DST(0.), nFrames);
498 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
500 for (i = 0; i < n; ++i, ++ppOutChannel)
503 if (pOutChannel->mConnected)
505 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
510 void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_DST type,
int nFrames)
512 ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
515 void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_SRC type,
int nFrames)
517 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
519 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
521 for (i = 0; i < n; ++i, ++ppOutChannel)
525 if (pOutChannel->mConnected)
527 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
532 void IPlugProcessor::ProcessBuffersAccumulating(
int nFrames)
534 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
536 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
538 for (i = 0; i < n; ++i, ++ppOutChannel)
541 if (pOutChannel->mConnected)
543 PLUG_SAMPLE_SRC* pDest = pOutChannel->mIncomingData;
544 PLUG_SAMPLE_DST* pSrc = *(pOutChannel->mData);
545 for (
int j = 0; j < nFrames; ++j, ++pDest, ++pSrc)
547 *pDest += (PLUG_SAMPLE_SRC) *pSrc;
553 void IPlugProcessor::ZeroScratchBuffers()
557 for (i = 0; i < nIn; ++i)
560 memset(pInChannel->mScratchBuf.Get(), 0, mBlockSize *
sizeof(PLUG_SAMPLE_DST));
563 for (i = 0; i < nOut; ++i)
565 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
566 memset(pOutChannel->mScratchBuf.Get(), 0, mBlockSize *
sizeof(PLUG_SAMPLE_DST));
570 void IPlugProcessor::SetBlockSize(
int blockSize)
572 if (blockSize != mBlockSize)
576 for (i = 0; i < nIn; ++i)
579 pInChannel->mScratchBuf.Resize(blockSize);
580 memset(pInChannel->mScratchBuf.Get(), 0, blockSize *
sizeof(PLUG_SAMPLE_DST));
583 for (i = 0; i < nOut; ++i)
585 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
586 pOutChannel->mScratchBuf.Resize(blockSize);
587 memset(pOutChannel->mScratchBuf.Get(), 0, blockSize *
sizeof(PLUG_SAMPLE_DST));
590 mBlockSize = blockSize;
int MaxNChannels(ERoute direction) const
The base class for IPlug Audio Processing.
IPlugProcessor(const Config &config, EAPI plugAPI)
IPlugProcessor constructor.
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.
double GetSampleRate() const
Encapsulates a MIDI message and provides helper functions.
int GetTotalNChannels(ERoute direction) const
Get the total number of channels across all direction buses for this IOConfig.
virtual void SetLatency(int latency)
Call this if the latency of your plug-in changes after initialization (perhaps from OnReset() ) This ...
An IOConfig is used to store bus info for each input/output configuration defined in the channel io s...
const IBusInfo * GetBusInfo(ERoute direction, int index) const
double GetSamplesPerBeat() const
virtual void GetBusName(ERoute direction, int busIdx, int nBuses, WDL_String &str) const
Get the name for a particular bus.
void SetChannelLabel(ERoute direction, int idx, const char *formatStr, bool zeroBased=false)
This allows you to label input/output channels in supporting VST2 hosts.
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!...
int NBuses(ERoute direction) const
ERoute
Used to identify whether a bus/channel connection is an input or an output.
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...
bool HasWildcardBus(ERoute direction) const
Check if we have any wildcard characters in the channel I/O configs.
const IOConfig * GetIOConfig(int idx) 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...
bool IsChannelConnected(ERoute direction, int chIdx) const
Used to manage scratch buffers for each channel of I/O, which may involve converting from single to d...
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...
int GetIOConfigWithChanCounts(std::vector< int > &inputBuses, std::vector< int > &outputBuses)
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...
std::unique_ptr< NChanDelayLine< sample > > mLatencyDelay
A multi-channel delay line used to delay the bypassed signal when a plug-in with latency is bypassed...
void LimitToStereoIO()
This is called by IPlugVST in order to limit a plug-in to stereo I/O for certain picky hosts...
int GetAUPluginType() const
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...
int MaxNChannelsForBus(ERoute direction, int busIdx) const
For a given input or output bus what is the maximum possible number of channels.
int NChansOnBusSAFE(ERoute direction, int index) const
int NChannelsConnected(ERoute direction) const