melder_debug.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /* melder_debug.cpp
  2. *
  3. * Copyright (C) 2000-2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "melder.h"
  19. #ifdef linux
  20. #include "../sys/GuiP.h"
  21. #endif
  22. #include <time.h>
  23. #include "../sys/praat_version.h"
  24. #ifdef _WIN32
  25. #include "../kar/UnicodeData.h"
  26. #include <windows.h>
  27. #endif
  28. int Melder_debug = 0;
  29. /*
  30. Melder_debug will always be set to 0 when Praat starts up.
  31. If Melder_debug is temporarily set to the following values
  32. (preferably with the "Debug..." command under Praat->Technical,
  33. which you can use from a script),
  34. the behaviour of Praat will temporarily change in the following ways:
  35. 1: Windows: use C-clock instead of multimedia-clock in melder_audio.cpp.
  36. 2: Windows: always reset waveOut, even when played to end, in melder_audio.cpp.
  37. 3: Windows: reset waveOut if unprepareHeader fails, and retry, in melder_audio.cpp. STAY: 20010214
  38. 4: Windows: fewer callbacks during sound play, in melder_audio.cpp. STAY: 20010214
  39. 6: Windows: info on metafile properties in Picture.cpp.
  40. 8: Windows: don't reset waveIn, in SoundRecorder.cpp.
  41. 9: flush Error in FunctionEditor_Sound_draw
  42. 10: geometric pens
  43. 11: clicked item in option menu in Ui.cpp
  44. 14: switches off the progress window in melder.cpp
  45. 15: don't use TrueType IPA fonts, but always bitmaps instead
  46. 16: Linux: open /dev/dsp without O_NDELAY
  47. 17: debugging on in Formula.cpp
  48. 18: no endian assumptions in abcio.cpp
  49. 19: show path name in UiOutfile_do
  50. 20: trace PortAudio
  51. 21: Mac: list supported document formats when printing
  52. 22: UTF-8 tests in logo
  53. 23: recognize special chunks in WAV files
  54. 24: measure buttons in drawing area
  55. 25: read crooked Manipulation files (January 2008)
  56. 26: force OT-GLA
  57. 27: force HG-GLA
  58. 28: don't use GSL in NUMfisherQ
  59. 29: use GSL in NUMinvFisherQ
  60. 30: pitch path finder: use octave jump cost across voiceless parts
  61. 31: Pitch analysis: formant pulling on
  62. 32: show info on file names in ExperimentMFC
  63. 33: trace the Pitch path finder
  64. 34: trace memory allocation and deallocation
  65. 35: debugging on for QuickTime movie file opening
  66. 37: debug autoThing
  67. 38: debug autoNUMvector
  68. 39: debug autostring
  69. 40: debug Thing_new
  70. 41: OTGrammar_getWinner: always first choice rather than random choice
  71. 42: OTGrammar_getWinner: always last choice rather than random choice
  72. 43: trace class table initialization
  73. 44: trace Collection
  74. 45: tracing structMatrix :: read ()
  75. 46: trace GTK parent sizes in _GuiObject_position ()
  76. 47: force resampling in OTGrammar RIP
  77. 48: compute sum, mean, stdev with naive implementation in double (64 bits)
  78. 49: compute sum, mean, stdev with naive implementation in longdouble (80 bits)
  79. 50: compute sum, mean, stdev with first-element offset (80 bits)
  80. 51: compute sum, mean, stdev with two cycles, as in R (80 bits)
  81. (other numbers than 48-51: compute sum, mean, stdev with simple pairwise algorithm, base case 64 [80 bits])
  82. 181: read and write native-endian real64
  83. 900: use DG Meta Serif Science instead of Palatino
  84. 1264: Mac: Sound_record_fixedTime uses microphone "FW Solo (1264)"
  85. (negative values are for David)
  86. */
  87. /*
  88. * In order to make sure that Melder_casual() and trace() can be called from anywhere,
  89. * including e.g. from Melder_realloc() or Melder_free(),
  90. * they cannot use any Melder_xxx() functions.
  91. */
  92. /*
  93. * peek32to8 substitutes for Melder_peek32to8(),
  94. * which can call Melder_realloc() and Melder_free();
  95. * also, we need no newline nativization, as Melder_32to8_inplace() does.
  96. */
  97. conststring8 MelderTrace::_peek32to8 (conststring32 string) {
  98. if (! string) return "";
  99. static char *buffer { nullptr };
  100. static int64 bufferSize { 0 };
  101. int64 n = str32len (string);
  102. int64 sizeNeeded = n * 4 + 1;
  103. if ((bufferSize - sizeNeeded) * (int64) sizeof (char) >= 10'000) {
  104. free (buffer);
  105. buffer = nullptr; // undangle
  106. bufferSize = 0;
  107. }
  108. if (sizeNeeded > bufferSize) {
  109. sizeNeeded = (int64) floor (sizeNeeded * 1.61803) + 100;
  110. buffer = (char *) realloc (buffer, (size_t) sizeNeeded * sizeof (char));
  111. if (buffer == nullptr) {
  112. bufferSize = 0;
  113. return "(out of memory during tracing)";
  114. }
  115. bufferSize = sizeNeeded;
  116. }
  117. int64 i, j;
  118. for (i = 0, j = 0; i < n; i ++) {
  119. char32 kar = string [i];
  120. if (kar <= 0x00'007F) { // 7 bits
  121. buffer [j ++] = (char) (char8) kar; // guarded truncation
  122. } else if (kar <= 0x00'07FF) { // 11 bits
  123. buffer [j ++] = (char) (char8) (0x00'00C0 | (kar >> 6)); // the upper 5 bits yield a number between 0xC4 and 0xDF
  124. buffer [j ++] = (char) (char8) (0x00'0080 | (kar & 0x00'003F)); // the lower 6 bits yield a number between 0x80 and 0xBF
  125. } else if (kar <= 0x00'FFFF) { // 16 bits
  126. buffer [j ++] = (char) (char8) (0x00'00E0 | (kar >> 12)); // the upper 4 bits yield a number between 0xE0 and 0xEF
  127. buffer [j ++] = (char) (char8) (0x00'0080 | ((kar >> 6) & 0x00'003F));
  128. buffer [j ++] = (char) (char8) (0x00'0080 | (kar & 0x00'003F));
  129. } else { // 21 bits
  130. buffer [j ++] = (char) (char8) (0x00'00F0 | (kar >> 18)); // the upper 3 bits yield a number between 0xF0 and 0xF4 (0x10FFFF >> 18 == 4)
  131. buffer [j ++] = (char) (char8) (0x00'0080 | ((kar >> 12) & 0x00'003F)); // the next 6 bits
  132. buffer [j ++] = (char) (char8) (0x00'0080 | ((kar >> 6) & 0x00'003F)); // the third 6 bits
  133. buffer [j ++] = (char) (char8) (0x00'0080 | (kar & 0x00'003F)); // the lower 6 bits
  134. }
  135. }
  136. buffer [j] = '\0';
  137. return buffer;
  138. }
  139. #ifdef _WIN32
  140. conststring16 MelderTrace::_peek32to16 (conststring32 string) {
  141. if (! string) return u"";
  142. static char16 *buffer { nullptr };
  143. static int64 bufferSize { 0 };
  144. int64 n = str32len (string);
  145. int64 sizeNeeded = n * 2 + 1;
  146. if ((bufferSize - sizeNeeded) * (int64) sizeof (char16) >= 10'000) {
  147. free (buffer);
  148. bufferSize = 0;
  149. }
  150. if (sizeNeeded > bufferSize) {
  151. sizeNeeded = (int64) floor (sizeNeeded * 1.61803) + 100;
  152. buffer = (char16 *) realloc (buffer, (size_t) sizeNeeded * sizeof (char16));
  153. if (! buffer) {
  154. bufferSize = 0;
  155. return u"(out of memory during tracing)";
  156. }
  157. bufferSize = sizeNeeded;
  158. }
  159. int64 i, j;
  160. for (i = 0, j = 0; i < n; i ++) {
  161. char32 kar = string [i];
  162. if (kar <= 0x00'D7FF) { // 16 bits
  163. buffer [j ++] = (char16) kar; // guarded truncation
  164. } else if (kar <= 0x00'DFFF) { // 16 bits
  165. buffer [j ++] = (char16) UNICODE_REPLACEMENT_CHARACTER; // forbidden for UTF-32
  166. } else if (kar <= 0x00'FFFF) { // 16 bits
  167. buffer [j ++] = (char16) kar; // guarded truncation
  168. } else if (kar <= 0x10'FFFF) { // 21 bits
  169. kar -= 0x01'0000;
  170. buffer [j ++] = (char16) (0x00'D800 | (kar >> 10)); // guarded truncation
  171. buffer [j ++] = (char16) (0x00'DC00 | (kar & 0x00'03FF)); // guarded truncation
  172. } else { // 21 bits
  173. buffer [j ++] = (char16) UNICODE_REPLACEMENT_CHARACTER;
  174. }
  175. }
  176. buffer [j] = u'\0';
  177. return buffer;
  178. }
  179. #endif
  180. /********** TRACE **********/
  181. bool Melder_isTracing = false;
  182. structMelderFile MelderTrace::_file { };
  183. void Melder_tracingToFile (MelderFile file) {
  184. MelderFile_copy (file, & MelderTrace::_file);
  185. MelderFile_delete (& MelderTrace::_file);
  186. }
  187. FILE * MelderTrace::_open (conststring8 sourceCodeFileName, int lineNumber, conststring8 functionName) {
  188. FILE *f;
  189. #if defined (_WIN32) && ! defined (__CYGWIN__)
  190. f = _wfopen ((const wchar_t *) MelderTrace::_peek32to16 (MelderTrace::_file. path), L"a");
  191. #else
  192. char utf8path [kMelder_MAXPATH+1];
  193. Melder_str32To8bitFileRepresentation_inplace (MelderTrace::_file. path, utf8path); // this Melder_xxx() function is OK to call
  194. f = fopen ((char *) utf8path, "a");
  195. #endif
  196. if (! f)
  197. f = stderr; // if the file cannot be opened, we can still trace to stderr!
  198. if (sourceCodeFileName) {
  199. const char *slashLocation = strrchr (sourceCodeFileName, Melder_DIRECTORY_SEPARATOR);
  200. fprintf (f, "%s (%s:%d): ", functionName, slashLocation ? slashLocation + 1 : sourceCodeFileName, lineNumber);
  201. } else {
  202. fprintf (f, "%s: ", functionName);
  203. }
  204. return f;
  205. }
  206. void MelderTrace::_close (FILE *f) {
  207. fprintf (f, "\n");
  208. if (f != stderr)
  209. fclose (f);
  210. }
  211. #if defined (linux) && ! defined (NO_GUI)
  212. static void theGtkLogHandler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data) {
  213. FILE *f = MelderTrace::_open (nullptr, 0, "GTK");
  214. fprintf (f, "%s", message);
  215. MelderTrace::_close (f);
  216. }
  217. static void theGlibLogHandler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data) {
  218. FILE *f = MelderTrace::_open (nullptr, 0, "GLib");
  219. fprintf (f, "%s", message);
  220. MelderTrace::_close (f);
  221. }
  222. static void theGlibGobjectLogHandler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data) {
  223. FILE *f = MelderTrace::_open (nullptr, 0, "GLib-GObject");
  224. fprintf (f, "%s", message);
  225. MelderTrace::_close (f);
  226. }
  227. #endif
  228. void Melder_setTracing (bool tracing) {
  229. time_t today = time (nullptr);
  230. #define xstr(s) str(s)
  231. #define str(s) #s
  232. if (! tracing)
  233. trace (U"switch tracing off"
  234. U" in Praat version ", Melder_peek8to32 (xstr (PRAAT_VERSION_STR)),
  235. U" at ", Melder_peek8to32 (ctime (& today))
  236. );
  237. Melder_isTracing = tracing;
  238. #if defined (linux) && ! defined (NO_GUI)
  239. static guint handler_id1, handler_id2, handler_id3;
  240. if (tracing) {
  241. handler_id1 = g_log_set_handler ("Gtk", (GLogLevelFlags) (G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), theGtkLogHandler, nullptr);
  242. handler_id2 = g_log_set_handler ("GLib", (GLogLevelFlags) (G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), theGlibLogHandler, nullptr);
  243. handler_id3 = g_log_set_handler ("GLib-GObject", (GLogLevelFlags) (G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), theGlibGobjectLogHandler, nullptr);
  244. } else {
  245. if (handler_id1) g_log_remove_handler ("Gtk", handler_id1);
  246. if (handler_id2) g_log_remove_handler ("GLib", handler_id2);
  247. if (handler_id3) g_log_remove_handler ("GLib-GObject", handler_id3);
  248. handler_id1 = handler_id2 = handler_id3 = 0;
  249. }
  250. #endif
  251. if (tracing)
  252. trace (U"switch tracing on"
  253. U" in Praat version ", Melder_peek8to32 (xstr (PRAAT_VERSION_STR)),
  254. U" at ", Melder_peek8to32 (ctime (& today))
  255. );
  256. }
  257. /* End of file melder_debug.cpp */