1 /*
2      File: AUPlugInDispatch.cpp
3  Abstract: AUPlugInDispatch.h
4   Version: 1.1
5 
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12 
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28 
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43 
44  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45 
46 */
47 /**
48 * Dispatcher for the Audio Component API.
49 * Copyright: Copyright Auburn Sounds 2016.
50 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
51 * Authors:   Guillaume Piolat
52 */
53 module dplug.au.audiocomponentdispatch;
54 
55 version(AU):
56 
57 import core.stdc.stdio;
58 import core.stdc.stdlib: malloc, free;
59 import derelict.carbon;
60 
61 import dplug.core.runtime;
62 import dplug.core.nogc;
63 import dplug.au.client;
64 
65 nothrow:
66 @nogc:
67 
68 //debug = logDispatcher;
69 // Factory function entry point for Audio Component
70 void* audioUnitComponentFactory(alias ClientClass)(void* inDesc)
71 {
72     ScopedForeignCallback!(false, true) scopedCallback;
73     scopedCallback.enter();
74     acquireAUFunctions();
75 
76     const(AudioComponentDescription)* desc = cast(const(AudioComponentDescription)*)inDesc;
77     AudioComponentPlugInInterface* pinter = cast(AudioComponentPlugInInterface*) malloc(PlugInInstance.sizeof);
78 
79     pinter.Open = &audioComponentOpen!ClientClass;
80     pinter.Close = &audioComponentClose;
81     pinter.Lookup = &audioComponentLookup;
82     pinter.reserved = null;
83     return pinter;
84 }
85 
86 private:
87 
88 struct PlugInInstance
89 {
90     AudioComponentPlugInInterface iface;
91     AUClient instance;
92 }
93 
94 extern(C)
95 {
96     OSStatus audioComponentOpen(ClientClass)(void *pSelf, AudioUnit compInstance)
97     {
98         PlugInInstance* acpi = cast(PlugInInstance *) pSelf;
99         assert(acpi);
100         ClientClass client = mallocNew!ClientClass();
101         AUClient auClient = mallocNew!AUClient(client, null, compInstance);
102         acpi.instance = auClient;
103         return noErr;
104     }
105 
106     OSStatus audioComponentClose(void* pSelf)
107     {
108         PlugInInstance* acpi = cast(PlugInInstance *) pSelf;
109         assert(acpi);
110         destroyFree(acpi.instance);
111         acpi.instance = null;
112         return noErr;
113     }
114 
115     AudioComponentMethod audioComponentLookup(SInt16 selector)
116     {
117         switch(selector)
118         {
119             case kAudioUnitInitializeSelect: // 1
120                 return cast(AudioComponentMethod)&AUMethodInitialize;
121             case kAudioUnitUninitializeSelect: // 2
122                 return cast(AudioComponentMethod)&AUMethodUninitialize;
123             case kAudioUnitGetPropertyInfoSelect: // 3
124                 return cast(AudioComponentMethod)&AUMethodGetPropertyInfo;
125             case kAudioUnitGetPropertySelect: // 4
126                 return cast(AudioComponentMethod)&AUMethodGetProperty;
127             case kAudioUnitSetPropertySelect: // 5
128                 return cast(AudioComponentMethod)&AUMethodSetProperty;
129             case kAudioUnitAddPropertyListenerSelect: // 10
130                 return cast(AudioComponentMethod)&AUMethodAddPropertyListener;
131             case kAudioUnitRemovePropertyListenerSelect: // 11
132                 return cast(AudioComponentMethod)&AUMethodRemovePropertyListener;
133             case kAudioUnitRemovePropertyListenerWithUserDataSelect: // 18
134                 return cast(AudioComponentMethod)&AUMethodRemovePropertyListenerWithUserData;
135             case kAudioUnitAddRenderNotifySelect: // 15
136                 return cast(AudioComponentMethod)&AUMethodAddRenderNotify;
137             case kAudioUnitRemoveRenderNotifySelect: //
138                 return cast(AudioComponentMethod)&AUMethodRemoveRenderNotify;
139             case kAudioUnitGetParameterSelect:
140                 return cast(AudioComponentMethod)&AUMethodGetParameter;
141             case kAudioUnitSetParameterSelect:
142                 return cast(AudioComponentMethod)&AUMethodSetParameter;
143             case kAudioUnitScheduleParametersSelect:
144                 return cast(AudioComponentMethod)&AUMethodScheduleParameters;
145             case kAudioUnitRenderSelect:
146                 return cast(AudioComponentMethod)&AUMethodRender;
147             case kAudioUnitResetSelect:
148                 return cast(AudioComponentMethod)&AUMethodReset;
149             case kAudioUnitComplexRenderSelect: // 19
150                 return null; // unsupported
151             case kAudioUnitProcessSelect: // 20
152                 return null;
153             case kAudioUnitProcessMultipleSelect: // 21
154                 return null;
155 
156             case kMusicDeviceMIDIEventSelect: // 0x0101
157                 return cast(AudioComponentMethod)&AUMethodMIDIEvent;
158             case kMusicDeviceSysExSelect: // 0x0102
159                 return cast(AudioComponentMethod)&AUMethodSysEx;
160             case kMusicDevicePrepareInstrumentSelect: // 0x0103
161                 return cast(AudioComponentMethod)&AUMethodPrepareInstrument;
162             case kMusicDeviceReleaseInstrumentSelect: // 0x0104
163                 return cast(AudioComponentMethod)&AUMethodReleaseInstrument;
164             case kMusicDeviceStartNoteSelect: // 0x0105
165                 return cast(AudioComponentMethod)&AUMethodStartNote;
166             case kMusicDeviceStopNoteSelect: // 0x0106
167                 return cast(AudioComponentMethod)&AUMethodStopNote;
168 
169             default:
170                 debug(logDispatcher) printf("WARNING: unsupported audioComponentLookup selector %d\n", selector);
171                 return null;
172         }
173     }
174 
175     AUClient getPlug(void *pSelf)
176     {
177         return (cast(PlugInInstance*) pSelf).instance;
178     }
179 
180     // <Dispatch methods>
181 
182     OSStatus AUMethodInitialize(void* pSelf)
183     {
184         debug(logDispatcher) printf("AUMethodInitialize\n");
185         return getPlug(pSelf).DoInitialize();
186     }
187 
188     OSStatus AUMethodUninitialize(void* pSelf)
189     {
190         debug(logDispatcher) printf("AUMethodUninitialize\n");
191         return getPlug(pSelf).DoUninitialize();
192     }
193 
194     OSStatus AUMethodGetPropertyInfo(void* pSelf,
195                                      AudioUnitPropertyID prop,
196                                      AudioUnitScope scope_,
197                                      AudioUnitElement elem,
198                                      UInt32* pOutDataSize,
199                                      Boolean* pOutWritable)
200     {
201         debug(logDispatcher) printf("AUMethodGetPropertyInfo\n");
202         return getPlug(pSelf).DoGetPropertyInfo(prop, scope_, elem, pOutDataSize, pOutWritable);
203     }
204 
205     OSStatus AUMethodGetProperty(void* pSelf, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* pOutData, UInt32* pIODataSize)
206     {
207         debug(logDispatcher) printf("AUMethodGetProperty\n");
208         return getPlug(pSelf).DoGetProperty(inID, inScope, inElement, pOutData, pIODataSize);
209     }
210 
211     OSStatus AUMethodSetProperty(void* pSelf, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* pInData, UInt32* pInDataSize)
212     {
213         debug(logDispatcher) printf("AUMethodSetProperty\n");
214         return getPlug(pSelf).DoSetProperty(inID, inScope, inElement, pInData, pInDataSize);
215     }
216 
217     OSStatus AUMethodAddPropertyListener(void* pSelf, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void* pUserData)
218     {
219         debug(logDispatcher) printf("AUMethodAddPropertyListener\n");
220         return getPlug(pSelf).DoAddPropertyListener(prop, proc, pUserData);
221     }
222 
223     OSStatus AUMethodRemovePropertyListener(void* pSelf, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc)
224     {
225         debug(logDispatcher) printf("AUMethodRemovePropertyListener\n");
226         return getPlug(pSelf).DoRemovePropertyListener(prop, proc);
227     }
228 
229     OSStatus AUMethodRemovePropertyListenerWithUserData(void* pSelf, AudioUnitPropertyID prop, AudioUnitPropertyListenerProc proc, void* pUserData)
230     {
231         debug(logDispatcher) printf("AUMethodRemovePropertyListenerWithUserData\n");
232         return getPlug(pSelf).DoRemovePropertyListenerWithUserData(prop, proc, pUserData);
233     }
234 
235     OSStatus AUMethodAddRenderNotify(void* pSelf, AURenderCallback proc, void* pUserData)
236     {
237         debug(logDispatcher) printf("AUMethodAddRenderNotify\n");
238         return getPlug(pSelf).DoAddRenderNotify(proc, pUserData);
239     }
240 
241     OSStatus AUMethodRemoveRenderNotify(void* pSelf, AURenderCallback proc, void* pUserData)
242     {
243         debug(logDispatcher) printf("AUMethodRemoveRenderNotify\n");
244         return getPlug(pSelf).DoRemoveRenderNotify(proc, pUserData);
245     }
246 
247     // Note: used even without Audio Component API
248     OSStatus AUMethodGetParameter(void* pSelf,
249                                   AudioUnitParameterID param,
250                                   AudioUnitScope scope_,
251                                   AudioUnitElement elem,
252                                   AudioUnitParameterValue *value)
253     {
254         debug(logDispatcher) printf("AUMethodGetParameter\n");
255         return getPlug(pSelf).DoGetParameter(param, scope_, elem, value);
256     }
257 
258     // Note: used even without Audio Component API
259     OSStatus AUMethodSetParameter(void* pSelf, AudioUnitParameterID param, AudioUnitScope scope_, AudioUnitElement elem, AudioUnitParameterValue value, UInt32 bufferOffset)
260     {
261         debug(logDispatcher) printf("AUMethodSetParameter\n");
262         return getPlug(pSelf).DoSetParameter(param, scope_, elem, value, bufferOffset);
263     }
264 
265     OSStatus AUMethodScheduleParameters(void* pSelf, const AudioUnitParameterEvent *pEvent, UInt32 nEvents)
266     {
267         debug(logDispatcher) printf("AUMethodScheduleParameters\n");
268         return getPlug(pSelf).DoScheduleParameters(pEvent, nEvents);
269     }
270 
271     OSStatus AUMethodRender(void* pSelf, AudioUnitRenderActionFlags* pIOActionFlags, const AudioTimeStamp* pInTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* pIOData)
272     {
273         debug(logDispatcher) printf("AUMethodRender\n");
274         return getPlug(pSelf).DoRender(pIOActionFlags, pInTimeStamp, inOutputBusNumber, inNumberFrames, pIOData);
275     }
276 
277     OSStatus AUMethodReset(void* pSelf, AudioUnitScope scope_, AudioUnitElement elem)
278     {
279         debug(logDispatcher) printf("AUMethodReset\n");
280         return getPlug(pSelf).DoReset(scope_, elem);
281     }
282 
283     OSStatus AUMethodMIDIEvent(void* pSelf, UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame)
284     {
285         debug(logDispatcher) printf("AUMethodMIDIEvent\n");
286         return getPlug(pSelf).DoMIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
287     }
288 
289     OSStatus AUMethodSysEx(void* pSelf, const UInt8* pInData, UInt32 inLength)
290     {
291         debug(logDispatcher) printf("AUMethodSysEx\n");
292         return getPlug(pSelf).DoSysEx(pInData, inLength);
293     }
294 
295     OSStatus AUMethodPrepareInstrument(void* pSelf, MusicDeviceInstrumentID inInstrument)
296     {
297         debug(logDispatcher) printf("AUMethodPrepareInstrument\n");
298         return getPlug(pSelf).DoPrepareInstrument(inInstrument);
299     }
300 
301     OSStatus AUMethodReleaseInstrument(void* pSelf, MusicDeviceInstrumentID inInstrument)
302     {
303         debug(logDispatcher) printf("AUMethodReleaseInstrument\n");
304         return getPlug(pSelf).DoReleaseInstrument(inInstrument);
305     }
306 
307     OSStatus AUMethodStartNote(void *pSelf, MusicDeviceInstrumentID inInstrument,
308                                MusicDeviceGroupID inGroupID, NoteInstanceID *outNoteInstanceID,
309                                UInt32 inOffsetSampleFrame, const MusicDeviceNoteParams *inParams)
310     {
311         debug(logDispatcher) printf("AUMethodStartNote\n");
312         return getPlug(pSelf).DoStartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, inParams);
313     }
314 
315     OSStatus AUMethodStopNote(void *pSelf, MusicDeviceGroupID inGroupID, NoteInstanceID inNoteInstanceID, UInt32 inOffsetSampleFrame)
316     {
317         debug(logDispatcher) printf("AUMethodStopNote\n");
318         return getPlug(pSelf).DoStopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);
319     }
320     // </Dispatch methods>
321 
322 }
323 
324