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 }