SpectrumEditor.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* SpectrumEditor.cpp
  2. *
  3. * Copyright (C) 1992-2011,2012,2013,2014,2015,2016,2017 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 "SpectrumEditor.h"
  19. #include "Sound_and_Spectrum.h"
  20. #include "EditorM.h"
  21. Thing_implement (SpectrumEditor, FunctionEditor, 0);
  22. #include "prefs_define.h"
  23. #include "SpectrumEditor_prefs.h"
  24. #include "prefs_install.h"
  25. #include "SpectrumEditor_prefs.h"
  26. #include "prefs_copyToInstance.h"
  27. #include "SpectrumEditor_prefs.h"
  28. static void updateRange (SpectrumEditor me) {
  29. if (Spectrum_getPowerDensityRange ((Spectrum) my data, & my minimum, & my maximum)) {
  30. my minimum = my maximum - my p_dynamicRange;
  31. } else {
  32. my minimum = -1000.0, my maximum = 1000.0;
  33. }
  34. }
  35. void structSpectrumEditor :: v_dataChanged () {
  36. updateRange (this);
  37. SpectrumEditor_Parent :: v_dataChanged ();
  38. }
  39. void structSpectrumEditor :: v_draw () {
  40. Spectrum spectrum = (Spectrum) our data;
  41. Graphics_setWindow (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
  42. Graphics_setColour (our graphics.get(), Graphics_WHITE);
  43. Graphics_fillRectangle (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
  44. Graphics_setColour (our graphics.get(), Graphics_BLACK);
  45. Graphics_rectangle (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
  46. Spectrum_drawInside (spectrum, our graphics.get(), our startWindow, our endWindow, our minimum, our maximum);
  47. FunctionEditor_drawRangeMark (this, our maximum, Melder_fixed (maximum, 1), U" dB", Graphics_TOP);
  48. FunctionEditor_drawRangeMark (this, our minimum, Melder_fixed (minimum, 1), U" dB", Graphics_BOTTOM);
  49. if (our cursorHeight > our minimum && our cursorHeight < our maximum)
  50. FunctionEditor_drawHorizontalHair (this, our cursorHeight, Melder_fixed (our cursorHeight, 1), U" dB");
  51. Graphics_setColour (our graphics.get(), Graphics_BLACK);
  52. /* Update buttons. */
  53. integer first, last;
  54. integer selectedSamples = Sampled_getWindowSamples (spectrum, our startSelection, our endSelection, & first, & last);
  55. GuiThing_setSensitive (our publishBandButton, selectedSamples != 0);
  56. GuiThing_setSensitive (our publishSoundButton, selectedSamples != 0);
  57. }
  58. bool structSpectrumEditor :: v_click (double xWC, double yWC, bool shiftKeyPressed) {
  59. our cursorHeight = our minimum + yWC * (our maximum - our minimum);
  60. return our SpectrumEditor_Parent :: v_click (xWC, yWC, shiftKeyPressed); // move cursor or drag selection
  61. }
  62. static autoSpectrum Spectrum_band (Spectrum me, double fmin, double fmax) {
  63. autoSpectrum band = Data_copy (me);
  64. double *re = & band -> z [1] [0], *im = & band -> z [2] [0];
  65. integer imin = Sampled_xToLowIndex (band.get(), fmin);
  66. integer imax = Sampled_xToHighIndex (band.get(), fmax);
  67. for (integer i = 1; i <= imin; i ++) re [i] = 0.0, im [i] = 0.0;
  68. for (integer i = imax; i <= band -> nx; i ++) re [i] = 0.0, im [i] = 0.0;
  69. return band;
  70. }
  71. static autoSound Spectrum_to_Sound_part (Spectrum me, double fmin, double fmax) {
  72. autoSpectrum band = Spectrum_band (me, fmin, fmax);
  73. autoSound sound = Spectrum_to_Sound (band.get());
  74. return sound;
  75. }
  76. void structSpectrumEditor :: v_play (double fmin, double fmax) {
  77. autoSound sound = Spectrum_to_Sound_part ((Spectrum) our data, fmin, fmax);
  78. Sound_play (sound.get(), nullptr, nullptr);
  79. }
  80. static void menu_cb_publishBand (SpectrumEditor me, EDITOR_ARGS_DIRECT) {
  81. autoSpectrum publish = Spectrum_band ((Spectrum) my data, my startSelection, my endSelection);
  82. Editor_broadcastPublication (me, publish.move());
  83. }
  84. static void menu_cb_publishSound (SpectrumEditor me, EDITOR_ARGS_DIRECT) {
  85. autoSound publish = Spectrum_to_Sound_part ((Spectrum) my data, my startSelection, my endSelection);
  86. Editor_broadcastPublication (me, publish.move());
  87. }
  88. static void menu_cb_passBand (SpectrumEditor me, EDITOR_ARGS_FORM) {
  89. EDITOR_FORM (U"Filter (pass Hann band)", U"Spectrum: Filter (pass Hann band)...");
  90. REAL (bandSmoothing, U"Band smoothing (Hz)", my default_bandSmoothing ())
  91. EDITOR_OK
  92. SET_REAL (bandSmoothing, my p_bandSmoothing)
  93. EDITOR_DO
  94. my pref_bandSmoothing() = my p_bandSmoothing = bandSmoothing;
  95. if (my endSelection <= my startSelection) Melder_throw (U"To apply a band-pass filter, first make a selection.");
  96. Editor_save (me, U"Pass band");
  97. Spectrum_passHannBand ((Spectrum) my data, my startSelection, my endSelection, my p_bandSmoothing);
  98. FunctionEditor_redraw (me);
  99. Editor_broadcastDataChanged (me);
  100. EDITOR_END
  101. }
  102. static void menu_cb_stopBand (SpectrumEditor me, EDITOR_ARGS_FORM) {
  103. EDITOR_FORM (U"Filter (stop Hann band)", nullptr)
  104. REAL (bandSmoothing, U"Band smoothing (Hz)", my default_bandSmoothing ())
  105. EDITOR_OK
  106. SET_REAL (bandSmoothing, my p_bandSmoothing)
  107. EDITOR_DO
  108. my pref_bandSmoothing () = my p_bandSmoothing = bandSmoothing;
  109. if (my endSelection <= my startSelection) Melder_throw (U"To apply a band-stop filter, first make a selection.");
  110. Editor_save (me, U"Stop band");
  111. Spectrum_stopHannBand ((Spectrum) my data, my startSelection, my endSelection, my p_bandSmoothing);
  112. FunctionEditor_redraw (me);
  113. Editor_broadcastDataChanged (me);
  114. EDITOR_END
  115. }
  116. static void menu_cb_moveCursorToPeak (SpectrumEditor me, EDITOR_ARGS_DIRECT) {
  117. double frequencyOfMaximum, heightOfMaximum;
  118. Spectrum_getNearestMaximum ((Spectrum) my data, 0.5 * (my startSelection + my endSelection), & frequencyOfMaximum, & heightOfMaximum);
  119. my startSelection = my endSelection = frequencyOfMaximum;
  120. my cursorHeight = heightOfMaximum;
  121. FunctionEditor_marksChanged (me, true);
  122. }
  123. static void menu_cb_setDynamicRange (SpectrumEditor me, EDITOR_ARGS_FORM) {
  124. EDITOR_FORM (U"Set dynamic range", nullptr)
  125. POSITIVE (dynamicRange, U"Dynamic range (dB)", my default_dynamicRange ())
  126. EDITOR_OK
  127. SET_REAL (dynamicRange, my p_dynamicRange)
  128. EDITOR_DO
  129. my pref_dynamicRange () = my p_dynamicRange = dynamicRange;
  130. updateRange (me);
  131. FunctionEditor_redraw (me);
  132. EDITOR_END
  133. }
  134. static void menu_cb_help_SpectrumEditor (SpectrumEditor, EDITOR_ARGS_DIRECT) { Melder_help (U"SpectrumEditor"); }
  135. static void menu_cb_help_Spectrum (SpectrumEditor, EDITOR_ARGS_DIRECT) { Melder_help (U"Spectrum"); }
  136. void structSpectrumEditor :: v_createMenus () {
  137. SpectrumEditor_Parent :: v_createMenus ();
  138. our publishBandButton = Editor_addCommand (this, U"File", U"Publish band", 0, menu_cb_publishBand);
  139. our publishSoundButton = Editor_addCommand (this, U"File", U"Publish band-filtered sound", 0, menu_cb_publishSound);
  140. Editor_addCommand (this, U"File", U"-- close --", 0, nullptr);
  141. Editor_addCommand (this, U"Edit", U"-- edit band --", 0, nullptr);
  142. Editor_addCommand (this, U"Edit", U"Pass band...", 0, menu_cb_passBand);
  143. Editor_addCommand (this, U"Edit", U"Stop band...", 0, menu_cb_stopBand);
  144. Editor_addCommand (this, U"Select", U"-- move to peak --", 0, nullptr);
  145. Editor_addCommand (this, U"Select", U"Move cursor to nearest peak", 'K', menu_cb_moveCursorToPeak);
  146. }
  147. void structSpectrumEditor :: v_createMenuItems_view (EditorMenu menu) {
  148. EditorMenu_addCommand (menu, U"Set dynamic range...", 0, menu_cb_setDynamicRange);
  149. EditorMenu_addCommand (menu, U"-- view settings --", 0, 0);
  150. SpectrumEditor_Parent :: v_createMenuItems_view (menu);
  151. }
  152. void structSpectrumEditor :: v_createHelpMenuItems (EditorMenu menu) {
  153. SpectrumEditor_Parent :: v_createHelpMenuItems (menu);
  154. EditorMenu_addCommand (menu, U"SpectrumEditor help", '?', menu_cb_help_SpectrumEditor);
  155. EditorMenu_addCommand (menu, U"Spectrum help", 0, menu_cb_help_Spectrum);
  156. }
  157. autoSpectrumEditor SpectrumEditor_create (conststring32 title, Spectrum data) {
  158. try {
  159. autoSpectrumEditor me = Thing_new (SpectrumEditor);
  160. FunctionEditor_init (me.get(), title, data);
  161. my cursorHeight = -1000;
  162. updateRange (me.get());
  163. return me;
  164. } catch (MelderError) {
  165. Melder_throw (U"Spectrum window not created.");
  166. }
  167. }
  168. /* End of file SpectrumEditor.cpp */