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 );
680 // DA: Uses split stereo track and then drag pan sliders for split-stereo-to-mono
681 #ifndef EXPERIMENTAL_DA
683 XXO("Split Stereo to Mo&no"), POPUP_MENU_FN( OnSplitStereoMono ),
685 #endif
686 EndSection();
687
688 BeginSection( "Format" );
689 POPUP_MENU_SUB_MENU( "Format", FormatMenuTable, mpData )
690 EndSection();
691
692 BeginSection( "Rate" );
693 POPUP_MENU_SUB_MENU( "Rate", RateMenuTable, mpData )
694 EndSection();
696
697
698void WaveTrackMenuTable::OnMultiView(wxCommandEvent & event)
699{
700 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
701 auto &view = WaveChannelView::Get(*pTrack);
702 bool multi = !view.GetMultiView();
703 const auto &displays = view.GetDisplays();
704 const auto display = displays.empty()
705 ? WaveChannelViewConstants::Waveform : displays.begin()->id;
706 view.SetMultiView(multi);
707
708 // Whichever sub-view was on top stays on top
709 // If going into Multi-view, it will be 1/nth the height.
710 // If exiting multi-view, it will be full height.
711 view.SetDisplay(display, !multi);
712}
713
715void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
716{
717 int idInt = event.GetId();
718 wxASSERT(idInt >= OnSetDisplayId &&
719 idInt <= lastDisplayId);
720 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
721
722 auto id = AllTypes()[ idInt - OnSetDisplayId ].id;
723
724 auto &view = WaveChannelView::Get(*pTrack);
725 if (view.GetMultiView()) {
726 if (!WaveChannelView::Get(*pTrack)
727 .ToggleSubView(WaveChannelView::Display{ id } )) {
728 // Trying to toggle off the last sub-view. It was refused.
729 // Decide what to do here. Turn off multi-view instead?
730 // PRL: I don't agree that it makes sense
731 }
732 else
734 }
735 else {
736 const auto displays = view.GetDisplays();
737 const bool wrongType =
738 !(displays.size() == 1 && displays[0].id == id);
739 if (wrongType) {
741
743 ProjectHistory::Get( *project ).ModifyState(true);
744
745 using namespace RefreshCode;
747 }
748 }
749}
750
753{
755 auto &tracks = TrackList::Get( *project );
756
757 const auto first = tracks.Any<WaveTrack>().find(mpData->pTrack);
758 const auto left = *first;
759 const auto right = *std::next(first);
760
761 const auto checkAligned = [](const WaveTrack& left, const WaveTrack& right)
762 {
763 auto eqTrims = [](double a, double b)
764 {
765 return std::abs(a - b) <=
766 std::numeric_limits<double>::epsilon() * std::max(a, b);
767 };
768 const auto eps = 0.5 / left.GetRate();
769 const auto rightIntervals = right.Intervals();
770 for(const auto& a : left.Intervals())
771 {
772 auto it = std::find_if(
773 rightIntervals.begin(),
774 rightIntervals.end(),
775 [&](const auto& b)
776 {
777 //Start() and End() are always snapped to a sample grid
778 return std::abs(a->Start() - b->Start()) < eps &&
779 std::abs(a->End() - b->End()) < eps &&
780 eqTrims(a->GetTrimLeft(), b->GetTrimLeft()) &&
781 eqTrims(a->GetTrimRight(), b->GetTrimRight()) &&
782 a->StretchRatioEquals(b->GetStretchRatio());
783 });
784 if(it == rightIntervals.end())
785 return false;
786 }
787 return true;
788 };
789
790 if(RealtimeEffectList::Get(*left).GetStatesCount() != 0 ||
792 !checkAligned(*left, *right))
793 {
794 const auto answer = BasicUI::ShowMessageBox(
795 XO(
796"The tracks you are attempting to merge to stereo contain clips at\n"
797"different positions, or otherwise mismatching clips. Merging them\n"
798"will render the tracks.\n\n"
799"This causes any realtime effects to be applied to the waveform and\n"
800"hidden data to be removed. Additionally, the entire track will\n"
801"become one large clip.\n\n"
802"Do you wish to continue?"
803 ),
806 .Caption(XO("Combine mono to stereo")));
808 return;
809 }
810
811 const auto viewMinimized =
812 ChannelView::Get(*left->GetChannel(0)).GetMinimized() &&
813 ChannelView::Get(*right->GetChannel(0)).GetMinimized();
814 const auto averageViewHeight =
816 WaveChannelView::Get(*right).GetHeight()) / 2;
817
818 left->SetPan(-1.0f);
819 right->SetPan(1.0f);
820 auto mix = MixAndRender(
822 tracks.Any<const WaveTrack>().find(left),
823 ++tracks.Any<const WaveTrack>().find(right)
824 },
825 Mixer::WarpOptions{ tracks.GetOwner() },
826 (*first)->GetName(),
828 //use highest sample rate
829 std::max(left->GetRate(), right->GetRate()),
830 //use widest sample format
831 std::max(left->GetSampleFormat(), right->GetSampleFormat()),
832 0.0, 0.0);
833
834 const auto newTrack = *mix->begin();
835
836 tracks.Insert(*first, std::move(*mix));
837 tracks.Remove(*left);
838 tracks.Remove(*right);
839
840 for(const auto& channel : newTrack->Channels())
841 {
842 // Set NEW track heights and minimized state
843 auto& view = ChannelView::Get(*channel);
844 view.SetMinimized(viewMinimized);
845 view.SetExpandedHeight(averageViewHeight);
846 }
847 ProjectHistory::Get( *project ).PushState(
848 /* i18n-hint: The string names a track */
849 XO("Made '%s' a stereo track").Format( newTrack->GetName() ),
850 XO("Make Stereo"));
851
852 using namespace RefreshCode;
854}
855
858{
860
861 int totalHeight = 0;
862 int nChannels = 0;
863
864 const auto pTrack = mpData->pTrack;
865 static_cast<WaveTrack*>(pTrack)->CopyClipEnvelopes();
866 auto unlinkedTracks = TrackList::Get(*project).UnlinkChannels(*pTrack);
867 assert(unlinkedTracks.size() == 2);
868 if(stereo)
869 {
870 static_cast<WaveTrack*>(unlinkedTracks[0])->SetPan(-1.0f);
871 static_cast<WaveTrack*>(unlinkedTracks[1])->SetPan(1.0f);
872 }
873
874 for (const auto track : unlinkedTracks) {
875 auto &view = ChannelView::Get(*track->GetChannel(0));
876
877 //make sure no channel is smaller than its minimum height
878 if (view.GetHeight() < view.GetMinimizedHeight())
879 view.SetExpandedHeight(view.GetMinimizedHeight());
880 totalHeight += view.GetHeight();
881 ++nChannels;
882 }
883
884 int averageHeight = totalHeight / nChannels;
885
886 for (const auto track : unlinkedTracks)
887 // Make tracks the same height
888 ChannelView::Get(*track->GetChannel(0)).SetExpandedHeight(averageHeight);
889}
890
893{
894 // Fix assertion violation in `TrackPanel::OnEnsureVisible` by
895 // dispatching any queued event
896 // TODO wide wave tracks -- remove this when there is no "leader" distinction
897 // any more
898 wxTheApp->Yield();
899
901
902 auto &trackFocus = TrackFocus::Get( *project );
903 const auto pTrack = mpData->pTrack;
904 const bool hasFocus = trackFocus.Get() == pTrack;
905 static_cast<WaveTrack*>(pTrack)->CopyClipEnvelopes();
906 if (auto track = TrackList::SwapChannels(*pTrack))
907 {
908 if (hasFocus)
909 trackFocus.Set(track);
910
911 ProjectHistory::Get( *project ).PushState(
912 /* i18n-hint: The string names a track */
913 XO("Swapped Channels in '%s'").Format( track->GetName() ),
914 XO("Swap Channels"));
915 }
916
918}
919
922{
923 SplitStereo(true);
924 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
926 ProjectHistory::Get( *project ).PushState(
927 /* i18n-hint: The string names a track */
928 XO("Split stereo track '%s'").Format( pTrack->GetName() ),
929 XO("Split"));
930
931 using namespace RefreshCode;
933}
934
937{
938 SplitStereo(false);
939 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
941 ProjectHistory::Get( *project ).PushState(
942 /* i18n-hint: The string names a track */
943 XO("Split Stereo to Mono '%s'").Format( pTrack->GetName() ),
944 XO("Split to Mono"));
945
946 using namespace RefreshCode;
948}
949
951{
954 {
955 {wxT("/SubViews/Extra"), wxT("WaveColor,SpectrogramSettings")},
956 }
957 };
958
960 return &result;
961}
962
964{
966}
967
968// drawing related
969#include "../../../../widgets/ASlider.h"
970#include "../../../ui/CommonTrackInfo.h"
971#include "../../../../TrackPanelDrawingContext.h"
972#include "ViewInfo.h"
973
974namespace {
975
977( LWSlider *(*Selector)
978 (const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow*),
979 wxDC *dc, const wxRect &rect, const Track *pTrack,
980 wxWindow *pParent,
981 bool captured, bool highlight )
982{
983 wxRect sliderRect = rect;
984 CommonTrackInfo::GetSliderHorizontalBounds( rect.GetTopLeft(), sliderRect );
985 auto wt = static_cast<const WaveTrack*>( pTrack );
986 Selector( sliderRect, wt, captured, pParent )->OnPaint(*dc, highlight);
987}
988
990( TrackPanelDrawingContext &context,
991 const wxRect &rect, const Track *pTrack )
992{
993 auto target = dynamic_cast<PanSliderHandle*>( context.target.get() );
994 auto dc = &context.dc;
995 bool hit = target && target->GetTrack().get() == pTrack;
996 bool captured = hit && target->IsDragging();
997
998 const auto artist = TrackArtist::Get( context );
999 auto pParent = FindProjectFrame( artist->parent->GetProject() );
1000
1002 &WaveTrackControls::PanSlider, dc, rect, pTrack,
1003 pParent, captured, hit);
1004}
1005
1007( TrackPanelDrawingContext &context,
1008 const wxRect &rect, const Track *pTrack )
1009{
1010 auto target = dynamic_cast<GainSliderHandle*>( context.target.get() );
1011 auto dc = &context.dc;
1012 bool hit = target && target->GetTrack().get() == pTrack;
1013 if( hit )
1014 hit=hit;
1015 bool captured = hit && target->IsDragging();
1016
1017 const auto artist = TrackArtist::Get( context );
1018 auto pParent = FindProjectFrame( artist->parent->GetProject() );
1019
1021 &WaveTrackControls::GainSlider, dc, rect, pTrack,
1022 pParent, captured, hit);
1023}
1024
1026 ( const TranslatableString &string, wxDC *dc, const wxRect &rect )
1027{
1028 static const int offset = 3;
1029 dc->DrawText(string.Translation(), rect.x + offset, rect.y);
1030}
1031
1033( TrackPanelDrawingContext &context,
1034 const wxRect &rect, const Track *pTrack )
1035{
1036 auto dc = &context.dc;
1037 auto wt = static_cast<const WaveTrack*>(pTrack);
1038
1042 auto rate = wt ? wt->GetRate() : 44100.0;
1044 if (!pTrack || TrackList::NChannels(*pTrack) > 1)
1045 // TODO: more-than-two-channels-message
1046 // more appropriate strings
1047 s = XO("Stereo, %dHz");
1048 else
1049 s = XO("Mono, %dHz");
1050 s.Format( (int) (rate + 0.5) );
1051
1052 StatusDrawFunction( s, dc, rect );
1053}
1054
1056( TrackPanelDrawingContext &context,
1057 const wxRect &rect, const Track *pTrack )
1058{
1059 auto dc = &context.dc;
1060 auto wt = static_cast<const WaveTrack*>(pTrack);
1061 auto format = wt ? wt->GetSampleFormat() : floatSample;
1062 auto s = GetSampleFormatStr(format);
1063 StatusDrawFunction( s, dc, rect );
1064}
1065
1066}
1067
1069
1070static const struct WaveTrackTCPLines
1072 (TCPLines&)*this =
1074 insert( end(), {
1075
1080
1081#ifdef EXPERIMENTAL_DA
1082 // DA: Does not have status information for a track.
1083#else
1088#endif
1089
1090 } );
1092
1093void WaveTrackControls::GetGainRect(const wxPoint &topleft, wxRect & dest)
1094{
1097 dest.y = topleft.y + results.first;
1098 dest.height = results.second;
1099}
1100
1101void WaveTrackControls::GetPanRect(const wxPoint &topleft, wxRect & dest)
1102{
1103 GetGainRect( topleft, dest );
1105 dest.y = topleft.y + results.first;
1106}
1107
1109{
1111}
1112
1114{
1115 return waveTrackTCPLines;
1116}
1117
1118namespace
1119{
1120std::unique_ptr<LWSlider>
1125}
1126
1128 CellularPanel &panel, const WaveTrack &wt )
1129{
1130 auto &controls = TrackControls::Get( wt );
1131 auto rect = panel.FindRect( controls );
1132 wxRect sliderRect;
1133 GetGainRect( rect.GetTopLeft(), sliderRect );
1134 return GainSlider( sliderRect, &wt, false, &panel );
1135}
1136
1138(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *pParent)
1139{
1140 static std::once_flag flag;
1141 std::call_once( flag, []{ ReCreateGainSlider({}); });
1143
1144 wxPoint pos = sliderRect.GetPosition();
1145 float gain = t ? t->GetGain() : 1.0;
1146
1147 gGain->Move(pos);
1148 gGain->Set(gain);
1149 gGainCaptured->Move(pos);
1150 gGainCaptured->Set(gain);
1151
1152 auto slider = (captured ? gGainCaptured : gGain).get();
1153 slider->SetParent( pParent );
1154 return slider;
1155}
1156
1158{
1159 if (message.appearance)
1160 return;
1161 const wxPoint point{ 0, 0 };
1162 wxRect sliderRect;
1163 GetGainRect(point, sliderRect);
1164
1165 float defPos = 1.0;
1166 /* i18n-hint: Title of the Gain slider, used to adjust the volume */
1167 gGain = std::make_unique<LWSlider>(nullptr, XO("Gain"),
1168 wxPoint(sliderRect.x, sliderRect.y),
1169 wxSize(sliderRect.width, sliderRect.height),
1170 DB_SLIDER);
1171 gGain->SetDefaultValue(defPos);
1172
1173 gGainCaptured = std::make_unique<LWSlider>(nullptr, XO("Gain"),
1174 wxPoint(sliderRect.x, sliderRect.y),
1175 wxSize(sliderRect.width, sliderRect.height),
1176 DB_SLIDER);
1177 gGainCaptured->SetDefaultValue(defPos);
1178}
1179
1181 CellularPanel &panel, const WaveTrack &wt )
1182{
1183 auto &controls = TrackControls::Get( wt );
1184 auto rect = panel.FindRect( controls );
1185 wxRect sliderRect;
1186 GetPanRect( rect.GetTopLeft(), sliderRect );
1187 return PanSlider( sliderRect, &wt, false, &panel );
1188}
1189
1191(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *pParent)
1192{
1193 static std::once_flag flag;
1194 std::call_once( flag, []{ ReCreatePanSlider({}); });
1196
1197 wxPoint pos = sliderRect.GetPosition();
1198 float pan = t ? t->GetPan() : 0.0;
1199
1200 gPan->Move(pos);
1201 gPan->Set(pan);
1202 gPanCaptured->Move(pos);
1203 gPanCaptured->Set(pan);
1204
1205 auto slider = (captured ? gPanCaptured : gPan).get();
1206 slider->SetParent( pParent );
1207 return slider;
1208}
1209
1211{
1212 if (message.appearance)
1213 return;
1214 const wxPoint point{ 0, 0 };
1215 wxRect sliderRect;
1216 GetPanRect(point, sliderRect);
1217
1218 float defPos = 0.0;
1219 /* i18n-hint: Title of the Pan slider, used to move the sound left or right */
1220 gPan = std::make_unique<LWSlider>(nullptr, XO("Pan"),
1221 wxPoint(sliderRect.x, sliderRect.y),
1222 wxSize(sliderRect.width, sliderRect.height),
1223 PAN_SLIDER);
1224 gPan->SetDefaultValue(defPos);
1225
1226 gPanCaptured = std::make_unique<LWSlider>(nullptr, XO("Pan"),
1227 wxPoint(sliderRect.x, sliderRect.y),
1228 wxSize(sliderRect.width, sliderRect.height),
1229 PAN_SLIDER);
1230 gPanCaptured->SetDefaultValue(defPos);
1231}
1232
1235 return [](WaveTrack &track) {
1236 return std::make_shared<WaveTrackControls>( track.SharedPointer() );
1237 };
1238}
1239
1242 return [](WaveTrack &) {
1244 };
1245}
1246
#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)
@ 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
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]
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:630
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:3506
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:4476
A Track that contains audio waveform data.
Definition: WaveTrack.h:222
void SetRate(double newRate)
Definition: WaveTrack.cpp:1090
float GetPan() const
Definition: WaveTrack.cpp:1130
double GetEndTime() const override
Implement WideSampleSequence.
Definition: WaveTrack.cpp:3050
float GetGain() const
Definition: WaveTrack.cpp:1112
double GetRate() const override
Definition: WaveTrack.cpp:1085
auto GetChannel(size_t iChannel)
Definition: WaveTrack.h:267
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:807
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