Audacity  3.0.3
DevicePrefs.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  DevicePrefs.cpp
6 
7  Joshua Haberman
8  Dominic Mazzoni
9  James Crook
10 
11 *******************************************************************//********************************************************************/
24 
25 
26 #include "DevicePrefs.h"
27 #include "AudioIOBase.h"
28 
29 #include "RecordingPrefs.h"
30 
31 #include <wx/defs.h>
32 
33 #include <wx/choice.h>
34 #include <wx/intl.h>
35 #include <wx/log.h>
36 #include <wx/textctrl.h>
37 
38 #include "portaudio.h"
39 
40 #include "Prefs.h"
41 #include "../ShuttleGui.h"
42 #include "DeviceManager.h"
43 
44 enum {
45  HostID = 10000,
49 };
50 
51 BEGIN_EVENT_TABLE(DevicePrefs, PrefsPanel)
52  EVT_CHOICE(HostID, DevicePrefs::OnHost)
53  EVT_CHOICE(RecordID, DevicePrefs::OnDevice)
55 
56 DevicePrefs::DevicePrefs(wxWindow * parent, wxWindowID winid)
57 : PrefsPanel(parent, winid, XO("Devices"))
58 {
59  Populate();
60 }
61 
63 {
64 }
65 
66 
68 {
70 }
71 
73 {
74  return XO("Preferences for Device");
75 }
76 
78 {
79  return "Devices_Preferences";
80 }
81 
83 {
84  // First any pre-processing for constructing the GUI.
86 
87  // Get current setting for devices
92 
93  //------------------------- Main section --------------------
94  // Now construct the GUI itself.
95  // Use 'eIsCreatingFromPrefs' so that the GUI is
96  // initialised with values from gPrefs.
99  // ----------------------- End of main section --------------
100 
101  wxCommandEvent e;
102  OnHost(e);
103 }
104 
105 
106 /*
107  * Get names of device hosts.
108  */
110 {
111  // Gather list of hosts. Only added hosts that have devices attached.
112  // FIXME: TRAP_ERR PaErrorCode not handled in DevicePrefs GetNamesAndLabels()
113  // With an error code won't add hosts, but won't report a problem either.
114  int nDevices = Pa_GetDeviceCount();
115  for (int i = 0; i < nDevices; i++) {
116  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
117  if ((info!=NULL)&&(info->maxOutputChannels > 0 || info->maxInputChannels > 0)) {
118  wxString name = wxSafeConvertMB2WX(Pa_GetHostApiInfo(info->hostApi)->name);
120  .contains( Verbatim( name ) )) {
121  mHostNames.push_back( Verbatim( name ) );
122  mHostLabels.push_back(name);
123  }
124  }
125  }
126 }
127 
129 {
130  S.SetBorder(2);
131  S.StartScroller();
132 
133  /* i18n-hint Software interface to audio devices */
134  S.StartStatic(XC("Interface", "device"));
135  {
136  S.StartMultiColumn(2);
137  {
138  S.Id(HostID);
139  mHost = S.TieChoice( XXO("&Host:"),
140  {
141  AudioIOHost,
143  }
144  );
145 
146  S.AddPrompt(XXO("Using:"));
147  S.AddFixedText( Verbatim(wxSafeConvertMB2WX(Pa_GetVersionText() ) ) );
148  }
149  S.EndMultiColumn();
150  }
151  S.EndStatic();
152 
153  S.StartStatic(XO("Playback"));
154  {
155  S.StartMultiColumn(2);
156  {
157  S.Id(PlayID);
158  mPlay = S.AddChoice(XXO("&Device:"),
159  {} );
160  }
161  S.EndMultiColumn();
162  }
163  S.EndStatic();
164 
165  // i18n-hint: modifier as in "Recording preferences", not progressive verb
166  S.StartStatic(XC("Recording", "preference"));
167  {
168  S.StartMultiColumn(2);
169  {
170  S.Id(RecordID);
171  mRecord = S.AddChoice(XXO("De&vice:"),
172  {} );
173 
174  S.Id(ChannelsID);
175  mChannels = S.AddChoice(XXO("Cha&nnels:"),
176  {} );
177  }
178  S.EndMultiColumn();
179  }
180  S.EndStatic();
181 
182  // These previously lived in recording preferences.
183  // However they are liable to become device specific.
184  // Buffering also affects playback, not just recording, so is a device characteristic.
185  S.StartStatic( XO("Latency"));
186  {
187  S.StartThreeColumn();
188  {
189  wxTextCtrl *w;
190  // only show the following controls if we use Portaudio v19, because
191  // for Portaudio v18 we always use default buffer sizes
192  w = S
193  .NameSuffix(XO("milliseconds"))
194  .TieNumericTextBox(XXO("&Buffer length:"),
196  9);
197  S.AddUnits(XO("milliseconds"));
198 
199  w = S
200  .NameSuffix(XO("milliseconds"))
201  .TieNumericTextBox(XXO("&Latency compensation:"),
203  S.AddUnits(XO("milliseconds"));
204  }
205  S.EndThreeColumn();
206  }
207  S.EndStatic();
208  S.EndScroller();
209 
210 }
211 
212 void DevicePrefs::OnHost(wxCommandEvent & e)
213 {
214  // Bail if we have no hosts
215  if (mHostNames.size() < 1)
216  return;
217 
218  // Find the index for the host API selected
219  int index = -1;
220  auto apiName = mHostLabels[mHost->GetCurrentSelection()];
221  int nHosts = Pa_GetHostApiCount();
222  for (int i = 0; i < nHosts; ++i) {
223  wxString name = wxSafeConvertMB2WX(Pa_GetHostApiInfo(i)->name);
224  if (name == apiName) {
225  index = i;
226  break;
227  }
228  }
229  // We should always find the host!
230  if (index < 0) {
231  wxLogDebug(wxT("DevicePrefs::OnHost(): API index not found"));
232  return;
233  }
234 
235  int nDevices = Pa_GetDeviceCount();
236 
237  // FIXME: TRAP_ERR PaErrorCode not handled. nDevices can be negative number.
238  if (nDevices == 0) {
239  mHost->Clear();
240  mHost->Append(_("No audio interfaces"), (void *) NULL);
241  mHost->SetSelection(0);
242  }
243 
244  const std::vector<DeviceSourceMap> &inMaps = DeviceManager::Instance()->GetInputDeviceMaps();
245  const std::vector<DeviceSourceMap> &outMaps = DeviceManager::Instance()->GetOutputDeviceMaps();
246 
247  wxArrayString playnames;
248  wxArrayString recordnames;
249  size_t i;
250  int devindex; /* temp variable to hold the numeric ID of each device in turn */
251  wxString device;
252  wxString recDevice;
253 
254  recDevice = mRecordDevice;
255  if (!this->mRecordSource.empty())
256  recDevice += wxT(": ") + mRecordSource;
257 
258  mRecord->Clear();
259  for (i = 0; i < inMaps.size(); i++) {
260  if (index == inMaps[i].hostIndex) {
261  device = MakeDeviceSourceString(&inMaps[i]);
262  devindex = mRecord->Append(device);
263  // We need to const cast here because SetClientData is a wx function
264  // It is okay because the original variable is non-const.
265  mRecord->SetClientData(devindex, const_cast<DeviceSourceMap *>(&inMaps[i]));
266  if (device == recDevice) { /* if this is the default device, select it */
267  mRecord->SetSelection(devindex);
268  }
269  }
270  }
271 
272  mPlay->Clear();
273  for (i = 0; i < outMaps.size(); i++) {
274  if (index == outMaps[i].hostIndex) {
275  device = MakeDeviceSourceString(&outMaps[i]);
276  devindex = mPlay->Append(device);
277  mPlay->SetClientData(devindex, const_cast<DeviceSourceMap *>(&outMaps[i]));
278  if (device == mPlayDevice) { /* if this is the default device, select it */
279  mPlay->SetSelection(devindex);
280  }
281  }
282  }
283 
284  /* deal with not having any devices at all */
285  if (mPlay->GetCount() == 0) {
286  playnames.push_back(_("No devices found"));
287  mPlay->Append(playnames[0], (void *) NULL);
288  mPlay->SetSelection(0);
289  }
290  if (mRecord->GetCount() == 0) {
291  recordnames.push_back(_("No devices found"));
292  mRecord->Append(recordnames[0], (void *) NULL);
293  mRecord->SetSelection(0);
294  }
295 
296  /* what if we have no device selected? we should choose the default on
297  * this API, as defined by PortAudio. We then fall back to using 0 only if
298  * that fails */
299  if (mPlay->GetCount() && mPlay->GetSelection() == wxNOT_FOUND) {
301  if (defaultMap)
302  mPlay->SetStringSelection(MakeDeviceSourceString(defaultMap));
303 
304  if (mPlay->GetSelection() == wxNOT_FOUND) {
305  mPlay->SetSelection(0);
306  }
307  }
308 
309  if (mRecord->GetCount() && mRecord->GetSelection() == wxNOT_FOUND) {
311  if (defaultMap)
312  mRecord->SetStringSelection(MakeDeviceSourceString(defaultMap));
313 
314  if (mPlay->GetSelection() == wxNOT_FOUND) {
315  mPlay->SetSelection(0);
316  }
317  }
318 
319  ShuttleGui::SetMinSize(mPlay, mPlay->GetStrings());
320  ShuttleGui::SetMinSize(mRecord, mRecord->GetStrings());
321  OnDevice(e);
322 }
323 
324 void DevicePrefs::OnDevice(wxCommandEvent & WXUNUSED(event))
325 {
326  int ndx = mRecord->GetCurrentSelection();
327  if (ndx == wxNOT_FOUND) {
328  ndx = 0;
329  }
330 
331  int sel = mChannels->GetSelection();
332  int cnt = 0;
333 
334  DeviceSourceMap *inMap = (DeviceSourceMap *) mRecord->GetClientData(ndx);
335  if (inMap != NULL) {
336  cnt = inMap->numChannels;
337  }
338 
339  if (sel != wxNOT_FOUND) {
340  mRecordChannels = sel + 1;
341  }
342 
343  mChannels->Clear();
344 
345  // Mimic old behavior
346  if (cnt <= 0) {
347  cnt = 16;
348  }
349 
350  // Place an artificial limit on the number of channels to prevent an
351  // outrageous number. I don't know if this is really necessary, but
352  // it doesn't hurt.
353  if (cnt > 256) {
354  cnt = 256;
355  }
356 
357  wxArrayStringEx channelnames;
358 
359  // Channel counts, mono, stereo etc...
360  for (int i = 0; i < cnt; i++) {
361  wxString name;
362 
363  if (i == 0) {
364  name = _("1 (Mono)");
365  }
366  else if (i == 1) {
367  name = _("2 (Stereo)");
368  }
369  else {
370  name = wxString::Format(wxT("%d"), i + 1);
371  }
372 
373  channelnames.push_back(name);
374  int index = mChannels->Append(name);
375  if (i == mRecordChannels - 1) {
376  mChannels->SetSelection(index);
377  }
378  }
379 
380  if (mChannels->GetCount() && mChannels->GetCurrentSelection() == wxNOT_FOUND) {
381  mChannels->SetSelection(0);
382  }
383 
384  ShuttleGui::SetMinSize(mChannels, channelnames);
385  Layout();
386 }
387 
389 {
390  ShuttleGui S(this, eIsSavingToPrefs);
392  DeviceSourceMap *map = NULL;
393 
394  if (mPlay->GetCount() > 0) {
395  map = (DeviceSourceMap *) mPlay->GetClientData(
396  mPlay->GetSelection());
397  }
398  if (map)
400 
401  map = NULL;
402  if (mRecord->GetCount() > 0) {
403  map = (DeviceSourceMap *) mRecord->GetClientData(mRecord->GetSelection());
404  }
405  if (map) {
408  if (map->totalSources >= 1)
410  else
412  AudioIORecordChannels.Write(mChannels->GetSelection() + 1);
413  }
414 
415  return true;
416 }
417 
418 namespace{
420  [](wxWindow *parent, wxWindowID winid, AudacityProject *)
421  {
422  wxASSERT(parent); // to justify safenew
423  return safenew DevicePrefs(parent, winid);
424  }
425 };
426 }
AudioIORecordingDevice
StringSetting AudioIORecordingDevice
Definition: AudioIOBase.cpp:945
PlayID
@ PlayID
Definition: DevicePrefs.cpp:46
ShuttleGui::NameSuffix
ShuttleGui & NameSuffix(const TranslatableString &suffix)
Definition: ShuttleGui.h:671
AudioIOLatencyCorrection
DoubleSetting AudioIOLatencyCorrection
Definition: AudioIOBase.cpp:935
AudioIOPlaybackDevice
StringSetting AudioIOPlaybackDevice
Definition: AudioIOBase.cpp:939
DevicePrefs::PopulateOrExchange
void PopulateOrExchange(ShuttleGui &S) override
Definition: DevicePrefs.cpp:128
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
AudioIOBase.h
anonymous_namespace{DevicePrefs.cpp}::sAttachment
PrefsPanel::Registration sAttachment
Definition: DevicePrefs.cpp:419
DevicePrefs::~DevicePrefs
virtual ~DevicePrefs()
Definition: DevicePrefs.cpp:62
ShuttleGuiBase::AddChoice
wxChoice * AddChoice(const TranslatableString &Prompt, const TranslatableStrings &choices, int Selected=-1)
Definition: ShuttleGui.cpp:398
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:551
ShuttleGui::SetMinSize
static void SetMinSize(wxWindow *window, const TranslatableStrings &items)
Definition: ShuttleGui.cpp:2470
DeviceSourceMap::numChannels
int numChannels
Definition: DeviceManager.h:40
ChannelsID
@ ChannelsID
Definition: DevicePrefs.cpp:48
ShuttleGuiBase::EndThreeColumn
void EndThreeColumn()
Definition: ShuttleGui.h:369
DevicePrefs::OnDevice
void OnDevice(wxCommandEvent &e)
Definition: DevicePrefs.cpp:324
RecordID
@ RecordID
Definition: DevicePrefs.cpp:47
DevicePrefs::HelpPageName
ManualPageID HelpPageName() override
If not empty string, the Help button is added below the panel.
Definition: DevicePrefs.cpp:77
DevicePrefs::GetNamesAndLabels
void GetNamesAndLabels()
Definition: DevicePrefs.cpp:109
Setting::Write
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:172
DevicePrefs::OnHost
void OnHost(wxCommandEvent &e)
Definition: DevicePrefs.cpp:212
MakeDeviceSourceString
wxString MakeDeviceSourceString(const DeviceSourceMap *map)
Definition: DeviceManager.cpp:54
DeviceSourceMap::deviceString
wxString deviceString
Definition: DeviceManager.h:42
PrefsPanel::Registration
Definition: PrefsPanel.h:84
DevicePrefs::GetDescription
TranslatableString GetDescription() override
Definition: DevicePrefs.cpp:72
XO
#define XO(s)
Definition: Internat.h:31
XC
#define XC(s, c)
Definition: Internat.h:37
ShuttleGuiBase::EndMultiColumn
void EndMultiColumn()
Definition: ShuttleGui.cpp:1238
wxArrayStringEx
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
Definition: wxArrayStringEx.h:18
ComponentInterfaceSymbol
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Definition: ComponentInterfaceSymbol.h:27
DeviceSourceMap
Definition: DeviceManager.h:35
DevicePrefs::mRecordChannels
long mRecordChannels
Definition: DevicePrefs.h:49
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
AudioIORecordingSourceIndex
IntSetting AudioIORecordingSourceIndex
Definition: AudioIOBase.cpp:949
Setting::Read
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:128
DevicePrefs::mHost
wxChoice * mHost
Definition: DevicePrefs.h:51
ShuttleGuiBase::EndScroller
void EndScroller()
Definition: ShuttleGui.cpp:971
DevicePrefs::mPlay
wxChoice * mPlay
Definition: DevicePrefs.h:52
DevicePrefs::Populate
void Populate()
Definition: DevicePrefs.cpp:82
AudioIOLatencyDuration
DoubleSetting AudioIOLatencyDuration
Definition: AudioIOBase.cpp:937
DevicePrefs::Commit
bool Commit() override
Definition: DevicePrefs.cpp:388
DeviceManager::GetDefaultOutputDevice
DeviceSourceMap * GetDefaultOutputDevice(int hostIndex)
Definition: DeviceManager.cpp:84
XXO
#define XXO(s)
Definition: Internat.h:44
ShuttleGuiBase::StartScroller
wxScrolledWindow * StartScroller(int iStyle=0)
Definition: ShuttleGui.cpp:938
ShuttleGuiBase::StartMultiColumn
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
Definition: ShuttleGui.cpp:1229
ShuttleGuiBase::AddUnits
void AddUnits(const TranslatableString &Prompt, int wrapWidth=0)
Left aligned text string.
Definition: ShuttleGui.cpp:263
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
AudioIORecordingSource
StringSetting AudioIORecordingSource
Definition: AudioIOBase.cpp:947
DevicePrefs::mRecord
wxChoice * mRecord
Definition: DevicePrefs.h:53
name
const TranslatableString name
Definition: Distortion.cpp:98
DevicePrefs::mChannels
wxChoice * mChannels
Definition: DevicePrefs.h:54
ShuttleGuiBase::StartThreeColumn
void StartThreeColumn()
Definition: ShuttleGui.h:368
ShuttleGuiBase::TieNumericTextBox
wxTextCtrl * TieNumericTextBox(const TranslatableString &Prompt, int &Value, const int nChars=0)
Definition: ShuttleGui.cpp:1673
DeviceSourceMap::totalSources
int totalSources
Definition: DeviceManager.h:39
RecordingPrefs.h
DEVICE_PREFS_PLUGIN_SYMBOL
#define DEVICE_PREFS_PLUGIN_SYMBOL
Definition: DevicePrefs.h:22
DeviceSourceMap::sourceIndex
int sourceIndex
Definition: DeviceManager.h:37
DeviceManager.h
DevicePrefs::GetSymbol
ComponentInterfaceSymbol GetSymbol() override
Definition: DevicePrefs.cpp:67
ShuttleGuiBase::StartStatic
wxStaticBox * StartStatic(const TranslatableString &Str, int iProp=0)
Definition: ShuttleGui.cpp:893
eIsSavingToPrefs
@ eIsSavingToPrefs
Definition: ShuttleGui.h:48
DevicePrefs::mRecordSource
wxString mRecordSource
Definition: DevicePrefs.h:48
TaggedIdentifier< ManualPageIDTag >
_
#define _(s)
Definition: Internat.h:75
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
AudioIOHost
StringSetting AudioIOHost
Definition: AudioIOBase.cpp:933
DeviceManager::GetDefaultInputDevice
DeviceSourceMap * GetDefaultInputDevice(int hostIndex)
Definition: DeviceManager.cpp:88
DeviceManager::Instance
static DeviceManager * Instance()
Gets the singleton instance.
Definition: DeviceManager.cpp:35
Setting::Reset
bool Reset()
Reset to the default value.
Definition: Prefs.h:183
DevicePrefs::mHostNames
TranslatableStrings mHostNames
Definition: DevicePrefs.h:43
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
DeviceManager::GetInputDeviceMaps
const std::vector< DeviceSourceMap > & GetInputDeviceMaps()
Definition: DeviceManager.cpp:40
HostID
@ HostID
Definition: DevicePrefs.cpp:45
DeviceSourceMap::sourceString
wxString sourceString
Definition: DeviceManager.h:41
PrefsPanel
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
Definition: PrefsPanel.h:51
DeviceManager::GetOutputDeviceMaps
const std::vector< DeviceSourceMap > & GetOutputDeviceMaps()
Definition: DeviceManager.cpp:46
Prefs.h
ShuttleGuiBase::AddPrompt
void AddPrompt(const TranslatableString &Prompt, int wrapWidth=0)
Right aligned text string.
Definition: ShuttleGui.cpp:238
ShuttleGuiBase::SetBorder
void SetBorder(int Border)
Definition: ShuttleGui.h:489
ByColumns
ByColumns_t ByColumns
Definition: Prefs.cpp:420
eIsCreatingFromPrefs
@ eIsCreatingFromPrefs
Definition: ShuttleGui.h:47
DevicePrefs.h
ShuttleGuiBase::EndStatic
void EndStatic()
Definition: ShuttleGui.cpp:922
safenew
#define safenew
Definition: MemoryX.h:10
DevicePrefs
A PrefsPanel used to select recording and playback devices and other settings.
Definition: DevicePrefs.h:25
DevicePrefs::mPlayDevice
wxString mPlayDevice
Definition: DevicePrefs.h:46
END_EVENT_TABLE
END_EVENT_TABLE()
ShuttleGuiBase::TieChoice
wxChoice * TieChoice(const TranslatableString &Prompt, TranslatableString &Selected, const TranslatableStrings &choices)
Definition: ShuttleGui.cpp:1727
DevicePrefs::mHostLabels
wxArrayStringEx mHostLabels
Definition: DevicePrefs.h:44
AudioIORecordChannels
IntSetting AudioIORecordChannels
Definition: AudioIOBase.cpp:943
DevicePrefs::mRecordDevice
wxString mRecordDevice
Definition: DevicePrefs.h:47
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631