iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugUtilities.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
21#include <algorithm>
22#include <cmath>
23#include <cstdio>
24#include <cstdlib>
25#include <cstring>
26#include <cctype>
27#include <string>
28
29#include "heapbuf.h"
30#include "wdlstring.h"
31#include "wdlutf8.h"
32
33#include "IPlugConstants.h"
34#include "IPlugPlatform.h"
35
36#ifdef OS_WIN
37#include <windows.h>
38#pragma warning(disable:4018 4267) // size_t/signed/unsigned mismatch..
39#pragma warning(disable:4800) // if (pointer) ...
40#pragma warning(disable:4805) // Compare bool and BOOL.
41#endif
42
43BEGIN_IPLUG_NAMESPACE
44
50template <typename T>
51T Clip(T x, T lo, T hi) { return std::min(std::max(x, lo), hi); }
52
57template <typename T>
58inline T Lerp(T a, T b, T f) { return ((b - a) * f + a); }
59
60static inline bool CStringHasContents(const char* str) { return str && str[0] != '\0'; }
61
62#define MAKE_QUOTE(str) #str
63#define MAKE_STR(str) MAKE_QUOTE(str)
64
66#define GET_PARAM_FROM_VARARG(paramType, vp, v) \
67{ \
68 v = 0.0; \
69 switch (paramType) { \
70 case IParam::kTypeBool: \
71 case IParam::kTypeInt: \
72 case IParam::kTypeEnum: { \
73 v = (double) va_arg(vp, int); \
74 break; \
75 } \
76 case IParam::kTypeDouble: \
77 default: { \
78 v = (double) va_arg(vp, double); \
79 break; \
80 } \
81 } \
82}
83
84#ifndef REMINDER
85#ifdef OS_WIN
86// This enables: #pragma REMINDER("change this line!") with click-through from VC++.
87#define REMINDER(msg) message(__FILE__ "(" MAKE_STR(__LINE__) "): " msg)
88#elif defined __APPLE__
89#define REMINDER(msg) WARNING msg
90#endif
91#endif
92
99static inline double DBToAmp(double dB)
100{
101 return std::exp(IAMP_DB * dB);
102}
103
107static inline double AmpToDB(double amp)
108{
109 return AMP_DB * std::log(std::fabs(amp));
110}
111
117static inline void GetVersionParts(int versionInteger, int& maj, int& min, int& pat)
118{
119 maj = (versionInteger & 0xFFFF0000) >> 16;
120 min = (versionInteger & 0x0000FF00) >> 8;
121 pat = versionInteger & 0x000000FF;
122}
123
127static inline int GetDecimalVersion(int versionInteger)
128{
129 int maj, min, pat;
130 GetVersionParts(versionInteger, maj, min, pat);
131 return 10000 * maj + 100 * min + pat;
132}
133
137static inline void GetVersionStr(int versionInteger, WDL_String& str)
138{
139 int maj, min, pat;
140 GetVersionParts(versionInteger, maj, min, pat);
141 str.SetFormatted(MAX_VERSION_STR_LEN, "v%d.%d.%d", maj, min, pat);
142}
143
150template <class SRC, class DEST>
151void CastCopy(DEST* pDest, SRC* pSrc, int n)
152{
153 for (int i = 0; i < n; ++i, ++pDest, ++pSrc)
154 {
155 *pDest = (DEST) *pSrc;
156 }
157}
158
162static void ToLower(char* cDest, const char* cSrc)
163{
164 int i, n = (int) strlen(cSrc);
165 for (i = 0; i < n; ++i)
166 {
167 cDest[i] = tolower(cSrc[i]);
168 }
169 cDest[i] = '\0';
170}
171
175static EHost LookUpHost(const char* inHost)
176{
177 char host[256];
178 ToLower(host, inHost);
179
180 // C4 is version >= 8.2
181 if (strstr(host, "reaper")) return kHostReaper;
182 if (strstr(host, "protools")) return kHostProTools;
183 if (strstr(host, "cubase")) return kHostCubase;
184 if (strstr(host, "nuendo")) return kHostNuendo;
185 if (strstr(host, "cakewalk")) return kHostSonar;
186 if (strstr(host, "vegas")) return kHostVegas;
187 if (strstr(host, "fruity")) return kHostFL;
188 if (strstr(host, "samplitude")) return kHostSamplitude;
189 if (strstr(host, "live")) return kHostAbletonLive;
190 if (strstr(host, "tracktion")) return kHostTracktion;
191 if (strstr(host, "ntracks")) return kHostNTracks;
192 if (strstr(host, "melodyne")) return kHostMelodyneStudio;
193 if (strstr(host, "vstmanlib")) return kHostVSTScanner;
194 if (strstr(host, "aulab")) return kHostAULab;
195 if (strstr(host, "forte")) return kHostForte;
196 if (strstr(host, "chainer")) return kHostChainer;
197 if (strstr(host, "audition")) return kHostAudition;
198 if (strstr(host, "orion")) return kHostOrion;
199 if (strstr(host, "bias")) return kHostBias;
200 if (strstr(host, "sawstudio")) return kHostSAWStudio;
201 if (strstr(host, "logic")) return kHostLogic;
202 if (strstr(host, "garageband")) return kHostGarageBand;
203 if (strstr(host, "digital")) return kHostDigitalPerformer;
204 if (strstr(host, "audiomulch")) return kHostAudioMulch;
205 if (strstr(host, "presonus")) return kHostStudioOne;
206 if (strstr(host, "vst3plugintesthost")) return kHostVST3TestHost;
207 if (strstr(host, "ardour")) return kHostArdour;
208 if (strstr(host, "renoise")) return kHostRenoise;
209 if (strstr(host, "openmpt")) return kHostOpenMPT;
210 if (strstr(host, "wavelab elements")) return kHostWaveLabElements; // check for wavelab elements should come before wavelab ...
211 if (strstr(host, "wavelab")) return kHostWaveLab;
212 if (strstr(host, "twistedwave")) return kHostTwistedWave;
213 if (strstr(host, "bitwig studio")) return kHostBitwig;
214 if (strstr(host, "reason")) return kHostReason;
215 if (strstr(host, "gwvst")) return kHostGoldWave5x;
216 if (strstr(host, "waveform")) return kHostWaveform;
217 if (strstr(host, "audacity")) return kHostAudacity;
218 if (strstr(host, "acoustica")) return kHostAcoustica;
219 if (strstr(host, "plugindoctor")) return kHostPluginDoctor;
220 if (strstr(host, "izotope rx")) return kHostiZotopeRX;
221 if (strstr(host, "savihost")) return kHostSAVIHost;
222 if (strstr(host, "blue cat's vst host")) return kHostBlueCat;
223 if (strstr(host, "mixbus")) return kHostMixbus32C;
224
225 if (strstr(host, "standalone")) return kHostStandalone;
226 if (strstr(host, "www")) return kHostWWW;
227
228 return kHostUnknown;
229
230}
231
240static void GetHostNameStr(EHost host, WDL_String& str)
241{
242 switch (host)
243 {
244 case kHostReaper: str.Set("reaper"); break;
245 case kHostProTools: str.Set("protools"); break;
246 case kHostCubase: str.Set("cubase"); break;
247 case kHostNuendo: str.Set("nuendo"); break;
248 case kHostSonar: str.Set("cakewalk"); break;
249 case kHostVegas: str.Set("vegas"); break;
250 case kHostFL: str.Set("fruity"); break;
251 case kHostSamplitude: str.Set("samplitude"); break;
252 case kHostAbletonLive: str.Set("live"); break;
253 case kHostTracktion: str.Set("tracktion"); break;
254 case kHostNTracks: str.Set("ntracks"); break;
255 case kHostMelodyneStudio: str.Set("melodyne"); break;
256 case kHostVSTScanner: str.Set("vstmanlib"); break;
257 case kHostAULab: str.Set("aulab"); break;
258 case kHostForte: str.Set("forte"); break;
259 case kHostChainer: str.Set("chainer"); break;
260 case kHostAudition: str.Set("audition"); break;
261 case kHostOrion: str.Set("orion"); break;
262 case kHostBias: str.Set("bias"); break;
263 case kHostSAWStudio: str.Set("sawstudio"); break;
264 case kHostLogic: str.Set("logic"); break;
265 case kHostGarageBand: str.Set("garageband"); break;
266 case kHostDigitalPerformer: str.Set("digital"); break;
267 case kHostAudioMulch: str.Set("audiomulch"); break;
268 case kHostStudioOne: str.Set("presonus"); break;
269 case kHostVST3TestHost: str.Set("vst3plugintesthost"); break;
270 case kHostArdour: str.Set("ardour"); break;
271 case kHostRenoise: str.Set("renoise"); break;
272 case kHostOpenMPT: str.Set("OpenMPT"); break;
273 case kHostWaveLabElements: str.Set("wavelab elements"); break;
274 case kHostWaveLab: str.Set("wavelab"); break;
275 case kHostTwistedWave: str.Set("twistedwave"); break;
276 case kHostBitwig: str.Set("bitwig studio"); break;
277 case kHostReason: str.Set("reason"); break;
278 case kHostGoldWave5x: str.Set("gwvst"); break;
279 case kHostWaveform: str.Set("waveform"); break;
280 case kHostAudacity: str.Set("audacity"); break;
281 case kHostAcoustica: str.Set("acoustica"); break;
282 case kHostPluginDoctor: str.Set("plugindoctor"); break;
283 case kHostiZotopeRX: str.Set("izotope rx"); break;
284 case kHostSAVIHost: str.Set("savihost"); break;
285 case kHostBlueCat: str.Set("blue cat's vst host"); break;
286 case kHostMixbus32C: str.Set("mixbus"); break;
287
288 case kHostStandalone: str.Set("standalone"); break;
289 case kHostWWW: str.Set("www"); break;
290
291 default: str.Set("Unknown"); break;
292 }
293}
294
300static void MidiNoteName(double midiPitch, WDL_String& noteName, bool cents = false, bool middleCisC4 = false)
301{
302 static const char noteNames[12][3] = {"C ","C#","D ","D#","E ","F ","F#","G ","G#","A ","A#","B "};
303
304 int midiPitchR = (int) std::round(midiPitch);
305 int pitchClass = midiPitchR % 12;
306 int octave = (midiPitchR / 12) - (middleCisC4? 1 : 2);
307
308 if (cents)
309 {
310 double frac = (midiPitch - (float) midiPitchR) * 100.;
311 noteName.SetFormatted(32, "%s%i %.0f", noteNames[pitchClass], octave, frac);
312 }
313 else
314 {
315 noteName.SetFormatted(32, "%s%i", noteNames[pitchClass], octave);
316 }
317}
318
319#if defined OS_WIN
320
321static int UTF8ToUTF16Len(const char* utf8Str)
322{
323 return std::max(MultiByteToWideChar(CP_UTF8, 0, utf8Str, -1, NULL, 0), 1);
324}
325
326static void UTF8ToUTF16(wchar_t* wideStr, const char* utf8Str, int maxLen)
327{
328 int requiredSize = UTF8ToUTF16Len(utf8Str);
329
330 if (requiredSize <= maxLen)
331 {
332 if (MultiByteToWideChar(CP_UTF8, 0, utf8Str, -1, wideStr, requiredSize))
333 return;
334 }
335
336 wideStr[0] = '\0';
337}
338
339static void UTF16ToUTF8(WDL_String& utf8Str, const wchar_t* wideStr)
340{
341 int requiredSize = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, NULL, 0, NULL, NULL);
342
343 if (requiredSize > 0 && utf8Str.SetLen(requiredSize))
344 {
345 WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, utf8Str.Get(), requiredSize, NULL, NULL);
346 return;
347 }
348
349 utf8Str.Set("");
350}
351
352class UTF8AsUTF16
353{
354public:
355
356 UTF8AsUTF16(const char* utf8Str)
357 {
358 mUTF16Str.Resize(UTF8ToUTF16Len(utf8Str));
359 UTF8ToUTF16(mUTF16Str.Get(), utf8Str, mUTF16Str.GetSize());
360 }
361
362 UTF8AsUTF16(const WDL_String& utf8Str) : UTF8AsUTF16(utf8Str.Get())
363 {
364 }
365
366 const wchar_t* Get() const { return mUTF16Str.Get(); }
367 int GetLength() const { return mUTF16Str.GetSize(); }
368
369 UTF8AsUTF16& ToUpperCase()
370 {
371 _wcsupr(mUTF16Str.Get());
372 return *this;
373 }
374
375 UTF8AsUTF16& ToLowerCase()
376 {
377 _wcslwr(mUTF16Str.Get());
378 return *this;
379 }
380
381private:
382
383 WDL_TypedBuf<wchar_t> mUTF16Str;
384};
385
386class UTF16AsUTF8
387{
388public:
389
390 UTF16AsUTF8(const wchar_t* wideStr)
391 {
392 UTF16ToUTF8(mUTF8Str, wideStr);
393 }
394
395 const char* Get() const { return mUTF8Str.Get(); }
396 int GetLength() const { return mUTF8Str.GetLength(); }
397
398private:
399
400 WDL_String mUTF8Str;
401};
402#endif
403
407static std::u16string UTF8ToUTF16String(const char* utf8)
408{
409 std::u16string result;
410 if (!utf8) return result;
411 while (*utf8)
412 {
413 int codepoint;
414 int len = wdl_utf8_parsechar(utf8, &codepoint);
415 if (len <= 0) break; // Invalid UTF-8 sequence
416 if (codepoint >= 0x10000 && codepoint <= 0x10FFFF)
417 {
418 result += static_cast<char16_t>(0xD800 + (((codepoint - 0x10000) >> 10) & 0x3FF));
419 result += static_cast<char16_t>(0xDC00 + ((codepoint - 0x10000) & 0x3FF));
420 }
421 else
422 {
423 result += static_cast<char16_t>(codepoint);
424 }
425 utf8 += len;
426 }
427 return result;
428}
429
433static std::string UTF16ToUTF8String(const std::u16string& u16str)
434{
435 std::string result;
436 for (size_t i = 0; i < u16str.size(); i++)
437 {
438 unsigned int ch = u16str[i];
439 if (ch >= 0xD800 && ch <= 0xDBFF && i + 1 < u16str.size())
440 {
441 unsigned int low = u16str[i + 1];
442 if (low >= 0xDC00 && low <= 0xDFFF)
443 {
444 ch = 0x10000 + ((ch - 0xD800) << 10) + (low - 0xDC00);
445 i++;
446 }
447 }
448 char buf[5];
449 int len = WDL_MakeUTFChar(buf, ch, sizeof(buf));
450 result.append(buf, len);
451 }
452 return result;
453}
454
458static std::string UTF16ToUTF8String(char16_t c)
459{
460 char buf[5];
461 int len = WDL_MakeUTFChar(buf, c, sizeof(buf));
462 return std::string(buf, len);
463}
464
469static std::string UTF16ToUTF8String(const char16_t* begin, const char16_t* end)
470{
471 return UTF16ToUTF8String(std::u16string(begin, end));
472}
473
474/*
475 * DOM Virtual Key Code to iPlug2 Virtual Key Code converter
476 *
477 * Virtual key code definitions adapted from Emscripten
478 * Copyright 2017 The Emscripten Authors. All rights reserved.
479 * Source: https://github.com/emscripten-core/emscripten/
480 * Licensed under MIT and University of Illinois/NCSA Open Source License
481 */
482
483// DOM Virtual Key codes (subset of most common keys)
484enum EDOMVirtualKey {
485 DOM_VK_BACK_SPACE = 0x08,
486 DOM_VK_TAB = 0x09,
487 DOM_VK_RETURN = 0x0D,
488 DOM_VK_SHIFT = 0x10,
489 DOM_VK_CONTROL = 0x11,
490 DOM_VK_ALT = 0x12,
491 DOM_VK_PAUSE = 0x13,
492 DOM_VK_CAPS_LOCK = 0x14,
493 DOM_VK_ESCAPE = 0x1B,
494 DOM_VK_SPACE = 0x20,
495 DOM_VK_PAGE_UP = 0x21,
496 DOM_VK_PAGE_DOWN = 0x22,
497 DOM_VK_END = 0x23,
498 DOM_VK_HOME = 0x24,
499 DOM_VK_LEFT = 0x25,
500 DOM_VK_UP = 0x26,
501 DOM_VK_RIGHT = 0x27,
502 DOM_VK_DOWN = 0x28,
503 DOM_VK_INSERT = 0x2D,
504 DOM_VK_DELETE = 0x2E,
505 DOM_VK_F1 = 0x70,
506 DOM_VK_F2 = 0x71,
507 DOM_VK_F3 = 0x72,
508 DOM_VK_F4 = 0x73,
509 DOM_VK_F5 = 0x74,
510 DOM_VK_F6 = 0x75,
511 DOM_VK_F7 = 0x76,
512 DOM_VK_F8 = 0x77,
513 DOM_VK_F9 = 0x78,
514 DOM_VK_F10 = 0x79,
515 DOM_VK_F11 = 0x7A,
516 DOM_VK_F12 = 0x7B,
517 DOM_VK_NUMPAD0 = 0x60,
518 DOM_VK_NUMPAD1 = 0x61,
519 DOM_VK_NUMPAD2 = 0x62,
520 DOM_VK_NUMPAD3 = 0x63,
521 DOM_VK_NUMPAD4 = 0x64,
522 DOM_VK_NUMPAD5 = 0x65,
523 DOM_VK_NUMPAD6 = 0x66,
524 DOM_VK_NUMPAD7 = 0x67,
525 DOM_VK_NUMPAD8 = 0x68,
526 DOM_VK_NUMPAD9 = 0x69
527};
528
534inline int DOMKeyToVirtualKey(uint32_t domKeyCode) {
535 switch(domKeyCode) {
536 case DOM_VK_BACK_SPACE: return kVK_BACK;
537 case DOM_VK_TAB: return kVK_TAB;
538 case DOM_VK_RETURN: return kVK_RETURN;
539 case DOM_VK_SHIFT: return kVK_SHIFT;
540 case DOM_VK_CONTROL: return kVK_CONTROL;
541 case DOM_VK_ALT: return kVK_MENU;
542 case DOM_VK_PAUSE: return kVK_PAUSE;
543 case DOM_VK_CAPS_LOCK: return kVK_CAPITAL;
544 case DOM_VK_ESCAPE: return kVK_ESCAPE;
545 case DOM_VK_SPACE: return kVK_SPACE;
546 case DOM_VK_PAGE_UP: return kVK_PRIOR;
547 case DOM_VK_PAGE_DOWN: return kVK_NEXT;
548 case DOM_VK_END: return kVK_END;
549 case DOM_VK_HOME: return kVK_HOME;
550 case DOM_VK_LEFT: return kVK_LEFT;
551 case DOM_VK_UP: return kVK_UP;
552 case DOM_VK_RIGHT: return kVK_RIGHT;
553 case DOM_VK_DOWN: return kVK_DOWN;
554 case DOM_VK_INSERT: return kVK_INSERT;
555 case DOM_VK_DELETE: return kVK_DELETE;
556
557 // Numbers (both main keyboard and numpad)
558 case 0x30: case DOM_VK_NUMPAD0: return kVK_0;
559 case 0x31: case DOM_VK_NUMPAD1: return kVK_1;
560 case 0x32: case DOM_VK_NUMPAD2: return kVK_2;
561 case 0x33: case DOM_VK_NUMPAD3: return kVK_3;
562 case 0x34: case DOM_VK_NUMPAD4: return kVK_4;
563 case 0x35: case DOM_VK_NUMPAD5: return kVK_5;
564 case 0x36: case DOM_VK_NUMPAD6: return kVK_6;
565 case 0x37: case DOM_VK_NUMPAD7: return kVK_7;
566 case 0x38: case DOM_VK_NUMPAD8: return kVK_8;
567 case 0x39: case DOM_VK_NUMPAD9: return kVK_9;
568
569 // Letters
570 case 0x41: return kVK_A;
571 case 0x42: return kVK_B;
572 case 0x43: return kVK_C;
573 case 0x44: return kVK_D;
574 case 0x45: return kVK_E;
575 case 0x46: return kVK_F;
576 case 0x47: return kVK_G;
577 case 0x48: return kVK_H;
578 case 0x49: return kVK_I;
579 case 0x4A: return kVK_J;
580 case 0x4B: return kVK_K;
581 case 0x4C: return kVK_L;
582 case 0x4D: return kVK_M;
583 case 0x4E: return kVK_N;
584 case 0x4F: return kVK_O;
585 case 0x50: return kVK_P;
586 case 0x51: return kVK_Q;
587 case 0x52: return kVK_R;
588 case 0x53: return kVK_S;
589 case 0x54: return kVK_T;
590 case 0x55: return kVK_U;
591 case 0x56: return kVK_V;
592 case 0x57: return kVK_W;
593 case 0x58: return kVK_X;
594 case 0x59: return kVK_Y;
595 case 0x5A: return kVK_Z;
596
597 // Function keys
598 case DOM_VK_F1: return kVK_F1;
599 case DOM_VK_F2: return kVK_F2;
600 case DOM_VK_F3: return kVK_F3;
601 case DOM_VK_F4: return kVK_F4;
602 case DOM_VK_F5: return kVK_F5;
603 case DOM_VK_F6: return kVK_F6;
604 case DOM_VK_F7: return kVK_F7;
605 case DOM_VK_F8: return kVK_F8;
606 case DOM_VK_F9: return kVK_F9;
607 case DOM_VK_F10: return kVK_F10;
608 case DOM_VK_F11: return kVK_F11;
609 case DOM_VK_F12: return kVK_F12;
610
611 default: return 0; // No mapping available
612 }
613}
614
615END_IPLUG_NAMESPACE
616
IPlug Constant definitions, Types, magic numbers.
Include to get consistently named preprocessor macros for different platforms and logging functionali...
static const double IAMP_DB
Magic number for dB to gain conversion.
static const double AMP_DB
Magic number for gain to dB conversion.
EHost
Host identifier.
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.
T Lerp(T a, T b, T f)
Linear interpolate between values a and b.
static void MidiNoteName(double midiPitch, WDL_String &noteName, bool cents=false, bool middleCisC4=false)
Converts a MIDI pitch number to a human-readable note name.
static double AmpToDB(double amp)
static int GetDecimalVersion(int versionInteger)
Helper function to get the version number as a decimal integer.
static std::string UTF16ToUTF8String(const std::u16string &u16str)
Convert UTF-16 std::u16string to UTF-8 std::string using WDL functions.
static std::u16string UTF8ToUTF16String(const char *utf8)
Convert UTF-8 string to UTF-16 std::u16string using WDL functions.
int DOMKeyToVirtualKey(uint32_t domKeyCode)
Converts a DOM virtual key code to an iPlug2 virtual key code.
static void GetHostNameStr(EHost host, WDL_String &str)
Gets a human-readable name from host identifier.
void CastCopy(DEST *pDest, SRC *pSrc, int n)
Helper function to loop through a buffer of samples copying and casting from e.g float to double.
static void GetVersionParts(int versionInteger, int &maj, int &min, int &pat)
Helper function to unpack the version number parts as individual integers.
static void ToLower(char *cDest, const char *cSrc)
Converts a C string to lowercase.
static void GetVersionStr(int versionInteger, WDL_String &str)
Helper function to get the semantic version number as a string from an integer.
static double DBToAmp(double dB)
Calculates gain from a given dB value.
static EHost LookUpHost(const char *inHost)
Gets the host ID from a human-readable name.