iPlug2 - C++ Audio Plug-in Framework
IPlugLogger.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 
22 #include <cstdio>
23 #include <cctype>
24 #include <cstdarg>
25 #include <cstdint>
26 #include <cstring>
27 #include <ctime>
28 #include <cassert>
29 
30 #include "wdlstring.h"
31 #include "mutex.h"
32 
33 #include "IPlugConstants.h"
34 #include "IPlugUtilities.h"
35 
36 BEGIN_IPLUG_NAMESPACE
37 
38 #ifdef NDEBUG
39  #define DBGMSG(...) do {} while(0)// should be optimized away
40 #else
41  #if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_WEB) || defined(OS_IOS)
42  #define DBGMSG(...) printf(__VA_ARGS__)
43  #elif defined OS_WIN
44  #ifdef OutputDebugString
45  #undef OutputDebugString
46  #define OutputDebugString OutputDebugStringA
47  #endif
48 
49  static void DBGMSG(const char* format, ...)
50  {
51  char buf[4096], * p = buf;
52  va_list args;
53  int n;
54 
55  va_start(args, format);
56  n = _vsnprintf(p, sizeof buf - 3, format, args); // buf-3 is room for CR/LF/NUL
57  va_end(args);
58 
59  p += (n < 0) ? sizeof buf - 3 : n;
60 
61  while (p > buf&& isspace(p[-1]))
62  *--p = '\0';
63 
64  *p++ = '\r';
65  *p++ = '\n';
66  *p = '\0';
67 
68  OutputDebugString(buf);
69  }
70  #endif
71 #endif
72 
73 #if defined TRACER_BUILD
74  #define TRACE Trace(TRACELOC, "");
75 
76  #if defined OS_WIN
77  #define SYS_THREAD_ID (intptr_t) GetCurrentThreadId()
78  #elif defined(OS_MAC) || defined(OS_LINUX) || defined(OS_WEB)
79  #define SYS_THREAD_ID (intptr_t) pthread_self()
80  #endif
81 
82  #else
83  #define TRACE
84  #endif
85 
86  #define TRACELOC __FUNCTION__,__LINE__
87  static void Trace(const char* funcName, int line, const char* fmtStr, ...);
88 
89  #define APPEND_TIMESTAMP(str) AppendTimestamp(__DATE__, __TIME__, str)
90 
91  struct LogFile
92  {
93  FILE* mFP;
94 
95  LogFile()
96  {
97  char logFilePath[100];
98  #ifdef OS_WIN
99  sprintf(logFilePath, "%s/%s", "C:\\", LOGFILE); // TODO: check windows logFilePath
100  #else
101  sprintf(logFilePath, "%s/%s", getenv("HOME"), LOGFILE);
102  #endif
103  mFP = fopen(logFilePath, "w");
104  assert(mFP);
105 
106  DBGMSG("Logging to %s\n", logFilePath);
107  }
108 
109  ~LogFile()
110  {
111  fclose(mFP);
112  mFP = nullptr;
113  }
114 
115  LogFile(const LogFile&) = delete;
116  LogFile& operator=(const LogFile&) = delete;
117  };
118 
119  static bool IsWhitespace(char c)
120  {
121  return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
122  }
123 
124  static const char* CurrentTime()
125  {
126  // TODO: replace with std::chrono based version
127  time_t t = time(0);
128  tm* pT = localtime(&t);
129 
130  char cStr[32];
131  strftime(cStr, 32, "%Y%m%d %H:%M ", pT);
132 
133  int tz = 60 * pT->tm_hour + pT->tm_min;
134  int yday = pT->tm_yday;
135  pT = gmtime(&t);
136  tz -= 60 * pT->tm_hour + pT->tm_min;
137  yday -= pT->tm_yday;
138  if (yday != 0)
139  {
140  if (yday > 1) yday = -1;
141  else if (yday < -1) yday = 1;
142  tz += 24 * 60 * yday;
143  }
144  int i = (int) strlen(cStr);
145  cStr[i++] = tz >= 0 ? '+' : '-';
146  if (tz < 0) tz = -tz;
147  sprintf(&cStr[i], "%02d%02d", tz / 60, tz % 60);
148 
149  static char sTimeStr[32];
150  strcpy(sTimeStr, cStr);
151  return sTimeStr;
152  }
153 
154  static const char* AppendTimestamp(const char* Mmm_dd_yyyy, const char* hh_mm_ss, const char* cStr)
155  {
156  static WDL_String str;
157  str.Set(cStr);
158  str.Append(" ");
159  WDL_String tStr;
160  tStr.Set("[");
161  tStr.Append(Mmm_dd_yyyy);
162  tStr.SetLen(7);
163  tStr.DeleteSub(4, 1);
164  tStr.Append(" ");
165  tStr.Append(hh_mm_ss);
166  tStr.SetLen(12);
167  tStr.Append("]");
168  str.Append(tStr.Get());
169  return str.Get();
170  }
171 
172  #if defined TRACER_BUILD
173 
174  const int TXTLEN = 1024;
175 
176  // _vsnsprintf
177 
178  #define VARARGS_TO_STR(str) { \
179  try { \
180  va_list argList; \
181  va_start(argList, format); \
182  int i = vsnprintf(str, TXTLEN-2, format, argList); \
183  if (i < 0 || i > TXTLEN-2) { \
184  str[TXTLEN-1] = '\0'; \
185  } \
186  va_end(argList); \
187  } \
188  catch(...) { \
189  strcpy(str, "parse error"); \
190  } \
191  strcat(str, "\r\n"); \
192  }
193 
194  static intptr_t GetOrdinalThreadID(intptr_t sysThreadID)
195  {
196  static WDL_TypedBuf<intptr_t> sThreadIDs;
197  int i, n = sThreadIDs.GetSize();
198  intptr_t* pThreadID = sThreadIDs.Get();
199  for (i = 0; i < n; ++i, ++pThreadID)
200  {
201  if (sysThreadID == *pThreadID)
202  {
203  return i;
204  }
205  }
206  sThreadIDs.Resize(n + 1);
207  *(sThreadIDs.Get() + n) = sysThreadID;
208  return n;
209  }
210 
211  #define MAX_LOG_LINES 16384
212  void Trace(const char* funcName, int line, const char* format, ...)
213  {
214  static int sTrace = 0;
215  static int32_t sProcessCount = 0;
216  static int32_t sIdleCount = 0;
217 
218  if (sTrace++ < MAX_LOG_LINES)
219  {
220  #ifndef TRACETOSTDOUT
221  static LogFile sLogFile;
222  assert(sLogFile.mFP);
223  #endif
224  static WDL_Mutex sLogMutex;
225  char str[TXTLEN];
226  VARARGS_TO_STR(str);
227 
228  #ifdef TRACETOSTDOUT
229  DBGMSG("[%ld:%s:%d]%s", GetOrdinalThreadID(SYS_THREAD_ID), funcName, line, str);
230  #else
231  WDL_MutexLock lock(&sLogMutex);
232  intptr_t threadID = GetOrdinalThreadID(SYS_THREAD_ID);
233 
234  if(strstr(funcName, "rocess") || strstr(funcName, "ender")) // These are not typos! by excluding the first character, we can use TRACE in methods called ProcessXXX or process etc.
235  {
236  if(++sProcessCount > MAX_PROCESS_TRACE_COUNT)
237  {
238  fflush(sLogFile.mFP);
239  return;
240  }
241  else if (sProcessCount == MAX_PROCESS_TRACE_COUNT)
242  {
243  fprintf(sLogFile.mFP, "**************** DISABLING PROCESS TRACING AFTER %d HITS ****************\n\n", sProcessCount);
244  fflush(sLogFile.mFP);
245  return;
246  }
247  }
248 
249 #ifdef VST2_API
250  if(strstr(str, "effGetProgram") || strstr(str, "effEditGetRect") || strstr(funcName, "MouseOver"))
251 #else
252  if(strstr(funcName, "MouseOver") || strstr(funcName, "idle"))
253 #endif
254  {
255  if(++sIdleCount > MAX_IDLE_TRACE_COUNT)
256  {
257  fflush(sLogFile.mFP);
258  return;
259  }
260  else if (sIdleCount == MAX_IDLE_TRACE_COUNT)
261  {
262  fprintf(sLogFile.mFP, "**************** DISABLING IDLE/MOUSEOVER TRACING AFTER %d HITS ****************\n", sIdleCount);
263  fflush(sLogFile.mFP);
264  return;
265  }
266  }
267 
268  if (threadID > 0)
269  fprintf(sLogFile.mFP, "*** -");
270 
271  fprintf(sLogFile.mFP, "[%ld:%s:%d]%s", threadID, funcName, line, str);
272  fflush(sLogFile.mFP);
273  #endif
274  }
275  }
276 
277  #ifdef VST2_API
278  #include "aeffectx.h"
279  static const char* VSTOpcodeStr(int opCode)
280  {
281  switch (opCode)
282  {
283  case effOpen:
284  return "effOpen";
285  case effClose:
286  return "effClose";
287  case effSetProgram:
288  return "effSetProgram";
289  case effGetProgram:
290  return "effGetProgram";
291  case effSetProgramName:
292  return "effSetProgramName";
293  case effGetProgramName:
294  return "effGetProgramName";
295  case effGetParamLabel:
296  return "effGetParamLabel";
297  case effGetParamDisplay:
298  return "effGetParamDisplay";
299  case effGetParamName:
300  return "effGetParamName";
301  case __effGetVuDeprecated:
302  return "__effGetVuDeprecated";
303  case effSetSampleRate:
304  return "effSetSampleRate";
305  case effSetBlockSize:
306  return "effSetBlockSize";
307  case effMainsChanged:
308  return "effMainsChanged";
309  case effEditGetRect:
310  return "effEditGetRect";
311  case effEditOpen:
312  return "effEditOpen";
313  case effEditClose:
314  return "effEditClose";
315  case __effEditDrawDeprecated:
316  return "__effEditDrawDeprecated";
317  case __effEditMouseDeprecated:
318  return "__effEditMouseDeprecated";
319  case __effEditKeyDeprecated:
320  return "__effEditKeyDeprecated";
321  case effEditIdle:
322  return "effEditIdle";
323  case __effEditTopDeprecated:
324  return "__effEditTopDeprecated";
325  case __effEditSleepDeprecated:
326  return "__effEditSleepDeprecated";
327  case __effIdentifyDeprecated:
328  return "__effIdentifyDeprecated";
329  case effGetChunk:
330  return "effGetChunk";
331  case effSetChunk:
332  return "effSetChunk";
333  case effProcessEvents:
334  return "effProcessEvents";
335  case effCanBeAutomated:
336  return "effCanBeAutomated";
337  case effString2Parameter:
338  return "effString2Parameter";
339  case __effGetNumProgramCategoriesDeprecated:
340  return "__effGetNumProgramCategoriesDeprecated";
341  case effGetProgramNameIndexed:
342  return "effGetProgramNameIndexed";
343  case __effCopyProgramDeprecated:
344  return "__effCopyProgramDeprecated";
345  case __effConnectInputDeprecated:
346  return "__effConnectInputDeprecated";
347  case __effConnectOutputDeprecated:
348  return "__effConnectOutputDeprecated";
349  case effGetInputProperties:
350  return "effGetInputProperties";
351  case effGetOutputProperties:
352  return "effGetOutputProperties";
353  case effGetPlugCategory:
354  return "effGetPlugCategory";
355  case __effGetCurrentPositionDeprecated:
356  return "__effGetCurrentPositionDeprecated";
357  case __effGetDestinationBufferDeprecated:
358  return "__effGetDestinationBufferDeprecated";
359  case effOfflineNotify:
360  return "effOfflineNotify";
361  case effOfflinePrepare:
362  return "effOfflinePrepare";
363  case effOfflineRun:
364  return "effOfflineRun";
365  case effProcessVarIo:
366  return "effProcessVarIo";
367  case effSetSpeakerArrangement:
368  return "effSetSpeakerArrangement";
369  case __effSetBlockSizeAndSampleRateDeprecated:
370  return "__effSetBlockSizeAndSampleRateDeprecated";
371  case effSetBypass:
372  return "effSetBypass";
373  case effGetEffectName:
374  return "effGetEffectName";
375  case __effGetErrorTextDeprecated:
376  return "__effGetErrorTextDeprecated";
377  case effGetVendorString:
378  return "effGetVendorString";
379  case effGetProductString:
380  return "effGetProductString";
381  case effGetVendorVersion:
382  return "effGetVendorVersion";
383  case effVendorSpecific:
384  return "effVendorSpecific";
385  case effCanDo:
386  return "effCanDo";
387  case effGetTailSize:
388  return "effGetTailSize";
389  case __effIdleDeprecated:
390  return "__effIdleDeprecated";
391  case __effGetIconDeprecated:
392  return "__effGetIconDeprecated";
393  case __effSetViewPositionDeprecated:
394  return "__effSetViewPositionDeprecated";
395  case effGetParameterProperties:
396  return "effGetParameterProperties";
397  case __effKeysRequiredDeprecated:
398  return "__effKeysRequiredDeprecated";
399  case effGetVstVersion:
400  return "effGetVstVersion";
401  case effEditKeyDown:
402  return "effEditKeyDown";
403  case effEditKeyUp:
404  return "effEditKeyUp";
405  case effSetEditKnobMode:
406  return "effSetEditKnobMode";
407  case effGetMidiProgramName:
408  return "effGetMidiProgramName";
409  case effGetCurrentMidiProgram:
410  return "effGetCurrentMidiProgram";
411  case effGetMidiProgramCategory:
412  return "effGetMidiProgramCategory";
413  case effHasMidiProgramsChanged:
414  return "effHasMidiProgramsChanged";
415  case effGetMidiKeyName:
416  return "effGetMidiKeyName";
417  case effBeginSetProgram:
418  return "effBeginSetProgram";
419  case effEndSetProgram:
420  return "effEndSetProgram";
421  case effGetSpeakerArrangement:
422  return "effGetSpeakerArrangement";
423  case effShellGetNextPlugin:
424  return "effShellGetNextPlugin";
425  case effStartProcess:
426  return "effStartProcess";
427  case effStopProcess:
428  return "effStopProcess";
429  case effSetTotalSampleToProcess:
430  return "effSetTotalSampleToProcess";
431  case effSetPanLaw:
432  return "effSetPanLaw";
433  case effBeginLoadBank:
434  return "effBeginLoadBank";
435  case effBeginLoadProgram:
436  return "effBeginLoadProgram";
437  case effSetProcessPrecision:
438  return "effSetProcessPrecision";
439  case effGetNumMidiInputChannels:
440  return "effGetNumMidiInputChannels";
441  case effGetNumMidiOutputChannels:
442  return "effGetNumMidiOutputChannels";
443  default:
444  return "unknown";
445  }
446  }
447  #endif
448 
449  #if defined AU_API
450  #include <AudioUnit/AudioUnitProperties.h>
451  #include <CoreServices/CoreServices.h>
452  static const char* AUSelectStr(int select)
453  {
454  switch (select)
455  {
456  case kComponentOpenSelect:
457  return "kComponentOpenSelect";
458  case kComponentCloseSelect:
459  return "kComponentCloseSelect";
460  case kComponentVersionSelect:
461  return "kComponentVersionSelect";
462  case kAudioUnitInitializeSelect:
463  return "kAudioUnitInitializeSelect";
464  case kAudioUnitUninitializeSelect:
465  return "kAudioUnitUninitializeSelect";
466  case kAudioUnitGetPropertyInfoSelect:
467  return "kAudioUnitGetPropertyInfoSelect";
468  case kAudioUnitGetPropertySelect:
469  return "kAudioUnitGetPropertySelect";
470  case kAudioUnitSetPropertySelect:
471  return "kAudioUnitSetPropertySelect";
472  case kAudioUnitAddPropertyListenerSelect:
473  return "kAudioUnitAddPropertyListenerSelect";
474  case kAudioUnitRemovePropertyListenerSelect:
475  return "kAudioUnitRemovePropertyListenerSelect";
476  case kAudioUnitAddRenderNotifySelect:
477  return "kAudioUnitAddRenderNotifySelect";
478  case kAudioUnitRemoveRenderNotifySelect:
479  return "kAudioUnitRemoveRenderNotifySelect";
480  case kAudioUnitGetParameterSelect:
481  return "kAudioUnitGetParameterSelect";
482  case kAudioUnitSetParameterSelect:
483  return "kAudioUnitSetParameterSelect";
484  case kAudioUnitScheduleParametersSelect:
485  return "kAudioUnitScheduleParametersSelect";
486  case kAudioUnitRenderSelect:
487  return "kAudioUnitRenderSelect";
488  case kAudioUnitResetSelect:
489  return "kAudioUnitResetSelect";
490  case kComponentCanDoSelect:
491  return "kComponentCanDoSelect";
492  case kAudioUnitComplexRenderSelect:
493  return "kAudioUnitComplexRenderSelect";
494  case kAudioUnitProcessSelect:
495  return "kAudioUnitProcessSelect";
496  case kAudioUnitProcessMultipleSelect:
497  return "kAudioUnitProcessMultipleSelect";
498  case kAudioUnitRange:
499  return "kAudioUnitRange";
500  case kAudioUnitRemovePropertyListenerWithUserDataSelect:
501  return "kAudioUnitRemovePropertyListenerWithUserDataSelect";
502  default:
503  return "unknown";
504  }
505  }
506 
507  static const char* AUPropertyStr(int propID)
508  {
509  switch (propID)
510  {
511  case kAudioUnitProperty_ClassInfo:
512  return "kAudioUnitProperty_ClassInfo";
513  case kAudioUnitProperty_MakeConnection:
514  return "kAudioUnitProperty_MakeConnection";
515  case kAudioUnitProperty_SampleRate:
516  return "kAudioUnitProperty_SampleRate";
517  case kAudioUnitProperty_ParameterList:
518  return "kAudioUnitProperty_ParameterList";
519  case kAudioUnitProperty_ParameterInfo:
520  return "kAudioUnitProperty_ParameterInfo";
521  case kAudioUnitProperty_FastDispatch:
522  return "kAudioUnitProperty_FastDispatch";
523  case kAudioUnitProperty_CPULoad:
524  return "kAudioUnitProperty_CPULoad";
525  case kAudioUnitProperty_StreamFormat:
526  return "kAudioUnitProperty_StreamFormat";
527  case kAudioUnitProperty_ElementCount:
528  return "kAudioUnitProperty_ElementCount";
529  case kAudioUnitProperty_Latency:
530  return "kAudioUnitProperty_Latency";
531  case kAudioUnitProperty_SupportedNumChannels:
532  return "kAudioUnitProperty_SupportedNumChannels";
533  case kAudioUnitProperty_MaximumFramesPerSlice:
534  return "kAudioUnitProperty_MaximumFramesPerSlice";
535  case kAudioUnitProperty_SetExternalBuffer:
536  return "kAudioUnitProperty_SetExternalBuffer";
537  case kAudioUnitProperty_ParameterValueStrings:
538  return "kAudioUnitProperty_ParameterValueStrings";
539  case kAudioUnitProperty_GetUIComponentList:
540  return "kAudioUnitProperty_GetUIComponentList";
541  case kAudioUnitProperty_AudioChannelLayout:
542  return "kAudioUnitProperty_AudioChannelLayout";
543  case kAudioUnitProperty_TailTime:
544  return "kAudioUnitProperty_TailTime";
545  case kAudioUnitProperty_BypassEffect:
546  return "kAudioUnitProperty_BypassEffect";
547  case kAudioUnitProperty_LastRenderError:
548  return "kAudioUnitProperty_LastRenderError";
549  case kAudioUnitProperty_SetRenderCallback:
550  return "kAudioUnitProperty_SetRenderCallback";
551  case kAudioUnitProperty_FactoryPresets:
552  return "kAudioUnitProperty_FactoryPresets";
553  case kAudioUnitProperty_ContextName:
554  return "kAudioUnitProperty_ContextName";
555  case kAudioUnitProperty_RenderQuality:
556  return "kAudioUnitProperty_RenderQuality";
557  case kAudioUnitProperty_HostCallbacks:
558  return "kAudioUnitProperty_HostCallbacks";
559  case kAudioUnitProperty_CurrentPreset:
560  return "kAudioUnitProperty_CurrentPreset";
561  case kAudioUnitProperty_InPlaceProcessing:
562  return "kAudioUnitProperty_InPlaceProcessing";
563  case kAudioUnitProperty_ElementName:
564  return "kAudioUnitProperty_ElementName";
565  case kAudioUnitProperty_CocoaUI:
566  return "kAudioUnitProperty_CocoaUI";
567  case kAudioUnitProperty_SupportedChannelLayoutTags:
568  return "kAudioUnitProperty_SupportedChannelLayoutTags";
569  case kAudioUnitProperty_ParameterIDName:
570  return "kAudioUnitProperty_ParameterIDName";
571  case kAudioUnitProperty_ParameterClumpName:
572  return "kAudioUnitProperty_ParameterClumpName";
573  case kAudioUnitProperty_PresentPreset:
574  return "kAudioUnitProperty_PresentPreset";
575  case kAudioUnitProperty_OfflineRender:
576  return "kAudioUnitProperty_OfflineRender";
577  case kAudioUnitProperty_ParameterStringFromValue:
578  return "kAudioUnitProperty_ParameterStringFromValue";
579  case kAudioUnitProperty_ParameterValueFromString:
580  return "kAudioUnitProperty_ParameterValueFromString";
581  case kAudioUnitProperty_IconLocation:
582  return "kAudioUnitProperty_IconLocation";
583  case kAudioUnitProperty_PresentationLatency:
584  return "kAudioUnitProperty_PresentationLatency";
585  case kAudioUnitProperty_DependentParameters:
586  return "kAudioUnitProperty_DependentParameters";
587  case kAudioUnitProperty_AUHostIdentifier:
588  return "kAudioUnitProperty_AUHostIdentifier";
589  case kAudioUnitProperty_MIDIOutputCallbackInfo:
590  return "kAudioUnitProperty_MIDIOutputCallbackInfo";
591  case kAudioUnitProperty_MIDIOutputCallback:
592  return "kAudioUnitProperty_MIDIOutputCallback";
593  case kAudioUnitProperty_InputSamplesInOutput:
594  return "kAudioUnitProperty_InputSamplesInOutput";
595  case kAudioUnitProperty_ClassInfoFromDocument:
596  return "kAudioUnitProperty_ClassInfoFromDocument";
597  #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1010
598  case kAudioUnitProperty_ShouldAllocateBuffer:
599  return "kAudioUnitProperty_ShouldAllocateBuffer";
600  case kAudioUnitProperty_FrequencyResponse:
601  return "kAudioUnitProperty_FrequencyResponse";
602  case kAudioUnitProperty_ParameterHistoryInfo:
603  return "kAudioUnitProperty_FrequencyResponse";
604  case kAudioUnitProperty_NickName:
605  return "kAudioUnitProperty_NickName";
606  #endif
607  #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1011
608  case kAudioUnitProperty_RequestViewController:
609  return "kAudioUnitProperty_RequestViewController";
610  case kAudioUnitProperty_ParametersForOverview:
611  return "kAudioUnitProperty_ParametersForOverview";
612  case kAudioUnitProperty_SupportsMPE:
613  return "kAudioUnitProperty_SupportsMPE";
614  #endif
615  default:
616  return "unknown";
617  }
618  }
619 
620  static const char* AUScopeStr(int scope)
621  {
622  switch (scope)
623  {
624  case kAudioUnitScope_Global:
625  return "kAudioUnitScope_Global";
626  case kAudioUnitScope_Input:
627  return "kAudioUnitScope_Input";
628  case kAudioUnitScope_Output:
629  return "kAudioUnitScope_Output";
630  case kAudioUnitScope_Group:
631  return "kAudioUnitScope_Group";
632  case kAudioUnitScope_Part:
633  return "kAudioUnitScope_Part";
634  case kAudioUnitScope_Note:
635  return "kAudioUnitScope_Note";
636  default:
637  return "unknown";
638  }
639  }
640  #endif // AU_API
641 
642 #else // TRACER_BUILD
643  static void Trace(const char* funcName, int line, const char* format, ...) {}
644 static const char* VSTOpcodeStr(int opCode) { return ""; }
645  static const char* AUSelectStr(int select) { return ""; }
646  static const char* AUPropertyStr(int propID) { return ""; }
647  static const char* AUScopeStr(int scope) { return ""; }
648 #endif // !TRACER_BUILD
649 
650 END_IPLUG_NAMESPACE
Utility functions and macros.
IPlug Constant definitions, Types, magic numbers.