1 //-----------------------------------------------------------------------------
2 // LICENSE
3 // (c) 2018, Steinberg Media Technologies GmbH, All Rights Reserved
4 // (c) 2018, Guillaume Piolat (contact@auburnsounds.com)
5 //-----------------------------------------------------------------------------
6 //
7 // This Software Development Kit is licensed under the terms of the General
8 // Public License (GPL) Version 3.
9 //
10 // This source is part of the "Auburn Sounds (Guillaume Piolat) extension to the 
11 // Steinberg VST 3 Plug-in SDK".
12 //
13 // Details of that license can be found at: www.gnu.org/licenses/gpl-3.0.html
14 //
15 // Dual-licence:
16 // 
17 // The "Auburn Sounds (Guillaume Piolat) extension to the Steinberg VST 3 Plug-in
18 // SDK", hereby referred to as DPLUG:VST3, is a language translation of the VST3 
19 // SDK suitable for usage in Dplug. Any Licensee of a currently valid Steinberg 
20 // VST 3 Plug-In SDK Licensing Agreement (version 2.2.4 or ulterior, hereby referred
21 // to as the AGREEMENT), is granted by Auburn Sounds (Guillaume Piolat) a non-exclusive, 
22 // worldwide, nontransferable license during the term the AGREEMENT to use parts
23 // of DPLUG:VST3 not covered by the AGREEMENT, as if they were originally 
24 // inside the Licensed Software Developer Kit mentionned in the AGREEMENT. 
25 // Under this licence all conditions that apply to the Licensed Software Developer 
26 // Kit also apply to DPLUG:VST3.
27 //
28 //-----------------------------------------------------------------------------
29 module dplug.vst3.ftypes;
30 
31 version(VST3):
32 
33 //debug = logVST3Client;
34 
35 import core.stdc.stdint;
36 
37 nothrow:
38 @nogc:
39 
40 alias int8 = byte;
41 alias uint8 = ubyte;
42 alias uchar = char;
43 alias int16 = short;
44 alias uint16 = ushort;
45 alias int32 = int;
46 alias uint32 = uint;
47 
48 enum int32 kMaxLong = int.max;
49 enum int32 kMinLong = int.min;
50 enum int32 kMaxInt32 = kMaxLong;
51 enum int32 kMinInt32 = kMinLong;
52 
53 alias int64 = long;
54 alias uint64 = ulong;
55 enum int64 kMaxInt64 = long.max;
56 enum int64 kMinInt64 = long.min;
57 enum uint64 kMinInt64u = ulong.max;
58 
59 alias TSize = int64;
60 alias tresult = int32;
61 
62 alias TPtrInt = size_t;
63 
64 alias TBool = uint8;
65 
66 alias char8 = char;
67 alias char16 = wchar;
68 alias tchar = char16;
69 
70 alias CStringA = const(char8)*;
71 alias CStringW = const(char16)*;
72 //alias CString = const(tchar)*;
73 
74 bool strEmpty (const(tchar)* str)
75 {
76     return (!str || *str == '\0');
77 }
78 
79 bool str8Empty (const(char8)* str)
80 {
81     return (!str || *str == '\0');
82 }
83 
84 bool str16Empty (const(char16)* str)
85 {
86     return (!str || *str == '\0');
87 }
88 
89 alias FIDString = const(char8)*; // identifier as string (used for attributes, messages)
90 
91 
92 // vsttypes.h
93 
94 
95 static immutable string kVstVersionString = "VST 3.6.11";
96 
97 
98 alias TChar = char16;           ///< UTF-16 character
99 alias String128 = TChar[128];   ///< 128 character UTF-16 string
100 
101 // This conflicts with dplug.core.nogc.CString
102 //alias CString = const(char8)* ;   ///< C-String
103 
104 //------------------------------------------------------------------------
105 // General
106 //------------------------------------------------------------------------
107 alias MediaType = int; ///< media type (audio/event)
108 
109 alias BusDirection = int; ///< bus direction (in/out)
110 
111 alias BusType = int32;          ///< bus type (main/aux)
112 alias IoMode = int32;           ///< I/O mode (see \ref vst3IoMode)
113 alias UnitID = int32;           ///< unit identifier
114 alias ParamValue = double;      ///< parameter value type
115 alias ParamID = uint32;         ///< parameter identifier
116 alias ProgramListID = int32;    ///< program list identifier
117 alias CtrlNumber = int16;       ///< MIDI controller number (see \ref ControllerNumbers for allowed values)
118 
119 alias TQuarterNotes = double;   ///< time expressed in quarter notes
120 alias TSamples = int64;         ///< time expressed in audio samples
121 
122 alias ColorSpec = uint32;       ///< color defining by 4 component ARGB value (Alpha/Red/Green/Blue)
123 
124 //------------------------------------------------------------------------
125 static const ParamID kNoParamId = 0xffffffff;   ///< default for uninitialized parameter ID
126 
127 
128 //------------------------------------------------------------------------
129 // Audio Types
130 //------------------------------------------------------------------------
131 alias Sample32 = float;             ///< 32-bit precision audio sample
132 alias Sample64 = double;            ///< 64-bit precision audio sample
133 
134 alias SampleRate = double; ///< sample rate
135 
136 
137 //------------------------------------------------------------------------
138 // Speaker Arrangements Types
139 //------------------------------------------------------------------------
140 alias SpeakerArrangement = uint64 ; ///< Bitset of speakers
141 alias Speaker = uint64 ; ///< Bit for one speaker
142 
143 //------------------------------------------------------------------------
144 /** Returns number of channels used in speaker arrangement.
145 \ingroup speakerArrangements */
146 /*@{*/
147 int getChannelCount(SpeakerArrangement arr) pure nothrow @nogc
148 {
149 	int count = 0;
150 	while (arr)
151 	{
152 		if (arr & 1)
153 			++count;
154 		arr >>= 1;
155 	}
156 	return count;
157 }
158 
159 SpeakerArrangement getSpeakerArrangement(int numChannels) pure nothrow @nogc
160 {
161     // 0 => 0, 1 => 1, 2 => 3, 3 => 7...
162     if (numChannels == 0)
163         return 0;
164     int arr = 1;
165     for (int i = 1; i < numChannels; ++i)
166     {
167         arr = (arr << 1) | 1;
168     }
169     return arr;
170 }
171 
172 version(Windows)
173 {
174     enum COM_COMPATIBLE = 1;
175 }
176 else
177 {
178     enum COM_COMPATIBLE = 0;
179 }
180 
181 // vststructsizecheck.h
182 
183 // necessary because D doesn't have the equivalent of #pragma(pack)
184 // Note that such type check highly slow down build by about 1 sec.
185 
186 template SMTG_TYPE_SIZE_CHECK(T, size_t Platform64Size, size_t MacOS32Size, size_t Win32Size)
187 {
188     enum size = T.sizeof;
189     static if ((void*).sizeof == 8)
190     {
191         // 64-bit
192         static assert(size == Platform64Size, "bad size for " ~ T.stringof);
193     }
194     else version(OSX)
195     {
196         // OSX 32-bit
197         static assert(size == MacOS32Size, "bad size for " ~ T.stringof);
198     }
199     else version(Windows)
200     {
201         // Windows 32-bit
202         static assert(size == Win32Size, "bad size for " ~ T.stringof);
203     }
204 }
205 
206 
207 // funknown.h
208 
209 static if (COM_COMPATIBLE)
210 {
211     TUID INLINE_UID(uint l1, uint l2, uint l3, uint l4) pure @safe
212     {
213         return
214         [
215             (l1 & 0x000000FF)      , (l1 & 0x0000FF00) >>  8,
216             (l1 & 0x00FF0000) >> 16, (l1 & 0xFF000000) >> 24,
217             (l2 & 0x00FF0000) >> 16, (l2 & 0xFF000000) >> 24,
218             (l2 & 0x000000FF)      , (l2 & 0x0000FF00) >>  8,
219             (l3 & 0xFF000000) >> 24, (l3 & 0x00FF0000) >> 16,
220             (l3 & 0x0000FF00) >>  8, (l3 & 0x000000FF)      ,
221             (l4 & 0xFF000000) >> 24, (l4 & 0x00FF0000) >> 16,
222             (l4 & 0x0000FF00) >>  8, (l4 & 0x000000FF)
223         ];
224     }
225 }
226 else
227 {
228     TUID INLINE_UID(uint l1, uint l2, uint l3, uint l4) pure @safe
229     {
230         return
231         [
232             (l1 & 0xFF000000) >> 24, (l1 & 0x00FF0000) >> 16,
233             (l1 & 0x0000FF00) >>  8, (l1 & 0x000000FF)      ,
234             (l2 & 0xFF000000) >> 24, (l2 & 0x00FF0000) >> 16,
235             (l2 & 0x0000FF00) >>  8, (l2 & 0x000000FF)      ,
236             (l3 & 0xFF000000) >> 24, (l3 & 0x00FF0000) >> 16,
237             (l3 & 0x0000FF00) >>  8, (l3 & 0x000000FF)      ,
238             (l4 & 0xFF000000) >> 24, (l4 & 0x00FF0000) >> 16,
239             (l4 & 0x0000FF00) >>  8, (l4 & 0x000000FF)
240         ];
241     }
242 }
243 
244 mixin template IMPLEMENT_REFCOUNT()
245 {
246     public nothrow @nogc
247     {
248         extern(Windows) override uint addRef()
249         {
250             return atomicAdd(_funknownRefCount, 1);
251         }
252 
253         extern(Windows) override uint release()
254         {
255             import dplug.core.nogc: destroyFree, debugLog;
256             debug(logVST3Client) debugLog(">release".ptr);
257 
258 
259             int decremented = atomicAdd(_funknownRefCount, -1);
260             if (decremented == 0)
261                 destroyFree(this);
262 
263             debug(logVST3Client) debugLog("<release".ptr);
264             return decremented;
265         }
266     }
267 
268     protected shared(int) _funknownRefCount = 1; // when constructed, first value is 1
269 }
270 
271 mixin template QUERY_INTERFACE(Interfaces...)// interfaces)
272 {
273     override tresult queryInterface (ref const TUID _iid, void** obj)
274     {
275         import dplug.core.nogc: destroyFree, debugLog;
276         debug(logVST3Client) debugLog(">queryInterface".ptr);
277 
278         foreach(initer; Interfaces)
279         {
280             if (iidEqual (_iid, initer.iid))
281             {
282                 addRef();
283                 *obj = cast(void*)( cast(initer)(this) );
284 
285                 debug(logVST3Client) debugLog("<queryInterface OK".ptr);
286                 return kResultOk;
287             }
288         }
289         debug(logVST3Client) debugLog("<queryInterface NULL".ptr);
290         *obj = null;
291         return kNoInterface;
292     }
293 }
294 
295 // speical case, when asking for a IUnknown return a richer interface
296 mixin template QUERY_INTERFACE_SPECIAL_CASE_IUNKNOWN(Interfaces...)// interfaces)
297 {
298     extern(Windows) override tresult queryInterface (ref const TUID _iid, void** obj)
299     {
300         foreach(initer; Interfaces)
301         {
302             if (iidEqual (_iid, initer.iid))
303             {
304                 addRef();
305                 *obj = cast(void*)( cast(initer)(this) );
306                 return kResultOk;
307             }
308         }
309 
310         if (iidEqual (_iid, FUnknown.iid))
311         {
312             addRef();
313             *obj = cast(void*)( cast(Interfaces[0])(this) );
314             return kResultOk;
315         }
316 
317         *obj = null;
318         return kNoInterface;
319     }
320 }
321 
322 
323 static if (COM_COMPATIBLE)
324 {
325     version(Windows)
326     {
327     enum : tresult
328     {
329         kNoInterface        = cast(tresult)(0x80004002L),   // E_NOINTERFACE
330         kResultOk           = cast(tresult)(0x00000000L),   // S_OK
331         kResultTrue         = kResultOk,
332         kResultFalse        = cast(tresult)(0x00000001L),   // S_FALSE
333         kInvalidArgument    = cast(tresult)(0x80070057L),   // E_INVALIDARG
334         kNotImplemented     = cast(tresult)(0x80004001L),   // E_NOTIMPL
335         kInternalError      = cast(tresult)(0x80004005L),   // E_FAIL
336         kNotInitialized     = cast(tresult)(0x8000FFFFL),   // E_UNEXPECTED
337         kOutOfMemory        = cast(tresult)(0x8007000EL)        // E_OUTOFMEMORY
338     }
339     }
340     else
341     {
342     enum : tresult
343     {
344         kNoInterface        = cast(tresult)(0x80000004L),   // E_NOINTERFACE
345         kResultOk           = cast(tresult)(0x00000000L),   // S_OK
346         kResultTrue         = kResultOk,
347         kResultFalse        = cast(tresult)(0x00000001L),   // S_FALSE
348         kInvalidArgument    = cast(tresult)(0x80000003L),   // E_INVALIDARG
349         kNotImplemented     = cast(tresult)(0x80000001L),   // E_NOTIMPL
350         kInternalError      = cast(tresult)(0x80000008L),   // E_FAIL
351         kNotInitialized     = cast(tresult)(0x8000FFFFL),   // E_UNEXPECTED
352         kOutOfMemory        = cast(tresult)(0x80000002L)        // E_OUTOFMEMORY
353     }
354     }
355 }
356 else
357 {
358 enum : tresult
359 {
360     kNoInterface = -1,
361     kResultOk,
362     kResultTrue = kResultOk,
363     kResultFalse,
364     kInvalidArgument,
365     kNotImplemented,
366     kInternalError,
367     kNotInitialized,
368     kOutOfMemory
369 }
370 }
371 
372 alias LARGE_INT = int64 ; // obsolete
373 
374 alias TUID = ubyte[16]; ///< plain UID type
375 
376 public bool iidEqual (const(TUID) iid1, const(TUID) iid2) pure
377 {
378     return iid1 == iid2;
379 }
380 
381 interface IUnknown
382 {
383 public:
384 @nogc:
385 nothrow:
386     tresult queryInterface(ref const(TUID) _iid, void** obj);
387     uint addRef();
388     uint release();
389 }
390 
391 interface FUnknown : IUnknown
392 {
393     __gshared immutable TUID iid = INLINE_UID(0x00000000, 0x00000000, 0xC0000000, 0x00000046);
394 }
395 
396 int atomicAdd(ref shared(int) var, int32 d)
397 {
398     import core.atomic;
399     return atomicOp!"+="(var, d); // Note: return the new value
400 }
401 
402 
403 // fstrdefs.h
404 
405 T* _tstrncpy(T) (T* dest, const(T)* source, uint32 count)
406 {
407     T* start = dest;
408     while (count && (*dest++ = *source++) != 0) // copy string
409         count--;
410 
411     if (count) // pad out with zeros
412     {
413         while (--count)
414             *dest++ = 0;
415     }
416     return start;
417 }
418 
419 char8* strncpy8 (char8* dest, const(char8)* source, uint32 count)
420 {
421     return _tstrncpy!char8(dest, source, count);
422 }
423 
424 char16* strncpy16 (char16* dest, const(char16)* source, uint32 count)
425 {
426     return _tstrncpy!char16(dest, source, count);
427 }
428 
429 /// Convert UTF-16 to UTF-8
430 void str16ToStr8 (char* dst, wchar* src, int32 n = -1)
431 {
432     int32 i = 0;
433     for (;;)
434     {
435         if (i == n)
436         {
437             dst[i] = 0;
438             return;
439         }
440 
441         wchar codeUnit = src[i];
442         if (codeUnit >= 127)
443             codeUnit = '?';
444 
445         dst[i] = cast(char)(codeUnit); // FUTURE: proper unicode conversion, this is US-ASCII only
446 
447         if (src[i] == 0)
448             break;
449         i++;
450     }
451 
452     while (n > i)
453     {
454         dst[i] = 0;
455         i++;
456     }
457 }
458 
459 void str8ToStr16 (char16* dst, const(char)[] src, int32 n = -1)
460 {
461     int32 i = 0;
462     for (;;)
463     {
464         if (i == src.length)
465         {
466             dst[i] = 0;
467             return;
468         }
469 
470         if (i == n)
471         {
472             dst[i] = 0;
473             return;
474         }
475 
476         version(BigEndian)
477         {
478             char8* pChr = cast(char8*)&dst[i];
479             pChr[0] = 0;
480             pChr[1] = src[i];
481         }
482         else
483         {
484             dst[i] = cast(char16)(src[i]);
485         }
486 
487         if (src[i] == 0)
488             break;
489 
490         i++;
491     }
492 
493     while (n > i)
494     {
495         dst[i] = 0;
496         i++;
497     }
498 }
499 
500 void str8ToStr16 (char16* dst, const(char8)* src, int32 n = -1)
501 {
502     int32 i = 0;
503     for (;;)
504     {
505         if (i == n)
506         {
507             dst[i] = 0;
508             return;
509         }
510 
511         version(BigEndian)
512         {
513             char8* pChr = cast(char8*)&dst[i];
514             pChr[0] = 0;
515             pChr[1] = src[i];
516         }
517         else
518         {
519             dst[i] = cast(char16)(src[i]);
520         }
521 
522         if (src[i] == 0)
523             break;
524 
525         i++;
526     }
527 
528     while (n > i)
529     {
530         dst[i] = 0;
531         i++;
532     }
533 }