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