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 "WaveTrackView.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 "Theme.h"
28#include "../../../../TrackArtist.h"
29#include "../../../../TrackPanel.h"
30#include "../../../../TrackPanelAx.h"
31#include "../../../../TrackPanelMouseEvent.h"
32#include "../../../../WaveTrack.h"
33#include "../../../../effects/RealtimeEffectManager.h"
34#include "../../../../prefs/PrefsDialog.h"
35#include "../../../../prefs/ThemePrefs.h"
36#include "../../../../widgets/AudacityMessageBox.h"
38#include "UserException.h"
39#include "Identifier.h"
40
41#include <wx/app.h>
42#include <wx/combobox.h>
43#include <wx/frame.h>
44#include <wx/sizer.h>
45
47{
48}
49
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(int 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
211int FormatMenuTable::IdOfFormat(int format)
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
256 AudacityProject *const project = &mpData->project;
257
258 ProgressDialog progress{ XO("Changing sample format"),
259 XO("Processing... 0%%"),
261
262 sampleCount totalSamples{ 0 };
263 for (const auto& channel : TrackList::Channels(pTrack))
264 // Hidden samples are processed too, they should be counted as well
265 totalSamples += channel->GetSequenceSamplesCount();
266 sampleCount processedSamples{ 0 };
267
268 // Below is the lambda function that is passed along the call chain to
269 // the Sequence::ConvertToSampleFormat. This callback function is used
270 // to report the conversion progress and update the progress dialog.
271 auto progressUpdate = [&progress, &totalSamples, &processedSamples]
272 (size_t newlyProcessedCount)->void
273 {
274 processedSamples += newlyProcessedCount;
275 double d_processed = processedSamples.as_double();
276 double d_total = totalSamples.as_double();
277 int percentage{ static_cast<int>((d_processed / d_total) * 100) };
278
279 auto progressStatus = progress.Update(d_processed, d_total,
280 XO("Processing... %i%%").Format(percentage));
281
282 if (progressStatus != ProgressResult::Success)
283 throw UserException{};
284 };
285
286 for (auto channel : TrackList::Channels(pTrack))
287 channel->ConvertToSampleFormat(
288 newFormat, progressUpdate);
289
290 ProjectHistory::Get( *project )
291 /* i18n-hint: The strings name a track and a format */
292 .PushState(XO("Changed '%s' to %s")
293 .Format( pTrack->GetName(), GetSampleFormatStr(newFormat) ),
294 XO("Format Change"));
295
296 using namespace RefreshCode;
298}
299
300
301//=============================================================================
302// Table class for a sub-menu
304{
306 : PopupMenuTable{ "SampleRate", XO("Rat&e") }
307 {}
309
310 static RateMenuTable &Instance();
311
312 void InitUserData(void *pUserData) override;
313
315
316 static int IdOfRate(int rate);
317 void SetRate(WaveTrack * pTrack, double rate);
318
319 void OnRateChange(wxCommandEvent & event);
320 void OnRateOther(wxCommandEvent & event);
321};
322
324{
325 static RateMenuTable instance;
326 return instance;
327}
328
329void RateMenuTable::InitUserData(void *pUserData)
330{
331 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
332}
333
334// Because of Bug 1780 we can't use AppendRadioItem
335// If we did, we'd get no message when clicking on Other...
336// when it is already selected.
338 static const auto fn = initFn< RateMenuTable >(
339 []( WaveTrack &track ){
340 return IdOfRate( (int)track.GetRate() );
341 }
342 );
343
344 AppendCheckItem( "8000", OnRate8ID, XXO("8000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
345 AppendCheckItem( "11025", OnRate11ID, XXO("11025 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
346 AppendCheckItem( "16000", OnRate16ID, XXO("16000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
347 AppendCheckItem( "22050", OnRate22ID, XXO("22050 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
348 AppendCheckItem( "44100", OnRate44ID, XXO("44100 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
349 AppendCheckItem( "48000", OnRate48ID, XXO("48000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
350 AppendCheckItem( "88200", OnRate88ID, XXO("88200 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
351 AppendCheckItem( "96000", OnRate96ID, XXO("96000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
352 AppendCheckItem( "176400", OnRate176ID, XXO("176400 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
353 AppendCheckItem( "192000", OnRate192ID, XXO("192000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
354 AppendCheckItem( "352800", OnRate352ID, XXO("352800 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
355 AppendCheckItem( "384000", OnRate384ID, XXO("384000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
356 AppendCheckItem( "Other", OnRateOtherID, XXO("&Other..."), POPUP_MENU_FN( OnRateOther ), fn );
357
359
360const int nRates = 12;
361
364static int gRates[nRates] = { 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000,
365176400, 192000, 352800, 384000 };
366
369{
370 for (int i = 0; i<nRates; i++) {
371 if (gRates[i] == rate)
372 return i + OnRate8ID;
373 }
374 return OnRateOtherID;
375}
376
379void RateMenuTable::SetRate(WaveTrack * pTrack, double rate)
380{
381 AudacityProject *const project = &mpData->project;
382 for (auto channel : TrackList::Channels(pTrack))
383 channel->SetRate(rate);
384
385 // Separate conversion of "rate" enables changing the decimals without affecting i18n
386 wxString rateString = wxString::Format(wxT("%.3f"), rate);
387 ProjectHistory::Get( *project )
388 /* i18n-hint: The string names a track */
389 .PushState(XO("Changed '%s' to %s Hz")
390 .Format( pTrack->GetName(), rateString),
391 XO("Rate Change"));
392}
393
396void RateMenuTable::OnRateChange(wxCommandEvent & event)
397{
398 int id = event.GetId();
399 wxASSERT(id >= OnRate8ID && id <= OnRate384ID);
400 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
401
402 SetRate(pTrack, gRates[id - OnRate8ID]);
403
404 using namespace RefreshCode;
406}
407
408void RateMenuTable::OnRateOther(wxCommandEvent &)
409{
410 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
411
412 int newRate;
413
416 while (true)
417 {
418 wxDialogWrapper dlg(mpData->pParent, wxID_ANY, XO("Set Rate"));
419 dlg.SetName();
420 ShuttleGui S(&dlg, eIsCreating);
421 wxString rate;
422 wxComboBox *cb;
423
424 rate.Printf(wxT("%ld"), lrint(pTrack->GetRate()));
425
426 wxArrayStringEx rates{
427 wxT("8000") ,
428 wxT("11025") ,
429 wxT("16000") ,
430 wxT("22050") ,
431 wxT("44100") ,
432 wxT("48000") ,
433 wxT("88200") ,
434 wxT("96000") ,
435 wxT("176400") ,
436 wxT("192000") ,
437 wxT("352800") ,
438 wxT("384000") ,
439 };
440
441 S.StartVerticalLay(true);
442 {
443 S.SetBorder(10);
444 S.StartHorizontalLay(wxEXPAND, false);
445 {
446 cb = S.AddCombo(XXO("New sample rate (Hz):"),
447 rate,
448 rates);
449#if defined(__WXMAC__)
450 // As of wxMac-2.8.12, setting manually is required
451 // to handle rates not in the list. See: Bug #427
452 cb->SetValue(rate);
453#endif
454 }
455 S.EndHorizontalLay();
456 S.AddStandardButtons();
457 }
458 S.EndVerticalLay();
459
460 dlg.SetClientSize(dlg.GetSizer()->CalcMin());
461 dlg.Center();
462
463 if (dlg.ShowModal() != wxID_OK)
464 {
465 return; // user cancelled dialog
466 }
467
468 long lrate;
469 if (cb->GetValue().ToLong(&lrate) && lrate >= 1 && lrate <= 1000000)
470 {
471 newRate = (int)lrate;
472 break;
473 }
474
476 XO("The entered value is invalid"),
477 XO("Error"),
478 wxICON_ERROR,
479 mpData->pParent);
480 }
481
482 SetRate(pTrack, newRate);
483
484 using namespace RefreshCode;
486}
487
488static const auto MenuPathStart = wxT("WaveTrackMenu");
489
490//=============================================================================
491// Class defining common command handlers for mono and stereo tracks
493 : ComputedPopupMenuTable< WaveTrackMenuTable, WaveTrackPopupMenuTable >
494{
496
500 {
502 }
503
504 void InitUserData(void *pUserData) override;
505
507
508 void OnMultiView(wxCommandEvent & event);
509 void OnSetDisplay(wxCommandEvent & event);
510
511 void OnChannelChange(wxCommandEvent & event);
512 void OnMergeStereo(wxCommandEvent & event);
513
514 // TODO: more-than-two-channels
515 // How should we define generalized channel manipulation operations?
516 void SplitStereo(bool stereo);
517
518 void OnSwapChannels(wxCommandEvent & event);
519 void OnSplitStereo(wxCommandEvent & event);
520 void OnSplitStereoMono(wxCommandEvent & event);
521};
522
524{
525 static WaveTrackMenuTable instance;
526 return instance;
527}
528
530{
531 mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
532}
533
534static std::vector<WaveTrackSubViewType> AllTypes()
535{
536 auto result = WaveTrackSubViewType::All();
537 if ( result.size() > reserveDisplays ) {
538 wxASSERT( false );
539 result.resize( reserveDisplays );
540 }
541 return result;
542}
543
545 // Functions usable in callbacks to check and disable items
546 static const auto isMono =
547 []( PopupMenuHandler &handler ) -> bool {
548 auto &track =
549 static_cast< WaveTrackMenuTable& >( handler ).FindWaveTrack();
550 return 1 == TrackList::Channels( &track ).size();
551 };
552
553 static const auto isUnsafe =
554 []( PopupMenuHandler &handler ) -> bool {
555 auto &project =
556 static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
557 return RealtimeEffectManager::Get(project).IsActive() &&
559 };
560
561
562 BeginSection( "SubViews" );
563 // Multi-view check mark item, if more than one track sub-view type is
564 // known
565 Append( []( My &table ) -> Registry::BaseItemPtr {
566 if ( WaveTrackSubViews::slots() > 1 )
567 return std::make_unique<Entry>(
568 "MultiView", Entry::CheckItem, OnMultiViewID, XXO("&Multi-view"),
569 POPUP_MENU_FN( OnMultiView ),
570 table,
571 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
572 auto &table = static_cast< WaveTrackMenuTable& >( handler );
573 auto &track = table.FindWaveTrack();
574 const auto &view = WaveTrackView::Get( track );
575 menu.Check( id, view.GetMultiView() );
576 } );
577 else
578 return nullptr;
579 } );
580
581 // Append either a checkbox or radio item for each sub-view.
582 // Radio buttons if in single-view mode, else checkboxes
584 for ( const auto &type : AllTypes() ) {
585 static const auto initFn = []( bool radio ){ return
586 [radio]( PopupMenuHandler &handler, wxMenu &menu, int id ){
587 // Find all known sub-view types
588 const auto allTypes = AllTypes();
589
590 // How to convert a type to a menu item id
591 const auto IdForType =
592 [&allTypes]( const WaveTrackSubViewType &type ) -> int {
593 const auto begin = allTypes.begin();
594 return OnSetDisplayId +
595 (std::find( begin, allTypes.end(), type ) - begin);
596 };
597
598 auto &table = static_cast< WaveTrackMenuTable& >( handler );
599 auto &track = table.FindWaveTrack();
600
601 const auto &view = WaveTrackView::Get( track );
602
603 const auto displays = view.GetDisplays();
604 const auto end = displays.end();
605 bool check = (end !=
606 std::find_if( displays.begin(), end,
607 [&]( const WaveTrackSubViewType &type ){
608 return id == IdForType( type ); } ) );
609 menu.Check( id, check );
610
611 // Bug2275 residual
612 // Disable the checking-off of the only sub-view
613 if ( !radio && displays.size() == 1 && check )
614 menu.Enable( id, false );
615 };
616 };
617 Append( [type, id]( My &table ) -> Registry::BaseItemPtr {
618 const auto pTrack = &table.FindWaveTrack();
619 const auto &view = WaveTrackView::Get( *pTrack );
620 const auto itemType =
621 view.GetMultiView() ? Entry::CheckItem : Entry::RadioItem;
622 return std::make_unique<Entry>( type.name.Internal(), itemType,
623 id, type.name.Msgid(),
624 POPUP_MENU_FN( OnSetDisplay ), table,
625 initFn( !view.GetMultiView() ) );
626 } );
627 ++id;
628 }
629 BeginSection( "Extra" );
631 EndSection();
632
633 BeginSection( "Channels" );
634 // If these are enabled again, choose a hot key for Mono that does not conflict
635 // with Multi View
636 // AppendRadioItem(OnChannelMonoID, XXO("&Mono"),
637 // POPUP_MENU_FN( OnChannelChange ),
638 // []( PopupMenuHandler &handler, wxMenu &menu, int id ){
639 // menu.Enable( id, isMono( handler ) );
640 // menu.Check( id, findTrack( handler ).GetChannel() == Track::MonoChannel );
641 // }
642 // );
643 // AppendRadioItem(OnChannelLeftID, XXO("&Left Channel"),
644 // POPUP_MENU_FN( OnChannelChange ),
645 // []( PopupMenuHandler &handler, wxMenu &menu, int id ){
646 // menu.Enable( id, isMono( handler ) );
647 // menu.Check( id, findTrack( handler ).GetChannel() == Track::LeftChannel );
648 // }
649 // );
650 // AppendRadioItem(OnChannelRightID, XXO("R&ight Channel"),
651 // POPUP_MENU_FN( OnChannelChange ),
652 // []( PopupMenuHandler &handler, wxMenu &menu, int id ){
653 // menu.Enable( id, isMono( handler ) );
654 // menu.Check( id, findTrack( handler ).GetChannel() == Track::RightChannel );
655 // }
656 // );
657 AppendItem( "MakeStereo", OnMergeStereoID, XXO("Ma&ke Stereo Track"),
658 POPUP_MENU_FN( OnMergeStereo ),
659 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
660 bool canMakeStereo = !isUnsafe( handler ) && isMono( handler );
661 if ( canMakeStereo ) {
662 AudacityProject &project =
663 static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
664 auto &tracks = TrackList::Get( project );
665 auto &table = static_cast< WaveTrackMenuTable& >( handler );
666 auto &track = table.FindWaveTrack();
667 auto next = * ++ tracks.Find(&track);
668 canMakeStereo =
669 (next &&
670 TrackList::Channels(next).size() == 1 &&
671 track_cast<WaveTrack*>(next));
672 }
673 menu.Enable( id, canMakeStereo );
674 }
675 );
676
677 AppendItem( "Swap", OnSwapChannelsID, XXO("Swap Stereo &Channels"),
678 POPUP_MENU_FN( OnSwapChannels ),
679 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
680 auto &track =
681 static_cast< WaveTrackMenuTable& >( handler ).FindWaveTrack();
682 bool isStereo =
683 2 == TrackList::Channels( &track ).size();
684 menu.Enable( id, isStereo && !isUnsafe( handler ) );
685 }
686 );
687
688 static const auto enableSplitStereo =
689 []( PopupMenuHandler &handler, wxMenu &menu, int id ){
690 menu.Enable( id, !isMono( handler ) && !isUnsafe( handler ) );
691 };
692
693 AppendItem( "Split", OnSplitStereoID, XXO("Spl&it Stereo Track"),
694 POPUP_MENU_FN( OnSplitStereo ), enableSplitStereo );
695 // DA: Uses split stereo track and then drag pan sliders for split-stereo-to-mono
696 #ifndef EXPERIMENTAL_DA
698 XXO("Split Stereo to Mo&no"), POPUP_MENU_FN( OnSplitStereoMono ),
700 #endif
701 EndSection();
702
703 BeginSection( "Format" );
704 POPUP_MENU_SUB_MENU( "Format", FormatMenuTable, mpData )
705 EndSection();
706
707 BeginSection( "Rate" );
708 POPUP_MENU_SUB_MENU( "Rate", RateMenuTable, mpData )
709 EndSection();
711
712
713void WaveTrackMenuTable::OnMultiView(wxCommandEvent & event)
714{
715 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
716 const auto &view = WaveTrackView::Get( *pTrack );
717 bool multi = !view.GetMultiView();
718 const auto &displays = view.GetDisplays();
719 const auto display = displays.empty()
720 ? WaveTrackViewConstants::Waveform : displays.begin()->id;
721 for (const auto channel : TrackList::Channels(pTrack)) {
722 auto &channelView = WaveTrackView::Get( *channel );
723 channelView.SetMultiView( multi );
724
725 // Whichever sub-view was on top stays on top
726 // If going into Multi-view, it will be 1/nth the height.
727 // If exiting multi-view, it will be full height.
728 channelView.SetDisplay(display, !multi);
729 }
730}
731
733void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
734{
735 int idInt = event.GetId();
736 wxASSERT(idInt >= OnSetDisplayId &&
737 idInt <= lastDisplayId);
738 const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
739
740 auto id = AllTypes()[ idInt - OnSetDisplayId ].id;
741
742 auto &view = WaveTrackView::Get( *pTrack );
743 if ( view.GetMultiView() ) {
744 for (auto channel : TrackList::Channels(pTrack)) {
745 if ( !WaveTrackView::Get( *channel )
746 .ToggleSubView( WaveTrackView::Display{ id } ) ) {
747 // Trying to toggle off the last sub-view. It was refused.
748 // Decide what to do here. Turn off multi-view instead?
749 // PRL: I don't agree that it makes sense
750 }
751 else
753 }
754 }
755 else {
756 const auto displays = view.GetDisplays();
757 const bool wrongType =
758 !(displays.size() == 1 && displays[0].id == id);
759 if (wrongType) {
760 for (auto channel : TrackList::Channels(pTrack)) {
761 WaveTrackView::Get( *channel )
763 }
764
765 AudacityProject *const project = &mpData->project;
766 ProjectHistory::Get( *project ).ModifyState(true);
767
768 using namespace RefreshCode;
770 }
771 }
772}
773
774#if 0
775void WaveTrackMenuTable::OnChannelChange(wxCommandEvent & event)
776{
777 int id = event.GetId();
778 wxASSERT(id >= OnChannelLeftID && id <= OnChannelMonoID);
779 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
780 wxASSERT(pTrack);
781 Track::ChannelType channel;
782 TranslatableString channelmsg;
783 switch (id) {
784 default:
785 case OnChannelMonoID:
786 channel = Track::MonoChannel;
787 channelmsg = XO("Mono");
788 break;
789 case OnChannelLeftID:
790 channel = Track::LeftChannel;
791 channelmsg = XO("Left Channel");
792 break;
793 case OnChannelRightID:
794 channel = Track::RightChannel;
795 channelmsg = XO("Right Channel");
796 break;
797 }
798 pTrack->SetChannel(channel);
799 AudacityProject *const project = &mpData->project;
800 ProjectHistory::Get( *project )
801 .PushState(
802/* i18n-hint: The strings name a track and a channel choice (mono, left, or right) */
803 XO("Changed '%s' to %s").Format( pTrack->GetName(), channelmsg ),
804 XO("Channel"));
806}
807#endif
808
811{
812 AudacityProject *const project = &mpData->project;
813 auto &tracks = TrackList::Get( *project );
814
815 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
816 wxASSERT(pTrack);
817
818 auto partner = static_cast< WaveTrack * >
819 ( *tracks.Find( pTrack ).advance( 1 ) );
820
821 bool bBothMinimizedp =
822 ((TrackView::Get( *pTrack ).GetMinimized()) &&
823 (TrackView::Get( *partner ).GetMinimized()));
824
825 tracks.MakeMultiChannelTrack( *pTrack, 2, false );
826
827 // Set partner's parameters to match target.
828 partner->Merge(*pTrack);
829
830 pTrack->SetPan( 0.0f );
831 partner->SetPan( 0.0f );
832
833 // Set NEW track heights and minimized state
834 auto
835 &view = WaveTrackView::Get( *pTrack ),
836 &partnerView = WaveTrackView::Get( *partner );
837 view.SetMinimized(false);
838 partnerView.SetMinimized(false);
839 int AverageHeight = (view.GetHeight() + partnerView.GetHeight()) / 2;
840 view.SetExpandedHeight(AverageHeight);
841 partnerView.SetExpandedHeight(AverageHeight);
842 view.SetMinimized(bBothMinimizedp);
843 partnerView.SetMinimized(bBothMinimizedp);
844
845 partnerView.RestorePlacements( view.SavePlacements() );
846 partnerView.SetMultiView( view.GetMultiView() );
847
848 ProjectHistory::Get( *project ).PushState(
849 /* i18n-hint: The string names a track */
850 XO("Made '%s' a stereo track").Format( pTrack->GetName() ),
851 XO("Make Stereo"));
852
853 using namespace RefreshCode;
855}
856
859{
860 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
861 wxASSERT(pTrack);
862 AudacityProject *const project = &mpData->project;
863 auto channels = TrackList::Channels( pTrack );
864
865 int totalHeight = 0;
866 int nChannels = 0;
867 for (auto channel : channels) {
868 // Keep original stereo track name.
869 channel->SetName(pTrack->GetName());
870 auto &view = TrackView::Get( *channel );
871 if (stereo)
872 channel->SetPanFromChannelType();
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 TrackList::Get( *project ).UnlinkChannels( *pTrack );
882 int averageHeight = totalHeight / nChannels;
883
884 for (auto channel : channels)
885 // Make tracks the same height
886 TrackView::Get( *channel ).SetExpandedHeight( averageHeight );
887}
888
891{
892 AudacityProject *const project = &mpData->project;
893
894 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
895 auto channels = TrackList::Channels( pTrack );
896 if (channels.size() != 2)
897 return;
898
899 auto &trackFocus = TrackFocus::Get( *project );
900 Track *const focused = trackFocus.Get();
901 const bool hasFocus = channels.contains( focused );
902
903 auto partner = *channels.rbegin();
904
905 if (TrackList::SwapChannels(*pTrack)) {
906 auto &tracks = TrackList::Get( *project );
907 if (hasFocus)
908 trackFocus.Set(partner);
909
910 ProjectHistory::Get( *project ).PushState(
911 /* i18n-hint: The string names a track */
912 XO("Swapped Channels in '%s'").Format( pTrack->GetName() ),
913 XO("Swap Channels"));
914 }
915
917}
918
921{
922 SplitStereo(true);
923 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
924 AudacityProject *const project = &mpData->project;
925 ProjectHistory::Get( *project ).PushState(
926 /* i18n-hint: The string names a track */
927 XO("Split stereo track '%s'").Format( pTrack->GetName() ),
928 XO("Split"));
929
930 using namespace RefreshCode;
932}
933
936{
937 SplitStereo(false);
938 WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
939 AudacityProject *const project = &mpData->project;
940 ProjectHistory::Get( *project ).PushState(
941 /* i18n-hint: The string names a track */
942 XO("Split Stereo to Mono '%s'").Format( pTrack->GetName() ),
943 XO("Split to Mono"));
944
945 using namespace RefreshCode;
947}
948
950{
953 {
954 {wxT("/SubViews/Extra"), wxT("WaveColor,SpectrogramSettings")},
955 }
956 };
957
959 return &result;
960}
961
963{
965}
966
967// drawing related
968#include "../../../../widgets/ASlider.h"
969#include "../../../../TrackInfo.h"
970#include "../../../../TrackPanelDrawingContext.h"
971#include "ViewInfo.h"
972
973namespace {
974
976( LWSlider *(*Selector)
977 (const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow*),
978 wxDC *dc, const wxRect &rect, const Track *pTrack,
979 wxWindow *pParent,
980 bool captured, bool highlight )
981{
982 wxRect sliderRect = rect;
983 TrackInfo::GetSliderHorizontalBounds( rect.GetTopLeft(), sliderRect );
984 auto wt = static_cast<const WaveTrack*>( pTrack );
985 Selector( sliderRect, wt, captured, pParent )->OnPaint(*dc, highlight);
986}
987
989( TrackPanelDrawingContext &context,
990 const wxRect &rect, const Track *pTrack )
991{
992 auto target = dynamic_cast<PanSliderHandle*>( context.target.get() );
993 auto dc = &context.dc;
994 bool hit = target && target->GetTrack().get() == pTrack;
995 bool captured = hit && target->IsClicked();
996
997 const auto artist = TrackArtist::Get( context );
998 auto pParent = FindProjectFrame( artist->parent->GetProject() );
999
1001 &WaveTrackControls::PanSlider, dc, rect, pTrack,
1002 pParent, captured, hit);
1003}
1004
1006( TrackPanelDrawingContext &context,
1007 const wxRect &rect, const Track *pTrack )
1008{
1009 auto target = dynamic_cast<GainSliderHandle*>( context.target.get() );
1010 auto dc = &context.dc;
1011 bool hit = target && target->GetTrack().get() == pTrack;
1012 if( hit )
1013 hit=hit;
1014 bool captured = hit && target->IsClicked();
1015
1016 const auto artist = TrackArtist::Get( context );
1017 auto pParent = FindProjectFrame( artist->parent->GetProject() );
1018
1020 &WaveTrackControls::GainSlider, dc, rect, pTrack,
1021 pParent, captured, hit);
1022}
1023
1025 ( const TranslatableString &string, wxDC *dc, const wxRect &rect )
1026{
1027 static const int offset = 3;
1028 dc->DrawText(string.Translation(), rect.x + offset, rect.y);
1029}
1030
1032( TrackPanelDrawingContext &context,
1033 const wxRect &rect, const Track *pTrack )
1034{
1035 auto dc = &context.dc;
1036 auto wt = static_cast<const WaveTrack*>(pTrack);
1037
1041 auto rate = wt ? wt->GetRate() : 44100.0;
1043 if (!pTrack || TrackList::Channels(pTrack).size() > 1)
1044 // TODO: more-than-two-channels-message
1045 // more appropriate strings
1046 s = XO("Stereo, %dHz");
1047 else {
1048 if (wt->GetChannel() == Track::MonoChannel)
1049 s = XO("Mono, %dHz");
1050 else if (wt->GetChannel() == Track::LeftChannel)
1051 s = XO("Left, %dHz");
1052 else if (wt->GetChannel() == Track::RightChannel)
1053 s = XO("Right, %dHz");
1054 }
1055 s.Format( (int) (rate + 0.5) );
1056
1057 StatusDrawFunction( s, dc, rect );
1058}
1059
1061( TrackPanelDrawingContext &context,
1062 const wxRect &rect, const Track *pTrack )
1063{
1064 auto dc = &context.dc;
1065 auto wt = static_cast<const WaveTrack*>(pTrack);
1066 auto format = wt ? wt->GetSampleFormat() : floatSample;
1067 auto s = GetSampleFormatStr(format);
1068 StatusDrawFunction( s, dc, rect );
1069}
1070
1071}
1072
1074
1075static const struct WaveTrackTCPLines
1077 (TCPLines&)*this =
1079 insert( end(), {
1080
1085
1086#ifdef EXPERIMENTAL_DA
1087 // DA: Does not have status information for a track.
1088#else
1093#endif
1094
1095 } );
1097
1098void WaveTrackControls::GetGainRect(const wxPoint &topleft, wxRect & dest)
1099{
1100 TrackInfo::GetSliderHorizontalBounds( topleft, dest );
1102 dest.y = topleft.y + results.first;
1103 dest.height = results.second;
1104}
1105
1106void WaveTrackControls::GetPanRect(const wxPoint &topleft, wxRect & dest)
1107{
1108 GetGainRect( topleft, dest );
1110 dest.y = topleft.y + results.first;
1111}
1112
1114{
1116}
1117
1119{
1120 return waveTrackTCPLines;
1121}
1122
1123namespace
1124{
1125std::unique_ptr<LWSlider>
1130}
1131
1133 CellularPanel &panel, const WaveTrack &wt )
1134{
1135 auto &controls = TrackControls::Get( wt );
1136 auto rect = panel.FindRect( controls );
1137 wxRect sliderRect;
1138 GetGainRect( rect.GetTopLeft(), sliderRect );
1139 return GainSlider( sliderRect, &wt, false, &panel );
1140}
1141
1143(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *pParent)
1144{
1145 static std::once_flag flag;
1146 std::call_once( flag, []{ ReCreateGainSlider({}); });
1147 static auto subscription = theTheme.Subscribe(ReCreateGainSlider);
1148
1149 wxPoint pos = sliderRect.GetPosition();
1150 float gain = t ? t->GetGain() : 1.0;
1151
1152 gGain->Move(pos);
1153 gGain->Set(gain);
1154 gGainCaptured->Move(pos);
1155 gGainCaptured->Set(gain);
1156
1157 auto slider = (captured ? gGainCaptured : gGain).get();
1158 slider->SetParent( pParent );
1159 return slider;
1160}
1161
1163{
1164 if (message.appearance)
1165 return;
1166 const wxPoint point{ 0, 0 };
1167 wxRect sliderRect;
1168 GetGainRect(point, sliderRect);
1169
1170 float defPos = 1.0;
1171 /* i18n-hint: Title of the Gain slider, used to adjust the volume */
1172 gGain = std::make_unique<LWSlider>(nullptr, XO("Gain"),
1173 wxPoint(sliderRect.x, sliderRect.y),
1174 wxSize(sliderRect.width, sliderRect.height),
1175 DB_SLIDER);
1176 gGain->SetDefaultValue(defPos);
1177
1178 gGainCaptured = std::make_unique<LWSlider>(nullptr, XO("Gain"),
1179 wxPoint(sliderRect.x, sliderRect.y),
1180 wxSize(sliderRect.width, sliderRect.height),
1181 DB_SLIDER);
1182 gGainCaptured->SetDefaultValue(defPos);
1183}
1184
1186 CellularPanel &panel, const WaveTrack &wt )
1187{
1188 auto &controls = TrackControls::Get( wt );
1189 auto rect = panel.FindRect( controls );
1190 wxRect sliderRect;
1191 GetPanRect( rect.GetTopLeft(), sliderRect );
1192 return PanSlider( sliderRect, &wt, false, &panel );
1193}
1194
1196(const wxRect &sliderRect, const WaveTrack *t, bool captured, wxWindow *pParent)
1197{
1198 static std::once_flag flag;
1199 std::call_once( flag, []{ ReCreatePanSlider({}); });
1200 static auto subscription = theTheme.Subscribe(ReCreatePanSlider);
1201
1202 wxPoint pos = sliderRect.GetPosition();
1203 float pan = t ? t->GetPan() : 0.0;
1204
1205 gPan->Move(pos);
1206 gPan->Set(pan);
1207 gPanCaptured->Move(pos);
1208 gPanCaptured->Set(pan);
1209
1210 auto slider = (captured ? gPanCaptured : gPan).get();
1211 slider->SetParent( pParent );
1212 return slider;
1213}
1214
1216{
1217 if (message.appearance)
1218 return;
1219 const wxPoint point{ 0, 0 };
1220 wxRect sliderRect;
1221 GetPanRect(point, sliderRect);
1222
1223 float defPos = 0.0;
1224 /* i18n-hint: Title of the Pan slider, used to move the sound left or right */
1225 gPan = std::make_unique<LWSlider>(nullptr, XO("Pan"),
1226 wxPoint(sliderRect.x, sliderRect.y),
1227 wxSize(sliderRect.width, sliderRect.height),
1228 PAN_SLIDER);
1229 gPan->SetDefaultValue(defPos);
1230
1231 gPanCaptured = std::make_unique<LWSlider>(nullptr, XO("Pan"),
1232 wxPoint(sliderRect.x, sliderRect.y),
1233 wxSize(sliderRect.width, sliderRect.height),
1234 PAN_SLIDER);
1235 gPanCaptured->SetDefaultValue(defPos);
1236}
1237
1240 return [](WaveTrack &track) {
1241 return std::make_shared<WaveTrackControls>( track.SharedPointer() );
1242 };
1243}
1244
1247 return [](WaveTrack &) {
1249 };
1250}
1251
#define DB_SLIDER
Definition: ASlider.h:33
#define PAN_SLIDER
Definition: ASlider.h:34
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
int format
Definition: ExportPCM.cpp:56
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#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)
sampleFormat
Definition: SampleFormat.h:29
@ floatSample
Definition: SampleFormat.h:34
@ int16Sample
Definition: SampleFormat.h:32
@ int24Sample
Definition: SampleFormat.h:33
@ eIsCreating
Definition: ShuttleGui.h:39
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
TrackInfo::TCPLines TCPLines
Definition: TrackInfo.cpp:102
An AudacityException with no visible message.
@ kTrackInfoSliderExtra
Definition: ViewInfo.h:100
@ kTrackInfoSliderHeight
Definition: ViewInfo.h:97
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< WaveTrackSubViewType > AllTypes()
TrackInfo::TCPLine TCPLine
const int nRates
static const auto enableSplitStereo
BeginSection("SubViews")
int id
static int gRates[nRates]
Append([](My &table) -> Registry::BaseItemPtr { if(WaveTrackSubViews::slots() > 1) return 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=WaveTrackView::Get(track);menu.Check(id, view.GetMultiView());});else return nullptr;})
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::Channels(next).size()==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:89
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 size_t slots()
How many static factories have been registered with this specialization of Site.
Definition: ClientData.h:258
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Definition: ClientData.h:333
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
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:62
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()
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 RealtimeEffectManager & Get(AudacityProject &project)
bool IsActive() const noexcept
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
static UIHandlePtr HitTest(std::weak_ptr< SoloButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< Track > &pTrack)
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:69
static TrackControls & Get(Track &track)
Track * Get()
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
void SetChannel(ChannelType c) noexcept
Definition: Track.cpp:242
ChannelType
Definition: Track.h:281
@ LeftChannel
Definition: Track.h:282
@ RightChannel
Definition: Track.h:283
@ MonoChannel
Definition: Track.h:284
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:297
wxString GetName() const
Definition: Track.h:466
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:486
static bool SwapChannels(Track &track)
If the given track is one of a pair of channels, swap them.
Definition: Track.cpp:657
void UnlinkChannels(Track &track)
Removes linkage if track belongs to a group.
Definition: Track.cpp:750
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1539
bool GetMinimized() const
Definition: TrackView.h:52
void SetExpandedHeight(int height)
Definition: TrackView.cpp:172
static TrackView & Get(Track &)
Definition: TrackView.cpp:69
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
PopupMenuTable * GetMenuExtension(Track *pTrack) override
std::weak_ptr< MuteButtonHandle > mMuteHandle
static unsigned DefaultWaveTrackHeight()
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)
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
void SetPan(float newPan) override
Definition: WaveTrack.cpp:524
float GetPan() const
Definition: WaveTrack.cpp:514
float GetGain() const
Definition: WaveTrack.cpp:496
double GetRate() const override
Definition: WaveTrack.cpp:479
void Merge(const Track &orig) override
Definition: WaveTrack.cpp:217
void SetDisplay(Display display, bool exclusive=true)
static WaveTrackView & Get(WaveTrack &track)
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
double as_double() const
Definition: SampleCount.h:45
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
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
std::unique_ptr< BaseItem > BaseItemPtr
Definition: Registry.h:71
AUDACITY_DLL_API void GetSliderHorizontalBounds(const wxPoint &topleft, wxRect &dest)
Definition: TrackInfo.cpp:488
AUDACITY_DLL_API unsigned DefaultTrackHeight(const TCPLines &topLines)
Definition: TrackInfo.cpp:566
AUDACITY_DLL_API std::pair< int, int > CalcItemY(const TCPLines &lines, unsigned iItem)
Definition: TrackInfo.cpp:146
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.
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(int format)
Converts a format enumeration to a wxWidgets menu item Id.
static FormatMenuTable & Instance()
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)
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
void SplitStereo(bool stereo)
Split a stereo track (or more-than-stereo?) into two (or more) tracks...
void OnSplitStereo(wxCommandEvent &event)
Split a stereo track into two tracks...
void OnChannelChange(wxCommandEvent &event)
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
static const std::vector< WaveTrackSubViewType > & All()
Discover all registered types.