Audacity  2.2.2
SpectralSelectionBar.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 SpectralSelectionBar.cpp
6 
7 Copyright 2014 Dominic Mazzoni
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 *******************************************************************//****************************************************************//*******************************************************************/
27 
28 
29 #include "../Audacity.h"
30 
31 #include <algorithm>
32 #include "../MemoryX.h"
33 
34 // For compilers that support precompilation, includes "wx/wx.h".
35 #include <wx/wxprec.h>
36 
37 #ifndef WX_PRECOMP
38 #include <wx/defs.h>
39 #include <wx/button.h>
40 #include <wx/checkbox.h>
41 #include <wx/combobox.h>
42 #include <wx/intl.h>
43 #include <wx/radiobut.h>
44 #include <wx/settings.h>
45 #include <wx/sizer.h>
46 #include <wx/valtext.h>
47 #include <wx/window.h>
48 #endif
49 #include <wx/statline.h>
50 
52 #include "SpectralSelectionBar.h"
53 
54 #include "../Prefs.h"
55 #include "../AllThemeResources.h"
56 #include "../SelectedRegion.h"
57 #include "../widgets/NumericTextCtrl.h"
58 
59 #include "../Experimental.h"
60 #include "../Internat.h"
61 
62 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
63 
65 
66 enum {
73 };
74 
75 BEGIN_EVENT_TABLE(SpectralSelectionBar, ToolBar)
76  EVT_SIZE(SpectralSelectionBar::OnSize)
77  EVT_TEXT(OnCenterID, SpectralSelectionBar::OnCtrl)
78  EVT_TEXT(OnWidthID, SpectralSelectionBar::OnCtrl)
79  EVT_TEXT(OnLowID, SpectralSelectionBar::OnCtrl)
80  EVT_TEXT(OnHighID, SpectralSelectionBar::OnCtrl)
81  EVT_CHOICE(OnChoiceID, SpectralSelectionBar::OnChoice)
82  EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, SpectralSelectionBar::OnUpdate)
83  EVT_COMMAND(wxID_ANY, EVT_BANDWIDTHTEXTCTRL_UPDATED, SpectralSelectionBar::OnUpdate)
85 
86 static const wxString preferencePath
87 (wxT("/GUI/Toolbars/SpectralSelection/CenterAndWidthChoice"));
88 
90 : ToolBar(SpectralSelectionBarID, _("Spectral Selection"), wxT("SpectralSelection"))
91 , mListener(NULL), mbCenterAndWidth(true)
92 , mCenter(0.0), mWidth(0.0), mLow(0.0), mHigh(0.0)
93 , mCenterCtrl(NULL), mWidthCtrl(NULL), mLowCtrl(NULL), mHighCtrl(NULL)
94 , mChoice(NULL)
95 {
96 }
97 
99 {
100  // Do nothing, sizer deletes the controls
101 }
102 
103 void SpectralSelectionBar::Create(wxWindow * parent)
104 {
105  ToolBar::Create(parent);
106  mHeight = wxWindowBase::GetSizer()->GetSize().GetHeight();
107 }
108 
110 {
111  SetBackgroundColour( theTheme.Colour( clrMedium ) );
112  gPrefs->Read(preferencePath, &mbCenterAndWidth, true);
113 
114  // This will be inherited by all children:
115  SetFont(wxFont(
116 #ifdef __WXMAC__
117  12
118 #else
119  9
120 #endif
121  ,
122  wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
123 
124  /* we don't actually need a control yet, but we want to use its methods
125  * to do some look-ups, so we'll have to create one. We can't make the
126  * look-ups static because they depend on translations which are done at
127  * runtime */
128 
129  wxString frequencyFormatName = mListener
131  : wxString(wxEmptyString);
132  wxString bandwidthFormatName = mListener
134  : wxString(wxEmptyString);
135 
136  wxFlexGridSizer *mainSizer;
137  Add((mainSizer = safenew wxFlexGridSizer(1, 1, 1)), 0,wxALIGN_TOP | wxLEFT | wxTOP, 5);
138 
139  //
140  // Top row, choice box
141  //
142 
143  const wxString choices[2] = {
144  _("Center frequency and Width"),
145  _("Low and High Frequencies"),
146  };
147  mChoice = safenew wxChoice
148  (this, OnChoiceID, wxDefaultPosition, wxDefaultSize, 2, choices,
149  0, wxDefaultValidator, _("Spectral Selection"));
150  mChoice->SetSelection(mbCenterAndWidth ? 0 : 1);
151 #ifdef __WXGTK__
152  // Combo boxes are taller on Linux, and if we don't do the following, the selection toolbar will
153  // be three units high.
154  wxSize sz = mChoice->GetBestSize();
155  sz.SetHeight( sz.y-4);
156  mChoice->SetMinSize( sz );
157 #endif
158 
159  mainSizer->Add(mChoice, 0, wxALIGN_TOP | wxEXPAND |wxRIGHT, 6);
160 
161  //
162  // Bottom row, split into two columns, each with one control
163  //
164 
165  {
166  auto subSizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
167 
169  this, OnCenterID,
170  NumericConverter::FREQUENCY, frequencyFormatName, 0.0, 44100.0,
173  );
174  mCenterCtrl->SetName(_("Center Frequency:"));
175  subSizer->Add(mCenterCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
176 
178  this, OnWidthID,
179  NumericConverter::BANDWIDTH, bandwidthFormatName, 0.0, 44100.0,
181  .InvalidValue( true, -1.0 )
182  );
183  mWidthCtrl->SetName(wxString(_("Bandwidth:")));
184  subSizer->Add(mWidthCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
185 
187  this, OnLowID,
188  NumericConverter::FREQUENCY, frequencyFormatName, 0.0, 44100.0,
191  );
192  mLowCtrl->SetName(_("Low Frequency:"));
193  subSizer->Add(mLowCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
194 
196  this, OnHighID,
197  NumericConverter::FREQUENCY, frequencyFormatName, 0.0, 44100.0,
200  );
201  mHighCtrl->SetName(wxString(_("High Frequency:")));
202  subSizer->Add(mHighCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
203 
204  mCenterCtrl->Show(mbCenterAndWidth);
206  mLowCtrl->Show(!mbCenterAndWidth);
207  mHighCtrl->Show(!mbCenterAndWidth);
208 
209  mainSizer->Add(subSizer.release(), 0, wxALIGN_CENTER_VERTICAL, 0);
210  }
211 
212  mainSizer->Layout();
213 
214  Layout();
215 
216  SetMinSize(GetSizer()->GetMinSize());
217 }
218 
220 {
221  {
222  wxCommandEvent e(EVT_FREQUENCYTEXTCTRL_UPDATED);
223  e.SetInt((mbCenterAndWidth? mCenterCtrl : mLowCtrl)->GetFormatIndex());
224  OnUpdate(e);
225  }
226 
227  if (mbCenterAndWidth)
228  {
229  wxCommandEvent e(EVT_BANDWIDTHTEXTCTRL_UPDATED);
230  e.SetInt(mWidthCtrl->GetFormatIndex());
231  OnUpdate(e);
232  }
233 
234  // Set label to pull in language change
235  SetLabel(_("Spectral Selection"));
236 
238 
239  // Give base class a chance
241 }
242 
244 {
245  mListener = l;
248 };
249 
250 void SpectralSelectionBar::OnSize(wxSizeEvent &evt)
251 {
252  Refresh(true);
253 
254  evt.Skip();
255 }
256 
258 {
259  const double nyq = mListener->SSBL_GetRate() / 2.0;
260 
261  double bottom, top;
262  if (mbCenterAndWidth) {
265  if ((mCenter < 0 || mWidth < 0) &&
266  (mLow >= 0 || mHigh >= 0))
267  // Transition from defined spectral selection to undefined
268  bottom = top = SelectedRegion::UndefinedFrequency;
269  else if (mCenter < 0 && mWidth < 0)
270  bottom = top = SelectedRegion::UndefinedFrequency;
271  else {
272  if (mCenter < 0) {
273  mWidth = log(std::min(nyq, exp(mWidth)));
274  // Choose arbitrary center for the width
275  mCenter = sqrt(nyq);
276  }
277  else if (mWidth < 0) {
278  mCenter = std::max(1.0, std::min(nyq, mCenter));
279  // Choose arbitrary width for the center
280  const double ratio = std::min(mCenter, nyq / mCenter);
281  mWidth = log(ratio * ratio);
282  }
283  else {
284  mCenter = std::max(1.0, std::min(nyq, mCenter));
285  double ratio = std::min(mCenter, nyq / mCenter);
286  mWidth = std::min(2 * log(ratio), mWidth);
287  }
288 
289  const double ratio = exp(mWidth / 2);
290  bottom = mCenter / ratio, top = mCenter * ratio;
291  }
292  }
293  else {
294  bottom = mLowCtrl->GetValue();
295  top = mHighCtrl->GetValue();
296 
297  if (bottom >= 0)
298  bottom = std::min(nyq, bottom);
299  else
301 
302  if (top >= 0)
303  top = std::min(nyq, top);
304  else
306  }
307 
308  mLow = bottom;
309  mHigh = top;
310  SetBounds();
311 
312  // Notify project and track panel, which may change
313  // the values again, and call back to us in SetFrequencies()
314  mListener->SSBL_ModifySpectralSelection(bottom, top, done);
315 }
316 
317 void SpectralSelectionBar::OnCtrl(wxCommandEvent & event)
318 {
319  ModifySpectralSelection(event.GetInt() != 0);
320 }
321 
322 void SpectralSelectionBar::OnChoice(wxCommandEvent &)
323 {
324  mbCenterAndWidth = (0 == mChoice->GetSelection());
326  gPrefs->Flush();
327 
330  mLowCtrl->Show(!mbCenterAndWidth);
331  mHighCtrl->Show(!mbCenterAndWidth);
332 
334  GetSizer()->Layout(); // Required so that the layout does not mess up on Windows when changing the format.
335  wxWindowBase::GetSizer()->SetMinSize(wxSize(0, mHeight)); // so that height of toolbar does not change
336  wxWindowBase::GetSizer()->SetSizeHints(this);
337  Updated();
338 }
339 
340 void SpectralSelectionBar::OnUpdate(wxCommandEvent &evt)
341 {
342  int index = evt.GetInt();
343  wxWindow *w = FindFocus();
344  bool centerFocus = (w && w == mCenterCtrl);
345  bool widthFocus = (w && w == mWidthCtrl);
346  bool lowFocus = (w && w == mLowCtrl);
347  bool highFocus = (w && w == mHighCtrl);
348 
349  evt.Skip(false);
350 
351  // Save formats before recreating the controls so they resize properly
352  wxEventType type = evt.GetEventType();
353  if (type == EVT_FREQUENCYTEXTCTRL_UPDATED) {
354  NumericTextCtrl *frequencyCtrl = (mbCenterAndWidth ? mCenterCtrl : mLowCtrl);
355  wxString frequencyFormatName = frequencyCtrl->GetBuiltinName(index);
356  mListener->SSBL_SetFrequencySelectionFormatName(frequencyFormatName);
357  }
358  else if (mbCenterAndWidth &&
359  type == EVT_BANDWIDTHTEXTCTRL_UPDATED) {
360  wxString bandwidthFormatName = mWidthCtrl->GetBuiltinName(index);
361  mListener->SSBL_SetBandwidthSelectionFormatName(bandwidthFormatName);
362  }
363 
364  // ToolBar::ReCreateButtons() will get rid of our sizers and controls
365  // so reset pointers first.
366  mCenterCtrl = mWidthCtrl = NULL;
367  mLowCtrl = mHighCtrl = NULL;
368 
371 
372 
373  if (centerFocus) {
374  mCenterCtrl->SetFocus();
375  }
376  else if (widthFocus) {
377  mWidthCtrl->SetFocus();
378  }
379  else if (lowFocus) {
380  mLowCtrl->SetFocus();
381  }
382  else if (highFocus) {
383  mHighCtrl->SetFocus();
384  }
385 
386  Updated();
387 }
388 
390 {
391  if (mbCenterAndWidth) {
394  }
395  else {
396  //Bug 1633
397  //The controls may not be able to show mHigh, e.g.
398  //if set to Hz, and in that case we should either show invalid
399  //or 'do the best we can' and truncate.
400  //If we set bounds we instead clip to the mHigh to mLow,
401  //So no SetBounds, for now.
402  //SetBounds();
405  }
406 }
407 
409 {
410  if (mHigh >= 0)
412  else
414 
415  if (mLow >= 0)
417  else
419 }
420 
421 void SpectralSelectionBar::SetFrequencies(double bottom, double top)
422 {
423  mLow = bottom;
424  mHigh = top;
425 
426  if (bottom > 0 && top >= bottom)
427  mWidth = log(top / bottom), mCenter = sqrt(top * bottom);
428  else
429  mWidth = mCenter = -1.0;
430 
432 }
433 
435 {
436  NumericTextCtrl *frequencyCtrl = (mbCenterAndWidth ? mCenterCtrl : mLowCtrl);
437  frequencyCtrl->SetFormatName(formatName);
438 
439  wxCommandEvent e(EVT_FREQUENCYTEXTCTRL_UPDATED);
440  e.SetInt(frequencyCtrl->GetFormatIndex());
441  OnUpdate(e);
442 }
443 
445 {
446  if (mbCenterAndWidth) {
447  mWidthCtrl->SetFormatName(formatName);
448 
449  wxCommandEvent e(EVT_BANDWIDTHTEXTCTRL_UPDATED);
450  e.SetInt(mWidthCtrl->GetFormatIndex());
451  OnUpdate(e);
452  }
453 }
454 
455 #endif // #ifdef EXPERIMENTAL_SPECTRAL_EDITING
virtual void SSBL_SetBandwidthSelectionFormatName(const wxString &formatName)=0
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
Options & InvalidValue(bool has, double value=-1.0)
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:88
virtual void UpdatePrefs()
Definition: ToolBar.cpp:540
virtual double SSBL_GetRate() const =0
virtual void SSBL_ModifySpectralSelection(double &bottom, double &top, bool done)=0
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:608
void SetFormatName(const wxString &formatName)
virtual void ReCreateButtons()
Definition: ToolBar.cpp:464
void SetListener(SpectralSelectionBarListener *l)
virtual const wxString & SSBL_GetFrequencySelectionFormatName()=0
void OnCtrl(wxCommandEvent &evt)
static const wxString preferencePath(wxT("/GUI/Toolbars/SpectralSelection/CenterAndWidthChoice"))
NumericTextCtrl * mCenterCtrl
NumericTextCtrl * mHighCtrl
virtual const wxString & SSBL_GetBandwidthSelectionFormatName()=0
#define safenew
Definition: Audacity.h:223
void SetMaxValue(double maxValue)
NumericTextCtrl * mWidthCtrl
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
(not quite a Toolbar) at foot of screen for setting and viewing the frequency selection range...
void SetFrequencySelectionFormatName(const wxString &formatName)
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:616
virtual void Create(wxWindow *parent)
Definition: ToolBar.cpp:443
int min(int a, int b)
void SetFrequencies(double bottom, double top)
void SetValue(double newValue)
void OnUpdate(wxCommandEvent &evt)
void Updated()
Definition: ToolBar.cpp:597
void SetMinValue(double minValue)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
void RegenerateTooltips() override
void SetLabel(const wxString &label)
Definition: ToolBar.cpp:379
bool Layout() override
void Create(wxWindow *parent) override
virtual void SSBL_SetFrequencySelectionFormatName(const wxString &formatName)=0
wxString GetBuiltinName(const int index)
NumericTextCtrl * mLowCtrl
void SetBandwidthSelectionFormatName(const wxString &formatName)
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1208
A class used to forward events to do with changes in the SpectralSelectionBar.
END_EVENT_TABLE()
void ModifySpectralSelection(bool done=false)
void OnChoice(wxCommandEvent &evt)
void OnSize(wxSizeEvent &evt)
static const int UndefinedFrequency
IMPLEMENT_CLASS(SpectralSelectionBar, ToolBar)
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed...
Definition: ToolBar.h:87
SpectralSelectionBarListener * mListener