Audacity  2.2.2
WaveTrackControls.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 WaveTrackControls.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 #include "../../../../Audacity.h"
12 #include "../../../../Experimental.h"
13 #include "WaveTrackControls.h"
14 #include "../../ui/PlayableTrackButtonHandles.h"
15 #include "WaveTrackSliderHandles.h"
16 
17 #include "../../../../AudioIO.h"
18 #include "../../../../HitTestResult.h"
19 #include "../../../../MixerBoard.h"
20 #include "../../../../Project.h"
21 #include "../../../../RefreshCode.h"
22 #include "../../../../WaveTrack.h"
23 #include "../../../../ShuttleGui.h"
24 #include "../../../../TrackPanel.h"
25 #include "../../../../TrackPanelMouseEvent.h"
26 #include "../../../../widgets/PopupMenuTable.h"
27 #include "../../../../ondemand/ODManager.h"
28 #include "../../../../prefs/PrefsDialog.h"
29 #include "../../../../prefs/SpectrumPrefs.h"
30 #include "../../../../prefs/TracksBehaviorsPrefs.h"
31 #include "../../../../prefs/WaveformPrefs.h"
32 #include "../../../../widgets/ErrorDialog.h"
33 
34 #include <wx/combobox.h>
35 
36 namespace
37 {
39  template<typename Pred>
40  void SetMenuChecks(wxMenu & menu, const Pred &pred)
41  {
42  for (auto &item : menu.GetMenuItems())
43  {
44  if (item->IsCheckable()) {
45  auto id = item->GetId();
46  menu.Check(id, pred(id));
47  }
48  }
49  }
50 }
51 
53 {
54 }
55 
56 
57 std::vector<UIHandlePtr> WaveTrackControls::HitTest
59  const AudacityProject *pProject)
60 {
61  // Hits are mutually exclusive, results single
62  const wxMouseState &state = st.state;
63  const wxRect &rect = st.rect;
64  if (state.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
65  auto track = FindTrack();
66  std::vector<UIHandlePtr> results;
67  auto result = [&]{
68  UIHandlePtr result;
69  if (NULL != (result = MuteButtonHandle::HitTest(
70  mMuteHandle, state, rect, pProject, track)))
71  return result;
72 
73  if (NULL != (result = SoloButtonHandle::HitTest(
74  mSoloHandle, state, rect, pProject, track)))
75  return result;
76 
77  if (NULL != (result = GainSliderHandle::HitTest(
78  mGainHandle, state, rect, track)))
79  return result;
80 
81  if (NULL != (result = PanSliderHandle::HitTest(
82  mPanHandle, state, rect, track)))
83  return result;
84 
85  return result;
86  }();
87  if (result) {
88  results.push_back(result);
89  return results;
90  }
91  }
92 
93  return TrackControls::HitTest(st, pProject);
94 }
95 
96 enum {
97  OnRate8ID = 30000, // <---
98  OnRate11ID, // |
99  OnRate16ID, // |
102  OnRate48ID, // | Leave these in order
110  // |
111  On16BitID, // |
112  On24BitID, // |
113  OnFloatID, // <---
114 
119 
123 
130 
134 
136 };
137 
138 
139 //=============================================================================
140 // Table class for a sub-menu
142 {
145 
146 public:
147  static WaveColorMenuTable &Instance();
148 
149 private:
150  void InitMenu(Menu *pMenu, void *pUserData) override;
151 
152  void DestroyMenu() override
153  {
154  mpData = NULL;
155  }
156 
158 
159  int IdOfWaveColor(int WaveColor);
160  void OnWaveColorChange(wxCommandEvent & event);
161 };
162 
164 {
165  static WaveColorMenuTable instance;
166  return instance;
167 }
168 
169 void WaveColorMenuTable::InitMenu(Menu *pMenu, void *pUserData)
170 {
171  mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
172  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
173  auto WaveColorId = IdOfWaveColor( pTrack->GetWaveColorIndex());
174  SetMenuChecks(*pMenu, [=](int id){ return id == WaveColorId; });
175 
176  AudacityProject *const project = ::GetActiveProject();
177  bool unsafe = project->IsAudioActive();
178  for (int i = OnInstrument1ID; i <= OnInstrument4ID; i++) {
179  pMenu->Enable(i, !unsafe);
180  }
181 }
182 
183 const wxString GetWaveColorStr(int colorIndex)
184 {
185  return wxString::Format( _("Instrument %i"), colorIndex+1 );
186 }
187 
188 
191  GetWaveColorStr(0), OnWaveColorChange)
193  GetWaveColorStr(1), OnWaveColorChange)
195  GetWaveColorStr(2), OnWaveColorChange)
197  GetWaveColorStr(3), OnWaveColorChange)
199 
201 int WaveColorMenuTable::IdOfWaveColor(int WaveColor)
202 { return OnInstrument1ID + WaveColor;}
203 
206 void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
207 {
208  int id = event.GetId();
209  wxASSERT(id >= OnInstrument1ID && id <= OnInstrument4ID);
210  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
211  wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
212 
213  int newWaveColor = id - OnInstrument1ID;
214 
215  AudacityProject *const project = ::GetActiveProject();
216 // TrackList *const tracks = project->GetTracks();
217 
218  pTrack->SetWaveColorIndex(newWaveColor);
219 
220  // Assume partner is wave or null
221  const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
222  if (partner)
223  partner->SetWaveColorIndex(newWaveColor);
224 
225  project->PushState(wxString::Format(_("Changed '%s' to %s"),
226  pTrack->GetName(),
227  GetWaveColorStr(newWaveColor)),
228  _("WaveColor Change"));
229 
230  using namespace RefreshCode;
232 }
233 
234 
235 
236 
237 //=============================================================================
238 // Table class for a sub-menu
240 {
241  FormatMenuTable() : mpData(NULL) {}
243 
244 public:
245  static FormatMenuTable &Instance();
246 
247 private:
248  void InitMenu(Menu *pMenu, void *pUserData) override;
249 
250  void DestroyMenu() override
251  {
252  mpData = NULL;
253  }
254 
256 
257  int IdOfFormat(int format);
258 
259  void OnFormatChange(wxCommandEvent & event);
260 };
261 
263 {
264  static FormatMenuTable instance;
265  return instance;
266 }
267 
268 void FormatMenuTable::InitMenu(Menu *pMenu, void *pUserData)
269 {
270  mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
271  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
272  auto formatId = IdOfFormat(pTrack->GetSampleFormat());
273  SetMenuChecks(*pMenu, [=](int id){ return id == formatId; });
274 
275  AudacityProject *const project = ::GetActiveProject();
276  bool unsafe = project->IsAudioActive();
277  for (int i = On16BitID; i <= OnFloatID; i++) {
278  pMenu->Enable(i, !unsafe);
279  }
280 }
281 
284  GetSampleFormatStr(int16Sample), OnFormatChange)
286  GetSampleFormatStr(int24Sample), OnFormatChange)
288  GetSampleFormatStr(floatSample), OnFormatChange)
290 
292 int FormatMenuTable::IdOfFormat(int format)
293 {
294  switch (format) {
295  case int16Sample:
296  return On16BitID;
297  case int24Sample:
298  return On24BitID;
299  case floatSample:
300  return OnFloatID;
301  default:
302  // ERROR -- should not happen
303  wxASSERT(false);
304  break;
305  }
306  return OnFloatID;// Compiler food.
307 }
308 
311 void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
312 {
313  int id = event.GetId();
314  wxASSERT(id >= On16BitID && id <= OnFloatID);
315  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
316  wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
317 
318  sampleFormat newFormat = int16Sample;
319 
320  switch (id) {
321  case On16BitID:
322  newFormat = int16Sample;
323  break;
324  case On24BitID:
325  newFormat = int24Sample;
326  break;
327  case OnFloatID:
328  newFormat = floatSample;
329  break;
330  default:
331  // ERROR -- should not happen
332  wxASSERT(false);
333  break;
334  }
335  if (newFormat == pTrack->GetSampleFormat())
336  return; // Nothing to do.
337 
338  AudacityProject *const project = ::GetActiveProject();
339  pTrack->ConvertToSampleFormat(newFormat);
340 
341  // Assume partner is wave or null
342  const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
343  if (partner)
344  partner->ConvertToSampleFormat(newFormat);
345 
346  /* i18n-hint: The strings name a track and a format */
347  project->PushState(wxString::Format(_("Changed '%s' to %s"),
348  pTrack->GetName(),
349  GetSampleFormatStr(newFormat)),
350  _("Format Change"));
351 
352  using namespace RefreshCode;
354 }
355 
356 
357 //=============================================================================
358 // Table class for a sub-menu
360 {
361  RateMenuTable() : mpData(NULL) {}
363 
364 public:
365  static RateMenuTable &Instance();
366 
367 private:
368  void InitMenu(Menu *pMenu, void *pUserData) override;
369 
370  void DestroyMenu() override
371  {
372  mpData = NULL;
373  }
374 
376 
377  int IdOfRate(int rate);
378  void SetRate(WaveTrack * pTrack, double rate);
379 
380  void OnRateChange(wxCommandEvent & event);
381  void OnRateOther(wxCommandEvent & event);
382 };
383 
385 {
386  static RateMenuTable instance;
387  return instance;
388 }
389 
390 void RateMenuTable::InitMenu(Menu *pMenu, void *pUserData)
391 {
392  mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
393  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
394  const auto rateId = IdOfRate((int)pTrack->GetRate());
395  SetMenuChecks(*pMenu, [=](int id){ return id == rateId; });
396 
397  AudacityProject *const project = ::GetActiveProject();
398  bool unsafe = project->IsAudioActive();
399  for (int i = OnRate8ID; i <= OnRateOtherID; i++) {
400  pMenu->Enable(i, !unsafe);
401  }
402 }
403 
405  POPUP_MENU_RADIO_ITEM(OnRate8ID, _("8000 Hz"), OnRateChange)
406  POPUP_MENU_RADIO_ITEM(OnRate11ID, _("11025 Hz"), OnRateChange)
407  POPUP_MENU_RADIO_ITEM(OnRate16ID, _("16000 Hz"), OnRateChange)
408  POPUP_MENU_RADIO_ITEM(OnRate22ID, _("22050 Hz"), OnRateChange)
409  POPUP_MENU_RADIO_ITEM(OnRate44ID, _("44100 Hz"), OnRateChange)
410  POPUP_MENU_RADIO_ITEM(OnRate48ID, _("48000 Hz"), OnRateChange)
411  POPUP_MENU_RADIO_ITEM(OnRate88ID, _("88200 Hz"), OnRateChange)
412  POPUP_MENU_RADIO_ITEM(OnRate96ID, _("96000 Hz"), OnRateChange)
413  POPUP_MENU_RADIO_ITEM(OnRate176ID, _("176400 Hz"), OnRateChange)
414  POPUP_MENU_RADIO_ITEM(OnRate192ID, _("192000 Hz"), OnRateChange)
415  POPUP_MENU_RADIO_ITEM(OnRate352ID, _("352800 Hz"), OnRateChange)
416  POPUP_MENU_RADIO_ITEM(OnRate384ID, _("384000 Hz"), OnRateChange)
417  POPUP_MENU_RADIO_ITEM(OnRateOtherID, _("&Other..."), OnRateOther)
419 
420 const int nRates = 12;
421 
424 static int gRates[nRates] = { 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000,
425 176400, 192000, 352800, 384000 };
426 
429 {
430  for (int i = 0; i<nRates; i++) {
431  if (gRates[i] == rate)
432  return i + OnRate8ID;
433  }
434  return OnRateOtherID;
435 }
436 
439 void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
440 {
441  AudacityProject *const project = ::GetActiveProject();
442  pTrack->SetRate(rate);
443  // Assume linked track is wave or null
444  const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
445  if (partner)
446  partner->SetRate(rate);
447  // Separate conversion of "rate" enables changing the decimals without affecting i18n
448  wxString rateString = wxString::Format(wxT("%.3f"), rate);
449  /* i18n-hint: The string names a track */
450  project->PushState(wxString::Format(_("Changed '%s' to %s Hz"),
451  pTrack->GetName(), rateString),
452  _("Rate Change"));
453 }
454 
457 void RateMenuTable::OnRateChange(wxCommandEvent & event)
458 {
459  int id = event.GetId();
460  wxASSERT(id >= OnRate8ID && id <= OnRate384ID);
461  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
462  wxASSERT(pTrack->GetKind() == Track::Wave);
463 
464  SetRate(pTrack, gRates[id - OnRate8ID]);
465 
466  using namespace RefreshCode;
468 }
469 
470 void RateMenuTable::OnRateOther(wxCommandEvent &)
471 {
472  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
473  wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
474 
475  int newRate;
476 
479  while (true)
480  {
481  wxDialogWrapper dlg(mpData->pParent, wxID_ANY, wxString(_("Set Rate")));
482  dlg.SetName(dlg.GetTitle());
483  ShuttleGui S(&dlg, eIsCreating);
484  wxString rate;
485  wxArrayString rates;
486  wxComboBox *cb;
487 
488  rate.Printf(wxT("%ld"), lrint(pTrack->GetRate()));
489 
490  rates.Add(wxT("8000"));
491  rates.Add(wxT("11025"));
492  rates.Add(wxT("16000"));
493  rates.Add(wxT("22050"));
494  rates.Add(wxT("44100"));
495  rates.Add(wxT("48000"));
496  rates.Add(wxT("88200"));
497  rates.Add(wxT("96000"));
498  rates.Add(wxT("176400"));
499  rates.Add(wxT("192000"));
500  rates.Add(wxT("352800"));
501  rates.Add(wxT("384000"));
502 
503  S.StartVerticalLay(true);
504  {
505  S.SetBorder(10);
506  S.StartHorizontalLay(wxEXPAND, false);
507  {
508  cb = S.AddCombo(_("New sample rate (Hz):"),
509  rate,
510  &rates);
511 #if defined(__WXMAC__)
512  // As of wxMac-2.8.12, setting manually is required
513  // to handle rates not in the list. See: Bug #427
514  cb->SetValue(rate);
515 #endif
516  }
517  S.EndHorizontalLay();
518  S.AddStandardButtons();
519  }
520  S.EndVerticalLay();
521 
522  dlg.SetClientSize(dlg.GetSizer()->CalcMin());
523  dlg.Center();
524 
525  if (dlg.ShowModal() != wxID_OK)
526  {
527  return; // user cancelled dialog
528  }
529 
530  long lrate;
531  if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000)
532  {
533  newRate = (int)lrate;
534  break;
535  }
536 
537  AudacityMessageBox(_("The entered value is invalid"), _("Error"),
538  wxICON_ERROR, mpData->pParent);
539  }
540 
541  SetRate(pTrack, newRate);
542 
543  using namespace RefreshCode;
545 }
546 
547 //=============================================================================
548 // Class defining common command handlers for mono and stereo tracks
550 {
551 public:
552  static WaveTrackMenuTable &Instance( Track * pTrack);
554 
555 protected:
556  WaveTrackMenuTable() : mpData(NULL) {mpTrack=NULL;}
557 
558  void InitMenu(Menu *pMenu, void *pUserData) override;
559 
560  void DestroyMenu() override
561  {
562  mpData = nullptr;
563  }
564 
566 
568 
569  void OnSetDisplay(wxCommandEvent & event);
570  void OnSpectrogramSettings(wxCommandEvent & event);
571 
572  void OnChannelChange(wxCommandEvent & event);
573  void OnMergeStereo(wxCommandEvent & event);
574 
575  void SplitStereo(bool stereo);
576 
577  void OnSwapChannels(wxCommandEvent & event);
578  void OnSplitStereo(wxCommandEvent & event);
579  void OnSplitStereoMono(wxCommandEvent & event);
580 };
581 
583 {
584  static WaveTrackMenuTable instance;
585  wxCommandEvent evt;
586  // Clear it out so we force a repopulate
587  instance.Invalidate( evt );
588  // Ensure we know how to poulate.
589  // Messy, but the design does not seem to offer an alternative.
590  // We won't use pTrack after populate.
591  instance.mpTrack = pTrack;
592  return instance;
593 }
594 
595 void WaveTrackMenuTable::InitMenu(Menu *pMenu, void *pUserData)
596 {
597  mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
598  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
599 
600  std::vector<int> checkedIds;
601 
602  const int display = pTrack->GetDisplay();
603  checkedIds.push_back(
604  display == WaveTrack::Waveform
605  ? (pTrack->GetWaveformSettings().isLinear()
607  : OnSpectrumID);
608 
609  // Bug 1253. Shouldn't open preferences if audio is busy.
610  // We can't change them on the fly yet anyway.
611  const bool bAudioBusy = gAudioIO->IsBusy();
612  pMenu->Enable(OnSpectrogramSettingsID,
613  (display == WaveTrack::Spectrum) && !bAudioBusy);
614 
615  AudacityProject *const project = ::GetActiveProject();
616  bool unsafe = EffectManager::Get().RealtimeIsActive() &&
617  project->IsAudioActive();
618 
619  const bool isMono = !pTrack->GetLink();
620  if ( isMono )
621  {
622  mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
623  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
624 
625  TrackList *const tracks = project->GetTracks();
626  Track *const next = tracks->GetNext(pTrack);
627 
628  if (isMono) {
629  const bool canMakeStereo =
630  (next && !next->GetLinked()
631  && pTrack->GetKind() == Track::Wave
632  && next->GetKind() == Track::Wave);
633  pMenu->Enable(OnMergeStereoID, canMakeStereo && !unsafe);
634 
635  int itemId;
636  switch (pTrack->GetChannel()) {
637  case Track::LeftChannel:
638  itemId = OnChannelLeftID;
639  break;
640  case Track::RightChannel:
641  itemId = OnChannelRightID;
642  break;
643  default:
644  itemId = OnChannelMonoID;
645  break;
646  }
647  checkedIds.push_back(itemId);
648  }
649  }
650  else
651  {
652  pMenu->Enable(OnMergeStereoID, false);
653  }
654 
655  SetMenuChecks(*pMenu, [&](int id){
656  auto end = checkedIds.end();
657  return end != std::find(checkedIds.begin(), end, id);
658  });
659 
660 
661  pMenu->Enable(OnSwapChannelsID, !isMono && !unsafe);
662  pMenu->Enable(OnSplitStereoID, !isMono && !unsafe);
663 
664 #ifndef EXPERIMENTAL_DA
665  // Can be achieved by split stereo and then dragging pan slider.
666  pMenu->Enable(OnSplitStereoMonoID, !isMono && !unsafe);
667 #endif
668 
669  // Several menu items no longer needed....
670 #if 0
671  pMenu->Enable(OnChannelMonoID, isMono);
672  pMenu->Enable(OnChannelLeftID, isMono);
673  pMenu->Enable(OnChannelRightID, isMono);
674 #endif
675 }
676 
679 
680  POPUP_MENU_RADIO_ITEM(OnWaveformID, _("Wa&veform"), OnSetDisplay)
681  POPUP_MENU_RADIO_ITEM(OnWaveformDBID, _("&Waveform (dB)"), OnSetDisplay)
682  POPUP_MENU_RADIO_ITEM(OnSpectrumID, _("&Spectrogram"), OnSetDisplay)
683  POPUP_MENU_ITEM(OnSpectrogramSettingsID, _("S&pectrogram Settings..."), OnSpectrogramSettings)
685 
686 // POPUP_MENU_RADIO_ITEM(OnChannelMonoID, _("&Mono"), OnChannelChange)
687 // POPUP_MENU_RADIO_ITEM(OnChannelLeftID, _("&Left Channel"), OnChannelChange)
688 // POPUP_MENU_RADIO_ITEM(OnChannelRightID, _("R&ight Channel"), OnChannelChange)
689  POPUP_MENU_ITEM(OnMergeStereoID, _("Ma&ke Stereo Track"), OnMergeStereo)
690 
691  POPUP_MENU_ITEM(OnSwapChannelsID, _("Swap Stereo &Channels"), OnSwapChannels)
692  POPUP_MENU_ITEM(OnSplitStereoID, _("Spl&it Stereo Track"), OnSplitStereo)
693 // DA: Uses split stereo track and then drag pan sliders for split-stereo-to-mono
694 #ifndef EXPERIMENTAL_DA
695  POPUP_MENU_ITEM(OnSplitStereoMonoID, _("Split Stereo to Mo&no"), OnSplitStereoMono)
696 #endif
697 
698  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpTrack);
699  if( pTrack && pTrack->GetDisplay() != WaveTrack::Spectrum ){
702  }
703 
707  POPUP_MENU_SUB_MENU(0, _("Rat&e"), RateMenuTable)
709 
710 
712 void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
713 {
714  int idInt = event.GetId();
715  wxASSERT(idInt >= OnWaveformID && idInt <= OnSpectrumID);
716  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
717  wxASSERT(pTrack && pTrack->GetKind() == Track::Wave);
718 
719  bool linear = false;
721  switch (idInt) {
722  default:
723  case OnWaveformID:
724  linear = true, id = WaveTrack::Waveform; break;
725  case OnWaveformDBID:
726  id = WaveTrack::Waveform; break;
727  case OnSpectrumID:
728  id = WaveTrack::Spectrum; break;
729  }
730 
731  const bool wrongType = pTrack->GetDisplay() != id;
732  const bool wrongScale =
733  (id == WaveTrack::Waveform &&
734  pTrack->GetWaveformSettings().isLinear() != linear);
735  if (wrongType || wrongScale) {
736  pTrack->SetLastScaleType();
738  if (wrongScale)
739  pTrack->GetIndependentWaveformSettings().scaleType = linear
742 
743  // Assume partner is wave or null
744  auto partner = static_cast<WaveTrack *>(pTrack->GetLink());
745  if (partner) {
746  partner->SetLastScaleType();
747  partner->SetDisplay(WaveTrack::WaveTrackDisplay(id));
748  if (wrongScale)
749  partner->GetIndependentWaveformSettings().scaleType = linear
752  }
753 
754  AudacityProject *const project = ::GetActiveProject();
755  project->ModifyState(true);
756 
757  using namespace RefreshCode;
759  }
760 }
761 
763 {
764  class ViewSettingsDialog final : public PrefsDialog
765  {
766  public:
767  ViewSettingsDialog
768  (wxWindow *parent, const wxString &title, PrefsDialog::Factories &factories,
769  int page)
770  : PrefsDialog(parent, title, factories)
771  , mPage(page)
772  {
773  }
774 
775  long GetPreferredPage() override
776  {
777  return mPage;
778  }
779 
780  void SavePreferredPage() override
781  {
782  }
783 
784  private:
785  const int mPage;
786  };
787 
788  if (gAudioIO->IsBusy()){
789  AudacityMessageBox(_("To change Spectrogram Settings, stop any\n"
790  "playing or recording first."),
791  _("Stop the Audio First"), wxOK | wxICON_EXCLAMATION | wxCENTRE);
792  return;
793  }
794 
795  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
796  // WaveformPrefsFactory waveformFactory(pTrack);
797  // TracksBehaviorsPrefsFactory tracksBehaviorsFactory();
798  SpectrumPrefsFactory spectrumFactory(pTrack);
799 
800  PrefsDialog::Factories factories;
801  // factories.push_back(&waveformFactory);
802  factories.push_back(&spectrumFactory);
803  const int page =
804  // (pTrack->GetDisplay() == WaveTrack::Spectrum) ? 1 :
805  0;
806 
807  wxString title(pTrack->GetName() + wxT(": "));
808  ViewSettingsDialog dialog(mpData->pParent, title, factories, page);
809 
810  if (0 != dialog.ShowModal()) {
811  // Redraw
812  AudacityProject *const project = ::GetActiveProject();
813  project->ModifyState(true);
814  //Bug 1725 Toolbar was left greyed out.
815  //This solution is overkill, but does fix the problem and is what the
816  //prefs dialog normally does.
819  }
820 }
821 
822 void WaveTrackMenuTable::OnChannelChange(wxCommandEvent & event)
823 {
824  int id = event.GetId();
825  wxASSERT(id >= OnChannelLeftID && id <= OnChannelMonoID);
826  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
827  wxASSERT(pTrack);
828  int channel;
829  wxString channelmsg;
830  switch (id) {
831  default:
832  case OnChannelMonoID:
833  channel = Track::MonoChannel;
834  channelmsg = _("Mono");
835  break;
836  case OnChannelLeftID:
837  channel = Track::LeftChannel;
838  channelmsg = _("Left Channel");
839  break;
840  case OnChannelRightID:
841  channel = Track::RightChannel;
842  channelmsg = _("Right Channel");
843  break;
844  }
845  pTrack->SetChannel(channel);
846  AudacityProject *const project = ::GetActiveProject();
847  /* i18n-hint: The strings name a track and a channel choice (mono, left, or right) */
848  project->PushState(wxString::Format(_("Changed '%s' to %s"),
849  pTrack->GetName(),
850  channelmsg),
851  _("Channel"));
853 }
854 
856 void WaveTrackMenuTable::OnMergeStereo(wxCommandEvent &)
857 {
858  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
859  wxASSERT(pTrack);
860  pTrack->SetLinked(true);
861  // Assume partner is wave or null
862  const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
863 
864  if (partner) {
865  // Set partner's parameters to match target.
866  partner->Merge(*pTrack);
867 
868  pTrack->SetPan( 0.0f );
870  partner->SetPan( 0.0f );
871  partner->SetChannel(Track::RightChannel);
872 
873  // Set NEW track heights and minimized state
874  bool bBothMinimizedp = ((pTrack->GetMinimized()) && (partner->GetMinimized()));
875  pTrack->SetMinimized(false);
876  partner->SetMinimized(false);
877  int AverageHeight = (pTrack->GetHeight() + partner->GetHeight()) / 2;
878  pTrack->SetHeight(AverageHeight);
879  partner->SetHeight(AverageHeight);
880  pTrack->SetMinimized(bBothMinimizedp);
881  partner->SetMinimized(bBothMinimizedp);
882 
883  //On Demand - join the queues together.
885  if (!ODManager::Instance()->MakeWaveTrackDependent(partner, pTrack))
886  {
887  ;
888  //TODO: in the future, we will have to check the return value of MakeWaveTrackDependent -
889  //if the tracks cannot merge, it returns false, and in that case we should not allow a merging.
890  //for example it returns false when there are two different types of ODTasks on each track's queue.
891  //we will need to display this to the user.
892  }
893 
894  AudacityProject *const project = ::GetActiveProject();
895  /* i18n-hint: The string names a track */
896  project->PushState(wxString::Format(_("Made '%s' a stereo track"),
897  pTrack->GetName()),
898  _("Make Stereo"));
899  }
900  else
901  pTrack->SetLinked(false);
902 
904 }
905 
908 {
909  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
910  wxASSERT(pTrack);
911 
912  if (stereo)
913  pTrack->SetPanFromChannelType();
915 
916  // Assume partner is present, and is wave
917  const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
918  wxASSERT(partner);
919  if (!partner)
920  return;
921 
922  if (partner)
923  {
924  // Keep original stereo track name.
925  partner->SetName(pTrack->GetName());
926  if (stereo)
927  partner->SetPanFromChannelType();
928  partner->SetChannel(Track::MonoChannel);
929 
930  //On Demand - have each channel add its own.
931  if (ODManager::IsInstanceCreated() && partner->GetKind() == Track::Wave)
933  }
934 
935  pTrack->SetLinked(false);
936  //make sure neither track is smaller than its minimum height
937  if (pTrack->GetHeight() < pTrack->GetMinimizedHeight())
938  pTrack->SetHeight(pTrack->GetMinimizedHeight());
939  if (partner)
940  {
941  if (partner->GetHeight() < partner->GetMinimizedHeight())
942  partner->SetHeight(partner->GetMinimizedHeight());
943 
944  // Make tracks the same height
945  if (pTrack->GetHeight() != partner->GetHeight())
946  {
947  pTrack->SetHeight((pTrack->GetHeight() + partner->GetHeight()) / 2.0);
948  partner->SetHeight(pTrack->GetHeight());
949  }
950  }
951 
953 }
954 
957 {
958  AudacityProject *const project = ::GetActiveProject();
959 
960  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
961  // Assume partner is wave or null
962  const auto partner = static_cast<WaveTrack*>(pTrack->GetLink());
963  Track *const focused = project->GetTrackPanel()->GetFocusedTrack();
964  const bool hasFocus =
965  (focused == pTrack || focused == partner);
966 
967  SplitStereo(false);
969  partner->SetChannel(Track::LeftChannel);
970 
971  TrackList *const tracks = project->GetTracks();
972  (tracks->MoveUp(partner));
973  partner->SetLinked(true);
974 
975  MixerBoard* pMixerBoard = project->GetMixerBoard();
976  if (pMixerBoard)
977  pMixerBoard->UpdateTrackClusters();
978 
979  if (hasFocus)
980  project->GetTrackPanel()->SetFocusedTrack(partner);
981 
982  /* i18n-hint: The string names a track */
983  project->PushState(wxString::Format(_("Swapped Channels in '%s'"),
984  pTrack->GetName()),
985  _("Swap Channels"));
986 
988 }
989 
991 void WaveTrackMenuTable::OnSplitStereo(wxCommandEvent &)
992 {
993  SplitStereo(true);
994  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
995  AudacityProject *const project = ::GetActiveProject();
996  /* i18n-hint: The string names a track */
997  project->PushState(wxString::Format(_("Split stereo track '%s'"),
998  pTrack->GetName()),
999  _("Split"));
1000 
1002 }
1003 
1006 {
1007  SplitStereo(false);
1008  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
1009  AudacityProject *const project = ::GetActiveProject();
1010  /* i18n-hint: The string names a track */
1011  project->PushState(wxString::Format(_("Split Stereo to Mono '%s'"),
1012  pTrack->GetName()),
1013  _("Split to Mono"));
1014 
1016 }
1017 
1018 //=============================================================================
1020 {
1021 
1022  WaveTrackMenuTable & result = WaveTrackMenuTable::Instance( pTrack );
1023  return &result;
1024 }
#define POPUP_MENU_SEPARATOR()
int GetKind() const override
Definition: WaveTrack.h:121
static bool IsInstanceCreated()
returns whether or not the singleton instance was created yet
Definition: ODManager.cpp:205
int IdOfWaveColor(int WaveColor)
Converts a WaveColor enumeration to a wxWidgets menu item Id.
void InitMenu(Menu *pMenu, void *pUserData) override
A list of TrackListNode items.
Definition: Track.h:618
static ODManager *(* Instance)()
Definition: ODManager.h:49
bool isLinear() const
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
Abstract base class used in importing a file.
Definition: Import.h:32
void DestroyMenu() override
void InitMenu(Menu *pMenu, void *pUserData) override
void SetLinked(bool l)
Definition: Track.cpp:244
void InitMenu(Menu *pMenu, void *pUserData) override
const WaveformSettings & GetWaveformSettings() const
Definition: WaveTrack.cpp:738
WaveformSettings & GetIndependentWaveformSettings()
Definition: WaveTrack.cpp:754
GetSampleFormatStr(int24Sample)
void DestroyMenu() override
void OnRateOther(wxCommandEvent &event)
void OnSplitStereo(wxCommandEvent &event)
Split a stereo track into two tracks...
void SetRate(double newRate)
Definition: WaveTrack.cpp:403
static UIHandlePtr HitTest(std::weak_ptr< SoloButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
void Merge(const Track &orig) override
Definition: WaveTrack.cpp:193
void SetHeight(int h)
Definition: Track.cpp:189
virtual std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *) override=0
static void RebuildAllMenuBars()
Definition: Menus.cpp:4653
bool GetLinked() const
Definition: Track.h:278
int WaveTrackDisplay
Definition: WaveTrack.h:531
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
int IdOfRate(int rate)
Converts a sampling rate to a wxWidgets menu item id.
bool GetMinimized() const
Definition: Track.cpp:214
virtual int GetMinimizedHeight() const
Definition: Track.cpp:129
bool MoveUp(Track *t)
Definition: Track.cpp:1198
Dialog that shows the current PrefsPanel in a tabbed divider.
Definition: PrefsDialog.h:35
TrackControls::InitMenuData * mpData
#define END_POPUP_MENU()
bool IsBusy()
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2910
void SetMinimized(bool isMinimized)
Definition: Track.cpp:219
void SetChannel(int c)
Definition: Track.h:291
void DestroyMenu() override
MixerBoard * GetMixerBoard()
Definition: Project.h:516
virtual void SetPanFromChannelType() override
Definition: WaveTrack.cpp:248
int GetWaveColorIndex() const
Definition: WaveTrack.h:143
POPUP_MENU_RADIO_ITEM(OnInstrument1ID, GetWaveColorStr(0), OnWaveColorChange) POPUP_MENU_RADIO_ITEM(OnInstrument2ID
#define POPUP_MENU_SUB_MENU(id, string, classname)
void MakeWaveTrackIndependent(WaveTrack *track)
if it shares a queue/task, creates a NEW queue/task for the track, and removes it from any previously...
Definition: ODManager.cpp:395
virtual int GetKind() const
Definition: Track.h:329
TrackControls::InitMenuData * mpData
void EndHorizontalLay()
void OnMergeStereo(wxCommandEvent &event)
Merge two tracks into one stereo track ??
void SetFocusedTrack(Track *t)
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
void EndVerticalLay()
void SetDisplay(WaveTrackDisplay display)
Definition: WaveTrack.h:594
int format
Definition: ExportPCM.cpp:56
void OnWaveColorChange(wxCommandEvent &event)
TrackControls::InitMenuData * mpData
Track * GetNext(Track *t, bool linked=false) const
Return a track in the list that comes after Track t.
Definition: Track.cpp:1048
const wxString GetWaveColorStr(int colorIndex)
void SetWaveColorIndex(int colorIndex)
Definition: WaveTrack.cpp:477
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
void OnChannelChange(wxCommandEvent &event)
std::vector< PrefsNode > Factories
Definition: PrefsDialog.h:50
sampleFormat
Definition: Types.h:188
#define lrint(dbl)
Definition: float_cast.h:136
static int gRates[nRates]
void OnSplitStereoMono(wxCommandEvent &event)
Split a stereo track into two mono tracks...
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
void ConvertToSampleFormat(sampleFormat format)
Definition: WaveTrack.cpp:486
wxString GetName() const
Definition: Track.h:270
bool IsAudioActive() const
Definition: Project.cpp:1447
const int nRates
static EffectManager & Get()
void ModifyState(bool bWantsAutoSave)
Definition: Project.cpp:4740
std::shared_ptr< UIHandle > UIHandlePtr
Definition: TrackPanel.h:59
void DestroyMenu() override
static RateMenuTable & Instance()
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
wxComboBox * AddCombo(const wxString &Prompt, const wxString &Selected, const wxArrayString *pChoices, long style=0)
Definition: ShuttleGui.cpp:440
static UIHandlePtr HitTest(std::weak_ptr< GainSliderHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< Track > &pTrack)
AudioIO * gAudioIO
Definition: AudioIO.cpp:482
static WaveColorMenuTable & Instance()
void OnSpectrogramSettings(wxCommandEvent &event)
void PushState(const wxString &desc, const wxString &shortDesc)
Definition: Project.cpp:4695
PopupMenuTable * GetMenuExtension(Track *pTrack) override
POPUP_MENU_ITEM(OnMoveUpID, _("Move Track &Up")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveUp")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveDownID
Track * GetLink() const
Definition: Track.cpp:269
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
sampleFormat GetSampleFormat() const
Definition: WaveTrack.h:146
TrackControls::InitMenuData * mpData
static FormatMenuTable & Instance()
void Invalidate(wxCommandEvent &evt)
void OnFormatChange(wxCommandEvent &event)
Track * GetFocusedTrack()
TrackPanel * GetTrackPanel()
Definition: Project.h:307
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
static UIHandlePtr HitTest(std::weak_ptr< MuteButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
double GetRate() const
Definition: WaveTrack.cpp:398
void SetLastScaleType() const
Definition: WaveTrack.cpp:315
void SetPan(float newPan) override
Definition: WaveTrack.cpp:430
TrackList * GetTracks()
Definition: Project.h:192
WaveTrackDisplay GetDisplay() const
Definition: WaveTrack.h:593
static WaveTrackMenuTable & Instance(Track *pTrack)
DECLARE_POPUP_MENU(WaveColorMenuTable)
void SetBorder(int Border)
Definition: ShuttleGui.h:286
void SplitStereo(bool stereo)
Split a stereo track into two tracks...
void OnSwapChannels(wxCommandEvent &event)
Swap the left and right channels of a stero track...
void InitMenu(Menu *pMenu, void *pUserData) override
bool RealtimeIsActive()
void SetRate(WaveTrack *pTrack, double rate)
virtual int GetChannel() const override
Definition: WaveTrack.cpp:236
static UIHandlePtr HitTest(std::weak_ptr< PanSliderHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< Track > &pTrack)
void OnRateChange(wxCommandEvent &event)
int GetHeight() const
Definition: Track.cpp:180
BEGIN_POPUP_MENU(SpectrumVRulerMenuTable)
void UpdateTrackClusters()
Definition: MixerBoard.cpp:973
void StartVerticalLay(int iProp=1)