Audacity 3.2.0
TrackMenus.cpp
Go to the documentation of this file.
1#include "../CommonCommandFlags.h"
2#include "../LabelTrack.h"
3#include "../Menus.h"
4#include "../MixAndRender.h"
5
6#include "Prefs.h"
7#include "Project.h"
8#include "../ProjectAudioIO.h"
9#include "ProjectHistory.h"
10#include "ProjectRate.h"
11#include "../ProjectSettings.h"
12#include "PluginManager.h"
13#include "ProjectStatus.h"
14#include "../ProjectWindow.h"
15#include "../SelectUtilities.h"
16#include "../ShuttleGui.h"
17#include "../SyncLock.h"
18#include "../TrackPanelAx.h"
19#include "../TrackPanel.h"
20#include "../TrackUtilities.h"
21#include "UndoManager.h"
22#include "../WaveClip.h"
23#include "ViewInfo.h"
24#include "../WaveTrack.h"
25#include "../commands/CommandContext.h"
26#include "../commands/CommandManager.h"
27#include "../effects/EffectManager.h"
28#include "../effects/EffectUI.h"
29#include "QualitySettings.h"
30#include "../tracks/playabletrack/wavetrack/ui/WaveTrackControls.h"
31#include "../widgets/ASlider.h"
32#include "../widgets/AudacityMessageBox.h"
33#include "../widgets/ProgressDialog.h"
34
35#include <wx/combobox.h>
36
37#ifdef EXPERIMENTAL_SCOREALIGN
38#include "../effects/ScoreAlignDialog.h"
39#include "audioreader.h"
40#include "scorealign.h"
41#include "scorealign-glue.h"
42#endif /* EXPERIMENTAL_SCOREALIGN */
43
44// private helper classes and functions
45namespace {
46
48(AudacityProject &project, bool toNewTrack)
49{
50 auto &tracks = TrackList::Get( project );
51 auto &trackFactory = WaveTrackFactory::Get( project );
52 auto rate = ProjectRate::Get(project).GetRate();
53 auto defaultFormat = QualitySettings::SampleFormatChoice();
54 auto &trackPanel = TrackPanel::Get( project );
55 auto &window = ProjectWindow::Get( project );
56
57 auto trackRange = tracks.Selected< WaveTrack >();
58 WaveTrack::Holder uNewLeft, uNewRight;
59 ::MixAndRender(trackRange.Filter<const WaveTrack>(),
60 Mixer::WarpOptions{ tracks },
61 tracks.MakeUniqueTrackName(_("Mix")),
62 &trackFactory, rate, defaultFormat, 0.0, 0.0, uNewLeft, uNewRight);
63
64 if (uNewLeft) {
65 // Remove originals, get stats on what tracks were mixed
66
67 // But before removing, determine the first track after the removal
68 auto last = *trackRange.rbegin();
69 auto insertionPoint = * ++ tracks.Find( last );
70
71 auto selectedCount = (trackRange + &Track::IsLeader).size();
72 wxString firstName;
73 int firstColour = -1;
74 if (selectedCount > 0) {
75 firstName = (*trackRange.begin())->GetName();
76 firstColour = (*trackRange.begin())->GetWaveColorIndex();
77 }
78 if (!toNewTrack) {
79 // Beware iterator invalidation!
80 for (auto &it = trackRange.first, &end = trackRange.second; it != end;)
81 tracks.Remove( *it++ );
82 }
83
84 // Add NEW tracks
85
86 auto pNewLeft = tracks.Add( uNewLeft );
87 decltype(pNewLeft) pNewRight{};
88 if (uNewRight)
89 {
90 pNewRight = tracks.Add(uNewRight);
91 tracks.MakeMultiChannelTrack(*pNewLeft, 2, true);
92 }
93
94 // If we're just rendering (not mixing), keep the track name the same
95 if (selectedCount==1) {
96 pNewLeft->SetName(firstName);
97 if (pNewRight) {
98 pNewRight->SetName(firstName);
99 }
100 }
101
102 // Bug 2218, remember more things...
103 if (selectedCount>=1) {
104 pNewLeft->SetWaveColorIndex(firstColour);
105 pNewLeft->SetSelected(!toNewTrack);
106 if (pNewRight) {
107 pNewRight->SetWaveColorIndex(firstColour);
108 pNewRight->SetSelected(!toNewTrack);
109 }
110 }
111
112 // Permute the tracks as needed
113 // The new track appears after the old tracks (or where the old tracks
114 // had been) so that they are in the same sync-lock group
115 if (insertionPoint)
116 {
117 std::vector<TrackNodePointer> arr;
118 arr.reserve( tracks.size() );
119 size_t begin = 0, ii = 0;
120 for (auto iter = tracks.ListOfTracks::begin(),
121 end = tracks.ListOfTracks::end(); iter != end; ++iter) {
122 arr.push_back( {iter, &tracks} );
123 if ( iter->get() == insertionPoint )
124 begin = ii;
125 ++ii;
126 }
127 auto mid = arr.end();
128 std::advance( mid, -TrackList::Channels( pNewLeft ).size() );
129 std::rotate( arr.begin() + begin, mid, arr.end() );
130 tracks.Permute( arr );
131 }
132
133 // Smart history/undo message
134 if (selectedCount==1) {
135 auto msg = XO("Rendered all audio in track '%s'").Format( firstName );
136 /* i18n-hint: Convert the audio into a more usable form, so apply
137 * panning and amplification and write to some external file.*/
138 ProjectHistory::Get( project ).PushState(msg, XO("Render"));
139 }
140 else {
141 auto msg = (pNewRight
142 ? XO("Mixed and rendered %d tracks into one new stereo track")
143 : XO("Mixed and rendered %d tracks into one new mono track")
144 )
145 .Format( (int)selectedCount );
146 ProjectHistory::Get( project ).PushState(msg, XO("Mix and Render"));
147 }
148
149 trackPanel.SetFocus();
150 TrackFocus::Get( project ).Set( pNewLeft );
151 pNewLeft->EnsureVisible();
152 }
153}
154
155void DoPanTracks(AudacityProject &project, float PanValue)
156{
157 auto &tracks = TrackList::Get( project );
158 auto &window = ProjectWindow::Get( project );
159
160 // count selected wave tracks
161 const auto range = tracks.Any< WaveTrack >();
162 const auto selectedRange = range + &Track::IsSelected;
163 auto count = selectedRange.size();
164
165 // iter through them, all if none selected.
166 for (auto left : count == 0 ? range : selectedRange )
167 left->SetPan( PanValue );
168
169 auto flags = UndoPush::NONE;
170 ProjectHistory::Get( project )
171 /*i18n-hint: One or more audio tracks have been panned*/
172 .PushState(XO("Panned audio track(s)"), XO("Pan Track"), flags);
173 flags = flags | UndoPush::CONSOLIDATE;
174}
175
176enum {
182 // The next two are only in one subMenu, so more easily handled at the end.
186
187static const std::vector< ComponentInterfaceSymbol >
188&alignLabels() { static std::vector< ComponentInterfaceSymbol > symbols{
189 { wxT("StartToZero"), XXO("Start to &Zero") },
190 { wxT("StartToSelStart"), XXO("Start to &Cursor/Selection Start") },
191 { wxT("StartToSelEnd"), XXO("Start to Selection &End") },
192 { wxT("EndToSelStart"), XXO("End to Cu&rsor/Selection Start") },
193 { wxT("EndToSelEnd"), XXO("End to Selection En&d") },
194}; return symbols; }
195
196const size_t kAlignLabelsCount(){ return alignLabels().size(); }
197
199(AudacityProject &project, int index, bool moveSel)
200{
201 auto &tracks = TrackList::Get( project );
202 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
203 auto &window = ProjectWindow::Get( project );
204
205 TranslatableString action, shortAction;
206 double delta = 0.0;
207 double newPos = -1.0;
208
209 auto channelRange = tracks.Selected< AudioTrack >();
210 auto trackRange = tracks.SelectedLeaders< AudioTrack >();
211
212 auto FindOffset = []( const Track *pTrack ) {
213 return TrackList::Channels(pTrack).min( &Track::GetOffset ); };
214
215 auto firstTrackOffset = [&]{ return FindOffset( *trackRange.begin() ); };
216 auto minOffset = [&]{ return trackRange.min( FindOffset ); };
217 auto avgOffset = [&]{
218 return trackRange.sum( FindOffset ) /
219 std::max( size_t(1), trackRange.size() ); };
220
221 auto maxEndOffset = [&]{
222 return std::max(0.0, channelRange.max( &Track::GetEndTime ) ); };
223
224 switch(index) {
225 case kAlignStartZero:
226 delta = -minOffset();
227 action = moveSel
228 /* i18n-hint: In this and similar messages describing editing actions,
229 the starting or ending points of tracks are re-"aligned" to other
230 times, and the time selection may be "moved" too. The first
231 noun -- "start" in this example -- is the object of a verb (not of
232 an implied preposition "from"). */
233 ? XO("Aligned/Moved start to zero")
234 : XO("Aligned start to zero");
235 shortAction = moveSel
236 /* i18n-hint: This and similar messages give shorter descriptions of
237 the aligning and moving editing actions */
238 ? XO("Align/Move Start")
239 : XO("Align Start");
240 break;
242 delta = selectedRegion.t0() - minOffset();
243 action = moveSel
244 ? XO("Aligned/Moved start to cursor/selection start")
245 : XO("Aligned start to cursor/selection start");
246 shortAction = moveSel
247 ? XO("Align/Move Start")
248 : XO("Align Start");
249 break;
251 delta = selectedRegion.t1() - minOffset();
252 action = moveSel
253 ? XO("Aligned/Moved start to selection end")
254 : XO("Aligned start to selection end");
255 shortAction = moveSel
256 ? XO("Align/Move Start")
257 : XO("Align Start");
258 break;
260 delta = selectedRegion.t0() - maxEndOffset();
261 action = moveSel
262 ? XO("Aligned/Moved end to cursor/selection start")
263 : XO("Aligned end to cursor/selection start");
264 shortAction =
265 moveSel
266 ? XO("Align/Move End")
267 : XO("Align End");
268 break;
269 case kAlignEndSelEnd:
270 delta = selectedRegion.t1() - maxEndOffset();
271 action = moveSel
272 ? XO("Aligned/Moved end to selection end")
273 : XO("Aligned end to selection end");
274 shortAction =
275 moveSel
276 ? XO("Align/Move End")
277 : XO("Align End");
278 break;
279 // index set in alignLabelsNoSync
280 case kAlignEndToEnd:
281 newPos = firstTrackOffset();
282 action = moveSel
283 ? XO("Aligned/Moved end to end")
284 : XO("Aligned end to end");
285 shortAction =
286 moveSel
287 ? XO("Align/Move End to End")
288 : XO("Align End to End");
289 break;
290 case kAlignTogether:
291 newPos = avgOffset();
292 action = moveSel
293 ? XO("Aligned/Moved together")
294 : XO("Aligned together");
295 shortAction =
296 moveSel
297 ? XO("Align/Move Together")
298 : XO("Align Together");
299 }
300
301 if ((unsigned)index >= kAlignLabelsCount()) {
302 // This is an alignLabelsNoSync command.
303 for (auto t : tracks.SelectedLeaders< AudioTrack >()) {
304 // This shifts different tracks in different ways, so no sync-lock
305 // move.
306 // Only align Wave and Note tracks end to end.
307 auto channels = TrackList::Channels(t);
308
309 auto trackStart = channels.min( &Track::GetStartTime );
310 auto trackEnd = channels.max( &Track::GetEndTime );
311
312 for (auto channel : channels)
313 // Move the track
314 channel->SetOffset(newPos + channel->GetStartTime() - trackStart);
315
316 if (index == kAlignEndToEnd)
317 newPos += (trackEnd - trackStart);
318 }
319 if (index == kAlignEndToEnd)
320 window.DoZoomFit();
321 }
322
323 if (delta != 0.0) {
324 // For a fixed-distance shift move sync-lock selected tracks also.
325 for (auto t : tracks.Any()
327 t->SetOffset(t->GetOffset() + delta);
328 }
329
330 if (moveSel)
331 selectedRegion.move(delta);
332
333 ProjectHistory::Get( project ).PushState(action, shortAction);
334}
335
336#ifdef EXPERIMENTAL_SCOREALIGN
337
338#ifdef USE_MIDI
339static const ReservedCommandFlag&
340 NoteTracksSelectedFlag() { static ReservedCommandFlag flag{
341 [](const AudacityProject &project){
342 return !TrackList::Get( project ).Selected<const NoteTrack>().empty();
343 }
344 }; return flag; } //gsw
345#endif
346
347// rough relative amount of time to compute one
348// frame of audio or midi, or one cell of matrix, or one iteration
349// of smoothing, measured on a 1.9GHz Core 2 Duo in 32-bit mode
350// (see COLLECT_TIMING_DATA below)
351#define AUDIO_WORK_UNIT 0.004F
352#define MIDI_WORK_UNIT 0.0001F
353#define MATRIX_WORK_UNIT 0.000002F
354#define SMOOTHING_WORK_UNIT 0.000001F
355
356// Write timing data to a file; useful for calibrating AUDIO_WORK_UNIT,
357// MIDI_WORK_UNIT, MATRIX_WORK_UNIT, and SMOOTHING_WORK_UNIT coefficients
358// Data is written to timing-data.txt; look in
359// audacity-src/win/Release/modules/
360#define COLLECT_TIMING_DATA
361
362// Audacity Score Align Progress class -- progress reports come here
363class ASAProgress final : public SAProgress {
364 private:
365 float mTotalWork;
366 float mFrames[2];
367 long mTotalCells; // how many matrix cells?
368 long mCellCount; // how many cells so far?
369 long mPrevCellCount; // cell_count last reported with Update()
370 std::optional<ProgressDialog> mProgress;
371 #ifdef COLLECT_TIMING_DATA
372 FILE *mTimeFile;
373 wxDateTime mStartTime;
374 long iterations;
375 #endif
376
377 public:
378 ASAProgress() {
379 smoothing = false;
380 #ifdef COLLECT_TIMING_DATA
381 mTimeFile = fopen("timing-data.txt", "w");
382 #endif
383 }
384 ~ASAProgress() {
385 #ifdef COLLECT_TIMING_DATA
386 fclose(mTimeFile);
387 #endif
388 }
389 void set_phase(int i) override {
390 float work[2]; // chromagram computation work estimates
391 float work2, work3 = 0; // matrix and smoothing work estimates
392 SAProgress::set_phase(i);
393 #ifdef COLLECT_TIMING_DATA
394 long ms = 0;
395 wxDateTime now = wxDateTime::UNow();
396 wxFprintf(mTimeFile, "Phase %d begins at %s\n",
397 i, now.FormatTime());
398 if (i != 0)
399 ms = now.Subtract(mStartTime).GetMilliseconds().ToLong();
400 mStartTime = now;
401 #endif
402 if (i == 0) {
403 mCellCount = 0;
404 for (int j = 0; j < 2; j++) {
405 mFrames[j] = durations[j] / frame_period;
406 }
407 mTotalWork = 0;
408 for (int j = 0; j < 2; j++) {
409 work[j] =
410 (is_audio[j] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[j];
411 mTotalWork += work[j];
412 }
413 mTotalCells = mFrames[0] * mFrames[1];
414 work2 = mTotalCells * MATRIX_WORK_UNIT;
415 mTotalWork += work2;
416 // arbitrarily assume 60 iterations to fit smooth segments and
417 // per frame per iteration is SMOOTHING_WORK_UNIT
418 if (smoothing) {
419 work3 =
420 wxMax(mFrames[0], mFrames[1]) * SMOOTHING_WORK_UNIT * 40;
421 mTotalWork += work3;
422 }
423 #ifdef COLLECT_TIMING_DATA
424 wxFprintf(mTimeFile,
425 " mTotalWork (an estimate) = %g\n", mTotalWork);
426 wxFprintf(mTimeFile, " work0 = %g, frames %g, is_audio %d\n",
427 work[0], mFrames[0], is_audio[0]);
428 wxFprintf(mTimeFile, " work1 = %g, frames %g, is_audio %d\n",
429 work[1], mFrames[1], is_audio[1]);
430 wxFprintf(mTimeFile, "work2 = %g, work3 = %g\n", work2, work3);
431 #endif
432 mProgress.emplace(XO("Synchronize MIDI with Audio"),
433 XO("Synchronizing MIDI and Audio Tracks"));
434 } else if (i < 3) {
435 wxFprintf(mTimeFile,
436 "Phase %d took %d ms for %g frames, coefficient = %g s/frame\n",
437 i - 1, ms, mFrames[i - 1], (ms * 0.001) / mFrames[i - 1]);
438 } else if (i == 3) {
439 wxFprintf(mTimeFile,
440 "Phase 2 took %d ms for %d cells, coefficient = %g s/cell\n",
441 ms, mCellCount, (ms * 0.001) / mCellCount);
442 } else if (i == 4) {
443 wxFprintf(mTimeFile,
444 "Phase 3 took %d ms for %d iterations on %g frames, "
445 "coefficient = %g s per frame per iteration\n",
446 ms, iterations, wxMax(mFrames[0], mFrames[1]),
447 (ms * 0.001) / (wxMax(mFrames[0], mFrames[1]) * iterations));
448 }
449 }
450 bool set_feature_progress(float s) override {
451 float work;
452 if (phase == 0) {
453 float f = s / frame_period;
454 work = (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * f;
455 } else if (phase == 1) {
456 float f = s / frame_period;
457 work = (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
458 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * f;
459 }
460 auto updateResult = mProgress->Update((int)(work), (int)(mTotalWork));
461 return (updateResult == ProgressResult::Success);
462 }
463 bool set_matrix_progress(int cells) override {
464 mCellCount += cells;
465 float work =
466 (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
467 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[1];
468 work += mCellCount * MATRIX_WORK_UNIT;
469 auto updateResult = mProgress->Update((int)(work), (int)(mTotalWork));
470 return (updateResult == ProgressResult::Success);
471 }
472 bool set_smoothing_progress(int i) override {
473 iterations = i;
474 float work =
475 (is_audio[0] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[0] +
476 (is_audio[1] ? AUDIO_WORK_UNIT : MIDI_WORK_UNIT) * mFrames[1] +
477 MATRIX_WORK_UNIT * mFrames[0] * mFrames[1];
478 work += i * wxMax(mFrames[0], mFrames[1]) * SMOOTHING_WORK_UNIT;
479 auto updateResult = mProgress->Update((int)(work), (int)(mTotalWork));
480 return (updateResult == ProgressResult::Success);
481 }
482};
483
484
485long mixer_process(void *mixer, float **buffer, long n)
486{
487 Mixer *mix = (Mixer *) mixer;
488 long frame_count = mix->Process(std::max(0L, n));
489 *buffer = (float *) mix->GetBuffer();
490 return frame_count;
491}
492
493#endif // EXPERIMENTAL_SCOREALIGN
494
495enum{
498};
499
500void DoSortTracks( AudacityProject &project, int flags )
501{
502 auto GetTime = [](const Track *t) {
503 return t->TypeSwitch< double >(
504 [&](const WaveTrack* w) {
505 auto stime = w->GetEndTime();
506
507 int ndx;
508 for (ndx = 0; ndx < w->GetNumClips(); ndx++) {
509 const auto c = w->GetClipByIndex(ndx);
510 if (c->GetPlaySamplesCount() == 0)
511 continue;
512 stime = std::min(stime, c->GetPlayStartTime());
513 }
514 return stime;
515 },
516 [&](const LabelTrack* l) {
517 return l->GetStartTime();
518 }
519 );
520 };
521
522 size_t ndx = 0;
523 // This one place outside of TrackList where we must use undisguised
524 // std::list iterators! Avoid this elsewhere!
525 std::vector<TrackNodePointer> arr;
526 auto &tracks = TrackList::Get( project );
527 arr.reserve(tracks.size());
528
529 // First find the permutation.
530 // This routine, very unusually, deals with the underlying stl list
531 // iterators, not with TrackIter! Dangerous!
532 for (auto iter = tracks.ListOfTracks::begin(),
533 end = tracks.ListOfTracks::end(); iter != end; ++iter) {
534 const auto &track = *iter;
535 if ( !track->IsLeader() )
536 // keep channels contiguous
537 ndx++;
538 else {
539 auto size = arr.size();
540 for (ndx = 0; ndx < size;) {
541 Track &arrTrack = **arr[ndx].first;
542 auto channels = TrackList::Channels(&arrTrack);
543 if(flags & kAudacitySortByName) {
544 //do case insensitive sort - cmpNoCase returns less than zero if
545 // the string is 'less than' its argument
546 //also if we have case insensitive equality, then we need to sort
547 // by case as well
548 //We sort 'b' before 'B' accordingly. We uncharacteristically
549 // use greater than for the case sensitive
550 //compare because 'b' is greater than 'B' in ascii.
551 auto cmpValue = track->GetName().CmpNoCase(arrTrack.GetName());
552 if ( cmpValue < 0 ||
553 ( 0 == cmpValue &&
554 track->GetName().CompareTo(arrTrack.GetName()) > 0 ) )
555 break;
556 }
557 //sort by time otherwise
558 else if(flags & kAudacitySortByTime) {
559 auto time1 = TrackList::Channels(track.get()).min( GetTime );
560
561 //get candidate's (from sorted array) time
562 auto time2 = channels.min( GetTime );
563
564 if (time1 < time2)
565 break;
566 }
567 ndx += channels.size();
568 }
569 }
570 arr.insert(arr.begin() + ndx, TrackNodePointer{iter, &tracks});
571 }
572
573 // Now apply the permutation
574 tracks.Permute(arr);
575}
576
577void SetTrackGain(AudacityProject &project, WaveTrack * wt, LWSlider * slider)
578{
579 wxASSERT(wt);
580 float newValue = slider->Get();
581
582 for (auto channel : TrackList::Channels(wt))
583 channel->SetGain(newValue);
584
585 ProjectHistory::Get( project )
586 .PushState(XO("Adjusted gain"), XO("Gain"), UndoPush::CONSOLIDATE);
587
588 TrackPanel::Get( project ).RefreshTrack(wt);
589}
590
591void SetTrackPan(AudacityProject &project, WaveTrack * wt, LWSlider * slider)
592{
593 wxASSERT(wt);
594 float newValue = slider->Get();
595
596 for (auto channel : TrackList::Channels(wt))
597 channel->SetPan(newValue);
598
599 ProjectHistory::Get( project )
600 .PushState(XO("Adjusted Pan"), XO("Pan"), UndoPush::CONSOLIDATE);
601
602 TrackPanel::Get( project ).RefreshTrack(wt);
603}
604
605}
606
607namespace TrackActions {
608
609// Menu handler functions
610
612
613void OnStereoToMono(const CommandContext &context)
614{
616 EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono")),
617 context,
619}
620
621void OnMixAndRender(const CommandContext &context)
622{
623 auto &project = context.project;
624 DoMixAndRender(project, false);
625}
626
628{
629 auto &project = context.project;
630 DoMixAndRender(project, true);
631}
632
633void OnResample(const CommandContext &context)
634{
635 auto &project = context.project;
636 auto projectRate = ProjectRate::Get(project).GetRate();
637 auto &tracks = TrackList::Get( project );
638 auto &undoManager = UndoManager::Get( project );
639 auto &window = ProjectWindow::Get( project );
640
641 int newRate;
642
643 while (true)
644 {
645 wxDialogWrapper dlg(&window, wxID_ANY, XO("Resample"));
646 ShuttleGui S(&dlg, eIsCreating);
647 wxString rate;
648 wxComboBox *cb;
649
650 rate.Printf(wxT("%ld"), lrint(projectRate));
651
652 wxArrayStringEx rates{
653 wxT("8000") ,
654 wxT("11025") ,
655 wxT("16000") ,
656 wxT("22050") ,
657 wxT("32000") ,
658 wxT("44100") ,
659 wxT("48000") ,
660 wxT("88200") ,
661 wxT("96000") ,
662 wxT("176400") ,
663 wxT("192000") ,
664 wxT("352800") ,
665 wxT("384000") ,
666 };
667
668 S.StartVerticalLay(true);
669 {
670 S.AddSpace(-1, 15);
671
672 S.StartHorizontalLay(wxCENTER, false);
673 {
674 cb = S.AddCombo(XXO("New sample rate (Hz):"),
675 rate,
676 rates);
677 }
678 S.EndHorizontalLay();
679
680 S.AddSpace(-1, 15);
681
682 S.AddStandardButtons();
683 }
684 S.EndVerticalLay();
685
686 dlg.Layout();
687 dlg.Fit();
688 dlg.Center();
689
690 if (dlg.ShowModal() != wxID_OK)
691 {
692 return; // user cancelled dialog
693 }
694
695 long lrate;
696 if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000)
697 {
698 newRate = (int)lrate;
699 break;
700 }
701
703 XO("The entered value is invalid"),
704 XO("Error"),
705 wxICON_ERROR,
706 &window);
707 }
708
709 int ndx = 0;
710 auto flags = UndoPush::NONE;
711 for (auto wt : tracks.Selected< WaveTrack >())
712 {
713 auto msg = XO("Resampling track %d").Format( ++ndx );
714
715 using namespace BasicUI;
716 auto progress = MakeProgress(XO("Resample"), msg);
717
718 // The resampling of a track may be stopped by the user. This might
719 // leave a track with multiple clips in a partially resampled state.
720 // But the thrown exception will cause rollback in the application
721 // level handler.
722
723 wt->Resample(newRate, progress.get());
724
725 // Each time a track is successfully, completely resampled,
726 // commit that to the undo stack. The second and later times,
727 // consolidate.
728
730 XO("Resampled audio track(s)"), XO("Resample Track"), flags);
731 flags = flags | UndoPush::CONSOLIDATE;
732 }
733
734 undoManager.StopConsolidating();
735
736 // Need to reset
737 window.FinishAutoScroll();
738}
739
740void OnRemoveTracks(const CommandContext &context)
741{
743}
744
745static void MuteTracks(const CommandContext &context, bool mute, bool selected)
746{
747 auto &project = context.project;
748 const auto &settings = ProjectSettings::Get( project );
749 auto &tracks = TrackList::Get( project );
750 auto &window = ProjectWindow::Get( project );
751
752 auto soloSimple = settings.IsSoloSimple();
753 auto soloNone = settings.IsSoloNone();
754
755 auto iter = selected ? tracks.Selected<PlayableTrack>() : tracks.Any<PlayableTrack>();
756 for (auto pt : iter)
757 {
758 pt->SetMute(mute);
759 if (soloSimple || soloNone)
760 pt->SetSolo(false);
761 }
762
763 ProjectHistory::Get( project ).ModifyState(true);
764}
765
766void OnMuteAllTracks(const CommandContext &context)
767{
768 MuteTracks(context, true, false);
769}
770
772{
773 MuteTracks(context, false, false);
774}
775
777{
778 MuteTracks(context, true, true);
779}
780
782{
783 MuteTracks(context, false, true);
784}
785
786void OnPanLeft(const CommandContext &context)
787{
788 auto &project = context.project;
789 DoPanTracks( project, -1.0);
790}
791
792void OnPanRight(const CommandContext &context)
793{
794 auto &project = context.project;
795 DoPanTracks( project, 1.0);
796}
797
798void OnPanCenter(const CommandContext &context)
799{
800 auto &project = context.project;
801 DoPanTracks( project, 0.0);
802}
803
804void OnAlignNoSync(const CommandContext &context)
805{
806 auto &project = context.project;
807
808 DoAlign(project,
809 context.index + kAlignLabelsCount(), false);
810}
811
812void OnAlign(const CommandContext &context)
813{
814 auto &project = context.project;
815
816 bool bMoveWith;
817 gPrefs->Read(wxT("/GUI/MoveSelectionWithTracks"), &bMoveWith, false);
818 DoAlign(project, context.index, bMoveWith);
819}
820
821/*
822// Now handled in OnAlign.
823void OnAlignMoveSel(int index)
824{
825 DoAlign(index, true);
826}
827*/
828
829void OnMoveSelectionWithTracks(const CommandContext &WXUNUSED(context) )
830{
831 bool bMoveWith;
832 gPrefs->Read(wxT("/GUI/MoveSelectionWithTracks"), &bMoveWith, false);
833 gPrefs->Write(wxT("/GUI/MoveSelectionWithTracks"), !bMoveWith);
834 gPrefs->Flush();
835
836}
837
838#ifdef EXPERIMENTAL_SCOREALIGN
839void OnScoreAlign(const CommandContext &context)
840{
841 auto &project = context.project;
842 auto &tracks = TrackList::Get( project );
843 const auto rate = ProjectSettings::Get( project ).GetRate();
844
845 int numWaveTracksSelected = 0;
846 int numNoteTracksSelected = 0;
847 int numOtherTracksSelected = 0;
848 double endTime = 0.0;
849
850 // Iterate through once to make sure that there is exactly
851 // one WaveTrack and one NoteTrack selected.
852 tracks.Selected().Visit(
853 [&](WaveTrack *wt) {
854 numWaveTracksSelected++;
855 endTime = endTime > wt->GetEndTime() ? endTime : wt->GetEndTime();
856 },
857 [&](NoteTrack *) {
858 numNoteTracksSelected++;
859 },
860 [&](Track*) {
861 numOtherTracksSelected++;
862 }
863 );
864
865 if(numWaveTracksSelected == 0 ||
866 numNoteTracksSelected != 1 ||
867 numOtherTracksSelected != 0){
869 XO("Please select at least one audio track and one MIDI track.") );
870 return;
871 }
872
873 // Creating the dialog also stores dialog into gScoreAlignDialog so
874 // that it can be deleted by CloseScoreAlignDialog() either here or
875 // if the program is quit by the user while the dialog is up.
876 ScoreAlignParams params;
877
878 // safe because the class maintains a global resource pointer
880
881 CloseScoreAlignDialog();
882
883 if (params.mStatus != wxID_OK) return;
884
885 // We're going to do it.
886 //pushing the state before the change is wrong (I think)
887 //PushState(XO("Sync MIDI with Audio"), XO("Sync MIDI with Audio"));
888 // Make a copy of the note track in case alignment is canceled or fails
889 auto holder = nt->Duplicate();
890 auto alignedNoteTrack = static_cast<NoteTrack*>(holder.get());
891 // Remove offset from NoteTrack because audio is
892 // mixed starting at zero and incorporating clip offsets.
893 if (alignedNoteTrack->GetOffset() < 0) {
894 // remove the negative offset data before alignment
895 nt->Clear(alignedNoteTrack->GetOffset(), 0);
896 } else if (alignedNoteTrack->GetOffset() > 0) {
897 alignedNoteTrack->Shift(alignedNoteTrack->GetOffset());
898 }
899 alignedNoteTrack->SetOffset(0);
900
901 WaveTrackConstArray waveTracks =
902 tracks->GetWaveTrackConstArray(true /* selectionOnly */);
903
904 int result;
905 {
906 Mixer mix(
907 waveTracks, // const WaveTrackConstArray &inputTracks
908 false, // mayThrow -- is this right?
909 Mixer::WarpOptions{ *tracks },
910 0.0, // double startTime
911 endTime, // double stopTime
912 2, // int numOutChannels
913 44100u, // size_t outBufferSize
914 true, // bool outInterleaved
915 rate, // double outRate
916 floatSample, // sampleFormat outFormat
917 true, // bool highQuality = true
918 NULL); // MixerSpec *mixerSpec = NULL
919
920 ASAProgress progress;
921
922 // There's a lot of adjusting made to incorporate the note track offset into
923 // the note track while preserving the position of notes within beats and
924 // measures. For debugging, you can see just the pre-scorealign note track
925 // manipulation by setting SKIP_ACTUAL_SCORE_ALIGNMENT. You could then, for
926 // example, save the modified note track in ".gro" form to read the details.
927 //#define SKIP_ACTUAL_SCORE_ALIGNMENT 1
928#ifndef SKIP_ACTUAL_SCORE_ALIGNMENT
929 result = scorealign((void *) &mix, &mixer_process,
930 2 /* channels */, 44100.0 /* srate */, endTime,
931 &alignedNoteTrack->GetSeq(), &progress, params);
932#else
933 result = SA_SUCCESS;
934#endif
935 }
936
937 if (result == SA_SUCCESS) {
938 tracks->Replace(nt, holder);
940 XO("Alignment completed: MIDI from %.2f to %.2f secs, Audio from %.2f to %.2f secs.")
941 .Format(
942 params.mMidiStart, params.mMidiEnd,
943 params.mAudioStart, params.mAudioEnd) );
944 ProjectHistory::Get( project )
945 .PushState(XO("Sync MIDI with Audio"), XO("Sync MIDI with Audio"));
946 } else if (result == SA_TOOSHORT) {
948 XO(
949"Alignment error: input too short: MIDI from %.2f to %.2f secs, Audio from %.2f to %.2f secs.")
950 .Format(
951 params.mMidiStart, params.mMidiEnd,
952 params.mAudioStart, params.mAudioEnd) );
953 } else if (result == SA_CANCEL) {
954 // wrong way to recover...
955 //project.OnUndo(); // recover any changes to note track
956 return; // no message when user cancels alignment
957 } else {
958 //project.OnUndo(); // recover any changes to note track
959 AudacityMessageBox( XO("Internal error reported by alignment process.") );
960 }
961}
962#endif /* EXPERIMENTAL_SCOREALIGN */
963
964void OnSortTime(const CommandContext &context)
965{
966 auto &project = context.project;
968
969 ProjectHistory::Get( project )
970 .PushState(XO("Tracks sorted by time"), XO("Sort by Time"));
971}
972
973void OnSortName(const CommandContext &context)
974{
975 auto &project = context.project;
977
978 ProjectHistory::Get( project )
979 .PushState(XO("Tracks sorted by name"), XO("Sort by Name"));
980}
981
982void OnSyncLock(const CommandContext &context)
983{
984 auto &project = context.project;
985 auto &trackPanel = TrackPanel::Get( project );
986
987 bool bSyncLockTracks;
988 gPrefs->Read(wxT("/GUI/SyncLockTracks"), &bSyncLockTracks, false);
989 gPrefs->Write(wxT("/GUI/SyncLockTracks"), !bSyncLockTracks);
990 gPrefs->Flush();
991
992 // Toolbar, project sync-lock handled within
994
995 trackPanel.Refresh(false);
996}
997
1000void OnTrackPan(const CommandContext &context)
1001{
1002 auto &project = context.project;
1003 auto &trackPanel = TrackPanel::Get( project );
1004
1005 const auto track = TrackFocus::Get( project ).Get();
1006 if (track) track->TypeSwitch( [&](WaveTrack *wt) {
1007 LWSlider *slider = WaveTrackControls::PanSlider( trackPanel, *wt );
1008 if (slider->ShowDialog())
1009 SetTrackPan(project, wt, slider);
1010 });
1011}
1012
1013void OnTrackPanLeft(const CommandContext &context)
1014{
1015 auto &project = context.project;
1016 auto &trackPanel = TrackPanel::Get( project );
1017
1018 const auto track = TrackFocus::Get( project ).Get();
1019 if (track) track->TypeSwitch( [&](WaveTrack *wt) {
1020 LWSlider *slider = WaveTrackControls::PanSlider( trackPanel, *wt );
1021 slider->Decrease(1);
1022 SetTrackPan(project, wt, slider);
1023 });
1024}
1025
1027{
1028 auto &project = context.project;
1029 auto &trackPanel = TrackPanel::Get( project );
1030
1031 const auto track = TrackFocus::Get( project ).Get();
1032 if (track) track->TypeSwitch( [&](WaveTrack *wt) {
1033 LWSlider *slider = WaveTrackControls::PanSlider( trackPanel, *wt );
1034 slider->Increase(1);
1035 SetTrackPan(project, wt, slider);
1036 });
1037}
1038
1039void OnTrackGain(const CommandContext &context)
1040{
1041 auto &project = context.project;
1042 auto &trackPanel = TrackPanel::Get( project );
1043
1045 const auto track = TrackFocus::Get( project ).Get();
1046 if (track) track->TypeSwitch( [&](WaveTrack *wt) {
1047 LWSlider *slider = WaveTrackControls::GainSlider( trackPanel, *wt );
1048 if (slider->ShowDialog())
1049 SetTrackGain(project, wt, slider);
1050 });
1051}
1052
1053void OnTrackGainInc(const CommandContext &context)
1054{
1055 auto &project = context.project;
1056 auto &trackPanel = TrackPanel::Get( project );
1057
1058 const auto track = TrackFocus::Get( project ).Get();
1059 if (track) track->TypeSwitch( [&](WaveTrack *wt) {
1060 LWSlider *slider = WaveTrackControls::GainSlider( trackPanel, *wt );
1061 slider->Increase(1);
1062 SetTrackGain(project, wt, slider);
1063 });
1064}
1065
1066void OnTrackGainDec(const CommandContext &context)
1067{
1068 auto &project = context.project;
1069 auto &trackPanel = TrackPanel::Get( project );
1070
1071 const auto track = TrackFocus::Get( project ).Get();
1072 if (track) track->TypeSwitch( [&](WaveTrack *wt) {
1073 LWSlider *slider = WaveTrackControls::GainSlider( trackPanel, *wt );
1074 slider->Decrease(1);
1075 SetTrackGain(project, wt, slider);
1076 });
1077}
1078
1079void OnTrackMenu(const CommandContext &context)
1080{
1081 auto &project = context.project;
1082 auto &trackPanel = TrackPanel::Get( project );
1083
1084 trackPanel.OnTrackMenu();
1085}
1086
1087void OnTrackMute(const CommandContext &context)
1088{
1089 auto &project = context.project;
1090
1091 // Use the temporary selection if it is specified, else the track focus
1092 auto track = context.temporarySelection.pTrack;
1093 if (!track)
1094 track = TrackFocus::Get( project ).Get();
1095
1096 if (track) track->TypeSwitch( [&](PlayableTrack *t) {
1097 TrackUtilities::DoTrackMute(project, t, false);
1098 });
1099}
1100
1101void OnTrackSolo(const CommandContext &context)
1102{
1103 auto &project = context.project;
1104
1105 const auto track = TrackFocus::Get( project ).Get();
1106 if (track) track->TypeSwitch( [&](PlayableTrack *t) {
1107 TrackUtilities::DoTrackSolo(project, t, false);
1108 });
1109}
1110
1111void OnTrackClose(const CommandContext &context)
1112{
1113 auto &project = context.project;
1114 auto &trackPanel = TrackPanel::Get( project );
1115
1116 const auto t = TrackFocus::Get( project ).Get();
1117 if (!t)
1118 return;
1119
1120 auto isAudioActive = ProjectAudioIO::Get( project ).IsAudioActive();
1121
1122 if (isAudioActive)
1123 {
1124 ProjectStatus::Get( project ).Set(
1125 XO("Can't delete track with active audio"));
1126 wxBell();
1127 return;
1128 }
1129
1131
1132 trackPanel.UpdateViewIfNoTracks();
1133 trackPanel.Refresh(false);
1134}
1135
1136void OnTrackMoveUp(const CommandContext &context)
1137{
1138 auto &project = context.project;
1139 auto &trackPanel = TrackPanel::Get( project );
1140 auto &tracks = TrackList::Get( project );
1141
1142 const auto focusedTrack = TrackFocus::Get( project ).Get();
1143 if (tracks.CanMoveUp(focusedTrack)) {
1144 DoMoveTrack(project, focusedTrack, TrackUtilities::OnMoveUpID);
1145 trackPanel.Refresh(false);
1146 }
1147}
1148
1150{
1151 auto &project = context.project;
1152 auto &trackPanel = TrackPanel::Get( project );
1153 auto &tracks = TrackList::Get( project );
1154
1155 const auto focusedTrack = TrackFocus::Get( project ).Get();
1156 if (tracks.CanMoveDown(focusedTrack)) {
1157 DoMoveTrack(project, focusedTrack, TrackUtilities::OnMoveDownID);
1158 trackPanel.Refresh(false);
1159 }
1160}
1161
1162void OnTrackMoveTop(const CommandContext &context)
1163{
1164 auto &project = context.project;
1165 auto &trackPanel = TrackPanel::Get( project );
1166 auto &tracks = TrackList::Get( project );
1167
1168 const auto focusedTrack = TrackFocus::Get( project ).Get();
1169 if (tracks.CanMoveUp(focusedTrack)) {
1170 DoMoveTrack(project, focusedTrack, TrackUtilities::OnMoveTopID);
1171 trackPanel.Refresh(false);
1172 }
1173}
1174
1176{
1177 auto &project = context.project;
1178 auto &trackPanel = TrackPanel::Get( project );
1179 auto &tracks = TrackList::Get( project );
1180
1181 const auto focusedTrack = TrackFocus::Get( project ).Get();
1182 if (tracks.CanMoveDown(focusedTrack)) {
1183 DoMoveTrack(project, focusedTrack, TrackUtilities::OnMoveBottomID);
1184 trackPanel.Refresh(false);
1185 }
1186}
1187
1188}; // struct Handler
1189
1190} // namespace
1191
1193 // Handler is not stateful. Doesn't need a factory registered with
1194 // AudacityProject.
1195 static TrackActions::Handler instance;
1196 return instance;
1197};
1198
1199// Menu definitions
1200
1201#define FN(X) (& TrackActions::Handler :: X)
1202
1203// Under /MenuBar
1204namespace {
1205using namespace MenuTable;
1207{
1208 // Tracks Menu (formerly Project Menu)
1210
1211 static BaseItemSharedPtr menu{
1213 Menu( wxT("Tracks"), XXO("&Tracks"),
1214 Section( "Add",
1215 Menu( wxT("Add"), XXO("Add &New") )
1216 ),
1217
1219
1220 Section( "",
1221 Menu( wxT("Mix"), XXO("Mi&x"),
1222 // Delayed evaluation
1223 // Stereo to Mono is an oddball command that is also subject to control
1224 // by the plug-in manager, as if an effect. Decide whether to show or
1225 // hide it.
1227 const PluginID ID =
1228 EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono"));
1229 const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID);
1230 if (plug && plug->IsEnabled())
1231 return Command( wxT("Stereo to Mono"),
1232 XXO("Mix Stereo Down to &Mono"), FN(OnStereoToMono),
1235 else
1236 return {};
1237 },
1238 Command( wxT("MixAndRender"), XXO("Mi&x and Render"),
1239 FN(OnMixAndRender),
1241 Command( wxT("MixAndRenderToNewTrack"),
1242 XXO("Mix and Render to Ne&w Track"),
1243 FN(OnMixAndRenderToNewTrack),
1244 AudioIONotBusyFlag() | WaveTracksSelectedFlag(), wxT("Ctrl+Shift+M") )
1245 ),
1246
1247 Command( wxT("Resample"), XXO("&Resample..."), FN(OnResample),
1249 ),
1250
1251 Section( "",
1252 Command( wxT("RemoveTracks"), XXO("Remo&ve Tracks"), FN(OnRemoveTracks),
1254 ),
1255
1256 Section( "",
1257 Menu( wxT("Mute"), XXO("M&ute/Unmute"),
1258 Command( wxT("MuteAllTracks"), XXO("&Mute All Tracks"),
1259 FN(OnMuteAllTracks), TracksExistFlag(), wxT("Ctrl+U") ),
1260 Command( wxT("UnmuteAllTracks"), XXO("&Unmute All Tracks"),
1261 FN(OnUnmuteAllTracks), TracksExistFlag(), wxT("Ctrl+Shift+U") ),
1262 Command( wxT("MuteTracks"), XXO("Mut&e Tracks"),
1263 FN(OnMuteSelectedTracks), EditableTracksSelectedFlag(), wxT("Ctrl+Alt+U") ),
1264 Command( wxT("UnmuteTracks"), XXO("U&nmute Tracks"),
1265 FN(OnUnmuteSelectedTracks), EditableTracksSelectedFlag(), wxT("Ctrl+Alt+Shift+U") )
1266 ),
1267
1268 Menu( wxT("Pan"), XXO("&Pan"),
1269 // As Pan changes are not saved on Undo stack,
1270 // pan settings for all tracks
1271 // in the project could very easily be lost unless we
1272 // require the tracks to be selected.
1273 Command( wxT("PanLeft"), XXO("&Left"), FN(OnPanLeft),
1275 Options{}.LongName( XO("Pan Left") ) ),
1276 Command( wxT("PanRight"), XXO("&Right"), FN(OnPanRight),
1278 Options{}.LongName( XO("Pan Right") ) ),
1279 Command( wxT("PanCenter"), XXO("&Center"), FN(OnPanCenter),
1281 Options{}.LongName( XO("Pan Center") ) )
1282 )
1283 ),
1284
1285 Section( "",
1286 Menu( wxT("Align"), XXO("&Align Tracks"), // XO("Just Move Tracks"),
1287 Section( "",
1288 // Mutual alignment of tracks independent of selection or zero
1289 CommandGroup(wxT("Align"),
1290 {
1291 { wxT("EndToEnd"), XXO("&Align End to End") },
1292 { wxT("Together"), XXO("Align &Together") },
1293 },
1294 FN(OnAlignNoSync), AudioIONotBusyFlag() | EditableTracksSelectedFlag())
1295 ),
1296
1297 Section( "",
1298 // Alignment commands using selection or zero
1299 CommandGroup(wxT("Align"),
1300 alignLabels(),
1302 ),
1303
1304 Section( "",
1305 Command( wxT("MoveSelectionWithTracks"),
1306 XXO("&Move Selection with Tracks (on/off)"),
1307 FN(OnMoveSelectionWithTracks),
1309 Options{}.CheckTest( wxT("/GUI/MoveSelectionWithTracks"), false ) )
1310 )
1311 ),
1312
1313 #if 0
1314 // TODO: Can these labels be made clearer?
1315 // Do we need this sub-menu at all?
1316 Menu( wxT("MoveSelectionAndTracks"), XO("Move Sele&ction and Tracks"), {
1317 CommandGroup(wxT("AlignMove"), alignLabels(),
1318 FN(OnAlignMoveSel), AudioIONotBusyFlag() | EditableTracksSelectedFlag()),
1319 } ),
1320 #endif
1321
1323
1324 #ifdef EXPERIMENTAL_SCOREALIGN
1325 Command( wxT("ScoreAlign"), XXO("Synchronize MIDI with Audio"),
1326 FN(OnScoreAlign),
1327 AudioIONotBusyFlag() | NoteTracksSelectedFlag() | WaveTracksSelectedFlag() ),
1328 #endif // EXPERIMENTAL_SCOREALIGN
1329
1331
1332 Menu( wxT("Sort"), XXO("S&ort Tracks"),
1333 Command( wxT("SortByTime"), XXO("By &Start Time"), FN(OnSortTime),
1335 Options{}.LongName( XO("Sort by Time") ) ),
1336 Command( wxT("SortByName"), XXO("By &Name"), FN(OnSortName),
1338 Options{}.LongName( XO("Sort by Name") ) )
1339 )
1340
1342 )
1343
1344#ifdef EXPERIMENTAL_SYNC_LOCK
1345 ,
1346
1347 Section( "",
1348 Command( wxT("SyncLock"), XXO("Sync-&Lock Tracks (on/off)"),
1349 FN(OnSyncLock), AlwaysEnabledFlag,
1350 Options{}.CheckTest( wxT("/GUI/SyncLockTracks"), false ) )
1351 )
1352
1353#endif
1354
1355 ) ) };
1356 return menu;
1357}
1358
1360 wxT(""),
1361 Shared( TracksMenu() )
1362};
1363
1365{
1367 static BaseItemSharedPtr menu{
1369 Menu( wxT("Track"), XXO("&Track"),
1370 Command( wxT("TrackPan"), XXO("Change P&an on Focused Track..."),
1371 FN(OnTrackPan),
1372 TrackPanelHasFocus() | TracksExistFlag(), wxT("Shift+P") ),
1373 Command( wxT("TrackPanLeft"), XXO("Pan &Left on Focused Track"),
1374 FN(OnTrackPanLeft),
1375 TrackPanelHasFocus() | TracksExistFlag(), wxT("Alt+Shift+Left") ),
1376 Command( wxT("TrackPanRight"), XXO("Pan &Right on Focused Track"),
1377 FN(OnTrackPanRight),
1378 TrackPanelHasFocus() | TracksExistFlag(), wxT("Alt+Shift+Right") ),
1379 Command( wxT("TrackGain"), XXO("Change Gai&n on Focused Track..."),
1380 FN(OnTrackGain),
1381 TrackPanelHasFocus() | TracksExistFlag(), wxT("Shift+G") ),
1382 Command( wxT("TrackGainInc"), XXO("&Increase Gain on Focused Track"),
1383 FN(OnTrackGainInc),
1384 TrackPanelHasFocus() | TracksExistFlag(), wxT("Alt+Shift+Up") ),
1385 Command( wxT("TrackGainDec"), XXO("&Decrease Gain on Focused Track"),
1386 FN(OnTrackGainDec),
1387 TrackPanelHasFocus() | TracksExistFlag(), wxT("Alt+Shift+Down") ),
1388 Command( wxT("TrackMenu"), XXO("Op&en Menu on Focused Track..."),
1389 FN(OnTrackMenu),
1391 Options{ wxT("Shift+M") }.SkipKeyDown() ),
1392 Command( wxT("TrackMute"), XXO("M&ute/Unmute Focused Track"),
1393 FN(OnTrackMute),
1394 TracksExistFlag() | TrackPanelHasFocus(), wxT("Shift+U") ),
1395 Command( wxT("TrackSolo"), XXO("&Solo/Unsolo Focused Track"),
1396 FN(OnTrackSolo),
1397 TracksExistFlag() | TrackPanelHasFocus(), wxT("Shift+S") ),
1398 Command( wxT("TrackClose"), XXO("&Close Focused Track"),
1399 FN(OnTrackClose),
1401 wxT("Shift+C") ),
1402 Command( wxT("TrackMoveUp"), XXO("Move Focused Track U&p"),
1403 FN(OnTrackMoveUp),
1405 Command( wxT("TrackMoveDown"), XXO("Move Focused Track Do&wn"),
1406 FN(OnTrackMoveDown),
1408 Command( wxT("TrackMoveTop"), XXO("Move Focused Track to T&op"),
1409 FN(OnTrackMoveTop),
1411 Command( wxT("TrackMoveBottom"), XXO("Move Focused Track to &Bottom"),
1412 FN(OnTrackMoveBottom),
1414 ) ) };
1415 return menu;
1416}
1417
1419 wxT("Optional/Extra/Part2"),
1421};
1422
1423}
1424
1425#undef FN
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:50
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
wxEvtHandler CommandHandlerObject
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & StereoRequiredFlag()
const ReservedCommandFlag & EditableTracksSelectedFlag()
const ReservedCommandFlag & AnyTracksSelectedFlag()
const ReservedCommandFlag & TracksExistFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
const ReservedCommandFlag & TrackPanelHasFocus()
int min(int a, int b)
EffectDistortion::Params params
Definition: Distortion.cpp:83
wxString PluginID
Definition: EffectManager.h:30
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
void MixAndRender(const TrackIterRange< const WaveTrack > &trackRange, const Mixer::WarpOptions &warpOptions, const wxString &newTrackName, WaveTrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime, WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effec...
FileConfig * gPrefs
Definition: Prefs.cpp:71
an object holding per-project preferred sample rate
@ floatSample
Definition: SampleFormat.h:34
@ eIsCreating
Definition: ShuttleGui.h:39
#define S(N)
Definition: ToChars.cpp:64
std::pair< ListOfTracks::iterator, ListOfTracks * > TrackNodePointer
Pairs a std::list iterator and a pointer to a list, for comparison purposes.
Definition: Track.h:48
static Settings & settings()
Definition: TrackInfo.cpp:87
static CommandHandlerObject & findCommandHandler(AudacityProject &)
#define FN(X)
static std::once_flag flag
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
Track subclass holding data representing sound (as notes, or samples, or ...)
Definition: Track.h:889
size_t size() const
How many attachment pointers are in the Site.
Definition: ClientData.h:251
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Definition: ClientData.h:309
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
TemporarySelection temporarySelection
AudacityProject & project
static EffectManager & Get()
const PluginID & GetEffectByIdentifier(const CommandID &strTarget)
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
Abstract base class used in importing a file.
Lightweight version of ASlider. In other words it does not have a window permanently associated with ...
Definition: ASlider.h:62
void Decrease(float steps)
Definition: ASlider.cpp:1505
void Increase(float steps)
Definition: ASlider.cpp:1482
float Get(bool convert=true)
Definition: ASlider.cpp:1457
bool ShowDialog()
Definition: ASlider.cpp:1068
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:89
static void ModifyAllProjectToolbarMenus()
Definition: Menus.cpp:592
Functions for doing the mixdown of the tracks.
Definition: Mix.h:58
size_t Process(size_t maxSamples)
Definition: Mix.cpp:454
constSamplePtr GetBuffer()
Retrieve the main buffer or the interleaved buffer.
Definition: Mix.cpp:540
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:67
void Clear(double t0, double t1) override
Definition: NoteTrack.cpp:521
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:909
void SetMute(bool m)
Definition: Track.cpp:319
bool IsEnabled() const
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectSettings & Get(AudacityProject &project)
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
static ProjectWindow & Get(AudacityProject &project)
ScoreAlignDialog is \TODO.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:73
Track * Get()
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:98
bool IsSelected() const
Definition: Track.cpp:383
virtual double GetStartTime() const =0
wxString GetName() const
Definition: Track.h:458
virtual double GetOffset() const =0
virtual double GetEndTime() const =0
bool IsLeader() const
Definition: Track.cpp:386
bool Any() const
Definition: Track.cpp:380
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:467
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1446
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1533
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
void RefreshTrack(Track *trk, bool refreshbacking=true)
Definition: TrackPanel.cpp:743
Holds a msgid for the translation catalog; may also bind format arguments.
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:67
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:216
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
static LWSlider * PanSlider(CellularPanel &panel, const WaveTrack &wt)
static LWSlider * GainSlider(CellularPanel &panel, const WaveTrack &wt)
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2800
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
Definition: WaveTrack.cpp:2015
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:105
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
#define lrint(dbl)
Definition: float_cast.h:169
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
Definition: BasicUI.h:271
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1275
std::unique_ptr< MenuItem > Menu(const Identifier &internalName, const TranslatableString &title, Args &&... args)
std::unique_ptr< MenuPart > Section(const Identifier &internalName, Args &&... args)
std::unique_ptr< CommandGroupItem > CommandGroup(const Identifier &name, std::vector< ComponentInterfaceSymbol > items, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, bool isEffect=false, CommandHandlerFinder finder=FinderScope::DefaultFinder())
std::unique_ptr< CommandItem > Command(const CommandID &name, const TranslatableString &label_in, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, const CommandManager::Options &options={}, CommandHandlerFinder finder=FinderScope::DefaultFinder())
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for, if Traits<Type>::iterated_type is defined.
Definition: PackedArray.h:126
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for, if Traits<Type>::iterated_type is defined.
Definition: PackedArray.h:112
PROJECT_RATE_API sampleFormat SampleFormatChoice()
std::unique_ptr< BaseItem > BaseItemPtr
Definition: Registry.h:71
std::shared_ptr< BaseItem > BaseItemSharedPtr
Definition: Registry.h:72
void DoTrackMute(AudacityProject &project, Track *t, bool exclusive)
void DoMoveTrack(AudacityProject &project, Track *target, MoveChoice choice)
Move a track up, down, to top or to bottom.
void DoTrackSolo(AudacityProject &project, Track *t, bool exclusive)
void DoRemoveTrack(AudacityProject &project, Track *toRemove)
void DoRemoveTracks(AudacityProject &project)
std::vector< CommandFlagOptions > & Options()
Definition: Menus.cpp:535
static const std::vector< ComponentInterfaceSymbol > & alignLabels()
Definition: TrackMenus.cpp:188
void DoAlign(AudacityProject &project, int index, bool moveSel)
Definition: TrackMenus.cpp:199
void SetTrackGain(AudacityProject &project, WaveTrack *wt, LWSlider *slider)
Definition: TrackMenus.cpp:577
void DoSortTracks(AudacityProject &project, int flags)
Definition: TrackMenus.cpp:500
void DoPanTracks(AudacityProject &project, float PanValue)
Definition: TrackMenus.cpp:155
void DoMixAndRender(AudacityProject &project, bool toNewTrack)
Definition: TrackMenus.cpp:48
void SetTrackPan(AudacityProject &project, WaveTrack *wt, LWSlider *slider)
Definition: TrackMenus.cpp:591
void OnSortTime(const CommandContext &context)
Definition: TrackMenus.cpp:964
void OnStereoToMono(const CommandContext &context)
Definition: TrackMenus.cpp:613
void OnMuteSelectedTracks(const CommandContext &context)
Definition: TrackMenus.cpp:776
void OnTrackGain(const CommandContext &context)
void OnTrackPanRight(const CommandContext &context)
void OnTrackMenu(const CommandContext &context)
void OnTrackMoveBottom(const CommandContext &context)
void OnPanCenter(const CommandContext &context)
Definition: TrackMenus.cpp:798
void OnTrackMoveDown(const CommandContext &context)
void OnAlignNoSync(const CommandContext &context)
Definition: TrackMenus.cpp:804
void OnTrackGainDec(const CommandContext &context)
void OnMixAndRenderToNewTrack(const CommandContext &context)
Definition: TrackMenus.cpp:627
void OnMoveSelectionWithTracks(const CommandContext &WXUNUSED(context))
Definition: TrackMenus.cpp:829
void OnTrackGainInc(const CommandContext &context)
void OnUnmuteSelectedTracks(const CommandContext &context)
Definition: TrackMenus.cpp:781
void OnResample(const CommandContext &context)
Definition: TrackMenus.cpp:633
void OnTrackPan(const CommandContext &context)
void OnTrackSolo(const CommandContext &context)
void OnTrackClose(const CommandContext &context)
void OnSortName(const CommandContext &context)
Definition: TrackMenus.cpp:973
void OnPanRight(const CommandContext &context)
Definition: TrackMenus.cpp:792
void OnSyncLock(const CommandContext &context)
Definition: TrackMenus.cpp:982
void OnAlign(const CommandContext &context)
Definition: TrackMenus.cpp:812
void OnTrackMute(const CommandContext &context)
void OnPanLeft(const CommandContext &context)
Definition: TrackMenus.cpp:786
void OnTrackPanLeft(const CommandContext &context)
void OnUnmuteAllTracks(const CommandContext &context)
Definition: TrackMenus.cpp:771
static void MuteTracks(const CommandContext &context, bool mute, bool selected)
Definition: TrackMenus.cpp:745
void OnMixAndRender(const CommandContext &context)
Definition: TrackMenus.cpp:621
void OnTrackMoveUp(const CommandContext &context)
void OnMuteAllTracks(const CommandContext &context)
Definition: TrackMenus.cpp:766
void OnRemoveTracks(const CommandContext &context)
Definition: TrackMenus.cpp:740
void OnTrackMoveTop(const CommandContext &context)