Audacity 3.2.0
AudioSetupToolBar.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 AudioSetupToolBar.cpp
6
7*******************************************************************//*******************************************************************/
13
14#include "AudioSetupToolBar.h"
15#include "ToolManager.h"
16
17#include <thread>
18
19#include <wx/log.h>
20#include <wx/menu.h>
21#include <wx/sizer.h>
22#include <wx/tooltip.h>
23
24#include "../ActiveProject.h"
25
26#include "AColor.h"
27#include "AllThemeResources.h"
28#include "AudioIOBase.h"
29#include "DeviceToolBar.h"
30#include "../KeyboardCapture.h"
31#include "Project.h"
32#include "../ProjectWindows.h"
33#include "DeviceManager.h"
34#include "../prefs/PrefsDialog.h"
35#include "../prefs/DevicePrefs.h"
36#include "../widgets/AButton.h"
37#include "../widgets/BasicMenu.h"
38#include "../widgets/wxWidgetsWindowPlacement.h"
39
40namespace {
41 static constexpr int kHost = 15000;
42 static constexpr int kInput = 15200;
43 static constexpr int kInputChannels = 15400;
44 static constexpr int kOutput = 15600;
45 static constexpr int kAudioSettings = 15800;
46
48 {
49 public:
50 ViewDeviceSettingsDialog(wxWindow* parent, AudacityProject& project,
52 int page)
53 : PrefsDialog(parent, &project, title, factories)
54 , mPage(page)
55 {
56 }
57
58 long GetPreferredPage() override
59 {
60 return mPage;
61 }
62
63 void SavePreferredPage() override
64 {
65 }
66
67 private:
68 const int mPage;
69 };
70}
71
73
77
78BEGIN_EVENT_TABLE(AudioSetupToolBar, ToolBar)
79 EVT_BUTTON(ID_AUDIO_SETUP_BUTTON, AudioSetupToolBar::OnAudioSetup)
81
82//Standard constructor
84: ToolBar( project, AudioSetupBarID, XO("Audio Setup"), wxT("Audio Setup") )
85{
86 mSubscription = DeviceManager::Instance()->Subscribe(
88}
89
91{
92}
93
95{
96 auto &toolManager = ToolManager::Get( project );
97 return *static_cast<AudioSetupToolBar*>( toolManager.GetToolBar(AudioSetupBarID) );
98}
99
101{
102 return Get( const_cast<AudacityProject&>( project )) ;
103}
104
105void AudioSetupToolBar::Create(wxWindow *parent)
106{
107 ToolBar::Create(parent);
108
109 // Simulate a size event to set initial meter placement/size
110 wxSizeEvent event(GetSize(), GetId());
111 event.SetEventObject(this);
112 GetEventHandler()->ProcessEvent(event);
113}
114
116{
117 mInput.reset();
118 mOutput.reset();
119 mInputChannels.reset();
120 mHost.reset();
121}
122
124{
125 SetBackgroundColour( theTheme.Colour( clrMedium ) );
127
129
130#if wxUSE_TOOLTIPS
132 wxToolTip::Enable(true);
133 wxToolTip::SetDelay(1000);
134#endif
135
136 // Set default order and mode
138
140}
141
143{
144#ifndef USE_AQUA_THEME
145 wxSize s = mSizer->GetSize();
146 wxPoint p = mSizer->GetPosition();
147
148 wxRect bevelRect(p.x, p.y, s.GetWidth() - 1, s.GetHeight() - 1);
149 AColor::Bevel(*dc, true, bevelRect);
150#endif
151}
152
154{
155 bool bUseAqua = false;
156
157#ifdef EXPERIMENTAL_THEME_PREFS
158 gPrefs->Read(wxT("/GUI/ShowMac"), &bUseAqua, false);
159#endif
160
161#ifdef USE_AQUA_THEME
162 bUseAqua = !bUseAqua;
163#endif
164
165 const auto size = theTheme.ImageSize(bmpRecoloredSetupUpSmall);
166
167 if (bUseAqua) {
168 MakeMacRecoloredImageSize(bmpRecoloredSetupUpSmall, bmpMacUpButtonSmall, size);
169 MakeMacRecoloredImageSize(bmpRecoloredSetupDownSmall, bmpMacDownButtonSmall, size);
170 MakeMacRecoloredImageSize(bmpRecoloredSetupUpHiliteSmall, bmpMacHiliteUpButtonSmall, size);
171 MakeMacRecoloredImageSize(bmpRecoloredSetupHiliteSmall, bmpMacHiliteButtonSmall, size);
172 }
173 else {
174 MakeRecoloredImageSize(bmpRecoloredSetupUpSmall, bmpUpButtonSmall, size);
175 MakeRecoloredImageSize(bmpRecoloredSetupDownSmall, bmpDownButtonSmall, size);
176 MakeRecoloredImageSize(bmpRecoloredSetupUpHiliteSmall, bmpHiliteUpButtonSmall, size);
177 MakeRecoloredImageSize(bmpRecoloredSetupHiliteSmall, bmpHiliteButtonSmall, size);
178 }
179
181 //i18n-hint: Audio setup button text, keep as short as possible
182 mAudioSetup->SetLabel(XO("Audio Setup"));
186 theTheme.Image(bmpRecoloredSetupUpSmall),
187 theTheme.Image(bmpRecoloredSetupUpHiliteSmall),
188 theTheme.Image(bmpRecoloredSetupDownSmall),
189 theTheme.Image(bmpRecoloredSetupHiliteSmall),
190 theTheme.Image(bmpRecoloredSetupUpSmall));
191 mAudioSetup->SetIcon(theTheme.Image(bmpSetup));
192 mAudioSetup->SetForegroundColour(theTheme.Colour(clrTrackPanelText));
193}
194
196{
197 int flags = wxALIGN_CENTER | wxRIGHT;
198
199 // (Re)allocate the button sizer
200 if (mSizer)
201 {
202 Detach(mSizer);
203 std::unique_ptr < wxSizer > {mSizer}; // DELETE it
204 }
205
206 Add((mSizer = safenew wxBoxSizer(wxHORIZONTAL)), 1, wxEXPAND);
207 mSizer->Add(mAudioSetup, 1, wxEXPAND);
208
209 // Layout the sizer
210 mSizer->Layout();
211
212 // Layout the toolbar
213 Layout();
214
215 SetMinSize(GetSizer()->GetMinSize());
216}
217
219{
220 bool isAudioSetupDown = false;
221
222 // ToolBar::ReCreateButtons() will get rid of its sizer and
223 // since we've attached our sizer to it, ours will get deleted too
224 // so clean ours up first.
225 if (mSizer)
226 {
227 isAudioSetupDown = mAudioSetup->IsDown();
228 Detach(mSizer);
229
230 std::unique_ptr < wxSizer > {mSizer}; // DELETE it
231 mSizer = nullptr;
232 }
233
235
236 if (isAudioSetupDown)
237 {
239 }
240
242
244}
245
246void AudioSetupToolBar::OnFocus(wxFocusEvent &event)
247{
248 KeyboardCapture::OnFocus( *this, event );
249}
250
251void AudioSetupToolBar::OnAudioSetup(wxCommandEvent& WXUNUSED(evt))
252{
253 wxMenu menu;
254
255 //i18n-hint: Audio setup menu
256 AppendSubMenu(menu, mHost, _("&Host"));
257 menu.AppendSeparator();
258
259 //i18n-hint: Audio setup menu
260 AppendSubMenu(menu, mOutput, _("&Playback Device"));
261 menu.AppendSeparator();
262
263 //i18n-hint: Audio setup menu
264 AppendSubMenu(menu, mInput, _("&Recording Device"));
265 menu.AppendSeparator();
266
267 //i18n-hint: Audio setup menu
268 AppendSubMenu(menu, mInputChannels, _("Recording &Channels"));
269 menu.AppendSeparator();
270 menu.Append(kAudioSettings, _("&Audio Settings..."));
271
272 menu.Bind(wxEVT_MENU_CLOSE, [this](auto&) { mAudioSetup->PopUp(); });
273 menu.Bind(wxEVT_MENU, &AudioSetupToolBar::OnMenu, this);
274
275 wxWindow* btn = FindWindow(ID_AUDIO_SETUP_BUTTON);
276 wxRect r = btn->GetRect();
277 BasicMenu::Handle{ &menu }.Popup(
279 { r.GetLeft(), r.GetBottom() }
280 );
281}
282
284{
285 wxString desc;
286 const std::vector<DeviceSourceMap> &inMaps = DeviceManager::Instance()->GetInputDeviceMaps();
287 const std::vector<DeviceSourceMap> &outMaps = DeviceManager::Instance()->GetOutputDeviceMaps();
288
289 auto selectedHost = GetSelectedRadioItemLabel(*mHost);
290 wxString oldHost = selectedHost ? *selectedHost : wxString{};
291
292 auto hostName = AudioIOHost.Read();
293
294 // if the prefs host name doesn't match the one displayed, it changed
295 // in another project's AudioSetupToolBar, so we need to repopulate everything.
296 if (oldHost != hostName)
298
299 auto devName = AudioIORecordingDevice.Read();
300 auto sourceName = AudioIORecordingSource.Read();
301 if (sourceName.empty())
302 desc = devName;
303 else
304 desc = devName + wxT(": ") + sourceName;
305
306 auto selectedInput = GetSelectedRadioItemLabel(*mInput);
307 if (selectedInput && *selectedInput != desc) {
308 if (auto item = mInput->FindItem(desc); item != wxNOT_FOUND) {
309 mInput->FindChildItem(item)->Check();
311 }
312 else if (mInput->GetMenuItemCount()) {
313 for (size_t i = 0; i < inMaps.size(); i++) {
314 if (inMaps[i].hostString == hostName &&
315 MakeDeviceSourceString(&inMaps[i]) == mInput->FindItem(kInput)->GetItemLabelText()) {
316 // use the default. It should exist but check just in case, falling back on the 0 index.
317 DeviceSourceMap* defaultMap = DeviceManager::Instance()->GetDefaultInputDevice(inMaps[i].hostIndex);
318 if (defaultMap) {
319 const auto menuId = mInput->FindItem(MakeDeviceSourceString(defaultMap));
320 auto item = mInput->FindChildItem(menuId);
321 if (item)
322 item->Check();
323
324 SetDevices(defaultMap, nullptr);
325 }
326 else {
327 //use the first item (0th index) if we have no familiar devices
328 auto item = mInput->FindChildItem(kInput);
329 if (item)
330 item->Check();
331
332 SetDevices(&inMaps[i], nullptr);
333 }
334 break;
335 }
336 }
337 }
338 }
339
340 devName = AudioIOPlaybackDevice.Read();
341 sourceName = AudioIOPlaybackSource.Read();
342 if (sourceName.empty())
343 desc = devName;
344 else
345 desc = devName + wxT(": ") + sourceName;
346
347 auto selectedOutput = GetSelectedRadioItemLabel(*mOutput);
348 if (selectedOutput && *selectedOutput != desc) {
349 if (auto item = mOutput->FindItem(desc); item != wxNOT_FOUND) {
350 mOutput->FindChildItem(item)->Check();
351 }
352 else if (mOutput->GetMenuItemCount()) {
353 for (size_t i = 0; i < outMaps.size(); i++) {
354 if (outMaps[i].hostString == hostName &&
355 MakeDeviceSourceString(&outMaps[i]) == mOutput->FindItem(kOutput)->GetItemLabelText()) {
356 // use the default. It should exist but check just in case, falling back on the 0 index.
357 DeviceSourceMap* defaultMap = DeviceManager::Instance()->GetDefaultInputDevice(outMaps[i].hostIndex);
358 if (defaultMap) {
359 const auto menuId = mOutput->FindItem(MakeDeviceSourceString(defaultMap));
360 auto item = mOutput->FindChildItem(menuId);
361 if (item)
362 item->Check();
363
364 SetDevices(nullptr, defaultMap);
365 }
366 else {
367 //use the first item (0th index) if we have no familiar devices
368 auto item = mOutput->FindChildItem(kOutput);
369 if (item)
370 item->Check();
371
372 SetDevices(nullptr, &outMaps[i]);
373 }
374 break;
375 }
376 }
377 }
378 }
379
380 long oldChannels = 0;
381 for (const auto & item : mInputChannels->GetMenuItems()) {
382 if (item->IsChecked())
383 oldChannels = item->GetId() - kInputChannels + 1;
384 }
385
386 auto newChannels = AudioIORecordChannels.ReadWithDefault(0);
387 if (newChannels > 0 && oldChannels != newChannels) {
388 auto item = mInputChannels->FindChildItem(kInputChannels + newChannels - 1);
389 if (item != nullptr)
390 item->Check();
391 }
392
393 selectedHost = GetSelectedRadioItemLabel(*mHost);
394 if (!hostName.empty() && selectedHost && selectedHost != hostName) {
395 const auto id = mHost->FindItem(hostName);
396 if (id != wxNOT_FOUND) {
397 mHost->FindChildItem(id)->Check();
398 }
399 }
400
402
403 // Set label to pull in language change
404 SetLabel(XO("Audio Setup"));
405
406 // Give base class a chance
408
409 Layout();
410 Refresh();
411}
412
414{
415 if (id == DeviceToolbarPrefsID())
416 UpdatePrefs();
418}
419
420
422{
423 auto gAudioIO = AudioIOBase::Get();
424 if (gAudioIO) {
425 // we allow changes when monitoring, but not when recording
426 bool audioStreamActive = gAudioIO->IsStreamActive() && !gAudioIO->IsMonitoring();
427
428 if (audioStreamActive) {
430 }
431 else {
433 }
434 }
435}
436
438{
439#if wxUSE_TOOLTIPS
440 for (long iWinID = ID_AUDIO_SETUP_BUTTON; iWinID < BUTTON_COUNT; iWinID++)
441 {
442 auto pCtrl = static_cast<AButton*>(this->FindWindow(iWinID));
444 switch (iWinID)
445 {
447 name = wxT("Open Audio Setup");
448 break;
449 }
450 std::vector<ComponentInterfaceSymbol> commands(
451 1u, { name, Verbatim(pCtrl->GetLabel()) });
452
453 // Some have a second
454 switch (iWinID)
455 {
457 break;
458 }
460 mProject, *pCtrl, commands.data(), commands.size());
461 }
462#endif
463}
464
466{
467 FillHosts();
470 // make the device display selection reflect the prefs if they exist
471 UpdatePrefs();
472}
473
475{
476 const std::vector<DeviceSourceMap> &inMaps = DeviceManager::Instance()->GetInputDeviceMaps();
477 const std::vector<DeviceSourceMap> &outMaps = DeviceManager::Instance()->GetOutputDeviceMaps();
478
479 wxArrayString hosts;
480
481 // go over our lists add the host to the list if it isn't there yet
482
483 for (auto & device : inMaps) {
484 if (!make_iterator_range(hosts).contains(device.hostString)) {
485 hosts.push_back(device.hostString);
486 }
487 }
488
489 for (auto & device : outMaps) {
490 if (!make_iterator_range(hosts).contains(device.hostString)) {
491 hosts.push_back(device.hostString);
492 }
493 }
494
495 mHost = std::make_unique<wxMenu>();
496
497 for (int i = 0; i < hosts.size(); ++i)
498 mHost->AppendRadioItem(kHost + i, hosts[i]);
499}
500
502{
503 const std::vector<DeviceSourceMap> &inMaps = DeviceManager::Instance()->GetInputDeviceMaps();
504 const std::vector<DeviceSourceMap> &outMaps = DeviceManager::Instance()->GetOutputDeviceMaps();
505
506 //read what is in the prefs
507 auto host = AudioIOHost.Read();
508 int foundHostIndex = -1;
509
510 // if the host is not in the hosts combo then we rescanned.
511 // set it to blank so we search for another host.
512 if (mHost->FindItem(host) == wxNOT_FOUND) {
513 host = wxT("");
514 }
515
516 for (auto & device : outMaps) {
517 if (device.hostString == host) {
518 foundHostIndex = device.hostIndex;
519 break;
520 }
521 }
522
523 if (foundHostIndex == -1) {
524 for (auto & device : inMaps) {
525 if (device.hostString == host) {
526 foundHostIndex = device.hostIndex;
527 break;
528 }
529 }
530 }
531
532 // If no host was found based on the prefs device host, load the first available one
533 if (foundHostIndex == -1) {
534 if (outMaps.size()) {
535 foundHostIndex = outMaps[0].hostIndex;
536 }
537 else if (inMaps.size()) {
538 foundHostIndex = inMaps[0].hostIndex;
539 }
540 }
541
542 // Make sure in/out are clear in case no host was found
543 mInput = std::make_unique<wxMenu>();
544 mOutput = std::make_unique<wxMenu>();
545
546 // If we still have no host it means no devices, in which case do nothing.
547 if (foundHostIndex == -1) {
548 return;
549 }
550
551 // Repopulate the Input/Output device list available to the user
552 for (int nextMenuId = kInput, i = 0; i < inMaps.size(); ++i) {
553 auto& device = inMaps[i];
554
555 if (foundHostIndex == device.hostIndex) {
556 mInput->AppendRadioItem(nextMenuId, MakeDeviceSourceString(&device));
557 nextMenuId++;
558
559 if (host.empty()) {
560 host = device.hostString;
561 AudioIOHost.Write(host);
562
563 const auto id = mHost->FindItem(host);
564 if (id != wxNOT_FOUND) {
565 mHost->FindChildItem(id)->Check();
566 }
567 }
568 }
569 }
570
571 for (int nextMenuId = kOutput, i = 0; i < outMaps.size(); ++i) {
572 auto& device = outMaps[i];
573
574 if (foundHostIndex == device.hostIndex) {
575 mOutput->AppendRadioItem(nextMenuId, MakeDeviceSourceString(&device));
576 nextMenuId++;
577
578 if (host.empty()) {
579 host = device.hostString;
580 AudioIOHost.Write(host);
581 gPrefs->Flush();
582
583 const auto id = mHost->FindItem(host);
584 if (id != wxNOT_FOUND) {
585 mHost->FindChildItem(id)->Check();
586 }
587 }
588 }
589 }
590
591 // The setting of the Device is left up to OnMenu
592}
593
595{
596 const std::vector<DeviceSourceMap> &inMaps = DeviceManager::Instance()->GetInputDeviceMaps();
597 auto host = AudioIOHost.Read();
598 auto device = AudioIORecordingDevice.Read();
599 auto source = AudioIORecordingSource.Read();
600 long newChannels;
601
602 auto oldChannels = AudioIORecordChannels.Read();
603 mInputChannels = std::make_unique<wxMenu>();
604
605 for (auto & dev: inMaps) {
606 if (source == dev.sourceString &&
607 device == dev.deviceString &&
608 host == dev.hostString) {
609
610 // add one selection for each channel of this source
611 for (size_t j = 0; j < (unsigned int)dev.numChannels; j++) {
612 wxString name;
613
614 if (j == 0) {
615 name = _("1 (Mono) Recording Channel");
616 }
617 else if (j == 1) {
618 name = _("2 (Stereo) Recording Channels");
619 }
620 else {
621 name = wxString::Format(wxT("%d"), (int)j + 1);
622 }
623 mInputChannels->AppendRadioItem(kInputChannels + j, name);
624 }
625 newChannels = dev.numChannels;
626 if (oldChannels <= newChannels && oldChannels >= 1) {
627 newChannels = oldChannels;
628 }
629 if (newChannels >= 1) {
630 auto item = mInputChannels->FindItem(kInputChannels + newChannels - 1);
631 if (item != nullptr)
632 item->Check();
633 }
634 AudioIORecordChannels.Write(newChannels);
635 break;
636 }
637 }
638}
639
640std::unique_ptr<wxMenu> AudioSetupToolBar::CloneMenu(const wxMenu& menu) const
641{
642 auto clonedMenu = std::make_unique<wxMenu>();
643
644 for (const auto& item : menu.GetMenuItems()) {
645 auto cloneMenuItem = clonedMenu->AppendRadioItem(item->GetId(), item->GetItemLabelText());
646
647 if (item->IsChecked())
648 cloneMenuItem->Check();
649 }
650
651 return clonedMenu;
652}
653
654void AudioSetupToolBar::AppendSubMenu(wxMenu& menu, const std::unique_ptr<wxMenu>& submenu, const wxString& title)
655{
656 auto clone = CloneMenu(*submenu);
657 auto menuItem = menu.AppendSubMenu(clone.release(), title);
658
659 const auto selected = GetSelectedRadioItemLabel(*submenu);
660 if (!selected) {
661 menuItem->Enable(false);
662 }
663}
664
665std::optional<wxString> AudioSetupToolBar::GetSelectedRadioItemLabel(const wxMenu& menu) const
666{
667 const auto& items = menu.GetMenuItems();
668
669 for (const auto& item : items) {
670 if (item->IsChecked())
671 return item->GetItemLabelText();
672 }
673
674 return std::nullopt;
675}
676
678{
679 // Hosts may have disappeared or appeared so a complete repopulate is needed.
682}
683
684//return true if host changed, false otherwise.
686{
687 auto item = mHost->FindChildItem(hostId);
688 if (!item)
689 return false;
690
691 // Update cache with selected host
692 item->Check();
693
694 auto oldHost = AudioIOHost.Read();
695 wxString newHost = item->GetItemLabelText();
696
697 if (oldHost == newHost)
698 return false;
699
700 //change the host and switch to correct devices.
701 AudioIOHost.Write(newHost);
702 gPrefs->Flush();
703
704 // populate the devices
706
707 return true;
708}
709
711{
712 if (in) {
715 if (in->totalSources >= 1)
717 else
719 gPrefs->Flush();
720
722 }
723
724 if (out) {
726 if (out->totalSources >= 1) {
728 } else {
730 }
731 gPrefs->Flush();
732 }
733}
734
735void AudioSetupToolBar::ChangeDevice(int deviceId, bool isInput)
736{
737 int newIndex = -1;
738 auto& device = isInput ? mInput : mOutput;
739
740 auto host = AudioIOHost.Read();
741 const std::vector<DeviceSourceMap>& maps = isInput ? DeviceManager::Instance()->GetInputDeviceMaps()
743
744 auto item = device->FindChildItem(deviceId);
745 if (item) {
746 // Update cache with the chosen device
747 item->Check();
748 wxString newDevice = item->GetItemLabelText();
749
750 for (size_t i = 0; i < maps.size(); ++i) {
751 wxString name = MakeDeviceSourceString(&maps[i]);
752 if (name == newDevice && maps[i].hostString == host) {
753 newIndex = i;
754 }
755 }
756 }
757
758 if (newIndex < 0) {
759 wxLogDebug(wxT("AudioSetupToolBar::OnMenu(): couldn't find device indices"));
760 return;
761 }
762
763 SetDevices(isInput ? &maps[newIndex] : nullptr,
764 isInput ? nullptr : &maps[newIndex]);
765}
766
767void AudioSetupToolBar::OnMenu(wxCommandEvent& event)
768{
769 int id = event.GetId();
770 bool audioSettingsChosen = false;
771
772 if ((id >= kHost) && (id < kInput)) {
773 ChangeHost(id);
774 }
775 else if ((id >= kInputChannels) && (id < kOutput)) {
776 if (auto item = mInputChannels->FindChildItem(id)) {
777 // Update cache with selected number of input channels
778 item->Check();
780 }
781 }
782 else if ((id >= kInput) && (id < kInputChannels)) {
783 ChangeDevice(id, true);
784 }
785 else if ((id >= kOutput) && (id < kAudioSettings)) {
786 ChangeDevice(id, false);
787 }
788 else if (id == kAudioSettings) {
789 audioSettingsChosen = true;
790 }
791
792 auto gAudioIO = AudioIOBase::Get();
793 if (gAudioIO) {
794 // We cannot have gotten here if gAudioIO->IsAudioTokenActive(),
795 // per the setting of AudioIONotBusyFlag and AudioIOBusyFlag in
796 // AudacityProject::GetUpdateFlags().
797 // However, we can have an invalid audio token (so IsAudioTokenActive()
798 // is false), but be monitoring.
799 // If monitoring, have to stop the stream, so HandleDeviceChange() can work.
800 // We could disable the Preferences command while monitoring, i.e.,
801 // set AudioIONotBusyFlag/AudioIOBusyFlag according to monitoring, as well.
802 // Instead allow it because unlike recording, for example, monitoring
803 // is not clearly something that should prohibit changing device.
804 // TODO: We *could* be smarter in this method and call HandleDeviceChange()
805 // only when the device choices actually changed. True of lots of prefs!
806 // As is, we always stop monitoring before handling the device change.
807 if (gAudioIO->IsMonitoring())
808 {
809 gAudioIO->StopStream();
810 while (gAudioIO->IsBusy()) {
811 using namespace std::chrono;
812 std::this_thread::sleep_for(100ms);
813 }
814 }
815
816 if (audioSettingsChosen) {
817 PrefsPanel::Factories factories;
818 factories.push_back(PrefsPanel::PrefsNode(DevicePrefsFactory));
819
820 ViewDeviceSettingsDialog dialog(&GetProjectFrame(mProject), mProject, XO("Audio Settings:"), factories, 0);
821 dialog.SetSize(600, 420);
822 dialog.Center();
823
824 if (0 != dialog.ShowModal()) {
826 }
827 }
828 else {
829 gAudioIO->HandleDeviceChange();
831 }
832 }
833}
834
836 []( AudacityProject &project ){
837 return ToolBar::Holder{ safenew AudioSetupToolBar{ project } };
838 }
839};
840
841namespace {
843 /* i18n-hint: Clicking this menu item shows the toolbar
844 that manages the audio devices */
845 AudioSetupBarID, wxT("ShowAudioSetupTB"), XXO("&Audio Setup Toolbar")
846};
847}
848
wxT("CloseDown"))
StringSetting AudioIORecordingSource
StringSetting AudioIOPlaybackSource
StringSetting AudioIOPlaybackDevice
StringSetting AudioIORecordingDevice
StringSetting AudioIOHost
IntSetting AudioIORecordingSourceIndex
IntSetting AudioIORecordChannels
static RegisteredToolbarFactory factory
IMPLEMENT_CLASS(AudioSetupToolBar, ToolBar)
END_EVENT_TABLE()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
DeviceChangeMessage
Definition: DeviceChange.h:16
wxString MakeDeviceSourceString(const DeviceSourceMap *map)
PrefsPanel * DevicePrefsFactory(wxWindow *parent, wxWindowID winid, AudacityProject *)
int DeviceToolbarPrefsID()
Methods for DeviceToolBar.
const TranslatableString name
Definition: Distortion.cpp:82
const TranslatableString desc
Definition: ExportPCM.cpp:58
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:431
static const auto title
FileConfig * gPrefs
Definition: Prefs.cpp:71
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
THEME_API Theme theTheme
Definition: Theme.cpp:82
@ AudioSetupBarID
Definition: ToolBar.h:85
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
A wxButton with mouse-over behaviour.
Definition: AButton.h:26
void SetButtonType(Type type)
Definition: AButton.cpp:225
void SetImages(const wxImage &up, const wxImage &over, const wxImage &down, const wxImage &overDown, const wxImage &dis)
Definition: AButton.cpp:283
void PushDown()
Definition: AButton.cpp:642
bool IsDown()
Definition: AButton.h:129
void SetButtonToggles(bool toggler)
Definition: AButton.h:135
void Disable()
Definition: AButton.cpp:625
void Enable()
Definition: AButton.cpp:616
void PopUp()
Definition: AButton.cpp:650
@ FrameButton
Definition: AButton.h:36
void SetIcon(const wxImage &icon)
Definition: AButton.cpp:304
void SetLabel(const TranslatableString &label)
Definition: AButton.cpp:267
static void Bevel(wxDC &dc, bool up, const wxRect &r)
Definition: AColor.cpp:266
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:91
A toolbar to allow easier changing of input and output devices .
void SetDevices(const DeviceSourceMap *in, const DeviceSourceMap *out)
void UpdateSelectedPrefs(int) override
void RegenerateTooltips() override
std::unique_ptr< wxMenu > mHost
void Populate() override
void OnAudioSetup(wxCommandEvent &event)
static AudioSetupToolBar & Get(AudacityProject &project)
void EnableDisableButtons() override
void OnMenu(wxCommandEvent &event)
void ChangeDevice(int deviceId, bool isInput)
void Repaint(wxDC *dc) override
std::optional< wxString > GetSelectedRadioItemLabel(const wxMenu &menu) const
void OnRescannedDevices(DeviceChangeMessage)
std::unique_ptr< wxMenu > mInputChannels
void AppendSubMenu(wxMenu &menu, const std::unique_ptr< wxMenu > &submenu, const wxString &title)
void Create(wxWindow *parent) override
std::unique_ptr< wxMenu > mInput
void ReCreateButtons() override
std::unique_ptr< wxMenu > mOutput
bool ChangeHost(int hostId)
std::unique_ptr< wxMenu > CloneMenu(const wxMenu &menu) const
void OnFocus(wxFocusEvent &event)
void UpdatePrefs() override
void Popup(const BasicUI::WindowPlacement &window, const Point &pos={})
Display the menu at pos, invoke at most one action, then hide it.
Definition: BasicMenu.cpp:209
size_t size() const
How many attachment pointers are in the Site.
Definition: ClientData.h:251
DeviceSourceMap * GetDefaultInputDevice(int hostIndex)
const std::vector< DeviceSourceMap > & GetInputDeviceMaps()
const std::vector< DeviceSourceMap > & GetOutputDeviceMaps()
static DeviceManager * Instance()
Gets the singleton instance.
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
Dialog that shows the current PrefsPanel in a tabbed divider.
Definition: PrefsDialog.h:35
static void Broadcast(int id=0)
Call this static function to notify all PrefsListener objects.
Definition: Prefs.cpp:98
virtual void UpdateSelectedPrefs(int id)
Definition: Prefs.cpp:128
std::vector< PrefsPanel::PrefsNode > Factories
Definition: PrefsPanel.h:69
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:252
bool ReadWithDefault(T *pVar, const T &defaultValue) const
overload of ReadWithDefault returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:206
bool Reset()
Reset to the default value.
Definition: Prefs.h:277
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:200
wxColour & Colour(int iIndex)
wxImage & Image(int iIndex)
wxSize ImageSize(int iIndex)
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed.
Definition: ToolBar.h:101
AudacityProject & mProject
Definition: ToolBar.h:250
static void MakeRecoloredImageSize(teBmps eBmpOut, teBmps eBmpIn, const wxSize &size)
Definition: ToolBar.cpp:782
void Add(wxWindow *window, int proportion=0, int flag=wxALIGN_TOP, int border=0, wxObject *userData=NULL)
Definition: ToolBar.cpp:686
virtual void ReCreateButtons()
Definition: ToolBar.cpp:516
void SetLabel(const wxString &label) override
Definition: ToolBar.cpp:398
wxBoxSizer * GetSizer()
Definition: ToolBar.cpp:678
void UpdatePrefs() override
Definition: ToolBar.cpp:605
static void MakeMacRecoloredImageSize(teBmps eBmpOut, teBmps eBmpIn, const wxSize &size)
Definition: ToolBar.cpp:770
virtual void Create(wxWindow *parent)
Definition: ToolBar.cpp:475
void Detach(wxWindow *window)
Definition: ToolBar.cpp:752
wxWindowPtr< ToolBar > Holder
Definition: ToolBar.h:105
static void SetButtonToolTip(AudacityProject &project, AButton &button, const ComponentInterfaceSymbol commands[], size_t nCommands)
Definition: ToolBar.cpp:947
static ToolManager & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
ViewDeviceSettingsDialog(wxWindow *parent, AudacityProject &project, const TranslatableString &title, PrefsPanel::Factories &factories, int page)
void OnFocus(wxWindow &window, wxFocusEvent &event)
a function useful to implement a focus event handler The window releases the keyboard if the event is...
wxString sourceString
Definition: DeviceManager.h:34
wxString deviceString
Definition: DeviceManager.h:35
Window placement information for wxWidgetsBasicUI can be constructed from a wxWindow pointer.