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)
426void 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();
442void IPlugProcessor::InitLatencyDelay()
446 mLatencyDelay = std::unique_ptr<NChanDelayLine<PLUG_SAMPLE_DST>>(
new NChanDelayLine<PLUG_SAMPLE_DST>(
MaxNChannels(ERoute::kInput),
MaxNChannels(ERoute::kOutput)));
451void IPlugProcessor::AttachBuffers(
ERoute direction,
int idx,
int n, PLUG_SAMPLE_DST** ppData,
int)
453 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
455 const auto endIdx = std::min(idx + n, channelData.GetSize());
457 for (
auto i = idx; i < endIdx; ++i)
461 if (pChannel->mConnected)
462 *(pChannel->mData) = *(ppData++);
466void IPlugProcessor::AttachBuffers(
ERoute direction,
int idx,
int n, PLUG_SAMPLE_SRC** ppData,
int nFrames)
468 WDL_PtrList<IChannelData<>>& channelData = mChannelData[direction];
470 const auto endIdx = std::min(idx + n, channelData.GetSize());
472 for (
auto i = idx; i < endIdx; ++i)
476 if (pChannel->mConnected)
478 if (direction == ERoute::kInput)
480 PLUG_SAMPLE_DST* pScratch = pChannel->mScratchBuf.Get();
481 CastCopy(pScratch, *(ppData++), nFrames);
482 *(pChannel->mData) = pScratch;
486 *(pChannel->mData) = pChannel->mScratchBuf.Get();
487 pChannel->mIncomingData = *(ppData++);
493void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_DST type,
int nFrames)
495 if (mLatency && mLatencyDelay)
496 mLatencyDelay->ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
501void IPlugProcessor::PassThroughBuffers(PLUG_SAMPLE_SRC type,
int nFrames)
504 PassThroughBuffers(PLUG_SAMPLE_DST(0.), nFrames);
507 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
509 for (i = 0; i < n; ++i, ++ppOutChannel)
512 if (pOutChannel->mConnected)
514 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
519void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_DST type,
int nFrames)
521 ProcessBlock(mScratchData[ERoute::kInput].Get(), mScratchData[ERoute::kOutput].Get(), nFrames);
524void IPlugProcessor::ProcessBuffers(PLUG_SAMPLE_SRC type,
int nFrames)
526 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
528 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
530 for (i = 0; i < n; ++i, ++ppOutChannel)
534 if (pOutChannel->mConnected)
536 CastCopy(pOutChannel->mIncomingData, *(pOutChannel->mData), nFrames);
541void IPlugProcessor::ProcessBuffersAccumulating(
int nFrames)
543 ProcessBuffers((PLUG_SAMPLE_DST) 0, nFrames);
545 IChannelData<>** ppOutChannel = mChannelData[ERoute::kOutput].GetList();
547 for (i = 0; i < n; ++i, ++ppOutChannel)
550 if (pOutChannel->mConnected)
552 PLUG_SAMPLE_SRC* pDest = pOutChannel->mIncomingData;
553 PLUG_SAMPLE_DST* pSrc = *(pOutChannel->mData);
554 for (
int j = 0; j < nFrames; ++j, ++pDest, ++pSrc)
556 *pDest += (PLUG_SAMPLE_SRC) *pSrc;
562void IPlugProcessor::ZeroScratchBuffers()
566 for (i = 0; i < nIn; ++i)
569 memset(pInChannel->mScratchBuf.Get(), 0, mBlockSize *
sizeof(PLUG_SAMPLE_DST));
572 for (i = 0; i < nOut; ++i)
574 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
575 memset(pOutChannel->mScratchBuf.Get(), 0, mBlockSize *
sizeof(PLUG_SAMPLE_DST));
579void IPlugProcessor::SetBlockSize(
int blockSize)
581 if (blockSize != mBlockSize)
585 for (i = 0; i < nIn; ++i)
588 pInChannel->mScratchBuf.Resize(blockSize);
589 memset(pInChannel->mScratchBuf.Get(), 0, blockSize *
sizeof(PLUG_SAMPLE_DST));
592 for (i = 0; i < nOut; ++i)
594 IChannelData<>* pOutChannel = mChannelData[ERoute::kOutput].Get(i);
595 pOutChannel->mScratchBuf.Resize(blockSize);
596 memset(pOutChannel->mScratchBuf.Get(), 0, blockSize *
sizeof(PLUG_SAMPLE_DST));
599 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