11 #include "pluginterfaces/vst/ivstparameterchanges.h" 12 #include "pluginterfaces/vst/vstspeaker.h" 13 #include "pluginterfaces/vst/ivstmidicontrollers.h" 14 #include "public.sdk/source/vst/vsteventshelper.h" 15 #include "IPlugVST3_ProcessorBase.h" 17 using namespace iplug;
21 #ifndef CUSTOM_BUSTYPE_FUNC 22 uint64_t iplug::GetAPIBusTypeForChannelIOConfig(
int configIdx,
ERoute dir,
int busIdx,
const IOConfig* pConfig, WDL_TypedBuf<uint64_t>* APIBusTypes)
24 assert(pConfig !=
nullptr);
25 assert(busIdx >= 0 && busIdx < pConfig->NBuses(dir));
27 int numChans = pConfig->
GetBusInfo(dir, busIdx)->NChans();
31 case 0:
return SpeakerArr::kEmpty;
32 case 1:
return SpeakerArr::kMono;
33 case 2:
return SpeakerArr::kStereo;
34 case 3:
return SpeakerArr::k30Cine;
35 case 4:
return SpeakerArr::kAmbi1stOrderACN;
36 case 5:
return SpeakerArr::k50;
37 case 6:
return SpeakerArr::k51;
38 case 7:
return SpeakerArr::k70Cine;
39 case 8:
return SpeakerArr::k71CineSideFill;
40 case 9:
return SpeakerArr::kAmbi2cdOrderACN;
41 case 10:
return SpeakerArr::k71_2;
42 case 16:
return SpeakerArr::kAmbi3rdOrderACN;
44 DBGMSG(
"do not yet know what to do here\n");
46 return SpeakerArr::kEmpty;
51 IPlugVST3ProcessorBase::IPlugVST3ProcessorBase(Config c,
IPlugAPIBase& plug)
55 SetChannelConnections(ERoute::kInput, 0,
MaxNChannels(ERoute::kInput),
true);
56 SetChannelConnections(ERoute::kOutput, 0,
MaxNChannels(ERoute::kOutput),
true);
67 memset(&mProcessContext, 0,
sizeof(ProcessContext));
76 int32 numEvent = pEventList->getEventCount();
77 for (int32 i=0; i<numEvent; i++)
80 if (pEventList->getEvent(i, event) == kResultOk)
84 case Event::kNoteOnEvent:
86 msg.
MakeNoteOnMsg(event.noteOn.pitch, event.noteOn.velocity * 127, event.sampleOffset, event.noteOn.channel);
88 processorQueue.
Push(msg);
92 case Event::kNoteOffEvent:
94 msg.
MakeNoteOffMsg(event.noteOff.pitch, event.sampleOffset, event.noteOff.channel);
96 processorQueue.
Push(msg);
99 case Event::kPolyPressureEvent:
101 msg.
MakePolyATMsg(event.polyPressure.pitch, event.polyPressure.pressure * 127., event.sampleOffset, event.polyPressure.channel);
103 processorQueue.
Push(msg);
106 case Event::kDataEvent:
108 ISysEx syx =
ISysEx(event.sampleOffset, event.data.bytes, event.data.size);
117 while (editorQueue.
Pop(msg))
125 if (!mMidiOutputQueue.Empty() && pOutputEvents)
130 while (!mMidiOutputQueue.Empty())
132 IMidiMsg& msg = mMidiOutputQueue.Peek();
134 if (msg.
StatusMsg() == IMidiMsg::kNoteOn)
136 Helpers::init(toAdd, Event::kNoteOnEvent, 0 , msg.mOffset);
138 toAdd.noteOn.channel = msg.
Channel();
140 toAdd.noteOn.tuning = 0.;
141 toAdd.noteOn.velocity = (float) msg.
Velocity() * (1.f / 127.f);
142 pOutputEvents->addEvent(toAdd);
144 else if (msg.
StatusMsg() == IMidiMsg::kNoteOff)
146 Helpers::init(toAdd, Event::kNoteOffEvent, 0 , msg.mOffset);
148 toAdd.noteOff.channel = msg.
Channel();
150 toAdd.noteOff.velocity = (float) msg.
Velocity() * (1.f / 127.f);
151 pOutputEvents->addEvent(toAdd);
153 else if (msg.
StatusMsg() == IMidiMsg::kPolyAftertouch)
155 Helpers::initLegacyMIDICCOutEvent(toAdd, ControllerNumbers::kCtrlPolyPressure, msg.
Channel(), msg.mData1, msg.mData2);
156 toAdd.sampleOffset = msg.mOffset;
157 pOutputEvents->addEvent(toAdd);
159 else if (msg.
StatusMsg() == IMidiMsg::kChannelAftertouch)
161 Helpers::initLegacyMIDICCOutEvent(toAdd, ControllerNumbers::kAfterTouch, msg.
Channel(), msg.mData1, msg.mData2);
162 toAdd.sampleOffset = msg.mOffset;
163 pOutputEvents->addEvent(toAdd);
165 else if (msg.
StatusMsg() == IMidiMsg::kProgramChange)
167 Helpers::initLegacyMIDICCOutEvent(toAdd, ControllerNumbers::kCtrlProgramChange, msg.
Channel(), msg.
Program(), 0);
168 toAdd.sampleOffset = msg.mOffset;
169 pOutputEvents->addEvent(toAdd);
171 else if (msg.
StatusMsg() == IMidiMsg::kControlChange)
173 Helpers::initLegacyMIDICCOutEvent(toAdd, msg.mData1, msg.
Channel(), msg.mData2, 0 );
174 toAdd.sampleOffset = msg.mOffset;
175 pOutputEvents->addEvent(toAdd);
177 else if (msg.
StatusMsg() == IMidiMsg::kPitchWheel)
179 toAdd.type = Event::kLegacyMIDICCOutEvent;
180 toAdd.midiCCOut.channel = msg.
Channel();
181 toAdd.sampleOffset = msg.mOffset;
182 toAdd.midiCCOut.controlNumber = ControllerNumbers::kPitchBend;
183 int16 tmp =
static_cast<int16
> (msg.
PitchWheel() * 0x3FFF);
184 toAdd.midiCCOut.value = (tmp & 0x7F);
185 toAdd.midiCCOut.value2 = ((tmp >> 7) & 0x7F);
186 pOutputEvents->addEvent(toAdd);
189 mMidiOutputQueue.Remove();
193 mMidiOutputQueue.Flush(numSamples);
200 while (sysExQueue.
Pop(sysExBuf))
202 toAdd.type = Event::kDataEvent;
203 toAdd.sampleOffset = sysExBuf.mOffset;
204 toAdd.data.type = DataEvent::kMidiSysEx;
205 toAdd.data.size = sysExBuf.mSize;
206 toAdd.data.bytes = (uint8*) sysExBuf.mData;
207 pOutputEvents->addEvent(toAdd);
212 void IPlugVST3ProcessorBase::AttachBuffers(
ERoute direction,
int idx,
int n, AudioBusBuffers& pBus,
int nFrames, int32 sampleSize)
214 if (sampleSize == kSample32)
215 IPlugProcessor::AttachBuffers(direction, idx, n, pBus.channelBuffers32, nFrames);
216 else if (sampleSize == kSample64)
217 IPlugProcessor::AttachBuffers(direction, idx, n, pBus.channelBuffers64, nFrames);
220 bool IPlugVST3ProcessorBase::SetupProcessing(
const ProcessSetup& setup, ProcessSetup& storedSetup)
222 if ((setup.symbolicSampleSize != kSample32) && (setup.symbolicSampleSize != kSample64))
227 SetSampleRate(setup.sampleRate);
228 IPlugProcessor::SetBlockSize(setup.maxSamplesPerBlock);
229 mMidiOutputQueue.Resize(setup.maxSamplesPerBlock);
235 bool IPlugVST3ProcessorBase::SetProcessing(
bool state)
243 bool IPlugVST3ProcessorBase::CanProcessSampleSize(int32 symbolicSampleSize)
245 switch (symbolicSampleSize)
248 case kSample64:
return true;
249 default:
return false;
253 void IPlugVST3ProcessorBase::PrepareProcessContext(ProcessData& data, ProcessSetup& setup)
257 if (data.processContext)
258 memcpy(&mProcessContext, data.processContext,
sizeof(ProcessContext));
260 if (mProcessContext.state & ProcessContext::kProjectTimeMusicValid)
261 timeInfo.mSamplePos = (double) mProcessContext.projectTimeSamples;
262 timeInfo.mPPQPos = mProcessContext.projectTimeMusic;
263 timeInfo.mTempo = mProcessContext.tempo;
264 timeInfo.mLastBar = mProcessContext.barPositionMusic;
265 timeInfo.mCycleStart = mProcessContext.cycleStartMusic;
266 timeInfo.mCycleEnd = mProcessContext.cycleEndMusic;
267 timeInfo.mNumerator = mProcessContext.timeSigNumerator;
268 timeInfo.mDenominator = mProcessContext.timeSigDenominator;
269 timeInfo.mTransportIsRunning = mProcessContext.state & ProcessContext::kPlaying;
270 timeInfo.mTransportLoopEnabled = mProcessContext.state & ProcessContext::kCycleActive;
271 const bool offline = setup.processMode == Steinberg::Vst::kOffline;
272 SetTimeInfo(timeInfo);
273 SetRenderingOffline(offline);
276 void IPlugVST3ProcessorBase::ProcessParameterChanges(ProcessData& data,
IPlugQueue<IMidiMsg>& fromProcessor)
278 IParameterChanges* paramChanges = data.inputParameterChanges;
282 int32 numParamsChanged = paramChanges->getParameterCount();
284 for (int32 i = 0; i < numParamsChanged; i++)
286 IParamValueQueue* paramQueue = paramChanges->getParameterData(i);
289 int32 numPoints = paramQueue->getPointCount();
293 if (paramQueue->getPoint(numPoints - 1, offsetSamples, value) == kResultTrue)
295 int idx = paramQueue->getParameterId();
301 const bool bypassed = (value > 0.5);
304 SetBypassed(bypassed);
310 if (idx >= 0 && idx < mPlug.NParams())
313 mPlug.mParams_mutex.Enter();
315 mPlug.GetParam(idx)->SetNormalized(value);
318 mPlug.OnParamChange(idx, kHost, offsetSamples);
320 mPlug.mParams_mutex.Leave();
323 else if (idx >= kMIDICCParamStartIdx)
325 int index = idx - kMIDICCParamStartIdx;
326 int channel = index / kCountCtrlNumber;
327 int ctrlr = index % kCountCtrlNumber;
331 if (ctrlr == kAfterTouch)
333 else if (ctrlr == kPitchBend)
338 fromProcessor.
Push(msg);
350 void IPlugVST3ProcessorBase::ProcessAudio(ProcessData& data, ProcessSetup& setup,
const BusList& ins,
const BusList& outs)
352 int32 sampleSize = setup.symbolicSampleSize;
354 if (sampleSize == kSample32 || sampleSize == kSample64)
358 SetChannelConnections(ERoute::kInput, 0,
MaxNChannels(ERoute::kInput),
false);
362 if (ins[1].
get()->isActive())
364 mSidechainActive =
true;
365 SetChannelConnections(ERoute::kInput, 0, data.inputs[0].numChannels,
true);
366 SetChannelConnections(ERoute::kInput, mMaxNChansForMainInputBus, data.inputs[1].numChannels,
true);
370 if (mSidechainActive)
372 ZeroScratchBuffers();
373 mSidechainActive =
false;
376 SetChannelConnections(ERoute::kInput, 0, data.inputs[0].numChannels,
true);
379 AttachBuffers(ERoute::kInput, 0, data.inputs[0].numChannels, data.inputs[0], data.numSamples, sampleSize);
382 AttachBuffers(ERoute::kInput, mMaxNChansForMainInputBus, data.inputs[1].numChannels, data.inputs[1], data.numSamples, sampleSize);
386 SetChannelConnections(ERoute::kInput, 0,
MaxNChannels(ERoute::kInput),
false);
387 SetChannelConnections(ERoute::kInput, 0, data.inputs[0].numChannels,
true);
388 AttachBuffers(ERoute::kInput, 0, data.inputs[0].numChannels, data.inputs[0], data.numSamples, sampleSize);
392 for (
int outBus = 0, chanOffset = 0; outBus < data.numOutputs; outBus++)
394 int busChannels = data.outputs[outBus].numChannels;
395 SetChannelConnections(ERoute::kOutput, chanOffset, busChannels, outs[outBus].
get()->isActive());
396 SetChannelConnections(ERoute::kOutput, chanOffset + busChannels,
MaxNChannels(ERoute::kOutput) - (chanOffset + busChannels),
false);
397 AttachBuffers(ERoute::kOutput, chanOffset, busChannels, data.outputs[outBus], data.numSamples, sampleSize);
398 chanOffset += busChannels;
403 if (sampleSize == kSample32)
404 PassThroughBuffers(0.f, data.numSamples);
406 PassThroughBuffers(0.0, data.numSamples);
411 mPlug.mParams_mutex.Enter();
413 if (sampleSize == kSample32)
414 ProcessBuffers(0.f, data.numSamples);
416 ProcessBuffers(0.0, data.numSamples);
418 mPlug.mParams_mutex.Leave();
426 PrepareProcessContext(data, setup);
427 ProcessParameterChanges(data, fromProcessor);
431 ProcessMidiIn(data.inputEvents, fromEditor, fromProcessor);
434 ProcessAudio(data, setup, ins, outs);
438 ProcessMidiOut(sysExFromEditor, sysExBuf, data.outputEvents, data.numSamples);
444 mMidiOutputQueue.Add(msg);
int MaxNChannels(ERoute direction) const
The base class of an IPlug plug-in, which interacts with the different plug-in APIs.
int Program() const
Get the program index from a Program Change message.
Encapsulates a MIDI message and provides helper functions.
void MakePitchWheelMsg(double value, int channel=0, int offset=0)
Create a pitch wheel/bend message.
EControlChangeMsg
Constants for MIDI CC messages.
int NoteNumber() const
Gets the MIDI note number.
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
size_t ElementsAvailable() const
int Velocity() const
Get the velocity value of a NoteOn/NoteOff message.
int Channel() const
Gets the channel of a MIDI message.
double PitchWheel() const
Get the value from a Pitchwheel message.
void MakePolyATMsg(int noteNumber, int pressure, int offset, int channel)
Create a Poly AfterTouch message.
ERoute
Used to identify whether a bus/channel connection is an input or an output.
void MakeNoteOffMsg(int noteNumber, int offset, int channel=0)
Make a Note Off message.
virtual void ProcessSysEx(ISysEx &msg)
Override this method to handle incoming MIDI System Exclusive (SysEx) messages.
virtual void ProcessMidiMsg(const IMidiMsg &msg)
Override this method to handle incoming MIDI messages.
The base class for IPlug Audio Processing.
bool SendMidiMsg(const IMidiMsg &msg) override
Send a single MIDI message // TODO: info about what thread should this be called on or not called on!...
EStatusMsg StatusMsg() const
Gets the MIDI Status message.
virtual void OnReset()
Override this method in your plug-in class to do something prior to playback etc. ...
void MakeChannelATMsg(int pressure, int offset, int channel)
Create a Channel AfterTouch message.
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...
A struct for dealing with SysEx messages.
This structure is used when queueing Sysex messages.
void MakeControlChangeMsg(EControlChangeMsg idx, double value, int channel=0, int offset=0)
Create a CC message.
void MakeNoteOnMsg(int noteNumber, int velocity, int offset, int channel=0)
Make a Note On message.
Encapsulates information about the host transport state.
int MaxNChannelsForBus(ERoute direction, int busIdx) const
For a given input or output bus what is the maximum possible number of channels.