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 }