Spectrogram_extensions.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. /* Spectrogram_extensions.cpp
  2. *
  3. * Copyright (C) 2014-2017 David Weenink
  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. See the GNU
  13. * 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. /*
  19. djmw 20140913
  20. */
  21. #include "Eigen_and_Matrix.h"
  22. #include "Spectrogram_extensions.h"
  23. #include "Matrix_extensions.h"
  24. #include "NUM2.h"
  25. Thing_implement (BandFilterSpectrogram, Matrix, 2);
  26. void structBandFilterSpectrogram :: v_info () {
  27. structDaata :: v_info ();
  28. MelderInfo_writeLine (U"Time domain:");
  29. MelderInfo_writeLine (U" Start time: ", xmin, U" seconds");
  30. MelderInfo_writeLine (U" End time: ", xmax, U" seconds");
  31. MelderInfo_writeLine (U" Total duration: ", xmax - xmin, U" seconds");
  32. MelderInfo_writeLine (U"Time sampling:");
  33. MelderInfo_writeLine (U" Number of time slices (frames): ", nx);
  34. MelderInfo_writeLine (U" Time step (frame distance): ", dx, U" seconds");
  35. MelderInfo_writeLine (U" First time slice (frame centre) at: ", x1, U" seconds");
  36. }
  37. void structBarkSpectrogram :: v_info () {
  38. structBandFilterSpectrogram :: v_info ();
  39. MelderInfo_writeLine (U"Frequency domain:");
  40. MelderInfo_writeLine (U" Lowest frequency: ", ymin, U" ", v_getFrequencyUnit ());
  41. MelderInfo_writeLine (U" Highest frequency: ", ymax, U" ", v_getFrequencyUnit ());
  42. MelderInfo_writeLine (U" Total bandwidth: ", ymax - ymin, U" ", v_getFrequencyUnit ());
  43. MelderInfo_writeLine (U"Frequency sampling:");
  44. MelderInfo_writeLine (U" Number of frequency bands (bins): ", ny);
  45. MelderInfo_writeLine (U" Frequency step (bin width): ", dy, U" ", v_getFrequencyUnit ());
  46. MelderInfo_writeLine (U" First frequency band around (bin centre at): ", y1, U" ", v_getFrequencyUnit ());
  47. }
  48. void structMelSpectrogram :: v_info () {
  49. structBandFilterSpectrogram :: v_info ();
  50. MelderInfo_writeLine (U"Frequency domain:");
  51. MelderInfo_writeLine (U" Lowest frequency: ", ymin, U" ", v_getFrequencyUnit ());
  52. MelderInfo_writeLine (U" Highest frequency: ", ymax, U" ", v_getFrequencyUnit ());
  53. MelderInfo_writeLine (U" Total bandwidth: ", ymax - ymin, U" ", v_getFrequencyUnit ());
  54. MelderInfo_writeLine (U"Frequency sampling:");
  55. MelderInfo_writeLine (U" Number of frequency bands (bins): ", ny);
  56. MelderInfo_writeLine (U" Frequency step (bin width): ", dy, U" ", v_getFrequencyUnit ());
  57. MelderInfo_writeLine (U" First frequency band around (bin centre at): ", y1, U" ", v_getFrequencyUnit ());
  58. }
  59. // Preconditions: 1 <= iframe <= nx; 1 <= irow <= ny
  60. double structBandFilterSpectrogram :: v_getValueAtSample (integer iframe, integer ifreq, int units) {
  61. double val = undefined;
  62. if (units == 0) {
  63. val = z [ifreq] [iframe];
  64. } else {
  65. val = -300.0; // minimum dB value
  66. if (z [ifreq] [iframe] > 0.0)
  67. val = 10.0 * log10 (z [ifreq] [iframe] / 4e-10); // power values
  68. }
  69. return val;
  70. }
  71. Thing_implement (BarkSpectrogram, BandFilterSpectrogram, 1);
  72. // dbs = scaleFactor * log10 (value/reference);
  73. // if (dbs < floor_db) { dbs = floor_dB }
  74. autoMatrix Spectrogram_to_Matrix_dB (Spectrogram me, double reference, double scaleFactor, double floor_dB) {
  75. try {
  76. autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1);
  77. for (integer i = 1; i <= my ny; i ++) {
  78. for (integer j = 1; j <= my nx; j ++) {
  79. double val = floor_dB;
  80. Melder_require (my z [i] [j] >= 0.0,
  81. U"Power in Spectrogram should be positive.");
  82. val = scaleFactor * log10 (my z [i] [j] / reference);
  83. if (val < floor_dB)
  84. val = floor_dB;
  85. thy z [i] [j] = val;
  86. }
  87. }
  88. return thee;
  89. } catch (MelderError) {
  90. Melder_throw (U"Matrix with dB values not created.");
  91. }
  92. }
  93. static double **NUMcosinesTable (integer n) {
  94. autoNUMmatrix<double> costab (1, n, 1, n);
  95. for (integer k = 1; k <= n; k ++) {
  96. for (integer j = 1; j <= n; j ++)
  97. costab [k] [j] = cos (NUMpi * (k - 1) * (j - 0.5) / n);
  98. }
  99. return costab.transfer();
  100. }
  101. // x [1..n] : input
  102. // y [1..n] : output
  103. static void NUMcosineTransform (double *x, double *y, integer n, double **cosinesTable) {
  104. for (integer k = 1; k <= n; k ++) {
  105. y [k] = 0.0;
  106. for (integer j = 1; j <= n; j ++)
  107. y [k] += x [j] * cosinesTable [k] [j];
  108. }
  109. }
  110. // x: input
  111. // y: output
  112. static void NUMinverseCosineTransform (double *x, double *y, integer n, double **cosinesTable) {
  113. for (integer j = 1; j <= n; j ++) {
  114. y [j] = 0.5 * x [1] * cosinesTable [1] [j];
  115. for (integer k = 2; k <= n; k ++)
  116. y [j] += x [k] * cosinesTable [k] [j];
  117. y [j] *= 2.0 / n;
  118. }
  119. }
  120. /* Precondition: 1. CC object has been created but individual frames not yet initialized
  121. * 2. Domains and number of frames conform
  122. * Steps:
  123. * 1. transform power-spectra to dB-spectra
  124. * 2. cosine transform of dB-spectrum
  125. */
  126. void BandFilterSpectrogram_into_CC (BandFilterSpectrogram me, CC thee, integer numberOfCoefficients) {
  127. autoNUMmatrix<double> cosinesTable (NUMcosinesTable (my ny), 1, 1);
  128. autoNUMvector<double> x (1, my ny);
  129. autoNUMvector<double> y (1, my ny);
  130. numberOfCoefficients = numberOfCoefficients > my ny - 1 ? my ny - 1 : numberOfCoefficients;
  131. Melder_assert (numberOfCoefficients > 0);
  132. // 20130220 new interpretation of maximumNumberOfCoefficients: necessary for the inverse transform
  133. for (integer frame = 1; frame <= my nx; frame ++) {
  134. CC_Frame ccframe = & thy frame [frame];
  135. for (integer i = 1; i <= my ny; i ++)
  136. x [i] = my v_getValueAtSample (frame, i, 1); // z [i] [frame];
  137. NUMcosineTransform (x.peek(), y.peek(), my ny, cosinesTable.peek());
  138. CC_Frame_init (ccframe, numberOfCoefficients);
  139. for (integer i = 1; i <= numberOfCoefficients; i ++)
  140. ccframe -> c [i] = y [i + 1];
  141. ccframe -> c0 = y [1];
  142. }
  143. }
  144. // Preconditions: Domains and number of frames conform
  145. // 0 <= first <= last <= my ny-1
  146. void CC_into_BandFilterSpectrogram (CC me, BandFilterSpectrogram thee, integer first, integer last, bool use_c0) {
  147. integer nf = my maximumNumberOfCoefficients + 1;
  148. autoNUMmatrix<double> cosinesTable (NUMcosinesTable (nf), 1, 1);
  149. autoNUMvector<double> x (1, nf);
  150. autoNUMvector<double> y (1, nf);
  151. for (integer frame = 1; frame <= my nx; frame ++) {
  152. CC_Frame ccframe = & my frame [frame];
  153. integer iend = last < ccframe -> numberOfCoefficients ? last : ccframe -> numberOfCoefficients;
  154. x [1] = use_c0 ? ccframe -> c0 : 0;
  155. for (integer i = 1; i <= my maximumNumberOfCoefficients; i ++)
  156. x [i + 1] = ( i < first || i > iend ? 0.0 : ccframe -> c [i] );
  157. NUMinverseCosineTransform (x.peek(), y.peek(), nf, cosinesTable.peek());
  158. for (integer i = 1; i <= nf; i ++)
  159. thy z [i] [frame] = BandFilterSpectrogram_DBREF * pow (10, y [i] / BandFilterSpectrogram_DBFAC);
  160. }
  161. }
  162. autoMelSpectrogram MFCC_to_MelSpectrogram (MFCC me, integer first, integer last, bool c0) {
  163. try {
  164. if (first == 0 && last == 0) // defaults
  165. first = 1, last = my maximumNumberOfCoefficients;
  166. if (first < 1)
  167. first = 1;
  168. if (last > my maximumNumberOfCoefficients)
  169. last = my maximumNumberOfCoefficients;
  170. if (first > last)
  171. first = 1, last = my maximumNumberOfCoefficients;
  172. double df = (my fmax - my fmin) / (my maximumNumberOfCoefficients + 1 + 1);
  173. autoMelSpectrogram thee = MelSpectrogram_create (my xmin, my xmax, my nx, my dx, my x1, my fmin, my fmax, my maximumNumberOfCoefficients + 1, df, df);
  174. CC_into_BandFilterSpectrogram (me, thee.get(), first, last, c0);
  175. return thee;
  176. } catch (MelderError) {
  177. Melder_throw (me, U"MelSpectrogram not created.");
  178. }
  179. }
  180. autoMFCC MelSpectrogram_to_MFCC (MelSpectrogram me, integer numberOfCoefficients) {
  181. try {
  182. if (numberOfCoefficients <= 0)
  183. numberOfCoefficients = my ny - 1;
  184. if (numberOfCoefficients > my ny - 1)
  185. numberOfCoefficients = my ny - 1;
  186. // 20130220 new interpretation of maximumNumberOfCoefficients necessary for inverse transform
  187. autoMFCC thee = MFCC_create (my xmin, my xmax, my nx, my dx, my x1, my ny - 1, my ymin, my ymax);
  188. BandFilterSpectrogram_into_CC (me, thee.get(), numberOfCoefficients);
  189. return thee;
  190. } catch (MelderError) {
  191. Melder_throw (me, U": MFCC not created.");
  192. }
  193. }
  194. autoBarkSpectrogram BarkSpectrogram_create (double tmin, double tmax, integer nt, double dt, double t1, double fmin, double fmax, integer nf, double df, double f1) {
  195. try {
  196. autoBarkSpectrogram me = Thing_new (BarkSpectrogram);
  197. Matrix_init (me.get(), tmin, tmax, nt, dt, t1, fmin, fmax, nf, df, f1);
  198. return me;
  199. } catch (MelderError) {
  200. Melder_throw (U"BarkSpectrogram not created.");
  201. }
  202. }
  203. double BandFilterSpectrogram_getFrequencyInHertz (BandFilterSpectrogram me, double f) {
  204. return my v_frequencyToHertz (f);
  205. }
  206. // xmin, xmax in hz versus bark/mel or lin
  207. void BandFilterSpectrogram_drawFrequencyScale (BandFilterSpectrogram me, Graphics g, double xmin, double xmax, double ymin, double ymax, bool garnish) {
  208. if (xmin < 0 || xmax < 0 || ymin < 0 || ymax < 0) {
  209. Melder_warning (U"Frequencies should be >= 0.");
  210. return;
  211. }
  212. // scale is in hertz
  213. if (xmin >= xmax) { // autoscaling
  214. xmin = 0;
  215. xmax = my v_frequencyToHertz (my ymax);
  216. }
  217. if (ymin >= ymax) { // autoscaling
  218. ymin = my ymin;
  219. ymax = my ymax;
  220. }
  221. integer n = 2000;
  222. Graphics_setInner (g);
  223. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  224. double dx = (xmax - xmin) / (n - 1);
  225. double x1 = xmin, y1 = my v_hertzToFrequency (x1);
  226. for (integer i = 2; i <= n; i ++) {
  227. double x2 = x1 + dx, y2 = my v_hertzToFrequency (x2);
  228. if (isdefined (y1) && isdefined (y2)) {
  229. double xo1, yo1, xo2, yo2;
  230. if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, & xo1, & yo1, & xo2, & yo2))
  231. Graphics_line (g, xo1, yo1, xo2, yo2);
  232. }
  233. x1 = x2;
  234. y1 = y2;
  235. }
  236. Graphics_unsetInner (g);
  237. if (garnish) {
  238. Graphics_drawInnerBox (g);
  239. Graphics_marksLeft (g, 2, true, true, false);
  240. Graphics_textLeft (g, true, Melder_cat (U"Frequency (", my v_getFrequencyUnit (), U")"));
  241. Graphics_marksBottom (g, 2, true, true, false);
  242. Graphics_textBottom (g, true, U"Frequency (Hz)");
  243. }
  244. }
  245. void BandFilterSpectrogram_paintImage (BandFilterSpectrogram me, Graphics g,
  246. double xmin, double xmax, double ymin, double ymax, double minimum, double maximum, bool garnish)
  247. {
  248. if (xmax <= xmin)
  249. xmin = my xmin, xmax = my xmax;
  250. if (ymax <= ymin)
  251. ymin = my ymin, ymax = my ymax;
  252. integer ixmin, ixmax, iymin, iymax;
  253. (void) Matrix_getWindowSamplesX (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx, &ixmin, &ixmax);
  254. (void) Matrix_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy, &iymin, &iymax);
  255. autoMatrix thee = Spectrogram_to_Matrix_dB ((Spectrogram) me, 4e-10, 10, -100);
  256. if (maximum <= minimum)
  257. (void) Matrix_getWindowExtrema (thee.get(), ixmin, ixmax, iymin, iymax, & minimum, & maximum);
  258. if (maximum <= minimum)
  259. minimum -= 1.0, maximum += 1.0;
  260. if (xmin >= xmax || ymin >= ymax)
  261. return;
  262. Graphics_setInner (g);
  263. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  264. Graphics_image (g, thy z.at,
  265. ixmin, ixmax, Sampled_indexToX (thee.get(), ixmin - 0.5), Sampled_indexToX (thee.get(), ixmax + 0.5),
  266. iymin, iymax, SampledXY_indexToY (thee.get(), iymin - 0.5), SampledXY_indexToY (thee.get(), iymax + 0.5),
  267. minimum, maximum
  268. );
  269. Graphics_unsetInner (g);
  270. if (garnish) {
  271. Graphics_drawInnerBox (g);
  272. Graphics_marksLeft (g, 2, true, true, false);
  273. Graphics_textLeft (g, true, Melder_cat (U"Frequency (", my v_getFrequencyUnit (), U")"));
  274. Graphics_marksBottom (g, 2, true, true, false);
  275. Graphics_textBottom (g, true, U"Time (s)");
  276. }
  277. }
  278. void BandFilterSpectrogram_drawSpectrumAtNearestTimeSlice (BandFilterSpectrogram me, Graphics g,
  279. double time, double fmin, double fmax, double dBmin, double dBmax, bool garnish)
  280. {
  281. if (time < my xmin || time > my xmax)
  282. return;
  283. if (fmin == 0.0 && fmax == 0.0) // autoscaling
  284. fmin = my ymin, fmax = my ymax;
  285. if (fmax <= fmin)
  286. fmin = my ymin, fmax = my ymax;
  287. integer icol = Matrix_xToNearestColumn (me, time);
  288. if (icol < 1)
  289. icol = 1;
  290. if (icol > my nx)
  291. icol = my nx;
  292. autoNUMvector<double> spectrum (1, my ny);
  293. for (integer i = 1; i <= my ny; i ++)
  294. spectrum [i] = my v_getValueAtSample (icol, i, 1); // dB's
  295. integer iymin, iymax;
  296. if (Matrix_getWindowSamplesY (me, fmin, fmax, & iymin, & iymax) < 2) // too few values
  297. return;
  298. if (dBmin == dBmax) { // autoscaling
  299. dBmin = spectrum [iymin];
  300. dBmax = dBmin;
  301. for (integer i = iymin + 1; i <= iymax; i ++) {
  302. if (spectrum [i] < dBmin) {
  303. dBmin = spectrum [i];
  304. } else if (spectrum [i] > dBmax) {
  305. dBmax = spectrum [i];
  306. }
  307. }
  308. if (dBmin == dBmax)
  309. dBmin -= 1.0, dBmax += 1.0;
  310. }
  311. Graphics_setWindow (g, fmin, fmax, dBmin, dBmax);
  312. Graphics_setInner (g);
  313. double x1 = my y1 + (iymin -1) * my dy, y1 = spectrum [iymin];
  314. for (integer i = iymin + 1; i <= iymax - 1; i ++) {
  315. double x2 = my y1 + (i -1) * my dy, y2 = spectrum [i];
  316. double xo1, yo1, xo2, yo2;
  317. if (NUMclipLineWithinRectangle (x1, y1, x2, y2, fmin, dBmin, fmax, dBmax, & xo1, & yo1, & xo2, & yo2))
  318. Graphics_line (g, xo1, yo1, xo2, yo2);
  319. x1 = x2;
  320. y1 = y2;
  321. }
  322. Graphics_unsetInner (g);
  323. if (garnish) {
  324. Graphics_drawInnerBox (g);
  325. Graphics_marksBottom (g, 2, true, true, false);
  326. Graphics_marksLeft (g, 2, true, true, false);
  327. Graphics_textLeft (g, true, U"Power (dB)");
  328. Graphics_textBottom (g, true, Melder_cat (U"Frequency (", my v_getFrequencyUnit (), U")"));
  329. }
  330. }
  331. void BarkSpectrogram_drawSekeyHansonFilterFunctions (BarkSpectrogram me, Graphics g, bool xIsHertz, int fromFilter, int toFilter,
  332. double zmin, double zmax, bool yscale_dB, double ymin, double ymax, bool garnish)
  333. {
  334. double xmin = zmin, xmax = zmax;
  335. if (zmin >= zmax) {
  336. zmin = my ymin;
  337. zmax = my ymax;
  338. xmin = ( xIsHertz ? my v_frequencyToHertz (zmin) : zmin );
  339. xmax = ( xIsHertz ? my v_frequencyToHertz (zmax) : zmax );
  340. }
  341. if (xIsHertz) {
  342. zmin = my v_hertzToFrequency (xmin);
  343. zmax = my v_hertzToFrequency (xmax);
  344. }
  345. if (ymin >= ymax) {
  346. ymin = ( yscale_dB ? -60.0 : 0.0 );
  347. ymax = ( yscale_dB ? 0.0 : 1.0 );
  348. }
  349. fromFilter = fromFilter <= 0 ? 1 : fromFilter;
  350. if (toFilter <= 0 || toFilter > my ny)
  351. toFilter = my ny;
  352. if (fromFilter > toFilter) {
  353. fromFilter = 1;
  354. toFilter = my ny;
  355. }
  356. integer n = xIsHertz ? 1000 : 500;
  357. autoNUMvector<double> xz (1, n), xhz (1, n), y (1, n);
  358. Graphics_setInner (g);
  359. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  360. double dz = (zmax - zmin) / (n - 1);
  361. for (integer iz = 1; iz <= n; iz ++) {
  362. double f = zmin + (iz - 1) * dz;
  363. xz [iz] = f;
  364. xhz [iz] = my v_frequencyToHertz (f); // just in case we need the linear scale
  365. }
  366. for (integer ifilter = fromFilter; ifilter <= toFilter; ifilter ++) {
  367. double zMid = Matrix_rowToY (me, ifilter);
  368. for (integer iz = 1; iz <= n; iz ++) {
  369. double z = xz [iz] - (zMid - 0.215);
  370. double amp = 7.0 - 7.5 * z - 17.5 * sqrt (0.196 + z * z);
  371. y [iz] = ( yscale_dB ? amp : pow (10.0, amp / 10.0) );
  372. }
  373. // the drawing
  374. double x1 = ( xIsHertz ? xhz [1] : xz [1] ), y1 = y [1];
  375. for (integer iz = 2; iz <= n; iz ++) {
  376. double x2 = ( xIsHertz ? xhz [iz] : xz [iz] ), y2 = y [iz];
  377. if (isdefined (x1) && isdefined (x2)) {
  378. double xo1, yo1, xo2, yo2;
  379. if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, & xo1, & yo1, & xo2, & yo2))
  380. Graphics_line (g, xo1, yo1, xo2, yo2);
  381. }
  382. x1 = x2;
  383. y1 = y2;
  384. }
  385. }
  386. Graphics_unsetInner (g);
  387. if (garnish) {
  388. double distance = yscale_dB ? 10.0 : 0.5;
  389. Graphics_drawInnerBox (g);
  390. Graphics_marksBottom (g, 2, true, true, false);
  391. Graphics_marksLeftEvery (g, 1.0, distance, true, true, false);
  392. Graphics_textLeft (g, true, yscale_dB ? U"Amplitude (dB)" : U"Amplitude");
  393. Graphics_textBottom (g, true, Melder_cat (U"Frequency (", xIsHertz ? U"Hz" : my v_getFrequencyUnit (), U")"));
  394. }
  395. }
  396. Thing_implement (MelSpectrogram, BandFilterSpectrogram, 2);
  397. autoMelSpectrogram MelSpectrogram_create (double tmin, double tmax, integer nt, double dt, double t1, double fmin, double fmax, integer nf, double df, double f1) {
  398. try {
  399. autoMelSpectrogram me = Thing_new (MelSpectrogram);
  400. Matrix_init (me.get(), tmin, tmax, nt, dt, t1, fmin, fmax, nf, df, f1);
  401. return me;
  402. } catch (MelderError) {
  403. Melder_throw (U"MelSpectrogram not created.");
  404. }
  405. }
  406. void BandFilterSpectrogram_drawTimeSlice (BandFilterSpectrogram me, Graphics g,
  407. double t, double fmin, double fmax, double min, double max, conststring32 xlabel, bool garnish)
  408. {
  409. Matrix_drawSliceY (me, g, t, fmin, fmax, min, max);
  410. if (garnish) {
  411. Graphics_drawInnerBox (g);
  412. Graphics_marksBottom (g, 2, true, true, false);
  413. Graphics_marksLeft (g, 2, true, true, false);
  414. if (xlabel) {
  415. Graphics_textBottom (g, false, xlabel);
  416. }
  417. }
  418. }
  419. void MelSpectrogram_drawTriangularFilterFunctions (MelSpectrogram me, Graphics g,
  420. bool xIsHertz, int fromFilter, int toFilter, double zmin, double zmax, bool yscale_dB, double ymin, double ymax, bool garnish)
  421. {
  422. double xmin = zmin, xmax = zmax;
  423. if (zmin >= zmax) {
  424. zmin = my ymin;
  425. zmax = my ymax; // mel
  426. xmin = xIsHertz ? my v_frequencyToHertz (zmin) : zmin;
  427. xmax = xIsHertz ? my v_frequencyToHertz (zmax) : zmax;
  428. }
  429. if (xIsHertz) {
  430. zmin = my v_hertzToFrequency (xmin);
  431. zmax = my v_hertzToFrequency (xmax);
  432. }
  433. if (ymin >= ymax) {
  434. ymin = yscale_dB ? -60.0 : 0.0;
  435. ymax = yscale_dB ? 0.0 : 1.0;
  436. }
  437. if (fromFilter <= 0)
  438. fromFilter = 1;
  439. if (toFilter <= 0 || toFilter > my ny)
  440. toFilter = my ny;
  441. if (fromFilter > toFilter)
  442. fromFilter = 1, toFilter = my ny;
  443. integer n = xIsHertz ? 1000 : 500;
  444. autoNUMvector<double> xz (1, n), xhz (1,n), y (1, n);
  445. Graphics_setInner (g);
  446. Graphics_setWindow (g, xmin, xmax, ymin, ymax);
  447. double dz = (zmax - zmin) / (n - 1);
  448. for (integer iz = 1; iz <= n; iz ++) {
  449. double f = zmin + (iz - 1) * dz;
  450. xz [iz] = f;
  451. xhz [iz] = my v_frequencyToHertz (f); // just in case we need the linear scale
  452. }
  453. for (integer ifilter = fromFilter; ifilter <= toFilter; ifilter ++) {
  454. double zc = Matrix_rowToY (me, ifilter), zl = zc - my dy, zh = zc + my dy;
  455. double xo1, yo1, xo2, yo2;
  456. if (yscale_dB) {
  457. for (integer iz = 1; iz <= n; iz ++) {
  458. double z = xz [iz];
  459. double amp = NUMtriangularfilter_amplitude (zl, zc, zh, z);
  460. y [iz] = yscale_dB ? (amp > 0.0 ? 20.0 * log10 (amp) : ymin - 10.0) : amp;
  461. }
  462. double x1 = ( xIsHertz ? xhz [1] : xz [1] ), y1 = y [1];
  463. if (isdefined (y1)) {
  464. for (integer iz = 1; iz <= n; iz ++) {
  465. double x2 = xIsHertz ? xhz [iz] : xz [iz], y2 = y [iz];
  466. if (isdefined (y2)) {
  467. if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, & xo1, & yo1, & xo2, & yo2))
  468. Graphics_line (g, xo1, yo1, xo2, yo2);
  469. }
  470. x1 = x2;
  471. y1 = y2;
  472. }
  473. }
  474. } else {
  475. double x1 = xIsHertz ? my v_frequencyToHertz (zl) : zl;
  476. double x2 = xIsHertz ? my v_frequencyToHertz (zc) : zc;
  477. if (NUMclipLineWithinRectangle (x1, 0, x2, 1, xmin, ymin, xmax, ymax, & xo1, & yo1, & xo2, & yo2))
  478. Graphics_line (g, xo1, yo1, xo2, yo2);
  479. double x3 = xIsHertz ? my v_frequencyToHertz (zh) : zh;
  480. if (NUMclipLineWithinRectangle (x2, 1, x3, 0, xmin, ymin, xmax, ymax, & xo1, & yo1, & xo2, & yo2))
  481. Graphics_line (g, xo1, yo1, xo2, yo2);
  482. }
  483. }
  484. Graphics_unsetInner (g);
  485. if (garnish) {
  486. Graphics_drawInnerBox (g);
  487. Graphics_marksBottom (g, 2, true, true, false);
  488. Graphics_marksLeftEvery (g, 1.0, yscale_dB ? 10.0 : 0.5, true, true, false);
  489. Graphics_textLeft (g, true, yscale_dB ? U"Amplitude (dB)" : U"Amplitude");
  490. Graphics_textBottom (g, true, Melder_cat (U"Frequency (", ( xIsHertz ? U"Hz" : my v_getFrequencyUnit () ), U")"));
  491. }
  492. }
  493. autoMatrix BandFilterSpectrogram_to_Matrix (BandFilterSpectrogram me, int to_dB) {
  494. try {
  495. int units = to_dB ? 1 : 0;
  496. autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1);
  497. for (integer i = 1; i <= my ny; i ++) {
  498. for (integer j = 1; j <= my nx; j ++)
  499. thy z [i] [j] = my v_getValueAtSample (j, i, units);
  500. }
  501. return thee;
  502. } catch (MelderError) {
  503. Melder_throw (me, U": not converted to Matrix.");
  504. }
  505. }
  506. autoBarkSpectrogram Matrix_to_BarkSpectrogram (Matrix me) {
  507. try {
  508. autoBarkSpectrogram thee = BarkSpectrogram_create (my xmin, my xmax, my nx, my dx, my x1,
  509. my ymin, my ymax, my ny, my dy, my y1);
  510. matrixcopy_preallocated (thy z.get(), my z.get());
  511. return thee;
  512. } catch (MelderError) {
  513. Melder_throw (me, U": not converted to BarkSpectrogram.");
  514. }
  515. }
  516. autoMelSpectrogram Matrix_to_MelSpectrogram (Matrix me) {
  517. try {
  518. autoMelSpectrogram thee = MelSpectrogram_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1);
  519. matrixcopy_preallocated (thy z.get(), my z.get());
  520. return thee;
  521. } catch (MelderError) {
  522. Melder_throw (me, U": not converted to MelSpectrogram.");
  523. }
  524. }
  525. autoIntensity BandFilterSpectrogram_to_Intensity (BandFilterSpectrogram me) {
  526. try {
  527. autoIntensity thee = Intensity_create (my xmin, my xmax, my nx, my dx, my x1);
  528. for (integer j = 1; j <= my nx; j ++) {
  529. longdouble p = 0.0;
  530. for (integer i = 1; i <= my ny; i ++)
  531. p += my z [i] [j]; // add power
  532. thy z [1] [j] = BandFilterSpectrogram_DBFAC * log10 ((double) p / BandFilterSpectrogram_DBREF);
  533. }
  534. return thee;
  535. } catch (MelderError) {
  536. Melder_throw (me, U": Intensity not created.");
  537. }
  538. }
  539. void BandFilterSpectrogram_equalizeIntensities (BandFilterSpectrogram me, double intensity_db) {
  540. for (integer j = 1; j <= my nx; j ++) {
  541. longdouble p = 0.0;
  542. for (integer i = 1; i <= my ny; i ++)
  543. p += my z [i] [j];
  544. double delta_db = intensity_db - BandFilterSpectrogram_DBFAC * log10 ((double) p / BandFilterSpectrogram_DBREF);
  545. double factor = pow (10.0, delta_db / 10.0);
  546. for (integer i = 1; i <= my ny; i ++)
  547. my z [i] [j] *= factor;
  548. }
  549. }
  550. void BandFilterSpectrogram_PCA_drawComponent (BandFilterSpectrogram me, PCA thee, Graphics g, integer component, double dblevel, double frequencyOffset, double scale, double tmin, double tmax, double fmin, double fmax) {
  551. Melder_require (component > 0 && component <= thy numberOfEigenvalues, U"Component too large.");
  552. // Scale Intensity
  553. autoBandFilterSpectrogram fcopy = Data_copy (me);
  554. BandFilterSpectrogram_equalizeIntensities (fcopy.get(), dblevel);
  555. autoMatrix mdb = Spectrogram_to_Matrix_dB ((Spectrogram) fcopy.get(), BandFilterSpectrogram_DBREF, BandFilterSpectrogram_DBFAC, BandFilterSpectrogram_DBFLOOR);
  556. autoMatrix him = Eigen_Matrix_to_Matrix_projectColumns (thee, mdb.get(), component);
  557. for (integer j = 1; j <= my nx; j ++)
  558. his z [component] [j] = frequencyOffset + scale * his z [component] [j];
  559. Matrix_drawRows (him.get(), g, tmin, tmax, component - 0.5, component + 0.5, fmin, fmax);
  560. }
  561. /*
  562. * MelSpectrograms_to_DTW (MelSpectrogram me, MelSpectrogram thee, dtw-params);
  563. * comparison on the basis of mfcc
  564. * BarkSpectrograms_to_DTW (BarkSpectrogram me, BarkSpectrogram thee, dtw-params);
  565. * comparison on the basis of bfcc!
  566. */
  567. /* End of file Spectrogram_extensions.cpp */