Audacity  3.0.3
AudioIOBase.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 AudioIOBase.cpp
6 
7 Paul Licameli split from AudioIO.cpp
8 
9 **********************************************************************/
10 
11 
12 #include "AudioIOBase.h"
13 
14 #include <wx/log.h>
15 #include <wx/sstream.h>
16 #include <wx/txtstrm.h>
17 
18 #include "Meter.h"
19 #include "Prefs.h"
20 
21 #if USE_PORTMIXER
22 #include "portmixer.h"
23 #endif
24 
25 #ifdef EXPERIMENTAL_MIDI_OUT
26 #include <portmidi.h>
27 #endif
28 
30 std::vector<long> AudioIOBase::mCachedPlaybackRates;
32 std::vector<long> AudioIOBase::mCachedCaptureRates;
33 std::vector<long> AudioIOBase::mCachedSampleRates;
35 
36 const int AudioIOBase::StandardRates[] = {
37  8000,
38  11025,
39  16000,
40  22050,
41  32000,
42  44100,
43  48000,
44  88200,
45  96000,
46  176400,
47  192000,
48  352800,
49  384000
50 };
51 
53 
54 const int AudioIOBase::RatesToTry[] = {
55  8000,
56  9600,
57  11025,
58  12000,
59  15000,
60  16000,
61  22050,
62  24000,
63  32000,
64  44100,
65  48000,
66  88200,
67  96000,
68  176400,
69  192000,
70  352800,
71  384000
72 };
74 
75 wxString AudioIOBase::DeviceName(const PaDeviceInfo* info)
76 {
77  wxString infoName = wxSafeConvertMB2WX(info->name);
78 
79  return infoName;
80 }
81 
82 wxString AudioIOBase::HostName(const PaDeviceInfo* info)
83 {
84  wxString hostapiName = wxSafeConvertMB2WX(Pa_GetHostApiInfo(info->hostApi)->name);
85 
86  return hostapiName;
87 }
88 
89 std::unique_ptr<AudioIOBase> AudioIOBase::ugAudioIO;
90 
92 {
93  return ugAudioIO.get();
94 }
95 
96 AudioIOBase::~AudioIOBase() = default;
97 
98 void AudioIOBase::SetMixer(int inputSource)
99 {
100 #if defined(USE_PORTMIXER)
101  int oldRecordSource = Px_GetCurrentInputSource(mPortMixer);
102  if ( inputSource != oldRecordSource )
103  Px_SetCurrentInputSource(mPortMixer, inputSource);
104 #endif
105 }
106 
108 {
109  // This should not happen, but it would screw things up if it did.
110  // Vaughan, 2010-10-08: But it *did* happen, due to a bug, and nobody
111  // caught it because this method just returned. Added wxASSERT().
112  wxASSERT(!IsStreamActive());
113  if (IsStreamActive())
114  return;
115 
116  // get the selected record and playback devices
117  const int playDeviceNum = getPlayDevIndex();
118  const int recDeviceNum = getRecordDevIndex();
119 
120  // If no change needed, return
121  if (mCachedPlaybackIndex == playDeviceNum &&
122  mCachedCaptureIndex == recDeviceNum)
123  return;
124 
125  // cache playback/capture rates
128  mCachedSampleRates = GetSupportedSampleRates(playDeviceNum, recDeviceNum);
129  mCachedPlaybackIndex = playDeviceNum;
130  mCachedCaptureIndex = recDeviceNum;
131  mCachedBestRateIn = 0.0;
132 
133 #if defined(USE_PORTMIXER)
134 
135  // if we have a PortMixer object, close it down
136  if (mPortMixer) {
137  #if __WXMAC__
138  // on the Mac we must make sure that we restore the hardware playthrough
139  // state of the sound device to what it was before, because there isn't
140  // a UI for this (!)
141  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
142  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
143  mPreviousHWPlaythrough = -1.0;
144  #endif
145  Px_CloseMixer(mPortMixer);
146  mPortMixer = NULL;
147  }
148 
149  // that might have given us no rates whatsoever, so we have to guess an
150  // answer to do the next bit
151  int numrates = mCachedSampleRates.size();
152  int highestSampleRate;
153  if (numrates > 0)
154  {
155  highestSampleRate = mCachedSampleRates[numrates - 1];
156  }
157  else
158  { // we don't actually have any rates that work for Rec and Play. Guess one
159  // to use for messing with the mixer, which doesn't actually do either
160  highestSampleRate = 44100;
161  // mCachedSampleRates is still empty, but it's not used again, so
162  // can ignore
163  }
164  mInputMixerWorks = false;
165  mEmulateMixerOutputVol = true;
166  mMixerOutputVol = 1.0;
167 
168  int error;
169  // This tries to open the device with the samplerate worked out above, which
170  // will be the highest available for play and record on the device, or
171  // 44.1kHz if the info cannot be fetched.
172 
173  PaStream *stream;
174 
175  PaStreamParameters playbackParameters;
176 
177  playbackParameters.device = playDeviceNum;
178  playbackParameters.sampleFormat = paFloat32;
179  playbackParameters.hostApiSpecificStreamInfo = NULL;
180  playbackParameters.channelCount = 1;
181  if (Pa_GetDeviceInfo(playDeviceNum))
182  playbackParameters.suggestedLatency =
183  Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
184  else
185  playbackParameters.suggestedLatency =
187 
188  PaStreamParameters captureParameters;
189 
190  captureParameters.device = recDeviceNum;
191  captureParameters.sampleFormat = paFloat32;;
192  captureParameters.hostApiSpecificStreamInfo = NULL;
193  captureParameters.channelCount = 1;
194  if (Pa_GetDeviceInfo(recDeviceNum))
195  captureParameters.suggestedLatency =
196  Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
197  else
198  captureParameters.suggestedLatency =
200 
201  // try opening for record and playback
202  // Not really doing I/O so pass nullptr for the callback function
203  error = Pa_OpenStream(&stream,
204  &captureParameters, &playbackParameters,
205  highestSampleRate, paFramesPerBufferUnspecified,
206  paClipOff | paDitherOff,
207  nullptr, NULL);
208 
209  if (!error) {
210  // Try portmixer for this stream
211  mPortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
212  if (!mPortMixer) {
213  Pa_CloseStream(stream);
214  error = true;
215  }
216  }
217 
218  // if that failed, try just for record
219  if( error ) {
220  error = Pa_OpenStream(&stream,
221  &captureParameters, NULL,
222  highestSampleRate, paFramesPerBufferUnspecified,
223  paClipOff | paDitherOff,
224  nullptr, NULL);
225 
226  if (!error) {
227  mPortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
228  if (!mPortMixer) {
229  Pa_CloseStream(stream);
230  error = true;
231  }
232  }
233  }
234 
235  // finally, try just for playback
236  if ( error ) {
237  error = Pa_OpenStream(&stream,
238  NULL, &playbackParameters,
239  highestSampleRate, paFramesPerBufferUnspecified,
240  paClipOff | paDitherOff,
241  nullptr, NULL);
242 
243  if (!error) {
244  mPortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
245  if (!mPortMixer) {
246  Pa_CloseStream(stream);
247  error = true;
248  }
249  }
250  }
251 
252  // FIXME: TRAP_ERR errors in HandleDeviceChange not reported.
253  // if it's still not working, give up
254  if( error )
255  return;
256 
257  // Set input source
258 #if USE_PORTMIXER
259  auto sourceIndex = AudioIORecordingSourceIndex.Read(); // defaults to -1
260  if (sourceIndex >= 0) {
261  //the current index of our source may be different because the stream
262  //is a combination of two devices, so update it.
263  sourceIndex = getRecordSourceIndex(mPortMixer);
264  if (sourceIndex >= 0)
265  SetMixer(sourceIndex);
266  }
267 #endif
268 
269  // Determine mixer capabilities - if it doesn't support control of output
270  // signal level, we emulate it (by multiplying this value by all outgoing
271  // samples)
272 
273  mMixerOutputVol = Px_GetPCMOutputVolume(mPortMixer);
274  mEmulateMixerOutputVol = false;
275  Px_SetPCMOutputVolume(mPortMixer, 0.0);
276  if (Px_GetPCMOutputVolume(mPortMixer) > 0.1)
277  mEmulateMixerOutputVol = true;
278  Px_SetPCMOutputVolume(mPortMixer, 0.2f);
279  if (Px_GetPCMOutputVolume(mPortMixer) < 0.1 ||
280  Px_GetPCMOutputVolume(mPortMixer) > 0.3)
281  mEmulateMixerOutputVol = true;
282  Px_SetPCMOutputVolume(mPortMixer, mMixerOutputVol);
283 
284  float inputVol = Px_GetInputVolume(mPortMixer);
285  mInputMixerWorks = true; // assume it works unless proved wrong
286  Px_SetInputVolume(mPortMixer, 0.0);
287  if (Px_GetInputVolume(mPortMixer) > 0.1)
288  mInputMixerWorks = false; // can't set to zero
289  Px_SetInputVolume(mPortMixer, 0.2f);
290  if (Px_GetInputVolume(mPortMixer) < 0.1 ||
291  Px_GetInputVolume(mPortMixer) > 0.3)
292  mInputMixerWorks = false; // can't set level accurately
293  Px_SetInputVolume(mPortMixer, inputVol);
294 
295  Pa_CloseStream(stream);
296 
297 
298  #if 0
299  wxPrintf("PortMixer: Playback: %s Recording: %s\n",
300  mEmulateMixerOutputVol? "emulated": "native",
301  mInputMixerWorks? "hardware": "no control");
302  #endif
303 
304  mMixerOutputVol = 1.0;
305 
306 #endif // USE_PORTMIXER
307 }
308 
310  AudacityProject *project, const std::weak_ptr<Meter> &wMeter)
311 {
312  if (( mOwningProject ) && ( mOwningProject != project))
313  return;
314 
315  auto meter = wMeter.lock();
316  if (meter)
317  {
318  mInputMeter = meter;
319  meter->Reset(mRate, true);
320  }
321  else
322  mInputMeter.reset();
323 }
324 
326  AudacityProject *project, const std::weak_ptr<Meter> &wMeter)
327 {
328  if (( mOwningProject ) && ( mOwningProject != project))
329  return;
330 
331  auto meter = wMeter.lock();
332  if (meter)
333  {
334  mOutputMeter = meter;
335  meter->Reset(mRate, true);
336  }
337  else
338  mOutputMeter.reset();
339 }
340 
342 {
343  return mPaused;
344 }
345 
347 {
348  if (mStreamToken != 0)
349  return true;
350 
351  return false;
352 }
353 
355 {
356  bool isActive = false;
357  // JKC: Not reporting any Pa error, but that looks OK.
358  if( mPortStreamV19 )
359  isActive = (Pa_IsStreamActive( mPortStreamV19 ) > 0);
360 
361 #ifdef EXPERIMENTAL_MIDI_OUT
363  isActive = true;
364 #endif
365  return isActive;
366 }
367 
368 bool AudioIOBase::IsStreamActive(int token) const
369 {
370  return (this->IsStreamActive() && this->IsAudioTokenActive(token));
371 }
372 
373 bool AudioIOBase::IsAudioTokenActive(int token) const
374 {
375  return ( token > 0 && token == mStreamToken );
376 }
377 
379 {
380  return ( mPortStreamV19 && mStreamToken==0 );
381 }
382 
383 std::vector<long> AudioIOBase::GetSupportedPlaybackRates(int devIndex, double rate)
384 {
385  if (devIndex == -1)
386  { // weren't given a device index, get the prefs / default one
387  devIndex = getPlayDevIndex();
388  }
389 
390  // Check if we can use the cached rates
391  if (mCachedPlaybackIndex != -1 && devIndex == mCachedPlaybackIndex
392  && (rate == 0.0 || make_iterator_range(mCachedPlaybackRates).contains(rate)))
393  {
394  return mCachedPlaybackRates;
395  }
396 
397  std::vector<long> supported;
398  int irate = (int)rate;
399  const PaDeviceInfo* devInfo = NULL;
400  int i;
401 
402  devInfo = Pa_GetDeviceInfo(devIndex);
403 
404  if (!devInfo)
405  {
406  wxLogDebug(wxT("GetSupportedPlaybackRates() Could not get device info!"));
407  return supported;
408  }
409 
410  // LLL: Remove when a proper method of determining actual supported
411  // DirectSound rate is devised.
412  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
413  bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
414 
415  PaStreamParameters pars;
416 
417  pars.device = devIndex;
418  pars.channelCount = 1;
419  pars.sampleFormat = paFloat32;
420  pars.suggestedLatency = devInfo->defaultHighOutputLatency;
421  pars.hostApiSpecificStreamInfo = NULL;
422 
423  // JKC: PortAudio Errors handled OK here. No need to report them
424  for (i = 0; i < NumRatesToTry; i++)
425  {
426  // LLL: Remove when a proper method of determining actual supported
427  // DirectSound rate is devised.
428  if (!(isDirectSound && RatesToTry[i] > 200000)){
429  if (Pa_IsFormatSupported(NULL, &pars, RatesToTry[i]) == 0)
430  supported.push_back(RatesToTry[i]);
431  Pa_Sleep( 10 );// There are ALSA drivers that don't like being probed
432  // too quickly.
433  }
434  }
435 
436  if (irate != 0 && !make_iterator_range(supported).contains(irate))
437  {
438  // LLL: Remove when a proper method of determining actual supported
439  // DirectSound rate is devised.
440  if (!(isDirectSound && RatesToTry[i] > 200000))
441  if (Pa_IsFormatSupported(NULL, &pars, irate) == 0)
442  supported.push_back(irate);
443  }
444 
445  return supported;
446 }
447 
448 std::vector<long> AudioIOBase::GetSupportedCaptureRates(int devIndex, double rate)
449 {
450  if (devIndex == -1)
451  { // not given a device, look up in prefs / default
452  devIndex = getRecordDevIndex();
453  }
454 
455  // Check if we can use the cached rates
456  if (mCachedCaptureIndex != -1 && devIndex == mCachedCaptureIndex
457  && (rate == 0.0 || make_iterator_range(mCachedCaptureRates).contains(rate)))
458  {
459  return mCachedCaptureRates;
460  }
461 
462  std::vector<long> supported;
463  int irate = (int)rate;
464  const PaDeviceInfo* devInfo = NULL;
465  int i;
466 
467  devInfo = Pa_GetDeviceInfo(devIndex);
468 
469  if (!devInfo)
470  {
471  wxLogDebug(wxT("GetSupportedCaptureRates() Could not get device info!"));
472  return supported;
473  }
474 
475  auto latencyDuration = AudioIOLatencyDuration.Read();
476  // Why not defaulting to 2 as elsewhere?
477  auto recordChannels = AudioIORecordChannels.ReadWithDefault(1);
478 
479  // LLL: Remove when a proper method of determining actual supported
480  // DirectSound rate is devised.
481  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
482  bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
483 
484  PaStreamParameters pars;
485 
486  pars.device = devIndex;
487  pars.channelCount = recordChannels;
488  pars.sampleFormat = paFloat32;
489  pars.suggestedLatency = latencyDuration / 1000.0;
490  pars.hostApiSpecificStreamInfo = NULL;
491 
492  for (i = 0; i < NumRatesToTry; i++)
493  {
494  // LLL: Remove when a proper method of determining actual supported
495  // DirectSound rate is devised.
496  if (!(isDirectSound && RatesToTry[i] > 200000))
497  {
498  if (Pa_IsFormatSupported(&pars, NULL, RatesToTry[i]) == 0)
499  supported.push_back(RatesToTry[i]);
500  Pa_Sleep( 10 );// There are ALSA drivers that don't like being probed
501  // too quickly.
502  }
503  }
504 
505  if (irate != 0 && !make_iterator_range(supported).contains(irate))
506  {
507  // LLL: Remove when a proper method of determining actual supported
508  // DirectSound rate is devised.
509  if (!(isDirectSound && RatesToTry[i] > 200000))
510  if (Pa_IsFormatSupported(&pars, NULL, irate) == 0)
511  supported.push_back(irate);
512  }
513 
514  return supported;
515 }
516 
518  int playDevice, int recDevice, double rate)
519 {
520  // Not given device indices, look up prefs
521  if (playDevice == -1) {
522  playDevice = getPlayDevIndex();
523  }
524  if (recDevice == -1) {
525  recDevice = getRecordDevIndex();
526  }
527 
528  // Check if we can use the cached rates
529  if (mCachedPlaybackIndex != -1 && mCachedCaptureIndex != -1 &&
530  playDevice == mCachedPlaybackIndex &&
531  recDevice == mCachedCaptureIndex &&
532  (rate == 0.0 || make_iterator_range(mCachedSampleRates).contains(rate)))
533  {
534  return mCachedSampleRates;
535  }
536 
537  auto playback = GetSupportedPlaybackRates(playDevice, rate);
538  auto capture = GetSupportedCaptureRates(recDevice, rate);
539  int i;
540 
541  // Return only sample rates which are in both arrays
542  std::vector<long> result;
543 
544  for (i = 0; i < (int)playback.size(); i++)
545  if (make_iterator_range(capture).contains(playback[i]))
546  result.push_back(playback[i]);
547 
548  // If this yields no results, use the default sample rates nevertheless
549 /* if (result.empty())
550  {
551  for (i = 0; i < NumStandardRates; i++)
552  result.push_back(StandardRates[i]);
553  }*/
554 
555  return result;
556 }
557 
563 {
564  auto rates = GetSupportedSampleRates();
565 
566  if (make_iterator_range(rates).contains(44100))
567  return 44100;
568 
569  if (make_iterator_range(rates).contains(48000))
570  return 48000;
571 
572  // if there are no supported rates, the next bit crashes. So check first,
573  // and give them a "sensible" value if there are no valid values. They
574  // will still get an error later, but with any luck may have changed
575  // something by then. It's no worse than having an invalid default rate
576  // stored in the preferences, which we don't check for
577  if (rates.empty()) return 44100;
578 
579  return rates.back();
580 }
581 
582 #if USE_PORTMIXER
583 int AudioIOBase::getRecordSourceIndex(PxMixer *portMixer)
584 {
585  int i;
586  auto sourceName = AudioIORecordingSource.Read();
587  int numSources = Px_GetNumInputSources(portMixer);
588  for (i = 0; i < numSources; i++) {
589  if (sourceName == wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(portMixer, i))))
590  return i;
591  }
592  return -1;
593 }
594 #endif
595 
596 int AudioIOBase::getPlayDevIndex(const wxString &devNameArg)
597 {
598  wxString devName(devNameArg);
599  // if we don't get given a device, look up the preferences
600  if (devName.empty())
601  devName = AudioIOPlaybackDevice.Read();
602 
603  auto hostName = AudioIOHost.Read();
604  PaHostApiIndex hostCnt = Pa_GetHostApiCount();
605  PaHostApiIndex hostNum;
606  for (hostNum = 0; hostNum < hostCnt; hostNum++)
607  {
608  const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
609  if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
610  {
611  for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
612  {
613  PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
614 
615  const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
616  if (dinfo && DeviceName(dinfo) == devName && dinfo->maxOutputChannels > 0 )
617  {
618  // this device name matches the stored one, and works.
619  // So we say this is the answer and return it
620  return deviceNum;
621  }
622  }
623 
624  // The device wasn't found so use the default for this host.
625  // LL: At this point, preferences and active no longer match.
626  return hinfo->defaultOutputDevice;
627  }
628  }
629 
630  // The host wasn't found, so use the default output device.
631  // FIXME: TRAP_ERR PaErrorCode not handled well (this code is similar to input code
632  // and the input side has more comments.)
633 
634  PaDeviceIndex deviceNum = Pa_GetDefaultOutputDevice();
635 
636  // Sometimes PortAudio returns -1 if it cannot find a suitable default
637  // device, so we just use the first one available
638  //
639  // LL: At this point, preferences and active no longer match
640  //
641  // And I can't imagine how far we'll get specifying an "invalid" index later
642  // on...are we certain "0" even exists?
643  if (deviceNum < 0) {
644  wxASSERT(false);
645  deviceNum = 0;
646  }
647 
648  return deviceNum;
649 }
650 
651 int AudioIOBase::getRecordDevIndex(const wxString &devNameArg)
652 {
653  wxString devName(devNameArg);
654  // if we don't get given a device, look up the preferences
655  if (devName.empty())
656  devName = AudioIORecordingDevice.Read();
657 
658  auto hostName = AudioIOHost.Read();
659  PaHostApiIndex hostCnt = Pa_GetHostApiCount();
660  PaHostApiIndex hostNum;
661  for (hostNum = 0; hostNum < hostCnt; hostNum++)
662  {
663  const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
664  if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
665  {
666  for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
667  {
668  PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
669 
670  const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
671  if (dinfo && DeviceName(dinfo) == devName && dinfo->maxInputChannels > 0 )
672  {
673  // this device name matches the stored one, and works.
674  // So we say this is the answer and return it
675  return deviceNum;
676  }
677  }
678 
679  // The device wasn't found so use the default for this host.
680  // LL: At this point, preferences and active no longer match.
681  return hinfo->defaultInputDevice;
682  }
683  }
684 
685  // The host wasn't found, so use the default input device.
686  // FIXME: TRAP_ERR PaErrorCode not handled well in getRecordDevIndex()
687  PaDeviceIndex deviceNum = Pa_GetDefaultInputDevice();
688 
689  // Sometimes PortAudio returns -1 if it cannot find a suitable default
690  // device, so we just use the first one available
691  // PortAudio has an error reporting function. We should log/report the error?
692  //
693  // LL: At this point, preferences and active no longer match
694  //
695  // And I can't imagine how far we'll get specifying an "invalid" index later
696  // on...are we certain "0" even exists?
697  if (deviceNum < 0) {
698  // JKC: This ASSERT will happen if you run with no config file
699  // This happens once. Config file will exist on the next run.
700  // TODO: Look into this a bit more. Could be relevant to blank Device Toolbar.
701  wxASSERT(false);
702  deviceNum = 0;
703  }
704 
705  return deviceNum;
706 }
707 
709 {
710  wxStringOutputStream o;
711  wxTextOutputStream s(o, wxEOL_UNIX);
712 
713  if (IsStreamActive()) {
714  return XO("Stream is active ... unable to gather information.\n")
715  .Translation();
716  }
717 
718 
719  // FIXME: TRAP_ERR PaErrorCode not handled. 3 instances in GetDeviceInfo().
720  int recDeviceNum = Pa_GetDefaultInputDevice();
721  int playDeviceNum = Pa_GetDefaultOutputDevice();
722  int cnt = Pa_GetDeviceCount();
723 
724  // PRL: why only into the log?
725  wxLogDebug(wxT("Portaudio reports %d audio devices"),cnt);
726 
727  s << wxT("==============================\n");
728  s << XO("Default recording device number: %d\n").Format( recDeviceNum );
729  s << XO("Default playback device number: %d\n").Format( playDeviceNum);
730 
731  auto recDevice = AudioIORecordingDevice.Read();
732  auto playDevice = AudioIOPlaybackDevice.Read();
733  int j;
734 
735  // This gets info on all available audio devices (input and output)
736  if (cnt <= 0) {
737  s << XO("No devices found\n");
738  return o.GetString();
739  }
740 
741  const PaDeviceInfo* info;
742 
743  for (j = 0; j < cnt; j++) {
744  s << wxT("==============================\n");
745 
746  info = Pa_GetDeviceInfo(j);
747  if (!info) {
748  s << XO("Device info unavailable for: %d\n").Format( j );
749  continue;
750  }
751 
752  wxString name = DeviceName(info);
753  s << XO("Device ID: %d\n").Format( j );
754  s << XO("Device name: %s\n").Format( name );
755  s << XO("Host name: %s\n").Format( HostName(info) );
756  s << XO("Recording channels: %d\n").Format( info->maxInputChannels );
757  s << XO("Playback channels: %d\n").Format( info->maxOutputChannels );
758  s << XO("Low Recording Latency: %g\n").Format( info->defaultLowInputLatency );
759  s << XO("Low Playback Latency: %g\n").Format( info->defaultLowOutputLatency );
760  s << XO("High Recording Latency: %g\n").Format( info->defaultHighInputLatency );
761  s << XO("High Playback Latency: %g\n").Format( info->defaultHighOutputLatency );
762 
763  auto rates = GetSupportedPlaybackRates(j, 0.0);
764 
765  /* i18n-hint: Supported, meaning made available by the system */
766  s << XO("Supported Rates:\n");
767  for (int k = 0; k < (int) rates.size(); k++) {
768  s << wxT(" ") << (int)rates[k] << wxT("\n");
769  }
770 
771  if (name == playDevice && info->maxOutputChannels > 0)
772  playDeviceNum = j;
773 
774  if (name == recDevice && info->maxInputChannels > 0)
775  recDeviceNum = j;
776 
777  // Sometimes PortAudio returns -1 if it cannot find a suitable default
778  // device, so we just use the first one available
779  if (recDeviceNum < 0 && info->maxInputChannels > 0){
780  recDeviceNum = j;
781  }
782  if (playDeviceNum < 0 && info->maxOutputChannels > 0){
783  playDeviceNum = j;
784  }
785  }
786 
787  bool haveRecDevice = (recDeviceNum >= 0);
788  bool havePlayDevice = (playDeviceNum >= 0);
789 
790  s << wxT("==============================\n");
791  if (haveRecDevice)
792  s << XO("Selected recording device: %d - %s\n").Format( recDeviceNum, recDevice );
793  else
794  s << XO("No recording device found for '%s'.\n").Format( recDevice );
795 
796  if (havePlayDevice)
797  s << XO("Selected playback device: %d - %s\n").Format( playDeviceNum, playDevice );
798  else
799  s << XO("No playback device found for '%s'.\n").Format( playDevice );
800 
801  std::vector<long> supportedSampleRates;
802 
803  if (havePlayDevice && haveRecDevice) {
804  supportedSampleRates = GetSupportedSampleRates(playDeviceNum, recDeviceNum);
805 
806  s << XO("Supported Rates:\n");
807  for (int k = 0; k < (int) supportedSampleRates.size(); k++) {
808  s << wxT(" ") << (int)supportedSampleRates[k] << wxT("\n");
809  }
810  }
811  else {
812  s << XO("Cannot check mutual sample rates without both devices.\n");
813  return o.GetString();
814  }
815 
816 #if defined(USE_PORTMIXER)
817  if (supportedSampleRates.size() > 0)
818  {
819  int highestSampleRate = supportedSampleRates.back();
820  bool EmulateMixerInputVol = true;
821  bool EmulateMixerOutputVol = true;
822  float MixerInputVol = 1.0;
823  float MixerOutputVol = 1.0;
824 
825  int error;
826 
827  PaStream *stream;
828 
829  PaStreamParameters playbackParameters;
830 
831  playbackParameters.device = playDeviceNum;
832  playbackParameters.sampleFormat = paFloat32;
833  playbackParameters.hostApiSpecificStreamInfo = NULL;
834  playbackParameters.channelCount = 1;
835  if (Pa_GetDeviceInfo(playDeviceNum)){
836  playbackParameters.suggestedLatency =
837  Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
838  }
839  else
840  playbackParameters.suggestedLatency =
842 
843  PaStreamParameters captureParameters;
844 
845  captureParameters.device = recDeviceNum;
846  captureParameters.sampleFormat = paFloat32;;
847  captureParameters.hostApiSpecificStreamInfo = NULL;
848  captureParameters.channelCount = 1;
849  if (Pa_GetDeviceInfo(recDeviceNum)){
850  captureParameters.suggestedLatency =
851  Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
852  }
853  else
854  captureParameters.suggestedLatency =
856 
857  // Not really doing I/O so pass nullptr for the callback function
858  error = Pa_OpenStream(&stream,
859  &captureParameters, &playbackParameters,
860  highestSampleRate, paFramesPerBufferUnspecified,
861  paClipOff | paDitherOff,
862  nullptr, NULL);
863 
864  if (error) {
865  error = Pa_OpenStream(&stream,
866  &captureParameters, NULL,
867  highestSampleRate, paFramesPerBufferUnspecified,
868  paClipOff | paDitherOff,
869  nullptr, NULL);
870  }
871 
872  if (error) {
873  s << XO("Received %d while opening devices\n").Format( error );
874  return o.GetString();
875  }
876 
877  PxMixer *PortMixer = Px_OpenMixer(stream, recDeviceNum, playDeviceNum, 0);
878 
879  if (!PortMixer) {
880  s << XO("Unable to open Portmixer\n");
881  Pa_CloseStream(stream);
882  return o.GetString();
883  }
884 
885  s << wxT("==============================\n");
886  s << XO("Available mixers:\n");
887 
888  // FIXME: ? PortMixer errors on query not reported in GetDeviceInfo
889  cnt = Px_GetNumMixers(stream);
890  for (int i = 0; i < cnt; i++) {
891  wxString name = wxSafeConvertMB2WX(Px_GetMixerName(stream, i));
892  s << XO("%d - %s\n").Format( i, name );
893  }
894 
895  s << wxT("==============================\n");
896  s << XO("Available recording sources:\n");
897  cnt = Px_GetNumInputSources(PortMixer);
898  for (int i = 0; i < cnt; i++) {
899  wxString name = wxSafeConvertMB2WX(Px_GetInputSourceName(PortMixer, i));
900  s << XO("%d - %s\n").Format( i, name );
901  }
902 
903  s << wxT("==============================\n");
904  s << XO("Available playback volumes:\n");
905  cnt = Px_GetNumOutputVolumes(PortMixer);
906  for (int i = 0; i < cnt; i++) {
907  wxString name = wxSafeConvertMB2WX(Px_GetOutputVolumeName(PortMixer, i));
908  s << XO("%d - %s\n").Format( i, name );
909  }
910 
911  // Determine mixer capabilities - if it doesn't support either
912  // input or output, we emulate them (by multiplying this value
913  // by all incoming/outgoing samples)
914 
915  MixerOutputVol = Px_GetPCMOutputVolume(PortMixer);
916  EmulateMixerOutputVol = false;
917  Px_SetPCMOutputVolume(PortMixer, 0.0);
918  if (Px_GetPCMOutputVolume(PortMixer) > 0.1)
919  EmulateMixerOutputVol = true;
920  Px_SetPCMOutputVolume(PortMixer, 0.2f);
921  if (Px_GetPCMOutputVolume(PortMixer) < 0.1 ||
922  Px_GetPCMOutputVolume(PortMixer) > 0.3)
923  EmulateMixerOutputVol = true;
924  Px_SetPCMOutputVolume(PortMixer, MixerOutputVol);
925 
926  MixerInputVol = Px_GetInputVolume(PortMixer);
927  EmulateMixerInputVol = false;
928  Px_SetInputVolume(PortMixer, 0.0);
929  if (Px_GetInputVolume(PortMixer) > 0.1)
930  EmulateMixerInputVol = true;
931  Px_SetInputVolume(PortMixer, 0.2f);
932  if (Px_GetInputVolume(PortMixer) < 0.1 ||
933  Px_GetInputVolume(PortMixer) > 0.3)
934  EmulateMixerInputVol = true;
935  Px_SetInputVolume(PortMixer, MixerInputVol);
936 
937  Pa_CloseStream(stream);
938 
939  s << wxT("==============================\n");
940  s << ( EmulateMixerInputVol
941  ? XO("Recording volume is emulated\n")
942  : XO("Recording volume is native\n") );
943  s << ( EmulateMixerOutputVol
944  ? XO("Playback volume is emulated\n")
945  : XO("Playback volume is native\n") );
946 
947  Px_CloseMixer(PortMixer);
948 
949  } //end of massive if statement if a valid sample rate has been found
950 #endif
951  return o.GetString();
952 }
953 
954 #ifdef EXPERIMENTAL_MIDI_OUT
955 // FIXME: When EXPERIMENTAL_MIDI_IN is added (eventually) this should also be enabled -- Poke
956 wxString AudioIOBase::GetMidiDeviceInfo()
957 {
958  wxStringOutputStream o;
959  wxTextOutputStream s(o, wxEOL_UNIX);
960 
961  if (IsStreamActive()) {
962  return XO("Stream is active ... unable to gather information.\n")
963  .Translation();
964  }
965 
966 
967  // XXX: May need to trap errors as with the normal device info
968  int recDeviceNum = Pm_GetDefaultInputDeviceID();
969  int playDeviceNum = Pm_GetDefaultOutputDeviceID();
970  int cnt = Pm_CountDevices();
971 
972  // PRL: why only into the log?
973  wxLogDebug(wxT("PortMidi reports %d MIDI devices"), cnt);
974 
975  s << wxT("==============================\n");
976  s << XO("Default recording device number: %d\n").Format( recDeviceNum );
977  s << XO("Default playback device number: %d\n").Format( playDeviceNum );
978 
979  wxString recDevice = gPrefs->Read(wxT("/MidiIO/RecordingDevice"), wxT(""));
980  wxString playDevice = gPrefs->Read(wxT("/MidiIO/PlaybackDevice"), wxT(""));
981 
982  // This gets info on all available audio devices (input and output)
983  if (cnt <= 0) {
984  s << XO("No devices found\n");
985  return o.GetString();
986  }
987 
988  for (int i = 0; i < cnt; i++) {
989  s << wxT("==============================\n");
990 
991  const PmDeviceInfo* info = Pm_GetDeviceInfo(i);
992  if (!info) {
993  s << XO("Device info unavailable for: %d\n").Format( i );
994  continue;
995  }
996 
997  wxString name = wxSafeConvertMB2WX(info->name);
998  wxString hostName = wxSafeConvertMB2WX(info->interf);
999 
1000  s << XO("Device ID: %d\n").Format( i );
1001  s << XO("Device name: %s\n").Format( name );
1002  s << XO("Host name: %s\n").Format( hostName );
1003  /* i18n-hint: Supported, meaning made available by the system */
1004  s << XO("Supports output: %d\n").Format( info->output );
1005  /* i18n-hint: Supported, meaning made available by the system */
1006  s << XO("Supports input: %d\n").Format( info->input );
1007  s << XO("Opened: %d\n").Format( info->opened );
1008 
1009  if (name == playDevice && info->output)
1010  playDeviceNum = i;
1011 
1012  if (name == recDevice && info->input)
1013  recDeviceNum = i;
1014 
1015  // XXX: This is only done because the same was applied with PortAudio
1016  // If PortMidi returns -1 for the default device, use the first one
1017  if (recDeviceNum < 0 && info->input){
1018  recDeviceNum = i;
1019  }
1020  if (playDeviceNum < 0 && info->output){
1021  playDeviceNum = i;
1022  }
1023  }
1024 
1025  bool haveRecDevice = (recDeviceNum >= 0);
1026  bool havePlayDevice = (playDeviceNum >= 0);
1027 
1028  s << wxT("==============================\n");
1029  if (haveRecDevice)
1030  s << XO("Selected MIDI recording device: %d - %s\n").Format( recDeviceNum, recDevice );
1031  else
1032  s << XO("No MIDI recording device found for '%s'.\n").Format( recDevice );
1033 
1034  if (havePlayDevice)
1035  s << XO("Selected MIDI playback device: %d - %s\n").Format( playDeviceNum, playDevice );
1036  else
1037  s << XO("No MIDI playback device found for '%s'.\n").Format( playDevice );
1038 
1039  // Mention our conditional compilation flags for Alpha only
1040 #ifdef IS_ALPHA
1041 
1042  // Not internationalizing these alpha-only messages
1043  s << wxT("==============================\n");
1044 #ifdef EXPERIMENTAL_MIDI_OUT
1045  s << wxT("EXPERIMENTAL_MIDI_OUT is enabled\n");
1046 #else
1047  s << wxT("EXPERIMENTAL_MIDI_OUT is NOT enabled\n");
1048 #endif
1049 #ifdef EXPERIMENTAL_MIDI_IN
1050  s << wxT("EXPERIMENTAL_MIDI_IN is enabled\n");
1051 #else
1052  s << wxT("EXPERIMENTAL_MIDI_IN is NOT enabled\n");
1053 #endif
1054 
1055 #endif
1056 
1057  return o.GetString();
1058 }
1059 #endif
1060 
1062  L"/AudioIO/Host", L"" };
1064  L"/AudioIO/LatencyCorrection", -130.0 };
1066  L"/AudioIO/LatencyDuration", 100.0 };
1068  L"/AudioIO/PlaybackDevice", L"" };
1070  L"/AudioIO/RecordChannels", 2 };
1072  L"/AudioIO/RecordingDevice", L"" };
1074  L"/AudioIO/RecordingSource", L"" };
1076  L"/AudioIO/RecordingSourceIndex", -1 };
AudioIORecordingDevice
StringSetting AudioIORecordingDevice
Definition: AudioIOBase.cpp:1071
AudioIOLatencyCorrection
DoubleSetting AudioIOLatencyCorrection
Definition: AudioIOBase.cpp:1063
AudioIOPlaybackDevice
StringSetting AudioIOPlaybackDevice
Definition: AudioIOBase.cpp:1067
AudioIOBase.h
AudioIOBase::GetDeviceInfo
wxString GetDeviceInfo()
Get diagnostic information on all the available audio I/O devices.
Definition: AudioIOBase.cpp:708
AudioIOBase::DeviceName
static wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:75
AudioIOBase::StandardRates
static const int StandardRates[]
Array of common audio sample rates.
Definition: AudioIOBase.h:201
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:549
IntSetting
Specialization of Setting for int.
Definition: Prefs.h:214
AudioIOBase::mOwningProject
AudacityProject * mOwningProject
Definition: AudioIOBase.h:259
AudioIOBase::mMidiOutputComplete
bool mMidiOutputComplete
True when output reaches mT1.
Definition: AudioIOBase.h:265
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
AudioIOBase::mPortStreamV19
PaStream * mPortStreamV19
Definition: AudioIOBase.h:275
PaStream
void PaStream
Definition: AudioIOBase.h:23
AudioIOBase::mInputMixerWorks
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIOBase.h:293
AudioIOBase::getPlayDevIndex
static int getPlayDevIndex(const wxString &devName={})
get the index of the device selected in the preferences.
Definition: AudioIOBase.cpp:596
AudioIOBase::getRecordDevIndex
static int getRecordDevIndex(const wxString &devName={})
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIOBase.cpp:651
XO
#define XO(s)
Definition: Internat.h:31
AudioIOBase::IsStreamActive
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIOBase.cpp:354
AudioIOBase::NumStandardRates
static const int NumStandardRates
How many standard sample rates there are.
Definition: AudioIOBase.h:203
Meter.h
AudioIOBase::GetSupportedPlaybackRates
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
Definition: AudioIOBase.cpp:383
AudioIOBase::IsPaused
bool IsPaused() const
Find out if playback / recording is currently paused.
Definition: AudioIOBase.cpp:341
AudioIOBase::ugAudioIO
static std::unique_ptr< AudioIOBase > ugAudioIO
Definition: AudioIOBase.h:255
AudioIOBase::mCachedSampleRates
static std::vector< long > mCachedSampleRates
Definition: AudioIOBase.h:301
AudioIOBase::IsBusy
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIOBase.cpp:346
AudioIORecordingSourceIndex
IntSetting AudioIORecordingSourceIndex
Definition: AudioIOBase.cpp:1075
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
StringSetting
Specialization of Setting for strings.
Definition: Prefs.h:228
AudioIOLatencyDuration
DoubleSetting AudioIOLatencyDuration
Definition: AudioIOBase.cpp:1065
AudioIOBase::NumRatesToTry
static const int NumRatesToTry
How many sample rates to try.
Definition: AudioIOBase.h:337
AudioIOBase::RatesToTry
static const int RatesToTry[]
Array of audio sample rates to try to use.
Definition: AudioIOBase.h:335
AudioIOBase::mPaused
bool mPaused
True if audio playback is paused.
Definition: AudioIOBase.h:262
AudioIOBase::SetCaptureMeter
void SetCaptureMeter(AudacityProject *project, const std::weak_ptr< Meter > &meter)
Definition: AudioIOBase.cpp:309
AudioIOBase::mCachedPlaybackRates
static std::vector< long > mCachedPlaybackRates
Definition: AudioIOBase.h:298
AudioIOBase::mMixerOutputVol
float mMixerOutputVol
Definition: AudioIOBase.h:294
AudioIOBase::mInputMeter
std::weak_ptr< Meter > mInputMeter
Definition: AudioIOBase.h:277
AudioIOBase::mCachedPlaybackIndex
static int mCachedPlaybackIndex
Definition: AudioIOBase.h:297
AudioIOBase::GetOptimalSupportedSampleRate
static int GetOptimalSupportedSampleRate()
Get a supported sample rate which can be used a an optimal default.
Definition: AudioIOBase.cpp:562
AudioIORecordingSource
StringSetting AudioIORecordingSource
Definition: AudioIOBase.cpp:1073
AudioIOBase::IsMonitoring
bool IsMonitoring() const
Returns true if we're monitoring input (but not recording or playing actual audio)
Definition: AudioIOBase.cpp:378
name
const TranslatableString name
Definition: Distortion.cpp:98
Setting::GetDefault
const T & GetDefault() const
Definition: Prefs.h:120
AudioIOBase::Get
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:91
AudioIOBase::mRate
double mRate
Audio playback rate in samples per second.
Definition: AudioIOBase.h:273
AudioIOBase::mMidiStreamActive
bool mMidiStreamActive
mMidiStreamActive tells when mMidiStream is open for output
Definition: AudioIOBase.h:268
AudioIOBase::GetSupportedSampleRates
static std::vector< long > GetSupportedSampleRates(int playDevice=-1, int recDevice=-1, double rate=0.0)
Get a list of sample rates the current input/output device combination supports.
Definition: AudioIOBase.cpp:517
AudioIOBase::SetMixer
void SetMixer(int inputSource)
Definition: AudioIOBase.cpp:98
AudioIOBase::HostName
static wxString HostName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:82
AudioIOBase::mCachedCaptureIndex
static int mCachedCaptureIndex
Definition: AudioIOBase.h:299
Setting::ReadWithDefault
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:134
AudioIOBase::IsAudioTokenActive
bool IsAudioTokenActive(int token) const
Returns true if the stream is active, or even if audio I/O is busy cleaning up its data or writing to...
Definition: AudioIOBase.cpp:373
AudioIOBase::GetSupportedCaptureRates
static std::vector< long > GetSupportedCaptureRates(int devIndex=-1, double rate=0.0)
Get a list of sample rates the input (recording) device supports.
Definition: AudioIOBase.cpp:448
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:1061
AudioIOBase::mOutputMeter
std::weak_ptr< Meter > mOutputMeter
Definition: AudioIOBase.h:278
AudioIOBase::mCachedBestRateIn
static double mCachedBestRateIn
Definition: AudioIOBase.h:302
AudioIOBase::mStreamToken
volatile int mStreamToken
Definition: AudioIOBase.h:270
Prefs.h
AudioIOBase
A singleton object supporting queries of the state of any active audio streams, and audio device capa...
Definition: AudioIOBase.h:118
AudioIOBase::HandleDeviceChange
void HandleDeviceChange()
update state after changing what audio devices are selected
Definition: AudioIOBase.cpp:107
AudioIOBase::mCachedCaptureRates
static std::vector< long > mCachedCaptureRates
Definition: AudioIOBase.h:300
DoubleSetting
Specialization of Setting for double.
Definition: Prefs.h:221
AudioIORecordChannels
IntSetting AudioIORecordChannels
Definition: AudioIOBase.cpp:1069
AudioIOBase::~AudioIOBase
virtual ~AudioIOBase()
AudioIOBase::SetPlaybackMeter
void SetPlaybackMeter(AudacityProject *project, const std::weak_ptr< Meter > &meter)
Definition: AudioIOBase.cpp:325
AudioIOBase::mEmulateMixerOutputVol
bool mEmulateMixerOutputVol
Definition: AudioIOBase.h:285