1 /*
2 Destroy FX AU Utilities is a collection of helpful utility functions
3 for creating and hosting Audio Unit plugins.
4 Copyright (C) 2003-2008 Sophia Poirier
5 All rights reserved.
6 7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 11 * Redistributions of source code must retain the above
12 copyright notice, this list of conditions and the
13 following disclaimer.
14 * Redistributions in binary form must reproduce the above
15 copyright notice, this list of conditions and the
16 following disclaimer in the documentation and/or other
17 materials provided with the distribution.
18 * Neither the name of Destroy FX nor the names of its
19 contributors may be used to endorse or promote products
20 derived from this software without specific prior
21 written permission.
22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 OF THE POSSIBILITY OF SUCH DAMAGE.
35 36 To contact the author, please visit http://destroyfx.org/
37 and use the contact form.
38 */39 // this is a modified version of dfx-au-utilities.h keeping only CFAUPreset related functionality40 41 /**
42 Audio Unit plug-in client. Port of Destroy FX AU Utilities.
43 44 Copyright: Copyright (C) 2003-2008 Sophia Poirier
45 Copyright (C) 2016 Guillaume Piolat
46 */47 moduledplug.au.dfxutil;
48 49 version(AU):
50 51 importcore.stdc.stdio: snprintf;
52 53 importstd.string;
54 importstd.exception: assumeUnique;
55 56 importderelict.carbon;
57 58 importdplug.core.nogc;
59 60 //-----------------------------------------------------------------------------61 // The following defines and implements CoreFoundation-like handling of62 // an AUPreset container object: CFAUPreset63 //-----------------------------------------------------------------------------64 65 enumUInt32kCFAUPreset_CurrentVersion = 0;
66 67 structCFAUPreset68 {
69 AUPresetauPreset;
70 uintversion_;
71 CFAllocatorRefallocator;
72 CFIndexretainCount;
73 }
74 75 aliasCFAUPresetRef = void*;
76 77 //-----------------------------------------------------------------------------78 // create an instance of a CFAUPreset object79 CFAUPresetRefCFAUPresetCreate(CFAllocatorRefinAllocator, SInt32inPresetNumber, CFStringRefinPresetName) nothrow @nogc80 {
81 CFAUPreset * newPreset = cast(CFAUPreset*) CFAllocatorAllocate(inAllocator, CFAUPreset.sizeof, 0);
82 if (newPreset != null)
83 {
84 newPreset.auPreset.presetNumber = inPresetNumber;
85 newPreset.auPreset.presetName = null;
86 // create our own a copy rather than retain the string, in case the input string is mutable,87 // this will keep it from changing under our feet88 if (inPresetName != null)
89 newPreset.auPreset.presetName = CFStringCreateCopy(inAllocator, inPresetName);
90 newPreset.version_ = kCFAUPreset_CurrentVersion;
91 newPreset.allocator = inAllocator;
92 newPreset.retainCount = 1;
93 }
94 returncast(CFAUPresetRef)newPreset;
95 }
96 97 extern(C)
98 {
99 //-----------------------------------------------------------------------------100 // retain a reference of a CFAUPreset object101 CFAUPresetRefCFAUPresetRetain(void* inPreset) nothrow @nogc102 {
103 if (inPreset != null)
104 {
105 CFAUPreset * incomingPreset = cast(CFAUPreset*) inPreset;
106 // retain the input AUPreset's name string for this reference to the preset107 if (incomingPreset.auPreset.presetName != null)
108 CFRetain(incomingPreset.auPreset.presetName);
109 incomingPreset.retainCount += 1;
110 }
111 returninPreset;
112 }
113 114 //-----------------------------------------------------------------------------115 // release a reference of a CFAUPreset object116 voidCFAUPresetRelease(void* inPreset) nothrow @nogc117 {
118 CFAUPreset* incomingPreset = cast(CFAUPreset*) inPreset;
119 // these situations shouldn't happen120 if (inPreset == null)
121 return;
122 if (incomingPreset.retainCount <= 0)
123 return;
124 125 // first release the name string, CF-style, since it's a CFString126 if (incomingPreset.auPreset.presetName != null)
127 CFRelease(incomingPreset.auPreset.presetName);
128 incomingPreset.retainCount -= 1;
129 // check if this is the end of this instance's life130 if (incomingPreset.retainCount == 0)
131 {
132 // wipe out the data so that, if anyone tries to access stale memory later, it will be (semi)invalid133 incomingPreset.auPreset.presetName = null;
134 incomingPreset.auPreset.presetNumber = 0;
135 // and finally, free the memory for the CFAUPreset struct136 CFAllocatorDeallocate(incomingPreset.allocator, cast(void*)inPreset);
137 }
138 }
139 140 //-----------------------------------------------------------------------------141 // This function is called when an item (an AUPreset) is added to the CFArray,142 // or when a CFArray containing an AUPreset is retained.143 const(void)* CFAUPresetArrayRetainCallBack(CFAllocatorRefinAllocator, const(void)* inPreset) nothrow @nogc144 {
145 returnCFAUPresetRetain(cast(void*)inPreset); // casting const away here!146 }
147 148 //-----------------------------------------------------------------------------149 // This function is called when an item (an AUPreset) is removed from the CFArray150 // or when the array is released.151 // Since a reference to the data belongs to the array, we need to release that here.152 voidCFAUPresetArrayReleaseCallBack(CFAllocatorRefinAllocator, const(void)* inPreset) nothrow @nogc153 {
154 CFAUPresetRelease(cast(void*)inPreset); // casting const away here!155 }
156 157 //-----------------------------------------------------------------------------158 // This function is called when someone wants to compare to items (AUPresets)159 // in the CFArray to see if they are equal or not.160 // For our AUPresets, we will compare based on the preset number and the name string.161 BooleanCFAUPresetArrayEqualCallBack(const(void)* inPreset1, const(void)* inPreset2) nothrow @nogc162 {
163 AUPreset * preset1 = cast(AUPreset*) inPreset1;
164 AUPreset * preset2 = cast(AUPreset*) inPreset2;
165 // the two presets are only equal if they have the same preset number and166 // if the two name strings are the same (which we rely on the CF function to compare)167 return (preset1.presetNumber == preset2.presetNumber) &&
168 (CFStringCompare(preset1.presetName, preset2.presetName, 0) == kCFCompareEqualTo);
169 }
170 171 //-----------------------------------------------------------------------------172 // This function is called when someone wants to get a description of173 // a particular item (an AUPreset) as though it were a CF type.174 // That happens, for example, when using CFShow().175 // This will create and return a CFString that indicates that176 // the object is an AUPreset and tells the preset number and preset name.177 CFStringRefCFAUPresetArrayCopyDescriptionCallBack(const(void)* inPreset) nothrow178 {
179 AUPreset * preset = cast(AUPreset*) inPreset;
180 returnCFStringCreateWithFormat(kCFAllocatorDefault, null,
181 CFStrLocal.fromString("AUPreset:\npreset number = %d\npreset name = %@"),
182 cast(int)preset.presetNumber, preset.presetName);
183 }
184 }
185 186 CFArrayCallBacksgetCFAUPresetArrayCallBacks() nothrow @nogc187 {
188 CFArrayCallBacksresult;
189 with(result)
190 {
191 version_ = 0; // currently, 0 is the only valid version value for this192 retain = &CFAUPresetArrayRetainCallBack;
193 release = &CFAUPresetArrayReleaseCallBack;
194 copyDescription = &CFAUPresetArrayCopyDescriptionCallBack;
195 equal = &CFAUPresetArrayEqualCallBack;
196 }
197 returnresult;
198 }
199 200 201 // CoreFoundation helpers202 203 structCFStrLocal204 {
205 nothrow:
206 @nogc:
207 208 CFStringRefparent;
209 aliasparentthis;
210 211 @disablethis();
212 @disablethis(this);
213 214 staticfromString(const(char)[] str)
215 {
216 CFStrLocals = void;
217 s.parent = toCFString(str);
218 returns;
219 }
220 221 ~this() nothrow222 {
223 CFRelease(parent);
224 }
225 }
226 227 228 /// Creates a CFString from an int give up its ownership.229 CFStringRefconvertIntToCFString(intnumber) nothrow @nogc230 {
231 char[16] str;
232 snprintf(str.ptr, str.length, "%d", number);
233 returnCFStringCreateWithCString(null, str.ptr, kCFStringEncodingUTF8);
234 }
235 236 /// Creates a CFString from a string and give up its ownership.237 CFStringReftoCFString(const(char)[] str) nothrow @nogc238 {
239 returnCFStringCreateWithCString(null, CString(str).storage, kCFStringEncodingUTF8);
240 }
241 242 /// Create string from a CFString, and give up its ownership.243 /// Such a string must be deallocated with `free`/`freeSlice`.244 /// It is guaranteed to finish with a terminal zero character ('\0').245 stringmallocStringFromCFString(CFStringRefcfStr) nothrow @nogc246 {
247 intn = cast(int)CFStringGetLength(cfStr) + 1;
248 char[] buf = mallocSlice!char(n);
249 CFStringGetCString(cfStr, buf.ptr, n, kCFStringEncodingUTF8);
250 returnassumeUnique(buf);
251 }
252 253 voidputNumberInDict(CFMutableDictionaryRefpDict, const(char)[] key, void* pNumber, CFNumberTypetype) nothrow @nogc254 {
255 CFStrLocalcfKey = CFStrLocal.fromString(key);
256 257 CFNumberRefpValue = CFNumberCreate(null, type, pNumber);
258 CFDictionarySetValue(pDict, cfKey, pValue);
259 CFRelease(pValue);
260 }
261 262 voidputStrInDict(CFMutableDictionaryRefpDict, const(char)[] key, const(char)[] value) nothrow @nogc263 {
264 CFStrLocalcfKey = CFStrLocal.fromString(key);
265 CFStrLocalcfValue = CFStrLocal.fromString(value);
266 CFDictionarySetValue(pDict, cfKey, cfValue);
267 }
268 269 voidputDataInDict(CFMutableDictionaryRefpDict, const(char)[] key, ubyte[] pChunk) nothrow @nogc270 {
271 CFStrLocalcfKey = CFStrLocal.fromString(key);
272 273 CFDataRefpData = CFDataCreate(null, pChunk.ptr, cast(CFIndex)(pChunk.length));
274 CFDictionarySetValue(pDict, cfKey, pData);
275 CFRelease(pData);
276 }
277 278 279 boolgetNumberFromDict(CFDictionaryRefpDict, const(char)[] key, void* pNumber, CFNumberTypetype) nothrow @nogc280 {
281 CFStrLocalcfKey = CFStrLocal.fromString(key);
282 283 CFNumberRefpValue = cast(CFNumberRef) CFDictionaryGetValue(pDict, cfKey);
284 if (pValue)
285 {
286 CFNumberGetValue(pValue, type, pNumber);
287 returntrue;
288 }
289 returnfalse;
290 }
291 292 /// Get a string in a dictionnary, and give up its ownership.293 boolgetStrFromDict(CFDictionaryRefpDict, const(char)[] key, outstringvalue) nothrow @nogc294 {
295 CFStrLocalcfKey = CFStrLocal.fromString(key);
296 297 CFStringRefpValue = cast(CFStringRef) CFDictionaryGetValue(pDict, cfKey);
298 if (pValue)
299 {
300 value = mallocStringFromCFString(pValue);
301 returntrue;
302 }
303 returnfalse;
304 }
305 306 /// Gets data from a CFDataRef dictionnary entry and give up its ownership.307 /// Must be deallocated with `free`/`freeSlice`.308 boolgetDataFromDict(CFDictionaryRefpDict, stringkey, outubyte[] pChunk) nothrow @nogc309 {
310 CFStrLocalcfKey = CFStrLocal.fromString(key);
311 CFDataRefpData = cast(CFDataRef) CFDictionaryGetValue(pDict, cfKey);
312 if (pData)
313 {
314 intn = cast(int)CFDataGetLength(pData);
315 pChunk = ( CFDataGetBytePtr(pData)[0..n] ).mallocDup;
316 returntrue;
317 }
318 returnfalse;
319 }