Audacity  2.2.2
ControlToolBar.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ControlToolBar.cpp
6 
7  Dominic Mazzoni
8  Shane T. Mueller
9  James Crook
10  Leland Lucius
11 
12 *******************************************************************//*******************************************************************/
34 
35 #include <algorithm>
36 #include <cfloat>
37 
38 #include "../Audacity.h"
39 #include "../Experimental.h"
40 #include "ControlToolBar.h"
41 
42 // For compilers that support precompilation, includes "wx/wx.h".
43 #include <wx/wxprec.h>
44 
45 #ifndef WX_PRECOMP
46 #include <wx/app.h>
47 #include <wx/dc.h>
48 #include <wx/event.h>
49 #include <wx/image.h>
50 #include <wx/intl.h>
51 #include <wx/statusbr.h>
52 #include <wx/timer.h>
53 #endif
54 #include <wx/tooltip.h>
55 #include <wx/datetime.h>
56 
57 #include "TranscriptionToolBar.h"
58 #include "MeterToolBar.h"
59 
60 #include "../AColor.h"
61 #include "../AllThemeResources.h"
62 #include "../AudioIO.h"
63 #include "../ImageManipulation.h"
64 #include "../Prefs.h"
65 #include "../Project.h"
66 #include "../Theme.h"
67 #include "../WaveTrack.h"
68 #include "../widgets/AButton.h"
69 #include "../widgets/Meter.h"
70 #include "../widgets/LinkingHtmlWindow.h"
71 #include "../widgets/ErrorDialog.h"
72 #include "../FileNames.h"
73 
74 #include "../tracks/ui/Scrubbing.h"
75 #include "../prefs/TracksPrefs.h"
76 #include "../toolbars/ToolManager.h"
77 #include "../TrackPanel.h"
78 
80 
81 //static
83 
87 
88 BEGIN_EVENT_TABLE(ControlToolBar, ToolBar)
89  EVT_CHAR(ControlToolBar::OnKeyEvent)
90  EVT_BUTTON(ID_PLAY_BUTTON, ControlToolBar::OnPlay)
91  EVT_BUTTON(ID_STOP_BUTTON, ControlToolBar::OnStop)
92  EVT_BUTTON(ID_RECORD_BUTTON, ControlToolBar::OnRecord)
93  EVT_BUTTON(ID_REW_BUTTON, ControlToolBar::OnRewind)
94  EVT_BUTTON(ID_FF_BUTTON, ControlToolBar::OnFF)
95  EVT_BUTTON(ID_PAUSE_BUTTON, ControlToolBar::OnPause)
97 
98 //Standard constructor
99 // This was called "Control" toolbar in the GUI before - now it is "Transport".
100 // Note that we use the legacy "Control" string as the section because this
101 // gets written to prefs and cannot be changed in prefs to maintain backwards
102 // compatibility
104 : ToolBar(TransportBarID, _("Transport"), wxT("Control"))
105 {
106  mPaused = false;
107 
108  gPrefs->Read(wxT("/GUI/ErgonomicTransportButtons"), &mErgonomicTransportButtons, true);
109  mStrLocale = gPrefs->Read(wxT("/Locale/Language"), wxT(""));
110 
111  mSizer = NULL;
112 
113  /* i18n-hint: These are strings for the status bar, and indicate whether Audacity
114  is playing or recording or stopped, and whether it is paused. */
115  mStatePlay = XO("Playing");
116  mStateStop = XO("Stopped");
117  mStateRecord = XO("Recording");
118  mStatePause = XO("Paused");
119 }
120 
122 {
123 }
124 
125 
126 void ControlToolBar::Create(wxWindow * parent)
127 {
128  ToolBar::Create(parent);
129 }
130 
131 // This is a convenience function that allows for button creation in
132 // MakeButtons() with fewer arguments
134  teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled,
135  int id,
136  bool processdownevents,
137  const wxChar *label)
138 {
139  AButton *r = ToolBar::MakeButton(pBar,
140  bmpRecoloredUpLarge, bmpRecoloredDownLarge, bmpRecoloredUpHiliteLarge, bmpRecoloredHiliteLarge,
141  eEnabledUp, eEnabledDown, eDisabled,
142  wxWindowID(id),
143  wxDefaultPosition, processdownevents,
144  theTheme.ImageSize( bmpRecoloredUpLarge ));
145  r->SetLabel(label);
146  enum { deflation =
147 #ifdef __WXMAC__
148  6
149 #else
150  12
151 #endif
152  };
153  r->SetFocusRect( r->GetClientRect().Deflate( deflation, deflation ) );
154 
155  return r;
156 }
157 
158 // static
160  teBmps eEnabledUp,
161  teBmps eEnabledDown,
162  teBmps eDisabled)
163 {
164  ToolBar::MakeAlternateImages(button, idx,
165  bmpRecoloredUpLarge, bmpRecoloredDownLarge, bmpRecoloredUpHiliteLarge, bmpRecoloredHiliteLarge,
166  eEnabledUp, eEnabledDown, eDisabled,
167  theTheme.ImageSize( bmpRecoloredUpLarge ));
168 }
169 
171 {
172  SetBackgroundColour( theTheme.Colour( clrMedium ) );
174 
175  mPause = MakeButton(this, bmpPause, bmpPause, bmpPauseDisabled,
176  ID_PAUSE_BUTTON, true, _("Pause"));
177 
178  mPlay = MakeButton(this, bmpPlay, bmpPlay, bmpPlayDisabled,
179  ID_PLAY_BUTTON, true, _("Play"));
180  MakeAlternateImages(*mPlay, 1, bmpLoop, bmpLoop, bmpLoopDisabled);
182  bmpCutPreview, bmpCutPreview, bmpCutPreviewDisabled);
184  bmpScrub, bmpScrub, bmpScrubDisabled);
186  bmpSeek, bmpSeek, bmpSeekDisabled);
188 
189  mStop = MakeButton(this, bmpStop, bmpStop, bmpStopDisabled ,
190  ID_STOP_BUTTON, false, _("Stop"));
191 
192  mRewind = MakeButton(this, bmpRewind, bmpRewind, bmpRewindDisabled,
193  ID_REW_BUTTON, false, _("Skip to Start"));
194 
195  mFF = MakeButton(this, bmpFFwd, bmpFFwd, bmpFFwdDisabled,
196  ID_FF_BUTTON, false, _("Skip to End"));
197 
198  mRecord = MakeButton(this, bmpRecord, bmpRecord, bmpRecordDisabled,
199  ID_RECORD_BUTTON, false, _("Record"));
200 
201  bool bPreferNewTrack;
202  gPrefs->Read("/GUI/PreferNewTrackRecord",&bPreferNewTrack, false);
203  if( !bPreferNewTrack )
204  MakeAlternateImages(*mRecord, 1, bmpRecordBelow, bmpRecordBelow,
205  bmpRecordBelowDisabled);
206  else
207  MakeAlternateImages(*mRecord, 1, bmpRecordBeside, bmpRecordBeside,
208  bmpRecordBesideDisabled);
209 
211 
212 #if wxUSE_TOOLTIPS
214  wxToolTip::Enable(true);
215  wxToolTip::SetDelay(1000);
216 #endif
217 
218  // Set default order and mode
219  ArrangeButtons();
220 }
221 
223 {
224 #if wxUSE_TOOLTIPS
225  for (long iWinID = ID_PLAY_BUTTON; iWinID < BUTTON_COUNT; iWinID++)
226  {
227  auto pCtrl = static_cast<AButton*>(this->FindWindow(iWinID));
228  const wxChar *name = nullptr;
229  switch (iWinID)
230  {
231  case ID_PLAY_BUTTON:
232  // Without shift
233  name = wxT("PlayStop");
234  break;
235  case ID_RECORD_BUTTON:
236  // Without shift
237  //name = wxT("Record");
238  name = wxT("Record1stChoice");
239  break;
240  case ID_PAUSE_BUTTON:
241  name = wxT("Pause");
242  break;
243  case ID_STOP_BUTTON:
244  name = wxT("Stop");
245  break;
246  case ID_FF_BUTTON:
247  name = wxT("CursProjectEnd");
248  break;
249  case ID_REW_BUTTON:
250  name = wxT("CursProjectStart");
251  break;
252  }
253  std::vector<TranslatedInternalString> commands(
254  1u, { name, pCtrl->GetLabel() } );
255 
256  // Some have a second
257  switch (iWinID)
258  {
259  case ID_PLAY_BUTTON:
260  // With shift
261  commands.push_back( { wxT("PlayLooped"), _("Loop Play") } );
262  break;
263  case ID_RECORD_BUTTON:
264  // With shift
265  { bool bPreferNewTrack;
266  gPrefs->Read("/GUI/PreferNewTrackRecord",&bPreferNewTrack, false);
267  // For the shortcut tooltip.
268  commands.push_back( {
269  wxT("Record2ndChoice"),
270  !bPreferNewTrack
271  ? _("Record New Track")
272  : _("Append Record")
273  } );
274  }
275  break;
276  case ID_PAUSE_BUTTON:
277  break;
278  case ID_STOP_BUTTON:
279  break;
280  case ID_FF_BUTTON:
281  // With shift
282  commands.push_back( {
283  wxT("SelEnd"), _("Select to End") } );
284  break;
285  case ID_REW_BUTTON:
286  // With shift
287  commands.push_back( {
288  wxT("SelStart"), _("Select to Start") } );
289  break;
290  }
291  ToolBar::SetButtonToolTip(*pCtrl, commands.data(), commands.size());
292  }
293 #endif
294 }
295 
297 {
298  bool updated = false;
299  bool active;
300 
301  gPrefs->Read( wxT("/GUI/ErgonomicTransportButtons"), &active, true );
302  if( mErgonomicTransportButtons != active )
303  {
305  updated = true;
306  }
307  wxString strLocale = gPrefs->Read(wxT("/Locale/Language"), wxT(""));
308  if (mStrLocale != strLocale)
309  {
310  mStrLocale = strLocale;
311  updated = true;
312  }
313 
314  if( updated )
315  {
316  ReCreateButtons(); // side effect: calls RegenerateTooltips()
317  Updated();
318  }
319  else
320  // The other reason to regenerate tooltips is if keyboard shortcuts for
321  // transport buttons changed, but that's too much work to check for, so just
322  // always do it. (Much cheaper than calling ReCreateButtons() in all cases.
324 
325 
326  // Set label to pull in language change
327  SetLabel(_("Transport"));
328 
329  // Give base class a chance
331 }
332 
334 {
335  int flags = wxALIGN_CENTER | wxRIGHT;
336 
337  // (Re)allocate the button sizer
338  if( mSizer )
339  {
340  Detach( mSizer );
341  std::unique_ptr < wxSizer > {mSizer}; // DELETE it
342  }
343 
344  Add((mSizer = safenew wxBoxSizer(wxHORIZONTAL)), 1, wxEXPAND);
345 
346  // Start with a little extra space
347  mSizer->Add( 5, 55 );
348 
349  // Add the buttons in order based on ergonomic setting
351  {
352  mPause->MoveBeforeInTabOrder( mRecord );
353  mPlay->MoveBeforeInTabOrder( mRecord );
354  mStop->MoveBeforeInTabOrder( mRecord );
355  mRewind->MoveBeforeInTabOrder( mRecord );
356  mFF->MoveBeforeInTabOrder( mRecord );
357 
358  mSizer->Add( mPause, 0, flags, 2 );
359  mSizer->Add( mPlay, 0, flags, 2 );
360  mSizer->Add( mStop, 0, flags, 2 );
361  mSizer->Add( mRewind, 0, flags, 2 );
362  mSizer->Add( mFF, 0, flags, 10 );
363  mSizer->Add( mRecord, 0, flags, 5 );
364  }
365  else
366  {
367  mRewind->MoveBeforeInTabOrder( mFF );
368  mPlay->MoveBeforeInTabOrder( mFF );
369  mRecord->MoveBeforeInTabOrder( mFF );
370  mPause->MoveBeforeInTabOrder( mFF );
371  mStop->MoveBeforeInTabOrder( mFF );
372 
373  mSizer->Add( mRewind, 0, flags, 2 );
374  mSizer->Add( mPlay, 0, flags, 2 );
375  mSizer->Add( mRecord, 0, flags, 2 );
376  mSizer->Add( mPause, 0, flags, 2 );
377  mSizer->Add( mStop, 0, flags, 2 );
378  mSizer->Add( mFF, 0, flags, 5 );
379  }
380 
381  // Layout the sizer
382  mSizer->Layout();
383 
384  // Layout the toolbar
385  Layout();
386 
387  // (Re)Establish the minimum size
388  SetMinSize( GetSizer()->GetMinSize() );
389 }
390 
392 {
393  bool playDown = false;
394  bool playShift = false;
395  bool pauseDown = false;
396  bool recordDown = false;
397  bool recordShift = false;
398 
399  // ToolBar::ReCreateButtons() will get rid of its sizer and
400  // since we've attached our sizer to it, ours will get deleted too
401  // so clean ours up first.
402  if( mSizer )
403  {
404  playDown = mPlay->IsDown();
405  playShift = mPlay->WasShiftDown();
406  pauseDown = mPause->IsDown();
407  recordDown = mRecord->IsDown();
408  recordShift = mRecord->WasShiftDown();
409  Detach( mSizer );
410 
411  std::unique_ptr < wxSizer > {mSizer}; // DELETE it
412  mSizer = NULL;
413  }
414 
416 
417  if (playDown)
418  {
419  ControlToolBar::PlayAppearance appearance =
422  SetPlay(playDown, appearance);
423  }
424 
425  if (pauseDown)
426  {
427  mPause->PushDown();
428  }
429 
430  if (recordDown)
431  {
432  SetRecord(recordDown, recordShift);
433  }
434 
436 
438 }
439 
440 void ControlToolBar::Repaint( wxDC *dc )
441 {
442 #ifndef USE_AQUA_THEME
443  wxSize s = mSizer->GetSize();
444  wxPoint p = mSizer->GetPosition();
445 
446  wxRect bevelRect( p.x, p.y, s.GetWidth() - 1, s.GetHeight() - 1 );
447  AColor::Bevel( *dc, true, bevelRect );
448 #endif
449 }
450 
452 {
454  bool tracks = false;
455 
456  bool paused = mPause->IsDown();
457  bool playing = mPlay->IsDown();
458  bool recording = mRecord->IsDown();
459  bool busy = gAudioIO->IsBusy();
460 
461  // Only interested in audio type tracks
462  if (p) {
463  TrackListIterator iter( p->GetTracks() );
464  for (Track *t = iter.First(); t; t = iter.Next()) {
465  if (dynamic_cast<const AudioTrack*>(t)) {
466  tracks = true;
467  break;
468  }
469  }
470  }
471 
472  if (p) {
473  TranscriptionToolBar *const playAtSpeedTB = p->GetTranscriptionToolBar();
474  if (playAtSpeedTB)
475  playAtSpeedTB->SetEnabled(CanStopAudioStream() && tracks && !recording);
476  }
477 
478  mPlay->SetEnabled(CanStopAudioStream() && tracks && !recording);
480  CanStopAudioStream() &&
481  !(busy && !recording && !paused) &&
482  !(playing && !paused)
483  );
484  mStop->SetEnabled(CanStopAudioStream() && (playing || recording));
485  mRewind->SetEnabled(IsPauseDown() || (!playing && !recording));
486  mFF->SetEnabled(tracks && (IsPauseDown() || (!playing && !recording)));
487 
488  //auto pProject = GetActiveProject();
490 }
491 
492 void ControlToolBar::SetPlay(bool down, PlayAppearance appearance)
493 {
494  if (down) {
495  mPlay->SetShift(appearance == PlayAppearance::Looped);
497  mPlay->SetAlternateIdx(static_cast<int>(appearance));
498  mPlay->PushDown();
499  }
500  else {
501  mPlay->PopUp();
503  }
506 }
507 
508 void ControlToolBar::SetStop(bool down)
509 {
510  if (down)
511  mStop->PushDown();
512  else {
513  if(FindFocus() == mStop)
514  mPlay->SetFocus();
515  mStop->PopUp();
516  }
518 }
519 
520 void ControlToolBar::SetRecord(bool down, bool append)
521 {
522  if (down)
523  {
524  mRecord->SetAlternateIdx(append ? 1 : 0);
525  mRecord->PushDown();
526  }
527  else
528  {
530  mRecord->PopUp();
531  }
533 }
534 
536 {
537  return mPause->IsDown();
538 }
539 
541 {
542  return mRecord->IsDown();
543 }
544 
546  const AudioIOStartStreamOptions &options,
547  PlayMode mode,
548  PlayAppearance appearance, /* = PlayOption::Straight */
549  bool backwards, /* = false */
550  bool playWhiteSpace /* = false */)
551 // STRONG-GUARANTEE (for state of mCutPreviewTracks)
552 {
553  if (!CanStopAudioStream())
554  return -1;
555 
556  bool useMidi = true;
557 
558  // Remove these lines to experiment with scrubbing/seeking of note tracks
559  if (options.pScrubbingOptions)
560  useMidi = false;
561 
562  // Uncomment this for laughs!
563  // backwards = true;
564 
565  double t0 = selectedRegion.t0();
566  double t1 = selectedRegion.t1();
567  // SelectedRegion guarantees t0 <= t1, so we need another boolean argument
568  // to indicate backwards play.
569  const bool looped = options.playLooped;
570 
571  if (backwards)
572  std::swap(t0, t1);
573 
574  SetPlay(true, appearance);
575 
576  bool success = false;
577  auto cleanup = finally( [&] {
578  if (!success) {
579  SetPlay(false);
580  SetStop(false);
581  SetRecord(false);
582  }
583  } );
584 
585  if (gAudioIO->IsBusy())
586  return -1;
587 
588  const bool cutpreview = appearance == PlayAppearance::CutPreview;
589  if (cutpreview && t0==t1)
590  return -1; /* msmeyer: makes no sense */
591 
593  if (!p)
594  return -1; // Should never happen, but...
595 
596  TrackList *t = p->GetTracks();
597  if (!t)
598  return -1; // Should never happen, but...
599 
600  p->mLastPlayMode = mode;
601 
602  bool hasaudio = false;
603  TrackListIterator iter(t);
604  for (Track *trk = iter.First(); trk; trk = iter.Next()) {
605  if (trk->GetKind() == Track::Wave
606 #ifdef EXPERIMENTAL_MIDI_OUT
607  || (trk->GetKind() == Track::Note && useMidi)
608 #endif
609  ) {
610  hasaudio = true;
611  break;
612  }
613  }
614 
615  double latestEnd = (playWhiteSpace)? t1 : t->GetEndTime();
616 
617  if (!hasaudio)
618  return -1; // No need to continue without audio tracks
619 
620 #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
621  double init_seek = 0.0;
622 #endif
623 
624  if (t1 == t0) {
625  if (looped) {
626  // play selection if there is one, otherwise
627  // set start of play region to project start,
628  // and loop the project from current play position.
629 
630  if ((t0 > p->GetSel0()) && (t0 < p->GetSel1())) {
631  t0 = p->GetSel0();
632  t1 = p->GetSel1();
633  }
634  else {
635  // loop the entire project
636  t0 = t->GetStartTime();
637  t1 = t->GetEndTime();
638  }
639  } else {
640  // move t0 to valid range
641  if (t0 < 0) {
642  t0 = t->GetStartTime();
643  }
644  else if (t0 > t->GetEndTime()) {
645  t0 = t->GetEndTime();
646  }
647 #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
648  else {
649  init_seek = t0; //AC: init_seek is where playback will 'start'
650  t0 = t->GetStartTime();
651  }
652 #endif
653  }
654  t1 = t->GetEndTime();
655  }
656  else {
657  // maybe t1 < t0, with backwards scrubbing for instance
658  if (backwards)
659  std::swap(t0, t1);
660 
661  t0 = std::max(0.0, std::min(t0, latestEnd));
662  t1 = std::max(0.0, std::min(t1, latestEnd));
663 
664  if (backwards)
665  std::swap(t0, t1);
666  }
667 
668  int token = -1;
669 
670  if (t1 != t0) {
671  if (cutpreview) {
672  const double tless = std::min(t0, t1);
673  const double tgreater = std::max(t0, t1);
674  double beforeLen, afterLen;
675  gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 2.0);
676  gPrefs->Read(wxT("/AudioIO/CutPreviewAfterLen"), &afterLen, 1.0);
677  double tcp0 = tless-beforeLen;
678  double diff = tgreater - tless;
679  double tcp1 = (tgreater+afterLen) - diff;
680  SetupCutPreviewTracks(tcp0, tless, tgreater, tcp1);
681  if (backwards)
682  std::swap(tcp0, tcp1);
683  if (mCutPreviewTracks)
684  {
685  AudioIOStartStreamOptions myOptions = options;
686  myOptions.cutPreviewGapStart = t0;
687  myOptions.cutPreviewGapLen = t1 - t0;
688  token = gAudioIO->StartStream(
689  mCutPreviewTracks->GetWaveTrackConstArray(false),
690  WaveTrackArray(),
691 #ifdef EXPERIMENTAL_MIDI_OUT
692  useMidi
693  ? mCutPreviewTracks->GetNoteTrackArray(false)
694  : NoteTrackArray(),
695 #endif
696  tcp0, tcp1, myOptions);
697  }
698  else
699  // Cannot create cut preview tracks, clean up and exit
700  return -1;
701  }
702  else {
703  // Lifted the following into AudacityProject::GetDefaultPlayOptions()
704  /*
705  if (!timetrack) {
706  timetrack = t->GetTimeTrack();
707  }
708  */
709  token = gAudioIO->StartStream(t->GetWaveTrackConstArray(false),
710  WaveTrackArray(),
711 #ifdef EXPERIMENTAL_MIDI_OUT
712  useMidi
713  ? t->GetNoteTrackArray(false)
714  : NoteTrackArray(),
715 #endif
716  t0, t1, options);
717  }
718  if (token != 0) {
719  success = true;
720  p->SetAudioIOToken(token);
721  mBusyProject = p;
722 #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
723  //AC: If init_seek was set, now's the time to make it happen.
724  gAudioIO->SeekStream(init_seek);
725 #endif
726  }
727  else {
728  // Bug1627 (part of it):
729  // infinite error spew when trying to start scrub:
730  // Problem was that the error dialog yields to events,
731  // causing recursion to this function in the scrub timer
732  // handler! Easy fix, just delay the user alert instead.
733  CallAfter( [=]{
734  // Show error message if stream could not be opened
735  ShowErrorDialog(this, _("Error"),
736  _("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."),
737  wxT("Error_opening_sound_device"));
738  });
739  }
740  }
741 
742  if (!success)
743  return -1;
744 
746 
747  // Let other UI update appearance
748  if (p)
750 
751  return token;
752 }
753 
754 void ControlToolBar::PlayCurrentRegion(bool looped /* = false */,
755  bool cutpreview /* = false */)
756 {
757  if (!CanStopAudioStream())
758  return;
759 
761 
762  if (p)
763  {
764 
765  double playRegionStart, playRegionEnd;
766  p->GetPlayRegion(&playRegionStart, &playRegionEnd);
767 
769  options.playLooped = looped;
770  if (cutpreview)
771  options.timeTrack = NULL;
772  ControlToolBar::PlayAppearance appearance =
776  PlayPlayRegion(SelectedRegion(playRegionStart, playRegionEnd),
777  options,
779  appearance);
780  }
781 }
782 
783 void ControlToolBar::OnKeyEvent(wxKeyEvent & event)
784 {
785  if (event.ControlDown() || event.AltDown()) {
786  event.Skip();
787  return;
788  }
789 
790  // Does not appear to be needed on Linux. Perhaps on some other platform?
791  // If so, "!CanStopAudioStream()" should probably apply.
792  if (event.GetKeyCode() == WXK_SPACE) {
793  if (gAudioIO->IsStreamActive(GetActiveProject()->GetAudioIOToken())) {
794  SetPlay(false);
795  SetStop(true);
796  StopPlaying();
797  }
798  else if (!gAudioIO->IsBusy()) {
799  //SetPlay(true);// Not needed as done in PlayPlayRegion
800  SetStop(false);
802  }
803  return;
804  }
805  event.Skip();
806 }
807 
808 void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt))
809 {
810  auto p = GetActiveProject();
811 
812  if (!CanStopAudioStream())
813  return;
814 
815  StopPlaying();
816 
817  if (p) p->TP_DisplaySelection();
818 
819  auto cleanup = finally( [&]{ UpdateStatusBar(p); } );
820  PlayDefault();
821 }
822 
823 void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
824 {
825  if (CanStopAudioStream()) {
826  StopPlaying();
828  }
829 }
830 
832 {
833  return (!gAudioIO->IsStreamActive() ||
834  gAudioIO->IsMonitoring() ||
836 }
837 
839 {
840  // Let control have precedence over shift
841  const bool cutPreview = mPlay->WasControlDown();
842  const bool looped = !cutPreview &&
843  mPlay->WasShiftDown();
844  PlayCurrentRegion(looped, cutPreview);
845 }
846 
847 void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
848 {
849  StopScrolling();
850 
851  AudacityProject *project = GetActiveProject();
852 
853  if(project) {
854  // Let scrubbing code do some appearance change
855  project->GetScrubber().StopScrubbing();
856  }
857 
858  if (!CanStopAudioStream())
859  return;
860 
861  mStop->PushDown();
862 
863  SetStop(false);
864  if(stopStream)
865  gAudioIO->StopStream();
866  SetPlay(false);
867  SetRecord(false);
868 
869  #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
870  gAudioIO->AILADisable();
871  #endif
872 
873  mPause->PopUp();
874  mPaused=false;
875  //Make sure you tell gAudioIO to unpause
877 
879 
880  mBusyProject = NULL;
881  // So that we continue monitoring after playing or recording.
882  // also clean the MeterQueues
883  if( project ) {
884  project->MayStartMonitoring();
885 
886  MeterPanel *meter = project->GetPlaybackMeter();
887  if( meter ) {
888  meter->Clear();
889  }
890 
891  meter = project->GetCaptureMeter();
892  if( meter ) {
893  meter->Clear();
894  }
895  }
896 
897  const auto toolbar = project->GetToolManager()->GetToolBar(ScrubbingBarID);
898  toolbar->EnableDisableButtons();
899 }
900 
902 {
903  if (!CanStopAudioStream())
905  else {
906  wxCommandEvent dummy;
907  OnPause(dummy);
908  }
909 }
910 
911 void ControlToolBar::OnRecord(wxCommandEvent &evt)
912 // STRONG-GUARANTEE (for state of current project's tracks)
913 {
914  // TODO: It would be neater if Menu items and Toolbar buttons used the same code for
915  // enabling/disabling, and all fell into the same action routines.
916  // Here instead we reduplicate some logic (from CommandHandler) because it isn't
917  // normally used for buttons.
918 
919  // Code from CommandHandler start...
921  wxASSERT( proj );
922  if( !proj )
923  return;
924 
925  CommandFlag flags = AlwaysEnabledFlag; // 0 means recalc flags.
926 
927  // NB: The call may have the side effect of changing flags.
928  bool allowed = proj->TryToMakeActionAllowed(
929  flags,
932 
933  if( !allowed )
934  return;
935  // ...end of code from CommandHandler.
936 
937  if (gAudioIO->IsBusy()) {
939  mRecord->PopUp();
940  else
941  mRecord->PushDown();
942  return;
943  }
945 
946  if( evt.GetInt() == 1 ) // used when called by keyboard shortcut. Default (0) ignored.
947  mRecord->SetShift(true);
948  if( evt.GetInt() == 2 )
949  mRecord->SetShift(false);
950 
951  SetRecord(true, mRecord->WasShiftDown());
952 
953  bool success = false;
954 
955  bool appendRecord = mRecord->WasShiftDown();
956 
957  bool bPreferNewTrack;
958  gPrefs->Read("/GUI/PreferNewTrackRecord",&bPreferNewTrack, false);
959  if( !bPreferNewTrack )
960  appendRecord = !appendRecord;
961 
962  TrackList *trackList = p->GetTracks();
963 
964  WaveTrackArray recordingTracks;
965 
966  auto cleanup = finally( [&] {
967  if (!success) {
968  SetPlay(false);
969  SetStop(false);
970  SetRecord(false);
971  }
972 
973  // Success or not:
975  } );
976 
977  if (p) {
978  TrackListIterator it(trackList);
979 
980  bool hasWave = false;
981  for (auto t = it.First(); t; t = it.Next()) {
982  if (t->GetKind() == Track::Wave) {
983  hasWave = true;
984  break;
985  }
986  }
987  if(!hasWave)
988  // Treat append-record like record, when there was no given wave track
989  // to append onto.
990  appendRecord = false;
991 
992  double t0 = p->GetSel0();
993  double t1 = p->GetSel1();
994  if (t1 == t0)
995  t1 = DBL_MAX; // record for a long, long time
996 
997  /* TODO: set up stereo tracks if that is how the user has set up
998  * their preferences, and choose sample format based on prefs */
999  WaveTrackConstArray playbackTracks;
1000 #ifdef EXPERIMENTAL_MIDI_OUT
1001  NoteTrackArray midiTracks;
1002 #endif
1003  bool duplex;
1004 #ifdef EXPERIMENTAL_DA
1005  gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, false);
1006 #else
1007  gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
1008 #endif
1009  if(duplex){
1010  playbackTracks = trackList->GetWaveTrackConstArray(false);
1011 #ifdef EXPERIMENTAL_MIDI_OUT
1012  midiTracks = trackList->GetNoteTrackArray(false);
1013 #endif
1014  }
1015  else {
1016  playbackTracks = WaveTrackConstArray();
1017 #ifdef EXPERIMENTAL_MIDI_OUT
1018  midiTracks = NoteTrackArray();
1019 #endif
1020  }
1021 
1022  int recordingChannels = 0;
1023  double allt0 = t0;
1024 
1025  using Candidates = std::vector<WaveTrack*>;
1026  Candidates candidates, selectedCandidates;
1027  auto addCandidates = [&](Candidates &candidates, WaveTrack *candidate){
1028  if (candidates.size() == recordingChannels)
1029  // nothing left to do
1030  return;
1031 
1032  if (candidate->GetLink() && !candidate->GetLinked())
1033  return;
1034 
1035  // This is written with odd seeming generality, looking forward to
1036  // the rewrite that removes assumption of at-most-stereo
1037 
1038  // count channels
1039  unsigned nChannels = 0;
1040  for (auto channel = candidate; channel;
1041  channel = channel->GetLinked()
1042  ? static_cast<WaveTrack*>(channel->GetLink()) : nullptr)
1043  ++nChannels;
1044 
1045  // Accumulate consecutive single channel tracks, or else one track of
1046  // the exact number of channels
1047  if (nChannels > 1)
1048  candidates.clear();
1049 
1050  if (nChannels == 1 || // <- comment this out to disallow recording
1051  // stereo into two adjacent mono tracks
1052  nChannels == recordingChannels) {
1053  for (auto channel = candidate; channel;
1054  channel = channel->GetLinked()
1055  ? static_cast<WaveTrack*>(channel->GetLink()) : nullptr)
1056  candidates.push_back(channel);
1057  }
1058  };
1059  if (appendRecord) {
1060  recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2);
1061 
1062  // Find the maximum end time of selected and all wave tracks
1063  // Find whether any tracks were selected. (If any are selected,
1064  // record only into them; else if tracks exist, record into all.)
1065  for (Track *tt = it.First(); tt; tt = it.Next()) {
1066  if (tt->GetKind() == Track::Wave) {
1067  WaveTrack *wt = static_cast<WaveTrack *>(tt);
1068  if (wt->GetEndTime() > allt0) {
1069  allt0 = wt->GetEndTime();
1070  }
1071  addCandidates( candidates, wt );
1072  if (wt->GetSelected())
1073  addCandidates( selectedCandidates, wt );
1074  if (wt->GetSelected()) {
1075  if (wt->GetEndTime() > t0) {
1076  t0 = wt->GetEndTime();
1077  }
1078  }
1079  }
1080  }
1081 
1082  // candidate null implies selectedCandidate also null
1083  if( candidates.empty() )
1084  appendRecord = false;
1085  }
1086 
1087  if (appendRecord) {
1088 
1089  // t0 is now: max(selection-start, end-of-selected-wavetracks)
1090  // allt0 is: max(selection-start, end-of-all-tracks)
1091  // Use end time of all wave tracks if none selected
1092  if (selectedCandidates.empty()) {
1093  t0 = allt0;
1094  }
1095 
1096  // Append recording:
1097  // Pad selected/all wave tracks to make them all the same length
1098  // Remove recording tracks from the list of tracks for duplex ("overdub")
1099  // playback.
1100  for (auto channel :
1101  selectedCandidates.empty() ? candidates : selectedCandidates)
1102  {
1103  auto wt = Track::Pointer<WaveTrack>(channel);
1104 
1105  if (duplex) {
1106  auto end = playbackTracks.end();
1107  auto it = std::find(playbackTracks.begin(), end, wt);
1108  if (it != end)
1109  playbackTracks.erase(it);
1110  }
1111  t1 = wt->GetEndTime();
1112 
1113  // A function that copies all the non-sample data between
1114  // wave tracks; in case the track recorded to changes scale
1115  // type (for instance), during the recording.
1116  auto updater = [](Track &d, const Track &s){
1117  auto &dst = static_cast<WaveTrack&>(d);
1118  auto &src = static_cast<const WaveTrack&>(s);
1119  dst.Reinit(src);
1120  };
1121 
1122  // Get a copy of the track to be appended, to be pushed into
1123  // undo history only later.
1124  auto pending = std::static_pointer_cast<WaveTrack>(
1126  updater, wt.get() ) );
1127 
1128  // End of current track is before or at recording start time.
1129  // Less than or equal, not just less than, to ensure a clip boundary.
1130  // when append recording.
1131  if (t1 <= t0) {
1132 
1133  // Pad the recording track with silence, up to the
1134  // maximum time.
1135  auto newTrack = p->GetTrackFactory()->NewWaveTrack();
1136  newTrack->SetWaveColorIndex( wt->GetWaveColorIndex() );
1137  newTrack->InsertSilence(0.0, t0 - t1);
1138  newTrack->Flush();
1139  pending->Clear(t1, t0);
1140  pending->Paste(t1, newTrack.get());
1141  }
1142  recordingTracks.push_back(pending);
1143  }
1144 
1145  if (t1 <= p->GetSel0() && p->GetSel1() > p->GetSel0()) {
1146  t1 = p->GetSel1(); // record within the selection
1147  } else {
1148  t1 = DBL_MAX; // record for a long, long time
1149  }
1150  }
1151 
1152  if( recordingTracks.empty() )
1153  { // recording to new track.
1154  bool recordingNameCustom, useTrackNumber, useDateStamp, useTimeStamp;
1155  wxString defaultTrackName, defaultRecordingTrackName;
1156 
1157  // Count the tracks.
1158  int numTracks = 0;
1159 
1160  for (Track *tt = it.First(); tt; tt = it.Next()) {
1161  if (tt->GetKind() == Track::Wave && !tt->GetLinked())
1162  numTracks++;
1163  }
1164  numTracks++;
1165 
1166  recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2);
1167 
1168  gPrefs->Read(wxT("/GUI/TrackNames/RecordingNameCustom"), &recordingNameCustom, false);
1169  gPrefs->Read(wxT("/GUI/TrackNames/TrackNumber"), &useTrackNumber, false);
1170  gPrefs->Read(wxT("/GUI/TrackNames/DateStamp"), &useDateStamp, false);
1171  gPrefs->Read(wxT("/GUI/TrackNames/TimeStamp"), &useTimeStamp, false);
1173  gPrefs->Read(wxT("/GUI/TrackNames/RecodingTrackName"), &defaultRecordingTrackName, defaultTrackName);
1174 
1175  wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName;
1176 
1177  for (int c = 0; c < recordingChannels; c++) {
1178  std::shared_ptr<WaveTrack> newTrack{
1179  p->GetTrackFactory()->NewWaveTrack().release()
1180  };
1181 
1182  newTrack->SetOffset(t0);
1183  wxString nameSuffix = wxString(wxT(""));
1184 
1185  if (useTrackNumber) {
1186  nameSuffix += wxString::Format(wxT("%d"), numTracks + c);
1187  }
1188 
1189  if (useDateStamp) {
1190  if (!nameSuffix.IsEmpty()) {
1191  nameSuffix += wxT("_");
1192  }
1193  nameSuffix += wxDateTime::Now().FormatISODate();
1194  }
1195 
1196  if (useTimeStamp) {
1197  if (!nameSuffix.IsEmpty()) {
1198  nameSuffix += wxT("_");
1199  }
1200  nameSuffix += wxDateTime::Now().FormatISOTime();
1201  }
1202 
1203  // ISO standard would be nice, but ":" is unsafe for file name.
1204  nameSuffix.Replace(wxT(":"), wxT("-"));
1205 
1206  if (baseTrackName.IsEmpty()) {
1207  newTrack->SetName(nameSuffix);
1208  }
1209  else if (nameSuffix.IsEmpty()) {
1210  newTrack->SetName(baseTrackName);
1211  }
1212  else {
1213  newTrack->SetName(baseTrackName + wxT("_") + nameSuffix);
1214  }
1215 
1216  if (recordingChannels > 2)
1217  newTrack->SetMinimized(true);
1218 
1219  if (recordingChannels == 2) {
1220  if (c == 0) {
1221  newTrack->SetChannel(Track::LeftChannel);
1222  newTrack->SetLinked(true);
1223  }
1224  else {
1225  newTrack->SetChannel(Track::RightChannel);
1226  }
1227  }
1228  else {
1229  newTrack->SetChannel( Track::MonoChannel );
1230  }
1231 
1232  p->GetTracks()->RegisterPendingNewTrack( newTrack );
1233  recordingTracks.push_back( newTrack );
1234  // Bug 1548. New track needs the focus.
1235  p->GetTrackPanel()->SetFocusedTrack( newTrack.get() );
1236  }
1237  }
1238 
1239  //Automated Input Level Adjustment Initialization
1240  #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1241  gAudioIO->AILAInitialize();
1242  #endif
1243 
1245  int token = gAudioIO->StartStream(playbackTracks,
1246  recordingTracks,
1247 #ifdef EXPERIMENTAL_MIDI_OUT
1248  midiTracks,
1249 #endif
1250  t0, t1, options);
1251 
1252  success = (token != 0);
1253 
1254  if (success) {
1255  p->SetAudioIOToken(token);
1256  mBusyProject = p;
1257 
1259  }
1260  else {
1261  CancelRecording();
1262 
1263  // Show error message if stream could not be opened
1264  ShowErrorDialog(this, _("Error"),
1265  _("Error opening sound device.\nTry changing the audio host, recording device and the project sample rate."),
1266  wxT("Error_opening_sound_device"));
1267  }
1268  }
1269 }
1270 
1271 
1272 void ControlToolBar::OnPause(wxCommandEvent & WXUNUSED(evt))
1273 {
1274  if (!CanStopAudioStream()) {
1275  return;
1276  }
1277 
1278 
1279  if(mPaused)
1280  {
1281  mPause->PopUp();
1282  mPaused=false;
1283  }
1284  else
1285  {
1286  mPause->PushDown();
1287  mPaused=true;
1288  }
1289 
1290 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1291  if (gAudioIO->IsScrubbing())
1293  else
1294 #endif
1295  {
1297  }
1298 
1300 }
1301 
1302 void ControlToolBar::OnRewind(wxCommandEvent & WXUNUSED(evt))
1303 {
1304  mRewind->PushDown();
1305  mRewind->PopUp();
1306 
1308  if (p) {
1309  p->StopIfPaused();
1310  p->Rewind(mRewind->WasShiftDown());
1311  }
1312 }
1313 
1314 void ControlToolBar::OnFF(wxCommandEvent & WXUNUSED(evt))
1315 {
1316  mFF->PushDown();
1317  mFF->PopUp();
1318 
1320 
1321  if (p) {
1322  p->StopIfPaused();
1323  p->SkipEnd(mFF->WasShiftDown());
1324  }
1325 }
1326 
1327 void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cutStart,
1328  double cutEnd, double WXUNUSED(playEnd))
1329 
1330 // STRONG-GUARANTEE (for state of mCutPreviewTracks)
1331 {
1334  if (p) {
1335  // Find first selected track (stereo or mono) and duplicate it
1336  const Track *track1 = NULL, *track2 = NULL;
1337  TrackListIterator it(p->GetTracks());
1338  for (Track *t = it.First(); t; t = it.Next())
1339  {
1340  if (t->GetSelected() &&
1341  (t->GetKind() == Track::Wave
1342 #ifdef EXPERIMENTAL_MIDI_OUT
1343  || t->GetKind() == Track::Note
1344 #endif
1345  ))
1346  {
1347  track1 = t;
1348  track2 = t->GetLink();
1349  break;
1350  }
1351  }
1352 
1353  if (track1)
1354  {
1355  // Duplicate and change tracks
1356  // Clear has a very small chance of throwing
1357  auto new1 = track1->Duplicate();
1358  new1->Clear(cutStart, cutEnd);
1359  decltype(new1) new2{};
1360  if (track2)
1361  {
1362  new2 = track2->Duplicate();
1363  new2->Clear(cutStart, cutEnd);
1364  }
1365 
1366  // use NOTHROW-GUARANTEE:
1367 
1369  mCutPreviewTracks->Add(std::move(new1));
1370  if (track2)
1371  mCutPreviewTracks->Add(std::move(new2));
1372  }
1373  }
1374 }
1375 
1377 {
1378  if (mCutPreviewTracks)
1379  mCutPreviewTracks->Clear();
1380  mCutPreviewTracks.reset();
1381 }
1382 
1383 // works out the width of the field in the status bar needed for the state (eg play, record pause)
1384 int ControlToolBar::WidthForStatusBar(wxStatusBar* const sb)
1385 {
1386  int xMax = 0;
1387  const auto pauseString = wxT(" ") + wxGetTranslation(mStatePause);
1388 
1389  auto update = [&] (const wxString &state) {
1390  int x, y;
1391  sb->GetTextExtent(
1392  wxGetTranslation(state) + pauseString + wxT("."),
1393  &x, &y
1394  );
1395  xMax = std::max(x, xMax);
1396  };
1397 
1398  update(mStatePlay);
1399  update(mStateStop);
1400  update(mStateRecord);
1401 
1402  // Note that Scrubbing + Paused is not allowed.
1403  for(const auto &state : Scrubber::GetAllUntranslatedStatusStrings())
1404  update(state);
1405 
1406  return xMax + 30; // added constant needed because xMax isn't large enough for some reason, plus some space.
1407 }
1408 
1410 {
1411  wxString state;
1412 
1413  auto pProject = GetActiveProject();
1414  auto scrubState =
1415  pProject ? pProject->GetScrubber().GetUntranslatedStateString() : wxString();
1416  if (!scrubState.IsEmpty())
1417  state = wxGetTranslation(scrubState);
1418  else if (mPlay->IsDown())
1419  state = wxGetTranslation(mStatePlay);
1420  else if (mRecord->IsDown())
1421  state = wxGetTranslation(mStateRecord);
1422  else
1423  state = wxGetTranslation(mStateStop);
1424 
1425  if (mPause->IsDown())
1426  {
1427  state.Append(wxT(" "));
1428  state.Append(wxGetTranslation(mStatePause));
1429  }
1430 
1431  state.Append(wxT("."));
1432 
1433  return state;
1434 }
1435 
1437 {
1438  pProject->GetStatusBar()->SetStatusText(StateForStatusBar(), stateStatusBarField);
1439 }
1440 
1442 {
1444  StartScrolling();
1445 #ifdef __WXMAC__
1446  else if (::GetActiveProject()->GetScrubber().HasStartedScrubbing()) {
1447  // PRL: cause many "unnecessary" refreshes. For reasons I don't understand,
1448  // doing this causes wheel rotation events (mapped from the double finger vertical
1449  // swipe) to be delivered more uniformly to the application, so that speed control
1450  // works better.
1453  }
1454 #endif
1455  else
1456  StopScrolling();
1457 }
1458 
1460 {
1462  const auto project = GetActiveProject();
1463  if (project) {
1464  auto mode = Mode::Centered;
1465 
1466 #if 0
1467  // Enable these lines to pin the playhead right instead of center,
1468  // when recording but not overdubbing.
1469  if (gAudioIO->GetNumCaptureChannels() > 0) {
1470  // recording
1471 
1472  // Display a fixed recording head while scrolling the waves continuously.
1473  // If you overdub, you may want to anticipate some context in existing tracks,
1474  // so center the head. If not, put it rightmost to display as much wave as we can.
1475  bool duplex;
1476 #ifdef EXPERIMENTAL_DA
1477  gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, false);
1478 #else
1479  gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
1480 #endif
1481  if (duplex) {
1482  // See if there is really anything being overdubbed
1483  if (gAudioIO->GetNumPlaybackChannels() == 0)
1484  // No.
1485  duplex = false;
1486  }
1487 
1488  if (!duplex)
1489  mode = Mode::Right;
1490  }
1491 #endif
1492 
1493  project->GetPlaybackScroller().Activate(mode);
1494  }
1495 }
1496 
1498 {
1499  const auto project = GetActiveProject();
1500  if(project)
1501  project->GetPlaybackScroller().Activate
1503 }
1504 
1506 {
1507  const auto project = GetActiveProject();
1508  project->GetTracks()->ApplyPendingTracks();
1509 }
1510 
1512 {
1513  const auto project = GetActiveProject();
1514  project->GetTracks()->ClearPendingTracks();
1515 }
AButton * mRecord
void EnableDisableButtons() override
void SetPlay(bool down, PlayAppearance appearance=PlayAppearance::Straight)
void SetAlternateIdx(unsigned idx)
Definition: AButton.cpp:248
A ToolBar that has the main Transport buttons.
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
A list of TrackListNode items.
Definition: Track.h:618
void StopStream()
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:2535
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
AudioIOStartStreamOptions GetDefaultPlayOptions()
Definition: Project.cpp:1291
void OnKeyEvent(wxKeyEvent &event)
virtual void UpdatePrefs()
Definition: ToolBar.cpp:535
double t0() const
void Pause(bool paused)
Definition: Scrubbing.cpp:678
double GetSel0() const
Definition: Project.h:204
void SetLabel(const wxString &label) override
Definition: ToolBar.cpp:374
void PopUp()
Definition: AButton.cpp:525
Scrubber & GetScrubber()
Definition: Project.h:801
void MakeButtonBackgroundsLarge()
Definition: ToolBar.cpp:701
bool IsDown()
Definition: AButton.h:123
double GetStartTime() const
Definition: Track.cpp:1413
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:603
void SetShift(bool shift)
Definition: AButton.cpp:546
void Clear()
Definition: Meter.cpp:335
bool WasShiftDown()
Definition: AButton.cpp:485
bool GetSelected() const
Definition: Track.h:275
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2918
void RegenerateTooltips() override
void Populate() override
void OnStop(const CommandContext &context)
virtual void ReCreateButtons()
Definition: ToolBar.cpp:459
void SetFocusRect(wxRect &r)
Definition: AButton.cpp:264
static AButton * MakeButton(ControlToolBar *pBar, teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled, int id, bool processdownevents, const wxChar *label)
wxString mStateRecord
AButton * mPause
void Reinit(const WaveTrack &orig)
Definition: WaveTrack.cpp:166
double GetEndTime() const
Definition: Track.cpp:1418
void SetAudioIOToken(int token)
Definition: Project.cpp:1442
void Rewind(bool shift)
Definition: Project.cpp:4960
static wxString GetDefaultAudioTrackNamePreference()
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:377
void RegisterPendingNewTrack(const std::shared_ptr< Track > &pTrack)
Definition: Track.cpp:1442
wxString label
Definition: Tags.cpp:727
wxString StateForStatusBar()
void OnPause(wxCommandEvent &evt)
void FollowModifierKeys()
Definition: AButton.cpp:258
void OnRecord(const CommandContext &context)
PlayMode
Definition: Project.h:125
void MayStartMonitoring()
Definition: Project.cpp:5527
void PlayCurrentRegion(bool looped=false, bool cutpreview=false)
void ReCreateButtons() override
void StopPlaying(bool stopStream=true)
#define XO(s)
Definition: Internat.h:33
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:1873
int teBmps
Definition: Theme.h:28
void Detach(wxWindow *window)
Definition: ToolBar.cpp:677
wxSize ImageSize(int iIndex)
Definition: Theme.cpp:1257
bool IsBusy()
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2910
static AButton * MakeButton(wxWindow *parent, teBmps eUp, teBmps eDown, teBmps eHilite, teBmps eDownHi, teBmps eStandardUp, teBmps eStandardDown, teBmps eDisabled, wxWindowID id, wxPoint placement, bool processdownevents, wxSize size)
Definition: ToolBar.cpp:765
ScrubbingOptions * pScrubbingOptions
Definition: AudioIO.h:139
MeterPanel is a panel that paints the meter used for monitoring or playback.
Definition: Meter.h:97
double t1() const
virtual ~ControlToolBar()
void ShowErrorDialog(wxWindow *parent, const wxString &dlogTitle, const wxString &message, const wxString &helpPage, const bool Close)
Displays an error dialog with a button that offers help.
bool IsPauseDown() const
#define safenew
Definition: Audacity.h:230
void HideQuickPlayIndicator(bool repaint_all=false)
Definition: Ruler.cpp:3342
static std::shared_ptr< TrackList > Create()
Definition: Track.cpp:792
void Repaint(wxDC *dc) override
std::shared_ptr< Track > RegisterPendingChangedTrack(Updater updater, Track *src)
Definition: Track.cpp:1424
void SetFocusedTrack(Track *t)
void UpdateStatusBar(AudacityProject *pProject)
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
void StopScrubbing()
Definition: Scrubbing.cpp:536
void ClearCutPreviewTracks()
wxString mStateStop
static std::vector< wxString > GetAllUntranslatedStatusStrings()
Definition: Scrubbing.cpp:974
WaveTrackConstArray GetWaveTrackConstArray(bool selectionOnly, bool includeMuted=true) const
Definition: Track.cpp:1349
MeterPanel * GetCaptureMeter()
Definition: Project.cpp:5097
static void Bevel(wxDC &dc, bool up, const wxRect &r)
Definition: AColor.cpp:202
Defines a selected portion of a project.
void OnFF(wxCommandEvent &evt)
void SetStop(bool down)
std::vector< std::shared_ptr< WaveTrack > > WaveTrackArray
Definition: AudioIO.h:65
struct holding stream options, including a pointer to the TimeTrack and AudioIOListener and whether t...
Definition: AudioIO.h:114
void UpdatePrefs() override
AdornedRulerPanel * GetRulerPanel()
Definition: Project.cpp:1432
wxString mStatePause
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:66
wxString mStrLocale
virtual void EnableDisableButtons()=0
bool IsPaused()
Find out if playback / recording is currently paused.
Definition: AudioIO.cpp:2885
wxBoxSizer * mSizer
void SetControl(bool control)
Definition: AButton.cpp:551
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ToolManager * GetToolManager()
Definition: Project.h:704
void SetEnabled(bool state)
Definition: AButton.h:98
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:101
void SetupCutPreviewTracks(double playStart, double cutStart, double cutEnd, double playEnd)
AudacityProject * GetOwningProject() const
Definition: AudioIO.h:225
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:611
static void MakeAlternateImages(AButton &button, int idx, teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled)
virtual void Create(wxWindow *parent)
Definition: ToolBar.cpp:438
void OnStop(wxCommandEvent &evt)
bool IsRecordDown() const
int min(int a, int b)
virtual Track * First(TrackList *val=nullptr)
Definition: Track.cpp:418
bool IsScrubbing()
Definition: AudioIO.h:190
bool WasControlDown()
Definition: AButton.cpp:490
std::vector< std::shared_ptr< NoteTrack > > NoteTrackArray
Definition: Track.h:53
TranscriptionToolBar * GetTranscriptionToolBar()
Definition: Project.cpp:5075
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
PlayMode mLastPlayMode
Definition: Project.h:557
void SetEnabled(bool enabled)
int StartStream(const WaveTrackConstArray &playbackTracks, const WaveTrackArray &captureTracks, double t0, double t1, const AudioIOStartStreamOptions &options)
Start recording or playing back audio.
Definition: AudioIO.cpp:1864
void Updated()
Definition: ToolBar.cpp:592
std::unique_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:78
An iterator for a TrackList.
Definition: Track.h:401
IMPLEMENT_CLASS(ControlToolBar, ToolBar)
void StartScrollingIfPreferred()
static void MakeAlternateImages(AButton &button, int idx, teBmps eUp, teBmps eDown, teBmps eHilite, teBmps eDownHi, teBmps eStandardUp, teBmps eStandardDown, teBmps eDisabled, wxSize size)
Definition: ToolBar.cpp:798
_("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
int WidthForStatusBar(wxStatusBar *const)
wxStatusBar * GetStatusBar()
Definition: Project.h:518
static AudacityProject * mBusyProject
CommandFlag
Definition: CommandFlag.h:16
AudioIO * gAudioIO
Definition: AudioIO.cpp:482
int PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, PlayMode playMode, PlayAppearance appearance=PlayAppearance::Straight, bool backwards=false, bool playWhiteSpace=false)
void SetRecord(bool down, bool append=false)
const wxChar * name
Definition: Distortion.cpp:94
bool IsMonitoring()
Returns true if we're monitoring input (but not recording or playing actual audio) ...
Definition: AudioIO.cpp:2942
Track * GetLink() const
Definition: Track.cpp:269
virtual Track * Next(bool skiplinked=false)
Definition: Track.cpp:460
PlaybackScroller & GetPlaybackScroller()
Definition: Project.h:832
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
static bool GetPinnedHeadPreference()
void StopIfPaused()
Definition: Menus.cpp:2349
AButton * mRewind
MeterPanel * GetPlaybackMeter()
Definition: Project.cpp:5083
TrackPanel * GetTrackPanel()
Definition: Project.h:307
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1225
void PushDown()
Definition: AButton.cpp:517
END_EVENT_TABLE()
double GetSel1() const
Definition: Project.h:205
TrackList * GetTracks()
Definition: Project.h:192
void OnPause(const CommandContext &context)
void GetPlayRegion(double *playRegionStart, double *playRegionEnd)
Definition: Project.cpp:5441
void Create(wxWindow *parent) override
static void SetButtonToolTip(AButton &button, const TranslatedInternalString commands[], size_t nCommands)
Definition: ToolBar.cpp:823
bool mErgonomicTransportButtons
wxString mStatePlay
A kind of ToolBar used to help with analysing voice recordings.
void SeekStream(double seconds)
Move the playback / recording position of the current stream by the specified amount from where it is...
Definition: AudioIO.h:187
void SetPaused(bool state)
Pause and un-pause playback and recording.
Definition: AudioIO.cpp:2868
void OnRecord(wxCommandEvent &evt)
void OnPlay(wxCommandEvent &evt)
unsigned GetNumPlaybackChannels() const
Definition: AudioIO.h:376
ToolBar * GetToolBar(int type) const
TrackFactory * GetTrackFactory()
Definition: Project.cpp:1427
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed...
Definition: ToolBar.h:87
void OnRewind(wxCommandEvent &evt)
virtual Holder Duplicate() const =0
bool TryToMakeActionAllowed(CommandFlag &flags, CommandFlag flagsRqd, CommandFlag mask)
Definition: Project.cpp:2304
void SkipEnd(bool shift)
Definition: Project.cpp:4978
A wxButton with mouse-over behaviour.
Definition: AButton.h:28
std::shared_ptr< TrackList > mCutPreviewTracks