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