iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugAUv3.mm
1 /*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#import <AudioToolbox/AudioToolbox.h>
12#include <CoreMIDI/CoreMIDI.h>
13
14#include "IPlugAUv3.h"
15#import "IPlugAUAudioUnit.h"
16
17#if !__has_feature(objc_arc)
18#error This file must be compiled with Arc. Use -fobjc-arc flag
19#endif
20
21using namespace iplug;
22
23IPlugAUv3::IPlugAUv3(const InstanceInfo& instanceInfo, const Config& config)
24: IPlugAPIBase(config, kAPIAUv3)
25, IPlugProcessor(config, kAPIAUv3)
26{
27 Trace(TRACELOC, "%s", config.pluginName);
28}
29
30void IPlugAUv3::SetAUAudioUnit(void* pAUAudioUnit)
31{
32 mAUAudioUnit = pAUAudioUnit;
33}
34
36{
37 const AUParameterAddress address = GetParamAddress(paramIdx);
38 [(__bridge IPLUG_AUAUDIOUNIT*) mAUAudioUnit beginInformHostOfParamChange:address];
39}
40
41void IPlugAUv3::InformHostOfParamChange(int paramIdx, double normalizedValue)
42{
43 const AUParameterAddress address = GetParamAddress(paramIdx);
44
45 [(__bridge IPLUG_AUAUDIOUNIT*) mAUAudioUnit informHostOfParamChange:address :(float) GetParam(paramIdx)->FromNormalized(normalizedValue)];
46}
47
49{
50 const AUParameterAddress address = GetParamAddress(paramIdx);
51 [(__bridge IPLUG_AUAUDIOUNIT*) mAUAudioUnit endInformHostOfParamChange:address];
52}
53
55{
56 uint8_t data[3] = { msg.mStatus, msg.mData1, msg.mData2 };
57
58 int64_t sampleTime = mLastTimeStamp.mSampleTime + msg.mOffset;
59
60 return [(__bridge IPLUG_AUAUDIOUNIT*) mAUAudioUnit sendMidiData: sampleTime : sizeof(data) : data];
61}
62
63//bool IPlugAUv3::SendMidiMsgs(WDL_TypedBuf<IMidiMsg>& msgs)
64//{
65// return false;
66//}
67
69{
70 int64_t sampleTime = mLastTimeStamp.mSampleTime + msg.mOffset;
71
72 return [(__bridge IPLUG_AUAUDIOUNIT*) mAUAudioUnit sendMidiData: sampleTime : msg.mSize : msg.mData];
73}
74
75//void IPlugAUv3::HandleOneEvent(AURenderEvent const *event, AUEventSampleTime startTime)
76//{
77// switch (event->head.eventType)
78// {
79// case AURenderEventParameter:
80// case AURenderEventParameterRamp:
81// {
82// AUParameterEvent const& paramEvent = event->parameter;
83// const int paramIdx = GetParamIdx(paramEvent.parameterAddress);
84// const double value = (double) paramEvent.value;
85// const int sampleOffset = (int) (paramEvent.eventSampleTime - startTime);
86// ENTER_PARAMS_MUTEX
87// GetParam(paramIdx)->Set(value);
88// LEAVE_PARAMS_MUTEX
89// OnParamChange(paramIdx, EParamSource::kHost, sampleOffset);
90// break;
91// }
92//
93// case AURenderEventMIDI:
94// {
95// IMidiMsg msg;
96// msg.mStatus = event->MIDI.data[0];
97// msg.mData1 = event->MIDI.data[1];
98// msg.mData2 = event->MIDI.data[2];
99// msg.mOffset = (int) (event->MIDI.eventSampleTime - startTime);
100// ProcessMidiMsg(msg);
101// mMidiMsgsFromProcessor.Push(msg);
102// break;
103// }
104// default:
105// break;
106// }
107//}
108//
109//void IPlugAUv3::PerformAllSimultaneousEvents(AUEventSampleTime now, AURenderEvent const *&event)
110//{
111// do {
112// HandleOneEvent(event, now);
113//
114// // Go to next event.
115// event = event->head.next;
116//
117// // While event is not null and is simultaneous (or late).
118// } while (event && event->head.eventSampleTime <= now);
119//}
120
121void IPlugAUv3::ProcessWithEvents(AudioTimeStamp const* pTimestamp, uint32_t frameCount, AURenderEvent const* pEvents, ITimeInfo& timeInfo)
122{
123 SetTimeInfo(timeInfo);
124
125 IMidiMsg midiMsg;
126 while (mMidiMsgsFromEditor.Pop(midiMsg))
127 {
128 ProcessMidiMsg(midiMsg);
129 }
130
131 mLastTimeStamp = *pTimestamp;
132 AUEventSampleTime now = AUEventSampleTime(pTimestamp->mSampleTime);
133 uint32_t framesRemaining = frameCount;
134
135 for (const AURenderEvent* pEvent = pEvents; pEvent != nullptr; pEvent = pEvent->head.next)
136 {
137 switch (pEvent->head.eventType)
138 {
139 case AURenderEventMIDI:
140 {
141 const AUMIDIEvent& midiEvent = pEvent->MIDI;
142
143 midiMsg = {static_cast<int>(midiEvent.eventSampleTime - now), midiEvent.data[0], midiEvent.data[1], midiEvent.data[2] };
144 ProcessMidiMsg(midiMsg);
145 mMidiMsgsFromProcessor.Push(midiMsg);
146 }
147 break;
148
149 case AURenderEventParameter:
150 case AURenderEventParameterRamp:
151 {
152 const AUParameterEvent& paramEvent = pEvent->parameter;
153
154 if (paramEvent.parameterAddress < NParams())
155 {
156 const int paramIdx = GetParamIdx(paramEvent.parameterAddress);
157
158 const double value = (double) paramEvent.value;
159 const int sampleOffset = (int) (paramEvent.eventSampleTime - now);
160 ENTER_PARAMS_MUTEX
161 GetParam(paramIdx)->Set(value);
162 LEAVE_PARAMS_MUTEX
163 OnParamChange(paramIdx, EParamSource::kHost, sampleOffset);
164 }
165
166 break;
167 }
168 break;
169
170 default:
171 break;
172 }
173 }
174
175 ENTER_PARAMS_MUTEX;
176 ProcessBuffers(0.f, framesRemaining); // what about bufferOffset
177 LEAVE_PARAMS_MUTEX;
178
179 //Output SYSEX from the editor, which has bypassed ProcessSysEx()
180 while (mSysExDataFromEditor.Pop(mSysexBuf))
181 {
182 ISysEx smsg {mSysexBuf.mOffset, mSysexBuf.mData, mSysexBuf.mSize};
183 SendSysEx(smsg);
184 }
185
186
187// while (framesRemaining > 0) {
188// // If there are no more events, we can process the entire remaining segment and exit.
189// if (event == nullptr) {
191// TODO - ProcessBuffers should be within param mutex lock
192// ProcessBuffers(0.f, framesRemaining); // what about bufferOffset
193// return;
194// }
195//
196// // **** start late events late.
197// auto timeZero = AUEventSampleTime(0);
198// auto headEventTime = event->head.eventSampleTime;
199// uint32_t const framesThisSegment = uint32_t(std::max(timeZero, headEventTime - now));
200//
201// // Compute everything before the next event.
202// if (framesThisSegment > 0)
203// {
205// TODO - ProcessBuffers should be within param mutex lock
206// ProcessBuffers(0.f, framesThisSegment); // what about bufferOffset
207//
208// // Advance frames.
209// framesRemaining -= framesThisSegment;
210//
211// // Advance time.
212// now += AUEventSampleTime(framesThisSegment);
213// }
214//
215// PerformAllSimultaneousEvents(now, event);
216// }
217}
218
219// this is called on a secondary thread (not main thread, not audio thread)
220void IPlugAUv3::SetParameterFromValueObserver(uint64_t address, float value)
221{
222 if (address < NParams())
223 {
224 const int paramIdx = GetParamIdx(address);
225
226 ENTER_PARAMS_MUTEX
227 IParam* pParam = GetParam(paramIdx);
228 assert(pParam);
229 pParam->Set((double) value);
230 LEAVE_PARAMS_MUTEX
231 OnParamChange(paramIdx, kHost, -1);
232 }
233}
234
235void IPlugAUv3::SendParameterValueFromObserver(uint64_t address, float value)
236{
237 if (address < NParams())
238 {
239 const int paramIdx = GetParamIdx(address);
240
241 SendParameterValueFromAPI(paramIdx, value, false); // will trigger OnParamChangeUI()
242 }
243}
244
245float IPlugAUv3::GetParameter(uint64_t address)
246{
247 const int paramIdx = GetParamIdx(address);
248
249 ENTER_PARAMS_MUTEX
250 const float val = (float) GetParam(paramIdx)->Value();
251 LEAVE_PARAMS_MUTEX
252 return val;
253}
254
255const char* IPlugAUv3::GetParamDisplay(uint64_t address, float value)
256{
257 const int paramIdx = GetParamIdx(address);
258
259 ENTER_PARAMS_MUTEX
260 GetParam(paramIdx)->GetDisplay(value, false, mParamDisplayStr);
261 LEAVE_PARAMS_MUTEX
262 return (const char*) mParamDisplayStr.Get();
263}
264
265float IPlugAUv3::GetParamStringToValue(uint64_t address, const char* str)
266{
267 const int paramIdx = GetParamIdx(address);
268
269 ENTER_PARAMS_MUTEX
270 float val = (float) GetParam(paramIdx)->StringToValue(str);
271 LEAVE_PARAMS_MUTEX
272 return val;
273}
274
275void IPlugAUv3::AttachInputBuffers(AudioBufferList* pInBufList)
276{
277 int chanIdx = 0;
278
279 if (pInBufList)
280 {
281 for (int i = 0; i < pInBufList->mNumberBuffers; i++)
282 {
283 int nConnected = pInBufList->mBuffers[i].mNumberChannels;
284 SetChannelConnections(ERoute::kInput, chanIdx, nConnected, true);
285 AttachBuffers(ERoute::kInput, chanIdx, nConnected, (float**) &(pInBufList->mBuffers[i].mData), GetBlockSize());
286 chanIdx += nConnected;
287 }
288
289 SetChannelConnections(ERoute::kInput, chanIdx, MaxNChannels(kInput) - chanIdx, false);
290 }
291}
292
293void IPlugAUv3::AttachOutputBuffers(AudioBufferList* pOutBufList, uint32_t busNumber)
294{
295 int chanIdx = 0;
296
297 if (pOutBufList)
298 {
299 int numChannelsInBus = pOutBufList->mNumberBuffers; // TODO: this assumes all busses have the same channel count
300
301 for (int i = 0; i < pOutBufList->mNumberBuffers; i++)
302 {
303 int nConnected = pOutBufList->mBuffers[i].mNumberChannels;
304 SetChannelConnections(ERoute::kOutput, (busNumber * numChannelsInBus) + chanIdx, nConnected, true);
305 AttachBuffers(ERoute::kOutput, (busNumber * numChannelsInBus) + chanIdx, nConnected, (float**) &(pOutBufList->mBuffers[i].mData), GetBlockSize());
306 chanIdx += nConnected;
307 }
308 SetChannelConnections(ERoute::kInput, chanIdx, MaxNChannels(kOutput) - chanIdx, false);
309 }
310}
311
312void IPlugAUv3::Prepare(double sampleRate, uint32_t blockSize)
313{
314 SetChannelConnections(ERoute::kInput, 0, MaxNChannels(ERoute::kInput), false);
315 SetChannelConnections(ERoute::kOutput, 0, MaxNChannels(ERoute::kOutput), false);
316 SetBlockSize(blockSize);
317 SetSampleRate(sampleRate);
318}
IPlug's parameter class.
The base class of an IPlug plug-in, which interacts with the different plug-in APIs.
Definition: IPlugAPIBase.h:43
virtual void SendParameterValueFromAPI(int paramIdx, double value, bool normalized)
This is called from the plug-in API class in order to update UI controls linked to plug-in parameters...
void InformHostOfParamChange(int idx, double normalizedValue) override
Implemented by the API class, called by the UI via SetParameterValue() with the value of a parameter ...
Definition: IPlugAUv3.mm:41
bool SendSysEx(const ISysEx &msg) override
Send a single MIDI System Exclusive (SysEx) message // TODO: info about what thread should this be ca...
Definition: IPlugAUv3.mm:68
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!
Definition: IPlugAUv3.mm:54
void BeginInformHostOfParamChange(int idx) override
Implemented by the API class, called by the UI (or by a delegate) at the beginning of a parameter cha...
Definition: IPlugAUv3.mm:35
void EndInformHostOfParamChange(int idx) override
Implemented by the API class, called by the UI (or by a delegate) at the end of a parameter change ge...
Definition: IPlugAUv3.mm:48
The base class for IPlug Audio Processing.
virtual void ProcessMidiMsg(const IMidiMsg &msg)
Override this method to handle incoming MIDI messages.
int GetBlockSize() const
int MaxNChannels(ERoute direction) const
Encapsulates information about the host transport state.
Definition: IPlugStructs.h:585
Encapsulates a MIDI message and provides helper functions.
Definition: IPlugMidi.h:31
A struct for dealing with SysEx messages.
Definition: IPlugMidi.h:539