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 }