Audacity 3.2.0
WaveTrackControls.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5WaveTrackControls.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12#include "WaveTrackControls.h"
13
14#include "../../ui/PlayableTrackButtonHandles.h"
16
17#include "WaveChannelView.h"
19#include "AudioIOBase.h"
20#include "../../../../CellularPanel.h"
21#include "Project.h"
22#include "ProjectAudioIO.h"
23#include "ProjectHistory.h"
24#include "../../../../ProjectWindows.h"
25#include "../../../../RefreshCode.h"
26#include "ShuttleGui.h"
27#include "SyncLock.h"
28#include "Theme.h"
29#include "../../../../TrackArtist.h"
30#include "../../../../TrackPanel.h"
31#include "TrackFocus.h"
32#include "../../../../TrackPanelMouseEvent.h"
33#include "WaveTrack.h"
35#include "../../../../prefs/PrefsDialog.h"
36#include "../../../../prefs/ThemePrefs.h"
37#include "AudacityMessageBox.h"
38#include "ProgressDialog.h"
39#include "UserException.h"
40#include "Identifier.h"
41
42#include <wx/app.h>
43#include <wx/combobox.h>
44#include <wx/frame.h>
45#include <wx/sizer.h>
46
47#include "MixAndRender.h"
48
50
51std::vector<UIHandlePtr> WaveTrackControls::HitTest
52(const TrackPanelMouseState & st,
53 const AudacityProject *pProject)
54{
55 // Hits are mutually exclusive, results single
56 const wxMouseState &state = st.state;
57 const wxRect &rect = st.rect;
58 if (state.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
59 auto track = FindTrack();
60 std::vector<UIHandlePtr> results;
61 auto result = [&]{
62 UIHandlePtr result;
63 if (NULL != (result = MuteButtonHandle::HitTest(
64 mMuteHandle, state, rect, pProject, track)))
65 return result;
66
67 if (NULL != (result = SoloButtonHandle::HitTest(
68 mSoloHandle, state, rect, pProject, track)))
69 return result;
70
71 if (NULL != (result = EffectsButtonHandle::HitTest(
72 mEffectsHandle, state, rect, pProject, track)))
73 return result;
74
75 if (NULL != (result = GainSliderHandle::HitTest(
76 mGainHandle, state, rect, track)))
77 return result;
78
79 if (NULL != (result = PanSliderHandle::HitTest(
80 mPanHandle, state, rect, track)))
81 return result;
82
83 return result;
84 }();
85 if (result) {
86 results.push_back(result);
87 return results;
88 }
89 }
90
91 return PlayableTrackControls::HitTest(st, pProject);
92}
93
95{
96 return *static_cast< WaveTrack* >( mpData->pTrack );
97};
98
99enum {
101
102 OnRate8ID = 30000, // <---
107 OnRate48ID, // | Leave these in order
115 // |
118 OnFloatID, // <---
119
121
123
127
129
133
135
136 // Range of ids for registered items -- keep this last!
138};
139
140
141namespace {
142using ValueFinder = std::function< int( WaveTrack& ) >;
143
144// A function that makes functions that check and enable sub-menu items,
145// parametrized by how you get the relevant value from a track's settings
146template< typename Table >
148{
149 return [findValue]( PopupMenuHandler &handler, wxMenu &menu, int id ){
150 auto pData = static_cast<Table&>( handler ).mpData;
151 const auto pTrack = static_cast<WaveTrack*>(pData->pTrack);
152 auto &project = pData->project;
153 bool unsafe = ProjectAudioIO::Get( project ).IsAudioActive();
154
155 menu.Check( id, id == findValue( *pTrack ) );
156 menu.Enable( id, !unsafe );
157 };
158};
159}
160
161
162//=============================================================================
163// Table class for a sub-menu
165{
167 : PopupMenuTable{ "SampleFormat", XO("&Format") }
168 {}
170
171 static FormatMenuTable &Instance();
172
173 void InitUserData(void *pUserData) override;
174
176
177 static int IdOfFormat(sampleFormat format);
178
179 void OnFormatChange(wxCommandEvent & event);
180};
181
183{
184 static FormatMenuTable instance;
185 return instance;
186}
187
188void FormatMenuTable::InitUserData(void *pUserData)
189{
190 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
191}
192
193
195 static const auto fn = initFn< FormatMenuTable >(
196 []( WaveTrack &track ){
197 return IdOfFormat( track.GetSampleFormat() );
198 }
199 );
200
202 GetSampleFormatStr(int16Sample), POPUP_MENU_FN( OnFormatChange ), fn );
204 GetSampleFormatStr( int24Sample), POPUP_MENU_FN( OnFormatChange ), fn );
206 GetSampleFormatStr(floatSample), POPUP_MENU_FN( OnFormatChange ), fn );
207
209
210
212{
213 switch (format) {
214 case int16Sample:
215 return On16BitID;
216 case int24Sample:
217 return On24BitID;
218 case floatSample:
219 return OnFloatID;
220 default:
221 // ERROR -- should not happen
222 wxASSERT(false);
223 break;
224 }
225 return OnFloatID;// Compiler food.
226}
227
230void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
231{
232 int id = event.GetId();
233 wxASSERT(id >= On16BitID && id <= OnFloatID);
234 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
235
236 sampleFormat newFormat = int16Sample;
237
238 switch (id) {
239 case On16BitID:
240 newFormat = int16Sample;
241 break;
242 case On24BitID:
243 newFormat = int24Sample;
244 break;
245 case OnFloatID:
246 newFormat = floatSample;
247 break;
248 default:
249 // ERROR -- should not happen
250 wxASSERT(false);
251 break;
252 }
253 if (newFormat == pTrack->GetSampleFormat())
254 return; // Nothing to do.
255
257
258 ProgressDialog progress{ XO("Changing sample format"),
259 XO("Processing... 0%%"),
261
262 // Safe assumption for tracks associated with the context menu
263 assert(pTrack->IsLeader());
264
265 // Simply finding a denominator for the progress dialog
266 // Hidden samples are processed too, they should be counted as well
267 // (Correctly counting all samples of all channels)
268 sampleCount totalSamples = pTrack->GetSequenceSamplesCount();
269 sampleCount processedSamples{ 0 };
270
271 // Below is the lambda function that is passed along the call chain to
272 // the Sequence::ConvertToSampleFormat. This callback function is used
273 // to report the conversion progress and update the progress dialog.
274 auto progressUpdate = [&progress, &totalSamples, &processedSamples]
275 (size_t newlyProcessedCount)->void
276 {
277 processedSamples += newlyProcessedCount;
278 double d_processed = processedSamples.as_double();
279 double d_total = totalSamples.as_double();
280 int percentage{ static_cast<int>((d_processed / d_total) * 100) };
281
282 auto progressStatus = progress.Update(d_processed, d_total,
283 XO("Processing... %i%%").Format(percentage));
284
285 if (progressStatus != ProgressResult::Success)
286 throw UserException{};
287 };
288
289 // We get here from the context menu only in the TrackControlPanel cell
290 // which is always associated with a leader track
291 assert(pTrack->IsLeader());
292 pTrack->ConvertToSampleFormat(newFormat, progressUpdate);
293
295 /* i18n-hint: The strings name a track and a format */
296 .PushState(XO("Changed '%s' to %s")
297 .Format( pTrack->GetName(), GetSampleFormatStr(newFormat) ),
298 XO("Format Change"));
299
300 using namespace RefreshCode;
302}
303
304
305//=============================================================================
306// Table class for a sub-menu
308{
310 : PopupMenuTable{ "SampleRate", XO("Rat&e") }
311 {}
313
314 static RateMenuTable &Instance();
315
316 void InitUserData(void *pUserData) override;
317
319
320 static int IdOfRate(int rate);
322 void SetRate(WaveTrack * pTrack, double rate);
323
324 void OnRateChange(wxCommandEvent & event);
325 void OnRateOther(wxCommandEvent & event);
326};
327
329{
330 static RateMenuTable instance;
331 return instance;
332}
333
334void RateMenuTable::InitUserData(void *pUserData)
335{
336 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
337}
338
339// Because of Bug 1780 we can't use AppendRadioItem
340// If we did, we'd get no message when clicking on Other...
341// when it is already selected.
343 static const auto fn = initFn< RateMenuTable >(
344 []( WaveTrack &track ){
345 return IdOfRate( (int)track.GetRate() );
346 }
347 );
348
349 AppendCheckItem( "8000", OnRate8ID, XXO("8000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
350 AppendCheckItem( "11025", OnRate11ID, XXO("11025 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
351 AppendCheckItem( "16000", OnRate16ID, XXO("16000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
352 AppendCheckItem( "22050", OnRate22ID, XXO("22050 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
353 AppendCheckItem( "44100", OnRate44ID, XXO("44100 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
354 AppendCheckItem( "48000", OnRate48ID, XXO("48000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
355 AppendCheckItem( "88200", OnRate88ID, XXO("88200 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
356 AppendCheckItem( "96000", OnRate96ID, XXO("96000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
357 AppendCheckItem( "176400", OnRate176ID, XXO("176400 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
358 AppendCheckItem( "192000", OnRate192ID, XXO("192000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
359 AppendCheckItem( "352800", OnRate352ID, XXO("352800 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
360 AppendCheckItem( "384000", OnRate384ID, XXO("384000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
361 AppendCheckItem( "Other", OnRateOtherID, XXO("&Other..."), POPUP_MENU_FN( OnRateOther ), fn );
362
364
365const int nRates = 12;
366
369static int gRates[nRates] = { 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000,
370176400, 192000, 352800, 384000 };
371
374{
375 for (int i = 0; i<nRates; i++) {
376 if (gRates[i] == rate)
377 return i + OnRate8ID;
378 }
379 return OnRateOtherID;
380}
381
382void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
383{
385 auto end1 = pTrack->GetEndTime();
386 pTrack->SetRate(rate);
387 if (SyncLockState::Get(*project).IsSyncLocked()) {
388 auto end2 = pTrack->GetEndTime();
389 for (auto pLocked : SyncLock::Group(pTrack)) {
390 if (pLocked != pTrack)
391 pLocked->SyncLockAdjust(end1, end2);
392 }
393 }
394
395 // Separate conversion of "rate" enables changing the decimals without affecting i18n
396 wxString rateString = wxString::Format(wxT("%.3f"), rate);
398 /* i18n-hint: The string names a track */
399 .PushState(XO("Changed '%s' to %s Hz")
400 .Format( pTrack->GetName(), rateString),
401 XO("Rate Change"));
402}
403
406void RateMenuTable::OnRateChange(wxCommandEvent & event)
407{
408 int id = event.GetId();
409 wxASSERT(id >= OnRate8ID && id <= OnRate384ID);
410 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
411
412 SetRate(pTrack, gRates[id - OnRate8ID]);
413
414 using namespace RefreshCode;
416}
417
418void RateMenuTable::OnRateOther(wxCommandEvent &)
419{
420 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
421
422 int newRate;
423
426 while (true)
427 {
428 wxDialogWrapper dlg(mpData->pParent, wxID_ANY, XO("Set Rate"));
429 dlg.SetName();
430 ShuttleGui S(&dlg, eIsCreating);
431 wxString rate;
432 wxComboBox *cb;
433
434 rate.Printf(wxT("%ld"), lrint(pTrack->GetRate()));
435
436 wxArrayStringEx rates{
437 wxT("8000") ,
438 wxT("11025") ,
439 wxT("16000") ,
440 wxT("22050") ,
441 wxT("44100") ,
442 wxT("48000") ,
443 wxT("88200") ,
444 wxT("96000") ,
445 wxT("176400") ,
446 wxT("192000") ,
447 wxT("352800") ,
448 wxT("384000") ,
449 };
450
451 S.StartVerticalLay(true);
452 {
453 S.SetBorder(10);
454 S.StartHorizontalLay(wxEXPAND, false);
455 {
456 cb = S.AddCombo(XXO("New sample rate (Hz):"),
457 rate,
458 rates);
459#if defined(__WXMAC__)
460 // As of wxMac-2.8.12, setting manually is required
461 // to handle rates not in the list. See: Bug #427
462 cb->SetValue(rate);
463#endif
464 }
465 S.EndHorizontalLay();
466 S.AddStandardButtons();
467 }
468 S.EndVerticalLay();
469
470 dlg.SetClientSize(dlg.GetSizer()->CalcMin());
471 dlg.Center();
472
473 if (dlg.ShowModal() != wxID_OK)
474 {
475 return; // user cancelled dialog
476 }
477
478 long lrate;
479 if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000)
480 {
481 newRate = (int)lrate;
482 break;
483 }
484
486 XO("The entered value is invalid"),
487 XO("Error"),
488 wxICON_ERROR,
489 mpData->pParent);
490 }
491
492 SetRate(pTrack, newRate);
493
494 using namespace RefreshCode;
496}
497
498static const auto MenuPathStart = wxT("WaveTrackMenu");
499
500//=============================================================================
501// Class defining common command handlers for mono and stereo tracks
503{
505
508 {
510 }
511
512 void InitUserData(void *pUserData) override;
513
515
516 void OnMultiView(wxCommandEvent & event);
517 void OnSetDisplay(wxCommandEvent & event);
518
519 void OnMergeStereo(wxCommandEvent & event);
520
521 // TODO: more-than-two-channels
522 // How should we define generalized channel manipulation operations?
525 void SplitStereo(bool stereo);
526
527 void OnSwapChannels(wxCommandEvent & event);
528 void OnSplitStereo(wxCommandEvent & event);
529 void OnSplitStereoMono(wxCommandEvent & event);
530};
531
533{
534 static WaveTrackMenuTable instance;
535 return instance;
536}
537
539{
540 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
541}
542
543static std::vector<WaveChannelSubViewType> AllTypes()
544{
545 auto result = WaveChannelSubViewType::All();
546 if (result.size() > reserveDisplays) {
547 wxASSERT( false );
548 result.resize(reserveDisplays);
549 }
550 return result;
551}
552
554 // Functions usable in callbacks to check and disable items
555 static const auto isMono =
556 []( PopupMenuHandler &handler ) -> bool {
557 auto &track =
558 static_cast< WaveTrackMenuTable& >( handler ).FindWaveTrack();
559 return 1 == TrackList::NChannels(track);
560 };
561
562 static const auto isUnsafe =
563 []( PopupMenuHandler &handler ) -> bool {
564 auto &project =
565 static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
568 };
569
570
571 BeginSection( "SubViews" );
572 // Multi-view check mark item, if more than one track sub-view type is
573 // known
574 Append(Adapt<My>([](My &table) {
576 ? std::make_unique<Entry>(
577 "MultiView", Entry::CheckItem, OnMultiViewID, XXO("&Multi-view"),
578 POPUP_MENU_FN( OnMultiView ),
579 table,
580 [](PopupMenuHandler &handler, wxMenu &menu, int id){
581 auto &table = static_cast<WaveTrackMenuTable&>(handler);
582 auto &track = table.FindWaveTrack();
583 const auto &view = WaveChannelView::Get(track);
584 menu.Check(id, view.GetMultiView());
585 })
586 : nullptr;
587 }));
588
589 // Append either a checkbox or radio item for each sub-view.
590 // Radio buttons if in single-view mode, else checkboxes
592 for ( const auto &type : AllTypes() ) {
593 static const auto initFn = []( bool radio ){ return
594 [radio]( PopupMenuHandler &handler, wxMenu &menu, int id ){
595 // Find all known sub-view types
596 const auto allTypes = AllTypes();
597
598 // How to convert a type to a menu item id
599 const auto IdForType =
600 [&allTypes](const WaveChannelSubViewType &type) -> int {
601 const auto begin = allTypes.begin();
602 return OnSetDisplayId +
603 (std::find(begin, allTypes.end(), type) - begin);
604 };
605
606 auto &table = static_cast< WaveTrackMenuTable& >( handler );
607 auto &track = table.FindWaveTrack();
608
609 const auto &view = WaveChannelView::Get(track);
610
611 const auto displays = view.GetDisplays();
612 const auto end = displays.end();
613 bool check = (end !=
614 std::find_if(displays.begin(), end,
615 [&](const WaveChannelSubViewType &type){
616 return id == IdForType(type); }));
617 menu.Check( id, check );
618
619 // Bug2275 residual
620 // Disable the checking-off of the only sub-view
621 if ( !radio && displays.size() == 1 && check )
622 menu.Enable( id, false );
623 };
624 };
625 Append(Adapt<My>([type, id](My &table) {
626 const auto pTrack = &table.FindWaveTrack();
627 const auto &view = WaveChannelView::Get(*pTrack);
628 const auto itemType =
629 view.GetMultiView() ? Entry::CheckItem : Entry::RadioItem;
630 return std::make_unique<Entry>( type.name.Internal(), itemType,
631 id, type.name.Msgid(),
632 POPUP_MENU_FN( OnSetDisplay ), table,
633 initFn( !view.GetMultiView() ) );
634 }));
635 ++id;
636 }
637 BeginSection( "Extra" );
639 EndSection();
640
641 BeginSection( "Channels" );
642 AppendItem( "MakeStereo", OnMergeStereoID, XXO("Ma&ke Stereo Track"),
643 POPUP_MENU_FN( OnMergeStereo ),
644 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
645 bool canMakeStereo = !isUnsafe( handler ) && isMono( handler );
646 if ( canMakeStereo ) {
648 static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
649 auto &tracks = TrackList::Get( project );
650 auto &table = static_cast< WaveTrackMenuTable& >( handler );
651 auto &track = table.FindWaveTrack();
652 auto next = * ++ tracks.Find(&track);
653 canMakeStereo =
654 (next &&
655 TrackList::NChannels(*next) == 1 &&
656 track_cast<WaveTrack*>(next));
657 }
658 menu.Enable( id, canMakeStereo );
659 }
660 );
661
662 AppendItem( "Swap", OnSwapChannelsID, XXO("Swap Stereo &Channels"),
663 POPUP_MENU_FN( OnSwapChannels ),
664 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
665 auto &track =
666 static_cast< WaveTrackMenuTable& >( handler ).FindWaveTrack();
667 bool isStereo =
668 2 == TrackList::NChannels(track);
669 menu.Enable( id, isStereo && !isUnsafe( handler ) );
670 }
671 );
672
673 static const auto enableSplitStereo =
674 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
675 menu.Enable( id, !isMono( handler ) && !isUnsafe( handler ) );
676 };
677
678 AppendItem( "Split", OnSplitStereoID, XXO("Spl&it Stereo Track"),
679 POPUP_MENU_FN( OnSplitStereo ), enableSplitStereo );
681 XXO("Split Stereo to Mo&no"), POPUP_MENU_FN( OnSplitStereoMono ),
683 EndSection();
684
685 BeginSection( "Format" );
686 POPUP_MENU_SUB_MENU( "Format", FormatMenuTable, mpData )
687 EndSection();
688
689 BeginSection( "Rate" );
690 POPUP_MENU_SUB_MENU( "Rate", RateMenuTable, mpData )
691 EndSection();
693
694
695void WaveTrackMenuTable::OnMultiView(wxCommandEvent & event)
696{
697 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
698 auto &view = WaveChannelView::Get(*pTrack);
699 bool multi = !view.GetMultiView();
700 const auto &displays = view.GetDisplays();
701 const auto display = displays.empty()
702 ? WaveChannelViewConstants::Waveform : displays.begin()->id;
703 view.SetMultiView(multi);
704
705 // Whichever sub-view was on top stays on top
706 // If going into Multi-view, it will be 1/nth the height.
707 // If exiting multi-view, it will be full height.
708 view.SetDisplay(display, !multi);
709}
710
712void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
713{
714 int idInt = event.GetId();
715 wxASSERT(idInt >= OnSetDisplayId &&
716 idInt <= lastDisplayId);
717 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
718
719 auto id = AllTypes()[ idInt - OnSetDisplayId ].id;
720
721 auto &view = WaveChannelView::Get(*pTrack);
722 if (view.GetMultiView()) {
723 if (!WaveChannelView::Get(*pTrack)
724 .ToggleSubView(WaveChannelView::Display{ id } )) {
725 // Trying to toggle off the last sub-view. It was refused.
726 // Decide what to do here. Turn off multi-view instead?
727 // PRL: I don't agree that it makes sense
728 }
729 else
731 }
732 else {
733 const auto displays = view.GetDisplays();
734 const bool wrongType =
735 !(displays.size() == 1 && displays[0].id == id);
736 if (wrongType) {
738
740 ProjectHistory::Get( *project ).ModifyState(true);
741
742 using namespace RefreshCode;
744 }
745 }
746}
747
750{
752 auto &tracks = TrackList::Get( *project );
753
754 const auto first = tracks.Any<WaveTrack>().find(mpData->pTrack);
755 const auto left = *first;
756 const auto right = *std::next(first);
757
758 const auto checkAligned = [](const WaveTrack& left, const WaveTrack& right)
759 {
760 auto eqTrims = [](double a, double b)
761 {
762 return std::abs(a - b) <=
763 std::numeric_limits<double>::epsilon() * std::max(a, b);
764 };
765 const auto eps = 0.5 / left.GetRate();
766 const auto rightIntervals = right.Intervals();
767 for(const auto& a : left.Intervals())
768 {
769 auto it = std::find_if(
770 rightIntervals.begin(),
771 rightIntervals.end(),
772 [&](const auto& b)
773 {
774 //Start() and End() are always snapped to a sample grid
775 return std::abs(a->Start() - b->Start()) < eps &&
776 std::abs(a->End() - b->End()) < eps &&
777 eqTrims(a->GetTrimLeft(), b->GetTrimLeft()) &&
778 eqTrims(a->GetTrimRight(), b->GetTrimRight()) &&
779 a->HasEqualPitchAndSpeed(*b);
780 });
781 if(it == rightIntervals.end())
782 return false;
783 }
784 return true;
785 };
786
787 if(RealtimeEffectList::Get(*left).GetStatesCount() != 0 ||
789 !checkAligned(*left, *right))
790 {
791 const auto answer = BasicUI::ShowMessageBox(
792 XO(
793"The tracks you are attempting to merge to stereo contain clips at\n"
794"different positions, or otherwise mismatching clips. Merging them\n"
795"will render the tracks.\n\n"
796"This causes any realtime effects to be applied to the waveform and\n"
797"hidden data to be removed. Additionally, the entire track will\n"
798"become one large clip.\n\n"
799"Do you wish to continue?"
800 ),
803 .Caption(XO("Combine mono to stereo")));
805 return;
806 }
807
808 const auto viewMinimized =
810 ChannelView::Get(*right->GetChannel(0)).GetMinimized();
811 const auto averageViewHeight =
813 WaveChannelView::Get(*right).GetHeight()) / 2;
814
815 left->SetPan(-1.0f);
816 right->SetPan(1.0f);
817 auto mix = MixAndRender(
819 tracks.Any<const WaveTrack>().find(left),
820 ++tracks.Any<const WaveTrack>().find(right)
821 },
822 Mixer::WarpOptions{ tracks.GetOwner() },
823 (*first)->GetName(),
825 //use highest sample rate
826 std::max(left->GetRate(), right->GetRate()),
827 //use widest sample format
828 std::max(left->GetSampleFormat(), right->GetSampleFormat()),
829 0.0, 0.0);
830
831 const auto newTrack = *mix->begin();
832
833 tracks.Insert(*first, std::move(*mix));
834 tracks.Remove(*left);
835 tracks.Remove(*right);
836
837 for(const auto& channel : newTrack->Channels())
838 {
839 // Set NEW track heights and minimized state
840 auto& view = ChannelView::Get(*channel);
841 view.SetMinimized(viewMinimized);
842 view.SetExpandedHeight(averageViewHeight);
843 }
844 ProjectHistory::Get( *project ).PushState(
845 /* i18n-hint: The string names a track */
846 XO("Made '%s' a stereo track").Format( newTrack->GetName() ),
847 XO("Make Stereo"));
848
849 using namespace RefreshCode;
851}
852
855{
857
858 int totalHeight = 0;
859 int nChannels = 0;
860
861 const auto pTrack = mpData->pTrack;
862 static_cast<WaveTrack*>(pTrack)->CopyClipEnvelopes();
863 auto unlinkedTracks = TrackList::Get(*project).UnlinkChannels(*pTrack);
864 assert(unlinkedTracks.size() == 2);
865 if(stereo)
866 {
867 static_cast<WaveTrack*>(unlinkedTracks[0])->SetPan(-1.0f);
868 static_cast<WaveTrack*>(unlinkedTracks[1])->SetPan(1.0f);
869 }
870
871 for (const auto track : unlinkedTracks) {
872 auto &view = ChannelView::Get(*track->GetChannel(0));
873
874 //make sure no channel is smaller than its minimum height
875 if (view.GetHeight() < view.GetMinimizedHeight())
876 view.SetExpandedHeight(view.GetMinimizedHeight());
877 totalHeight += view.GetHeight();
878 ++nChannels;
879 }
880
881 int averageHeight = totalHeight / nChannels;
882
883 for (const auto track : unlinkedTracks)
884 // Make tracks the same height
885 ChannelView::Get(*track->GetChannel(0)).SetExpandedHeight(averageHeight);
886}
887
890{
891 // Fix assertion violation in `TrackPanel::OnEnsureVisible` by
892 // dispatching any queued event
893 // TODO wide wave tracks -- remove this when there is no "leader" distinction
894 // any more
895 wxTheApp->Yield();
896
898
899 auto &trackFocus = TrackFocus::Get( *project );
900 const auto pTrack = mpData->pTrack;
901 const bool hasFocus = trackFocus.Get() == pTrack;
902 static_cast<WaveTrack*>(pTrack)->CopyClipEnvelopes();
903 if (auto track = TrackList::SwapChannels(*pTrack))
904 {
905 if (hasFocus)
906 trackFocus.Set(track);
907
908 ProjectHistory::Get( *project ).PushState(
909 /* i18n-hint: The string names a track */
910 XO("Swapped Channels in '%s'").Format( track->GetName() ),
911 XO("Swap Channels"));
912 }
913
915}
916
919{
920 SplitStereo(true);
921 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
923 ProjectHistory::Get( *project ).PushState(
924 /* i18n-hint: The string names a track */
925 XO("Split stereo track '%s'").Format( pTrack->GetName() ),
926 XO("Split"));
927
928 using namespace RefreshCode;
930}
931
934{
935 SplitStereo(false);
936 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
938 ProjectHistory::Get( *project ).PushState(
939 /* i18n-hint: The string names a track */
940 XO("Split Stereo to Mono '%s'").Format( pTrack->GetName() ),
941 XO("Split to Mono"));
942
943 using namespace RefreshCode;
945}
946
948{
951 {
952 {wxT("/SubViews/Extra"), wxT("WaveColor,SpectrogramSettings")},
953 }
954 };
955
957 return &result;
958}
959
961{
963}
964
965// drawing related
966#include "../../../../widgets/ASlider.h"
967#include "../../../ui/CommonTrackInfo.h"
968#include "../../../../TrackPanelDrawingContext.h"
969#include "ViewInfo.h"
970
971namespace {
972
974( LWSlider *(*Selector)
975 (const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow*),
976 wxDC *dc, const wxRect &rect, const Track *pTrack,
977 wxWindow *pParent,
978 bool captured, bool highlight )
979{
980 wxRect sliderRect = rect;
981 CommonTrackInfo::GetSliderHorizontalBounds( rect.GetTopLeft(), sliderRect );
982 auto wt = static_cast<const WaveTrack*>( pTrack );
983 Selector( sliderRect, wt, captured, pParent )->OnPaint(*dc, highlight);
984}
985
987( TrackPanelDrawingContext &context,
988 const wxRect &rect, const Track *pTrack )
989{
990 auto target = dynamic_cast<PanSliderHandle*>( context.target.get() );
991 auto dc = &context.dc;
992 bool hit = target && target->GetTrack().get() == pTrack;
993 bool captured = hit && target->IsDragging();
994
995 const auto artist = TrackArtist::Get( context );
996 auto pParent = FindProjectFrame( artist->parent->GetProject() );
997
999 &WaveTrackControls::PanSlider, dc, rect, pTrack,
1000 pParent, captured, hit);
1001}
1002
1004( TrackPanelDrawingContext &context,
1005 const wxRect &rect, const Track *pTrack )
1006{
1007 auto target = dynamic_cast<GainSliderHandle*>( context.target.get() );
1008 auto dc = &context.dc;
1009 bool hit = target && target->GetTrack().get() == pTrack;
1010 if( hit )
1011 hit=hit;
1012 bool captured = hit && target->IsDragging();
1013
1014 const auto artist = TrackArtist::Get( context );
1015 auto pParent = FindProjectFrame( artist->parent->GetProject() );
1016
1018 &WaveTrackControls::GainSlider, dc, rect, pTrack,
1019 pParent, captured, hit);
1020}
1021
1023 ( const TranslatableString &string, wxDC *dc, const wxRect &rect )
1024{
1025 static const int offset = 3;
1026 dc->DrawText(string.Translation(), rect.x + offset, rect.y);
1027}
1028
1030( TrackPanelDrawingContext &context,
1031 const wxRect &rect, const Track *pTrack )
1032{
1033 auto dc = &context.dc;
1034 auto wt = static_cast<const WaveTrack*>(pTrack);
1035
1039 auto rate = wt ? wt->GetRate() : 44100.0;
1041 if (!pTrack || TrackList::NChannels(*pTrack) > 1)
1042 // TODO: more-than-two-channels-message
1043 // more appropriate strings
1044 s = XO("Stereo, %dHz");
1045 else
1046 s = XO("Mono, %dHz");
1047 s.Format( (int) (rate + 0.5) );
1048
1049 StatusDrawFunction( s, dc, rect );
1050}
1051
1053( TrackPanelDrawingContext &context,
1054 const wxRect &rect, const Track *pTrack )
1055{
1056 auto dc = &context.dc;
1057 auto wt = static_cast<const WaveTrack*>(pTrack);
1058 auto format = wt ? wt->GetSampleFormat() : floatSample;
1059 auto s = GetSampleFormatStr(format);
1060 StatusDrawFunction( s, dc, rect );
1061}
1062
1063}
1064
1066
1067static const struct WaveTrackTCPLines
1069 (TCPLines&)*this =
1071 insert( end(), {
1072
1077
1082
1083 } );
1085
1086void WaveTrackControls::GetGainRect(const wxPoint &topleft, wxRect & dest)
1087{
1090 dest.y = topleft.y + results.first;
1091 dest.height = results.second;
1092}
1093
1094void WaveTrackControls::GetPanRect(const wxPoint &topleft, wxRect & dest)
1095{
1096 GetGainRect( topleft, dest );
1098 dest.y = topleft.y + results.first;
1099}
1100
1102{
1104}
1105
1107{
1108 return waveTrackTCPLines;
1109}
1110
1111namespace
1112{
1113std::unique_ptr<LWSlider>
1118}
1119
1121 CellularPanel &panel, const WaveTrack &wt )
1122{
1123 auto &controls = TrackControls::Get( wt );
1124 auto rect = panel.FindRect( controls );
1125 wxRect sliderRect;
1126 GetGainRect( rect.GetTopLeft(), sliderRect );
1127 return GainSlider( sliderRect, &wt, false, &panel );
1128}
1129
1131(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *pParent)
1132{
1133 static std::once_flag flag;
1134 std::call_once( flag, []{ ReCreateGainSlider({}); });
1136
1137 wxPoint pos = sliderRect.GetPosition();
1138 float gain = t ? t->GetGain() : 1.0;
1139
1140 gGain->Move(pos);
1141 gGain->Set(gain);
1142 gGainCaptured->Move(pos);
1143 gGainCaptured->Set(gain);
1144
1145 auto slider = (captured ? gGainCaptured : gGain).get();
1146 slider->SetParent( pParent );
1147 return slider;
1148}
1149
1151{
1152 if (message.appearance)
1153 return;
1154 const wxPoint point{ 0, 0 };
1155 wxRect sliderRect;
1156 GetGainRect(point, sliderRect);
1157
1158 float defPos = 1.0;
1159 /* i18n-hint: Title of the Gain slider, used to adjust the volume */
1160 gGain = std::make_unique<LWSlider>(nullptr, XO("Gain"),
1161 wxPoint(sliderRect.x, sliderRect.y),
1162 wxSize(sliderRect.width, sliderRect.height),
1163 DB_SLIDER);
1164 gGain->SetDefaultValue(defPos);
1165
1166 gGainCaptured = std::make_unique<LWSlider>(nullptr, XO("Gain"),
1167 wxPoint(sliderRect.x, sliderRect.y),
1168 wxSize(sliderRect.width, sliderRect.height),
1169 DB_SLIDER);
1170 gGainCaptured->SetDefaultValue(defPos);
1171}
1172
1174 CellularPanel &panel, const WaveTrack &wt )
1175{
1176 auto &controls = TrackControls::Get( wt );
1177 auto rect = panel.FindRect( controls );
1178 wxRect sliderRect;
1179 GetPanRect( rect.GetTopLeft(), sliderRect );
1180 return PanSlider( sliderRect, &wt, false, &panel );
1181}
1182
1184(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *pParent)
1185{
1186 static std::once_flag flag;
1187 std::call_once( flag, []{ ReCreatePanSlider({}); });
1189
1190 wxPoint pos = sliderRect.GetPosition();
1191 float pan = t ? t->GetPan() : 0.0;
1192
1193 gPan->Move(pos);
1194 gPan->Set(pan);
1195 gPanCaptured->Move(pos);
1196 gPanCaptured->Set(pan);
1197
1198 auto slider = (captured ? gPanCaptured : gPan).get();
1199 slider->SetParent( pParent );
1200 return slider;
1201}
1202
1204{
1205 if (message.appearance)
1206 return;
1207 const wxPoint point{ 0, 0 };
1208 wxRect sliderRect;
1209 GetPanRect(point, sliderRect);
1210
1211 float defPos = 0.0;
1212 /* i18n-hint: Title of the Pan slider, used to move the sound left or right */
1213 gPan = std::make_unique<LWSlider>(nullptr, XO("Pan"),
1214 wxPoint(sliderRect.x, sliderRect.y),
1215 wxSize(sliderRect.width, sliderRect.height),
1216 PAN_SLIDER);
1217 gPan->SetDefaultValue(defPos);
1218
1219 gPanCaptured = std::make_unique<LWSlider>(nullptr, XO("Pan"),
1220 wxPoint(sliderRect.x, sliderRect.y),
1221 wxSize(sliderRect.width, sliderRect.height),
1222 PAN_SLIDER);
1223 gPanCaptured->SetDefaultValue(defPos);
1224}
1225
1228 return [](WaveTrack &track) {
1229 return std::make_shared<WaveTrackControls>( track.SharedPointer() );
1230 };
1231}
1232
1235 return [](WaveTrack &) {
1237 };
1238}
1239
#define DB_SLIDER
Definition: ASlider.h:33
#define PAN_SLIDER
Definition: ASlider.h:34
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
std::vector< TrackInfo::TCPLine > TCPLines
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
TrackListHolder MixAndRender(const TrackIterRange< const WaveTrack > &trackRange, const Mixer::WarpOptions &warpOptions, const wxString &newTrackName, WaveTrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime)
Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effec...
#define END_POPUP_MENU()
#define POPUP_MENU_SUB_MENU(stringId, classname, pUserData)
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
@ pdlgHideStopButton
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
TranslatableString GetSampleFormatStr(sampleFormat format)
constexpr sampleFormat int16Sample
Definition: SampleFormat.h:43
constexpr sampleFormat floatSample
Definition: SampleFormat.h:45
constexpr sampleFormat int24Sample
Definition: SampleFormat.h:44
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30
@ eIsCreating
Definition: ShuttleGui.h:37
const auto tracks
const auto project
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
An AudacityException with no visible message.
@ kTrackInfoSliderExtra
Definition: ViewInfo.h:101
@ kTrackInfoSliderHeight
Definition: ViewInfo.h:98
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetWaveTrackControls)
static const auto fn
EndSection()
AppendCheckItem("8000", OnRate8ID, XXO("8000 Hz"), POPUP_MENU_FN(OnRateChange), fn)
static std::vector< WaveChannelSubViewType > AllTypes()
TrackInfo::TCPLine TCPLine
Append(Adapt< My >([](My &table) { return(WaveChannelSubViews::numFactories() > 1) ? std::make_unique< Entry >("MultiView", Entry::CheckItem, OnMultiViewID, XXO("&Multi-view"), POPUP_MENU_FN(OnMultiView), table, [](PopupMenuHandler &handler, wxMenu &menu, int id){ auto &table=static_cast< WaveTrackMenuTable & >(handler);auto &track=table.FindWaveTrack();const auto &view=WaveChannelView::Get(track);menu.Check(id, view.GetMultiView());}) :nullptr;}))
const int nRates
static const auto enableSplitStereo
BeginSection("SubViews")
int id
static int gRates[nRates]
@ OnRate16ID
@ OnRate352ID
@ On16BitID
@ OnMultiViewID
@ OnChannelRightID
@ OnRate176ID
@ OnRate88ID
@ OnFloatID
@ ChannelMenuID
@ OnRate192ID
@ OnSplitStereoMonoID
@ OnRate48ID
@ OnMergeStereoID
@ reserveDisplays
@ OnRate384ID
@ OnRate44ID
@ OnRateOtherID
@ OnSplitStereoID
@ lastDisplayId
@ On24BitID
@ OnRate22ID
@ OnSetDisplayId
@ OnChannelLeftID
@ OnChannelMonoID
@ OnRate8ID
@ OnRate96ID
@ OnSwapChannelsID
@ FirstAttachedItemId
@ OnRate11ID
WaveTrackTCPLines waveTrackTCPLines
AppendRadioItem("16Bit", On16BitID, GetSampleFormatStr(int16Sample), POPUP_MENU_FN(OnFormatChange), fn)
WaveTrackPopupMenuTable & GetWaveTrackMenuTable()
static const auto isMono
static const auto MenuPathStart
static const auto isUnsafe
AppendItem("MakeStereo", OnMergeStereoID, XXO("Ma&ke Stereo Track"), POPUP_MENU_FN(OnMergeStereo), [](PopupMenuHandler &handler, wxMenu &menu, int id){ bool canMakeStereo=!isUnsafe(handler) &&isMono(handler);if(canMakeStereo) { AudacityProject &project=static_cast< WaveTrackMenuTable & >(handler).mpData->project;auto &tracks=TrackList::Get(project);auto &table=static_cast< WaveTrackMenuTable & >(handler);auto &track=table.FindWaveTrack();auto next= *++tracks.Find(&track);canMakeStereo=(next &&TrackList::NChannels(*next)==1 &&track_cast< WaveTrack * >(next));} menu.Enable(id, canMakeStereo);})
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:90
Formerly part of TrackPanel, this abstract base class has no special knowledge of Track objects and i...
Definition: CellularPanel.h:34
wxRect FindRect(const TrackPanelCell &cell)
static ChannelView & Get(Channel &channel)
bool GetMinimized() const
Definition: ChannelView.h:68
int GetHeight() const
void SetExpandedHeight(int height)
static size_t numFactories()
How many static factories have been registered with this specialization of Site.
Definition: ClientData.h:266
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Definition: ClientData.h:317
virtual std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *) override=0
std::shared_ptr< Track > FindTrack()
static UIHandlePtr HitTest(std::weak_ptr< EffectsButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
Abstract base class used in importing a file.
static UIHandlePtr HitTest(std::weak_ptr< GainSliderHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< Track > &pTrack)
Lightweight version of ASlider. In other words it does not have a window permanently associated with ...
Definition: ASlider.h:64
static UIHandlePtr HitTest(std::weak_ptr< MuteButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
static UIHandlePtr HitTest(std::weak_ptr< PanSliderHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< Track > &pTrack)
static const TCPLines & StaticWaveTCPLines()
const TranslatableString & Caption() const
ProgressDialog Class.
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 RealtimeEffectList & Get(AudacityProject &project)
size_t GetStatesCount() const noexcept
static RealtimeEffectManager & Get(AudacityProject &project)
bool IsActive() const noexcept
To be called only from main thread.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
static UIHandlePtr HitTest(std::weak_ptr< SoloButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
static TrackIterRange< Track > Group(Track *pTrack)
Definition: SyncLock.cpp:161
bool IsSyncLocked() const
Definition: SyncLock.cpp:43
static SyncLockState & Get(AudacityProject &project)
Definition: SyncLock.cpp:26
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:69
static TrackControls & Get(Track &track)
Track * Get()
Definition: TrackFocus.cpp:156
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:122
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:160
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:56
static Track * SwapChannels(Track &track)
Definition: Track.cpp:527
size_t NChannels() const
Definition: Track.cpp:960
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
std::vector< Track * > UnlinkChannels(Track &track)
Removes linkage if track belongs to a group.
Definition: Track.cpp:691
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
Can be thrown when user cancels operations, as with a progress dialog. Delayed handler does nothing.
Definition: UserException.h:17
bool Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len, sampleFormat effectiveFormat=widestSampleFormat)
Random-access assignment of a range of samples.
Definition: WaveTrack.cpp:3560
void SetDisplay(Display display, bool exclusive=true)
static WaveChannelView & Get(WaveChannel &channel)
PopupMenuTable * GetMenuExtension(Track *pTrack) override
std::weak_ptr< MuteButtonHandle > mMuteHandle
static unsigned DefaultWaveTrackHeight()
~WaveTrackControls() override
std::weak_ptr< PanSliderHandle > mPanHandle
static void GetGainRect(const wxPoint &topLeft, wxRect &dest)
static void GetPanRect(const wxPoint &topLeft, wxRect &dest)
std::weak_ptr< EffectsButtonHandle > mEffectsHandle
const TCPLines & GetTCPLines() const override
std::weak_ptr< GainSliderHandle > mGainHandle
static LWSlider * PanSlider(CellularPanel &panel, const WaveTrack &wt)
std::weak_ptr< SoloButtonHandle > mSoloHandle
static void ReCreatePanSlider(struct ThemeChangeMessage)
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
static void ReCreateGainSlider(struct ThemeChangeMessage)
static LWSlider * GainSlider(CellularPanel &panel, const WaveTrack &wt)
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:4529
A Track that contains audio waveform data.
Definition: WaveTrack.h:227
void SetRate(double newRate)
Definition: WaveTrack.cpp:1146
sampleFormat GetSampleFormat() const override
Definition: WaveTrack.cpp:1276
float GetPan() const
Definition: WaveTrack.cpp:1186
void SetPan(float newPan)
Definition: WaveTrack.cpp:1196
double GetEndTime() const override
Implement WideSampleSequence.
Definition: WaveTrack.cpp:3105
float GetGain() const
Definition: WaveTrack.cpp:1168
double GetRate() const override
Definition: WaveTrack.cpp:1141
auto Intervals()
Definition: WaveTrack.h:1043
auto GetChannel(size_t iChannel)
Definition: WaveTrack.h:272
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
double as_double() const
Definition: SampleCount.h:46
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
void SetName(const TranslatableString &title)
#define lrint(dbl)
Definition: float_cast.h:169
@ YesNo
Two buttons.
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:277
AUDACITY_DLL_API unsigned DefaultTrackHeight(const TCPLines &topLines)
AUDACITY_DLL_API void GetSliderHorizontalBounds(const wxPoint &topleft, wxRect &dest)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
AUDACITY_DLL_API std::pair< int, int > CalcItemY(const TCPLines &lines, unsigned iItem)
Definition: TrackInfo.cpp:79
static float findValue(const float *spectrum, float bin0, float bin1, unsigned nBins, bool autocorrelation, int gain, int range)
void SliderDrawFunction(LWSlider *(*Selector)(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *), wxDC *dc, const wxRect &rect, const Track *pTrack, wxWindow *pParent, bool captured, bool highlight)
void Status1DrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
std::function< int(WaveTrack &) > ValueFinder
void GainSliderDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
void Status2DrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
void PanSliderDrawFunction(TrackPanelDrawingContext &context, const wxRect &rect, const Track *pTrack)
PopupMenuTableEntry::InitFunction initFn(const ValueFinder &findValue)
void StatusDrawFunction(const TranslatableString &string, wxDC *dc, const wxRect &rect)
For defining overrides of the method.
MessageBoxOptions && ButtonStyle(Button style) &&
Definition: BasicUI.h:107
void OnFormatChange(wxCommandEvent &event)
void InitUserData(void *pUserData) override
Called before the menu items are appended.
PlayableTrackControls::InitMenuData * mpData
DECLARE_POPUP_MENU(FormatMenuTable)
static int IdOfFormat(sampleFormat format)
Converts a format enumeration to a wxWidgets menu item Id.
static FormatMenuTable & Instance()
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:56
std::function< void(PopupMenuHandler &handler, wxMenu &menu, int id) > InitFunction
void InitUserData(void *pUserData) override
Called before the menu items are appended.
DECLARE_POPUP_MENU(RateMenuTable)
void SetRate(WaveTrack *pTrack, double rate)
Sets the sample rate for a track.
void OnRateOther(wxCommandEvent &event)
static int IdOfRate(int rate)
Converts a sampling rate to a wxWidgets menu item id.
static RateMenuTable & Instance()
PlayableTrackControls::InitMenuData * mpData
void OnRateChange(wxCommandEvent &event)
std::optional< PreferredSystemAppearance > appearance
Definition: Theme.h:112
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Definition: Track.h:825
static const std::vector< WaveChannelSubViewType > & All()
Discover all registered types.
void SplitStereo(bool stereo)
Splits stereo track into two mono tracks, preserving panning if stereo is set.
void OnSplitStereo(wxCommandEvent &event)
Split a stereo track into two tracks...
DECLARE_POPUP_MENU(WaveTrackMenuTable)
void InitUserData(void *pUserData) override
Called before the menu items are appended.
void OnSplitStereoMono(wxCommandEvent &event)
Split a stereo track into two mono tracks...
static WaveTrackMenuTable & Instance()
void OnSwapChannels(wxCommandEvent &event)
Swap the left and right channels of a stero track...
void OnMultiView(wxCommandEvent &event)
void OnSetDisplay(wxCommandEvent &event)
Set the Display mode based on the menu choice in the Track Menu.
void OnMergeStereo(wxCommandEvent &event)
Merge two tracks into one stereo track ??
WaveTrack & FindWaveTrack() const
PlayableTrackControls::InitMenuData * mpData