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