ERPWindow.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /* ERPWindow.cpp
  2. *
  3. * Copyright (C) 2012-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 "ERPWindow.h"
  19. #include "EditorM.h"
  20. #include "Preferences.h"
  21. Thing_implement (ERPWindow, SoundEditor, 0);
  22. #include "prefs_define.h"
  23. #include "ERPWindow_prefs.h"
  24. #include "prefs_install.h"
  25. #include "ERPWindow_prefs.h"
  26. #include "prefs_copyToInstance.h"
  27. #include "ERPWindow_prefs.h"
  28. typedef struct { int inclination, azimuth; double topX, topY; } BiosemiLocationData;
  29. static BiosemiLocationData biosemiCapCoordinates64 [1+64] =
  30. {
  31. /*
  32. * BioSemi says:
  33. * "Spherical coordinates in degrees,
  34. * by inclination (from Cz, pos is right hemisphere, neg is left hemisphere),
  35. * and azimuth (from T7 for left hemisphere, and from T8 for the right hemisphere, pos is anti-clockwise, neg is clockwise)"
  36. */
  37. {0,0,0.0,0.0},
  38. { -92, -72, 0.0, 0.0 }, // 1 Fp1
  39. { -92, -54, 0.0, 0.0 }, // 2 AF7
  40. { -74, -65, 0.0, 0.0 }, // 3 AF3
  41. { -50, -68, 0.0, 0.0 }, // 4 F1
  42. { -60, -51, 0.0, 0.0 }, // 5 F3
  43. { -75, -41, 0.0, 0.0 }, // 6 F5
  44. { -92, -36, 0.0, 0.0 }, // 7 F7
  45. { -92, -18, 0.0, 0.0 }, // 8 FT7
  46. { -72, -21, 0.0, 0.0 }, // 9 FC5
  47. { -50, -28, 0.0, 0.0 }, // 10 FC3
  48. { -32, -45, 0.0, 0.0 }, // 11 FC1
  49. { -23, 0, 0.0, 0.0 }, // 12 C1
  50. { -46, 0, 0.0, 0.0 }, // 13 C3
  51. { -69, 0, 0.0, 0.0 }, // 14 C5
  52. { -92, 0, 0.0, 0.0 }, // 15 T7
  53. { -92, 18, 0.0, 0.0 }, // 16 TP7
  54. { -72, 21, 0.0, 0.0 }, // 17 CP5
  55. { -50, 28, 0.0, 0.0 }, // 18 CP3
  56. { -32, 45, 0.0, 0.0 }, // 19 CP1
  57. { -50, 68, 0.0, 0.0 }, // 20 P1
  58. { -60, 51, 0.0, 0.0 }, // 21 P3
  59. { -75, 41, 0.0, 0.0 }, // 22 P5
  60. { -92, 36, 0.0, 0.0 }, // 23 P7
  61. {-115, 40, 0.0, 0.0 }, // 24 P9
  62. { -92, 54, 0.0, 0.0 }, // 25 PO7
  63. { -74, 65, 0.0, 0.0 }, // 26 PO3
  64. { -92, 72, 0.0, 0.0 }, // 27 O1
  65. { 115, -90, 0.0, 0.0 }, // 28 Iz
  66. { 92, -90, 0.0, 0.0 }, // 29 Oz
  67. { 69, -90, 0.0, 0.0 }, // 30 POz
  68. { 46, -90, 0.0, 0.0 }, // 31 Pz
  69. { 23, -90, 0.0, 0.0 }, // 32 CPz
  70. { 92, 90, 0.0, 0.0 }, // 33 Fpz
  71. { 92, 72, 0.0, 0.0 }, // 34 Fp2
  72. { 92, 54, 0.0, 0.0 }, // 35 AF8
  73. { 74, 65, 0.0, 0.0 }, // 36 AF4
  74. { 69, 90, 0.0, 0.0 }, // 37 AFz
  75. { 46, 90, 0.0, 0.0 }, // 38 Fz
  76. { 50, 68, 0.0, 0.0 }, // 39 F2
  77. { 60, 51, 0.0, 0.0 }, // 40 F4
  78. { 75, 41, 0.0, 0.0 }, // 41 F6
  79. { 92, 36, 0.0, 0.0 }, // 42 F8
  80. { 92, 18, 0.0, 0.0 }, // 43 FT8
  81. { 72, 21, 0.0, 0.0 }, // 44 FC6
  82. { 50, 28, 0.0, 0.0 }, // 45 FC4
  83. { 32, 45, 0.0, 0.0 }, // 46 FC2
  84. { 23, 90, 0.0, 0.0 }, // 47 FCz
  85. { 0, 0, 0.0, 0.0 }, // 48 Cz
  86. { 23, 0, 0.0, 0.0 }, // 49 C2
  87. { 46, 0, 0.0, 0.0 }, // 50 C4
  88. { 69, 0, 0.0, 0.0 }, // 51 C6
  89. { 92, 0, 0.0, 0.0 }, // 52 T8
  90. { 92, -18, 0.0, 0.0 }, // 53 TP8
  91. { 72, -21, 0.0, 0.0 }, // 54 CP6
  92. { 50, -28, 0.0, 0.0 }, // 55 CP4
  93. { 32, -45, 0.0, 0.0 }, // 56 CP2
  94. { 50, -68, 0.0, 0.0 }, // 57 P2
  95. { 60, -51, 0.0, 0.0 }, // 58 P4
  96. { 75, -41, 0.0, 0.0 }, // 59 P6
  97. { 92, -36, 0.0, 0.0 }, // 60 P8
  98. { 115, -40, 0.0, 0.0 }, // 61 P10
  99. { 92, -54, 0.0, 0.0 }, // 62 PO8
  100. { 74, -65, 0.0, 0.0 }, // 63 PO4
  101. { 92, -72, 0.0, 0.0 } // 64 O2
  102. };
  103. static BiosemiLocationData biosemiCapCoordinates32 [1+32] =
  104. {
  105. /*
  106. * BioSemi says:
  107. * "Spherical coordinates in degrees,
  108. * by inclination (from Cz, pos is right hemisphere, neg is left hemisphere),
  109. * and azimuth (from T7 for left hemisphere, and from T8 for the right hemisphere, pos is anti-clockwise, neg is clockwise)"
  110. */
  111. {0,0,0.0,0.0},
  112. { -92, -72, 0.0, 0.0 }, // 1 Fp1
  113. { -74, -65, 0.0, 0.0 }, // 2 AF3
  114. { -92, -36, 0.0, 0.0 }, // 3 F7
  115. { -60, -51, 0.0, 0.0 }, // 4 F3
  116. { -32, -45, 0.0, 0.0 }, // 5 FC1
  117. { -72, -21, 0.0, 0.0 }, // 6 FC5
  118. { -92, 0, 0.0, 0.0 }, // 7 T7
  119. { -46, 0, 0.0, 0.0 }, // 8 C3
  120. { -32, 45, 0.0, 0.0 }, // 9 CP1
  121. { -72, 21, 0.0, 0.0 }, // 10 CP5
  122. { -92, 36, 0.0, 0.0 }, // 11 P7
  123. { -60, 51, 0.0, 0.0 }, // 12 P3
  124. { 46, -90, 0.0, 0.0 }, // 13 Pz
  125. { -74, 65, 0.0, 0.0 }, // 14 PO3
  126. { -92, 72, 0.0, 0.0 }, // 15 O1
  127. { 92, -90, 0.0, 0.0 }, // 16 Oz
  128. { 92, -72, 0.0, 0.0 }, // 17 O2
  129. { 74, -65, 0.0, 0.0 }, // 18 PO4
  130. { 60, -51, 0.0, 0.0 }, // 19 P4
  131. { 92, -36, 0.0, 0.0 }, // 20 P8
  132. { 72, -21, 0.0, 0.0 }, // 21 CP6
  133. { 32, -45, 0.0, 0.0 }, // 22 CP2
  134. { 46, 0, 0.0, 0.0 }, // 23 C4
  135. { 92, 0, 0.0, 0.0 }, // 24 T8
  136. { 72, 21, 0.0, 0.0 }, // 25 FC6
  137. { 32, 45, 0.0, 0.0 }, // 26 FC2
  138. { 60, 51, 0.0, 0.0 }, // 27 F4
  139. { 92, 36, 0.0, 0.0 }, // 28 F8
  140. { 74, 65, 0.0, 0.0 }, // 29 AF4
  141. { 92, 72, 0.0, 0.0 }, // 30 Fp2
  142. { 46, 90, 0.0, 0.0 }, // 31 Fz
  143. { 0, 0, 0.0, 0.0 }, // 32 Cz
  144. };
  145. void ERP_drawScalp_garnish (Graphics graphics, double vmin, double vmax, enum kGraphics_colourScale colourScale) {
  146. integer n = 201;
  147. autoMAT legend (n, 2, kTensorInitializationType::RAW);
  148. for (integer irow = 1; irow <= n; irow ++) {
  149. for (integer icol = 1; icol <= 2; icol ++) {
  150. legend [irow] [icol] = (irow - 1) / (n - 1.0);
  151. }
  152. }
  153. Graphics_setColourScale (graphics, colourScale);
  154. Graphics_image (graphics, legend.at, 1, 2, 0.85, 0.98, 1, n, -0.8, +0.8, 0.0, 1.0);
  155. Graphics_setColourScale (graphics, kGraphics_colourScale::GREY);
  156. Graphics_rectangle (graphics, 0.85, 0.98, -0.8, +0.8);
  157. Graphics_setTextAlignment (graphics, Graphics_RIGHT, Graphics_TOP);
  158. Graphics_text (graphics, 1.0, -0.8, vmin * 1e6, U" μV");
  159. Graphics_setTextAlignment (graphics, Graphics_RIGHT, Graphics_BOTTOM);
  160. Graphics_text (graphics, 1.0, +0.8, vmax * 1e6, U" μV");
  161. }
  162. void ERP_drawScalp (ERP me, Graphics graphics, double tmin, double tmax, double vmin, double vmax, enum kGraphics_colourScale colourScale, bool garnish) {
  163. Graphics_setInner (graphics);
  164. Graphics_setWindow (graphics, -1.0, 1.0, -1.0, 1.0);
  165. //Graphics_setGrey (graphics, 1.0);
  166. //Graphics_fillRectangle (graphics, -1.1, 1.1, -1.01, 1.19);
  167. //Graphics_setColour (graphics, Graphics_BLACK);
  168. integer numberOfDrawableChannels =
  169. my ny >= 64 && Melder_equ (my channelNames [64].get(), U"O2") ? 64 :
  170. my ny >= 32 && Melder_equ (my channelNames [32].get(), U"Cz") ? 32 :
  171. 0;
  172. BiosemiLocationData *biosemiLocationData = numberOfDrawableChannels == 64 ? biosemiCapCoordinates64 : numberOfDrawableChannels == 32 ? biosemiCapCoordinates32 : 0;
  173. for (integer ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
  174. double inclination = (double) biosemiLocationData [ichan]. inclination;
  175. double azimuth = (double) biosemiLocationData [ichan]. azimuth;
  176. bool rightHemisphere = inclination >= 0.0;
  177. double r = fabs (inclination / 115.0);
  178. double theta = rightHemisphere ? azimuth * (NUMpi / 180.0) : (azimuth + 180.0) * (NUMpi / 180.0);
  179. biosemiLocationData [ichan]. topX = r * cos (theta);
  180. biosemiLocationData [ichan]. topY = r * sin (theta);
  181. }
  182. integer n = 201;
  183. double d = 2.0 / (n - 1);
  184. autoVEC mean (numberOfDrawableChannels, kTensorInitializationType::RAW);
  185. for (integer ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
  186. mean [ichan] = tmin == tmax ?
  187. Sampled_getValueAtX (me, tmin, ichan, 0, true) :
  188. Vector_getMean (me, tmin, tmax, ichan);
  189. }
  190. autoMAT image (n, n, kTensorInitializationType::RAW);
  191. for (integer irow = 1; irow <= n; irow ++) {
  192. double y = -1.0 + (irow - 1) * d;
  193. for (integer icol = 1; icol <= n; icol ++) {
  194. double x = -1.0 + (icol - 1) * d;
  195. if (x * x + y * y <= 1.0) {
  196. double value = undefined;
  197. longdouble sum = 0.0, weight = 0.0;
  198. for (integer ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
  199. double dx = x - biosemiLocationData [ichan]. topX;
  200. double dy = y - biosemiLocationData [ichan]. topY;
  201. double distance = sqrt (dx * dx + dy * dy);
  202. if (distance < 1e-12) {
  203. value = mean [ichan];
  204. break;
  205. }
  206. distance = distance * distance * distance * distance * distance * distance;
  207. sum += mean [ichan] / distance;
  208. weight += 1.0 / distance;
  209. }
  210. if (isundef (value))
  211. value = ( sum == 0.0 ? 0.0 : double (sum / weight) );
  212. image [irow] [icol] = value;
  213. }
  214. }
  215. }
  216. double whiteValue = colourScale == kGraphics_colourScale::BLUE_TO_RED ? 0.5 * (vmin + vmax) : vmin;
  217. Graphics_setColourScale (graphics, colourScale);
  218. for (integer irow = 1; irow <= n; irow ++) {
  219. double y = -1.0 + (irow - 1) * d;
  220. for (integer icol = 1; icol <= n; icol ++) {
  221. double x = -1.0 + (icol - 1) * d;
  222. if (x * x + y * y > 1.0) {
  223. image [irow] [icol] = whiteValue;
  224. }
  225. }
  226. }
  227. Graphics_image (graphics, image.at, 1, n, -1.0-0.5/n, 1.0+0.5/n, 1, n, -1.0-0.5/n, 1.0+0.5/n, vmin, vmax);
  228. Graphics_setColourScale (graphics, kGraphics_colourScale::GREY);
  229. Graphics_setLineWidth (graphics, 2.0);
  230. /*
  231. * Nose.
  232. */
  233. Graphics_setGrey (graphics, colourScale == kGraphics_colourScale::BLUE_TO_RED ? 1.0 : 0.5);
  234. {// scope
  235. double x [3] = { -0.08, 0.0, 0.08 }, y [3] = { 0.99, 1.18, 0.99 };
  236. Graphics_fillArea (graphics, 3, x, y);
  237. }
  238. Graphics_setColour (graphics, Graphics_BLACK);
  239. Graphics_line (graphics, -0.08, 0.99, 0.0, 1.18);
  240. Graphics_line (graphics, 0.08, 0.99, 0.0, 1.18);
  241. /*
  242. * Ears.
  243. */
  244. Graphics_setGrey (graphics, colourScale == kGraphics_colourScale::BLUE_TO_RED ? 1.0 : 0.5);
  245. Graphics_fillRectangle (graphics, -1.09, -1.00, -0.08, 0.08);
  246. Graphics_fillRectangle (graphics, 1.09, 1.00, -0.08, 0.08);
  247. Graphics_setColour (graphics, Graphics_BLACK);
  248. Graphics_line (graphics, -0.99, 0.08, -1.09, 0.08);
  249. Graphics_line (graphics, -1.09, 0.08, -1.09, -0.08);
  250. Graphics_line (graphics, -1.09, -0.08, -0.99, -0.08);
  251. Graphics_line (graphics, 0.99, 0.08, 1.09, 0.08);
  252. Graphics_line (graphics, 1.09, 0.08, 1.09, -0.08);
  253. Graphics_line (graphics, 1.09, -0.08, 0.99, -0.08);
  254. /*
  255. * Scalp.
  256. */
  257. Graphics_ellipse (graphics, -1.0, 1.0, -1.0, 1.0);
  258. Graphics_setLineWidth (graphics, 1.0);
  259. Graphics_unsetInner (graphics);
  260. if (garnish) {
  261. ERP_drawScalp_garnish (graphics, vmin, vmax, colourScale);
  262. }
  263. }
  264. void structERPWindow :: v_drawSelectionViewer () {
  265. ERP erp = (ERP) our data;
  266. Graphics_setWindow (our graphics.get(), -1.1, 1.1, -1.01, 1.19);
  267. Graphics_setColour (our graphics.get(), Graphics_WINDOW_BACKGROUND_COLOUR);
  268. Graphics_fillRectangle (our graphics.get(), -1.1, 1.1, -1.01, 1.19);
  269. Graphics_setColour (our graphics.get(), Graphics_BLACK);
  270. integer numberOfDrawableChannels =
  271. erp -> ny >= 64 && Melder_equ (erp -> channelNames [64].get(), U"O2") ? 64 :
  272. erp -> ny >= 32 && Melder_equ (erp -> channelNames [32].get(), U"Cz") ? 32 :
  273. 0;
  274. BiosemiLocationData *biosemiLocationData = numberOfDrawableChannels == 64 ? biosemiCapCoordinates64 : numberOfDrawableChannels == 32 ? biosemiCapCoordinates32 : 0;
  275. for (integer ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
  276. double inclination = (double) biosemiLocationData [ichan]. inclination;
  277. double azimuth = (double) biosemiLocationData [ichan]. azimuth;
  278. bool rightHemisphere = inclination >= 0.0;
  279. double r = fabs (inclination / 115.0);
  280. double theta = rightHemisphere ? azimuth * (NUMpi / 180.0) : (azimuth + 180.0) * (NUMpi / 180.0);
  281. biosemiLocationData [ichan]. topX = r * cos (theta);
  282. biosemiLocationData [ichan]. topY = r * sin (theta);
  283. }
  284. integer n = 201;
  285. double d = 2.0 / (n - 1);
  286. autoVEC means (numberOfDrawableChannels, kTensorInitializationType::RAW);
  287. for (integer ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
  288. means [ichan] =
  289. our startSelection == our endSelection ?
  290. Sampled_getValueAtX (erp, our startSelection, ichan, 0, true) :
  291. Vector_getMean (erp, our startSelection, our endSelection, ichan);
  292. }
  293. autoMAT image (n, n, kTensorInitializationType::RAW);
  294. for (integer irow = 1; irow <= n; irow ++) {
  295. double y = -1.0 + (irow - 1) * d;
  296. for (integer icol = 1; icol <= n; icol ++) {
  297. double x = -1.0 + (icol - 1) * d;
  298. if (x * x + y * y <= 1.0) {
  299. double value = undefined;
  300. longdouble sum = 0.0, weight = 0.0;
  301. for (integer ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
  302. double dx = x - biosemiLocationData [ichan]. topX;
  303. double dy = y - biosemiLocationData [ichan]. topY;
  304. double distance = sqrt (dx * dx + dy * dy);
  305. if (distance < 1e-12) {
  306. value = means [ichan];
  307. break;
  308. }
  309. distance = distance * distance * distance * distance * distance * distance;
  310. sum += means [ichan] / distance;
  311. weight += 1.0 / distance;
  312. }
  313. if (isundef (value))
  314. value = ( sum == 0.0 ? 0.0 : double (sum / weight) );
  315. image [irow] [icol] = value;
  316. }
  317. }
  318. }
  319. double minimum = 0.0, maximum = 0.0;
  320. for (integer irow = 1; irow <= n; irow ++) {
  321. for (integer icol = 1; icol <= n; icol ++) {
  322. double value = image [irow] [icol];
  323. if (value < minimum) minimum = value;
  324. else if (value > maximum) maximum = value;
  325. }
  326. }
  327. double absoluteExtremum = - minimum > maximum ? - minimum : maximum;
  328. if (p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy::FIXED_RANGE) {
  329. minimum = p_sound_scaling_minimum;
  330. maximum = p_sound_scaling_maximum;
  331. } else if (p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy::FIXED_HEIGHT) {
  332. double mean = 0.5 * (minimum + maximum);
  333. minimum = mean - 0.5 * p_sound_scaling_height;
  334. maximum = mean + 0.5 * p_sound_scaling_height;
  335. } else {
  336. minimum = - absoluteExtremum;
  337. maximum = absoluteExtremum;
  338. }
  339. for (integer irow = 1; irow <= n; irow ++) {
  340. double y = -1.0 + (irow - 1) * d;
  341. for (integer icol = 1; icol <= n; icol ++) {
  342. double x = -1.0 + (icol - 1) * d;
  343. if (x * x + y * y > 1.0) {
  344. image [irow] [icol] = minimum +
  345. ( our p_scalp_colourScale == kGraphics_colourScale::BLUE_TO_RED ? 0.46 : 0.1875 ) * (maximum - minimum);
  346. // -0.625 * absoluteExtremum;
  347. }
  348. }
  349. }
  350. Graphics_setColourScale (our graphics.get(), our p_scalp_colourScale);
  351. Graphics_image (our graphics.get(), image.at, 1, n, -1.0-0.5/n, 1.0+0.5/n, 1, n, -1.0-0.5/n, 1.0+0.5/n, minimum, maximum);
  352. Graphics_setColourScale (our graphics.get(), kGraphics_colourScale::GREY);
  353. Graphics_setLineWidth (our graphics.get(), 2.0);
  354. /*
  355. * Nose.
  356. */
  357. Graphics_setGrey (our graphics.get(), our p_scalp_colourScale == kGraphics_colourScale::BLUE_TO_RED ? 1.0 : 0.5);
  358. {// scope
  359. double x [3] = { -0.08, 0.0, 0.08 }, y [3] = { 0.99, 1.18, 0.99 };
  360. Graphics_fillArea (our graphics.get(), 3, x, y);
  361. }
  362. Graphics_setColour (our graphics.get(), Graphics_BLACK);
  363. Graphics_line (our graphics.get(), -0.08, 0.99, 0.0, 1.18);
  364. Graphics_line (our graphics.get(), 0.08, 0.99, 0.0, 1.18);
  365. /*
  366. * Ears.
  367. */
  368. Graphics_setGrey (our graphics.get(), our p_scalp_colourScale == kGraphics_colourScale::BLUE_TO_RED ? 1.0 : 0.5);
  369. Graphics_fillRectangle (our graphics.get(), -1.09, -1.00, -0.08, 0.08);
  370. Graphics_fillRectangle (our graphics.get(), 1.09, 1.00, -0.08, 0.08);
  371. Graphics_setColour (our graphics.get(), Graphics_BLACK);
  372. Graphics_line (our graphics.get(), -0.99, 0.08, -1.09, 0.08);
  373. Graphics_line (our graphics.get(), -1.09, 0.08, -1.09, -0.08);
  374. Graphics_line (our graphics.get(), -1.09, -0.08, -0.99, -0.08);
  375. Graphics_line (our graphics.get(), 0.99, 0.08, 1.09, 0.08);
  376. Graphics_line (our graphics.get(), 1.09, 0.08, 1.09, -0.08);
  377. Graphics_line (our graphics.get(), 1.09, -0.08, 0.99, -0.08);
  378. /*
  379. * Scalp.
  380. */
  381. Graphics_ellipse (our graphics.get(), -1.0, 1.0, -1.0, 1.0);
  382. Graphics_setLineWidth (our graphics.get(), 1.0);
  383. }
  384. OPTIONMENU_ENUM_VARIABLE (kGraphics_colourScale, v_prefs_scalpColourSpace)
  385. void structERPWindow :: v_prefs_addFields (EditorCommand cmd) {
  386. OPTIONMENU_ENUM_FIELD (kGraphics_colourScale, v_prefs_scalpColourSpace,
  387. U"Scalp colour space", kGraphics_colourScale::BLUE_TO_RED)
  388. }
  389. void structERPWindow :: v_prefs_setValues (EditorCommand cmd) {
  390. SET_ENUM (v_prefs_scalpColourSpace, kGraphics_colourScale, p_scalp_colourScale)
  391. }
  392. void structERPWindow :: v_prefs_getValues (EditorCommand /* cmd */) {
  393. pref_scalp_colourScale () = p_scalp_colourScale = v_prefs_scalpColourSpace;
  394. FunctionEditor_redraw (this);
  395. }
  396. autoERPWindow ERPWindow_create (conststring32 title, ERP data) {
  397. Melder_assert (data);
  398. try {
  399. autoERPWindow me = Thing_new (ERPWindow);
  400. SoundEditor_init (me.get(), title, data);
  401. return me;
  402. } catch (MelderError) {
  403. Melder_throw (U"ERP window not created.");
  404. }
  405. }
  406. /* End of file ERPWindow.cpp */