Audacity  3.0.3
Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | Friends | List of all members
AudioIO Class Referencefinal

AudioIO uses the PortAudio library to play and record sound. More...

#include <AudioIO.h>

Inheritance diagram for AudioIO:
[legend]
Collaboration diagram for AudioIO:
[legend]

Public Types

using PostRecordingAction = std::function< void()>
 

Public Member Functions

void StartMonitoring (const AudioIOStartStreamOptions &options)
 Start up Portaudio for capture and recording as needed for input monitoring and software playthrough only. More...
 
int StartStream (const TransportTracks &tracks, double t0, double t1, const AudioIOStartStreamOptions &options)
 Start recording or playing back audio. More...
 
void StopStream () override
 Stop recording, playback or input monitoring. More...
 
void SeekStream (double seconds)
 Move the playback / recording position of the current stream by the specified amount from where it is now. More...
 
void CallAfterRecording (PostRecordingAction action)
 Enqueue action for main thread idle time, not before the end of any recording in progress. More...
 
wxString LastPaErrorString ()
 
wxLongLong GetLastPlaybackTime () const
 
AudacityProjectGetOwningProject () const
 
void SetPaused (bool state)
 Pause and un-pause playback and recording. More...
 
void SetMixer (int inputSource, float inputVolume, float playbackVolume)
 
void GetMixer (int *inputSource, float *inputVolume, float *playbackVolume)
 
bool InputMixerWorks ()
 Find out if the input hardware level control is available. More...
 
bool OutputMixerEmulated ()
 Find out if the output level control is being emulated via software attenuation. More...
 
wxArrayString GetInputSourceNames ()
 Get the list of inputs to the current mixer device. More...
 
sampleFormat GetCaptureFormat ()
 
unsigned GetNumPlaybackChannels () const
 
unsigned GetNumCaptureChannels () const
 
bool IsCapturing () const
 
bool IsAvailable (AudacityProject *projecT) const
 Function to automatically set an acceptable volume. More...
 
double GetBestRate (bool capturing, bool playing, double sampleRate)
 Return a valid sample rate that is supported by the current I/O device(s). More...
 
double GetStreamTime ()
 During playback, the track time most recently played. More...
 
void DelayActions (bool recording)
 
- Public Member Functions inherited from AudioIoCallback
 AudioIoCallback ()
 
 ~AudioIoCallback ()
 
int AudioCallback (constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
 
std::shared_ptr< AudioIOListenerGetListener () const
 
void SetListener (const std::shared_ptr< AudioIOListener > &listener)
 
int CallbackDoSeek ()
 
void CallbackCheckCompletion (int &callbackReturn, unsigned long len)
 
unsigned CountSoloingTracks ()
 
bool TrackShouldBeSilent (const WaveTrack &wt)
 
bool TrackHasBeenFadedOut (const WaveTrack &wt)
 
bool AllTracksAlreadySilent ()
 
void CheckSoundActivatedRecordingLevel (float *inputSamples, unsigned long framesPerBuffer)
 
void AddToOutputChannel (unsigned int chan, float *outputMeterFloats, float *outputFloats, const float *tempBuf, bool drop, unsigned long len, WaveTrack *vt)
 
bool FillOutputBuffers (float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
 
void DrainInputBuffers (constSamplePtr inputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackFlags statusFlags, float *tempFloats)
 
void UpdateTimePosition (unsigned long framesPerBuffer)
 
void DoPlaythrough (constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
 
void SendVuInputMeterData (const float *inputSamples, unsigned long framesPerBuffer)
 
void SendVuOutputMeterData (const float *outputMeterFloats, unsigned long framesPerBuffer)
 
size_t GetCommonlyReadyPlayback ()
 Get the number of audio samples ready in all of the playback buffers. More...
 
const std::vector< std::pair< double, double > > & LostCaptureIntervals ()
 
AudioIOExtRange Extensions ()
 
- Public Member Functions inherited from AudioIOBase
 AudioIOBase ()
 
virtual ~AudioIOBase ()
 
 AudioIOBase (const AudioIOBase &)=delete
 
AudioIOBaseoperator= (const AudioIOBase &)=delete
 
void SetCaptureMeter (AudacityProject *project, const std::weak_ptr< Meter > &meter)
 
void SetPlaybackMeter (AudacityProject *project, const std::weak_ptr< Meter > &meter)
 
void HandleDeviceChange ()
 update state after changing what audio devices are selected More...
 
wxString GetDeviceInfo () const
 Get diagnostic information on all the available audio I/O devices. More...
 
std::vector< AudioIODiagnosticsGetAllDeviceInfo ()
 Get diagnostic information for audio devices and also for extensions. More...
 
bool IsPaused () const
 Find out if playback / recording is currently paused. More...
 
bool IsBusy () const
 Returns true if audio i/o is busy starting, stopping, playing, or recording. More...
 
bool IsStreamActive () const
 Returns true if the audio i/o is running at all, but not during cleanup. More...
 
bool IsStreamActive (int token) const
 
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 disk. More...
 
bool IsMonitoring () const
 Returns true if we're monitoring input (but not recording or playing actual audio) More...
 
void SetMixer (int inputSource)
 

Static Public Member Functions

static AudioIOGet ()
 
static bool ValidateDeviceNames (const wxString &play, const wxString &rec)
 Ensure selected device names are valid. More...
 
static void Init ()
 
static void Deinit ()
 
- Static Public Member Functions inherited from AudioIOBase
static AudioIOBaseGet ()
 
static std::vector< long > GetSupportedPlaybackRates (int DevIndex=-1, double rate=0.0)
 Get a list of sample rates the output (playback) device supports. More...
 
static std::vector< long > GetSupportedCaptureRates (int devIndex=-1, double rate=0.0)
 Get a list of sample rates the input (recording) device supports. More...
 
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. More...
 
static int GetOptimalSupportedSampleRate ()
 Get a supported sample rate which can be used a an optimal default. More...
 

Private Member Functions

 AudioIO ()
 
 ~AudioIO ()
 
bool DelayingActions () const
 
void SetMeters ()
 Set the current VU meters - this should be done once after each call to StartStream currently. More...
 
bool StartPortAudioStream (const AudioIOStartStreamOptions &options, unsigned int numPlaybackChannels, unsigned int numCaptureChannels, sampleFormat captureFormat)
 Opens the portaudio stream(s) used to do playback or recording (or both) through. More...
 
void TrackBufferExchange ()
 
void FillPlayBuffers ()
 First part of TrackBufferExchange. More...
 
PlaybackSlice GetPlaybackSlice (size_t available)
 Called one or more times by FillPlayBuffers. More...
 
bool RepositionPlayback (size_t frames, size_t available, bool progress)
 FillPlayBuffers calls this to update its cursors into tracks for changes of position or speed. More...
 
void DrainRecordBuffers ()
 Second part of TrackBufferExchange. More...
 
size_t GetCommonlyFreePlayback ()
 Get the number of audio samples free in all of the playback buffers. More...
 
size_t GetCommonlyAvailCapture ()
 Get the number of audio samples ready in all of the recording buffers. More...
 
bool AllocateBuffers (const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate, bool scrubbing)
 Allocate RingBuffer structures, and others, needed for playback and recording. More...
 
void StartStreamCleanup (bool bOnlyBuffers=false)
 Clean up after StartStream if it fails. More...
 

Private Attributes

std::mutex mPostRecordingActionMutex
 
PostRecordingAction mPostRecordingAction
 
bool mDelayingActions { false }
 

Friends

class AudioThread
 

Additional Inherited Members

- Public Attributes inherited from AudioIoCallback
int mbHasSoloTracks
 
int mCallbackReturn
 
long mNumPauseFrames
 How many frames of zeros were output due to pauses? More...
 
std::unique_ptr< AudioThreadmThread
 
ArrayOf< std::unique_ptr< Resample > > mResample
 
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
 
WaveTrackArray mCaptureTracks
 
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
 
WaveTrackArray mPlaybackTracks
 
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
 
double mFactor
 
unsigned long mMaxFramesOutput
 
bool mbMicroFades
 
double mSeek
 
double mPlaybackRingBufferSecs
 
double mCaptureRingBufferSecs
 
size_t mPlaybackSamplesToCopy
 Preferred batch size for replenishing the playback RingBuffer. More...
 
size_t mPlaybackQueueMinimum
 Occupancy of the queue we try to maintain, with bigger batches if needed. More...
 
double mMinCaptureSecsToCopy
 
bool mSoftwarePlaythrough
 
bool mPauseRec
 True if Sound Activated Recording is enabled. More...
 
float mSilenceLevel
 
unsigned int mNumCaptureChannels
 
unsigned int mNumPlaybackChannels
 
sampleFormat mCaptureFormat
 
unsigned long long mLostSamples { 0 }
 
volatile bool mAudioThreadShouldCallTrackBufferExchangeOnce
 
volatile bool mAudioThreadTrackBufferExchangeLoopRunning
 
volatile bool mAudioThreadTrackBufferExchangeLoopActive
 
std::atomic< bool > mForceFadeOut { false }
 
wxLongLong mLastPlaybackTimeMillis
 
volatile double mLastRecordingOffset
 
PaError mLastPaError
 
bool mSimulateRecordingErrors { false }
 
bool mDetectUpstreamDropouts { true }
 
- Static Public Attributes inherited from AudioIoCallback
static int mNextStreamToken = 0
 
- Static Public Attributes inherited from AudioIOBase
static const int StandardRates []
 Array of common audio sample rates. More...
 
static const int NumStandardRates = WXSIZEOF(AudioIOBase::StandardRates)
 How many standard sample rates there are. More...
 
- Protected Member Functions inherited from AudioIoCallback
void SetRecordingException ()
 
void ClearRecordingException ()
 
- Static Protected Member Functions inherited from AudioIOBase
static wxString DeviceName (const PaDeviceInfo *info)
 
static wxString HostName (const PaDeviceInfo *info)
 
static int getRecordDevIndex (const wxString &devName={})
 get the index of the supplied (named) recording device, or the device selected in the preferences if none given. More...
 
static int getPlayDevIndex (const wxString &devName={})
 get the index of the device selected in the preferences. More...
 
- Protected Attributes inherited from AudioIoCallback
bool mUpdateMeters
 
volatile bool mUpdatingMeters
 
std::weak_ptr< AudioIOListenermListener
 
bool mUsingAlsa { false }
 
wxMutex mSuspendAudioThread
 
wxAtomicInt mRecordingException {}
 
std::vector< std::pair< double, double > > mLostCaptureIntervals
 
bool mDetectDropouts { true }
 
RecordingSchedule mRecordingSchedule {}
 
PlaybackSchedule mPlaybackSchedule
 
- Protected Attributes inherited from AudioIOBase
AudacityProjectmOwningProject
 
bool mPaused
 True if audio playback is paused. More...
 
volatile int mStreamToken
 
double mRate
 Audio playback rate in samples per second. More...
 
PaStreammPortStreamV19
 
std::weak_ptr< MetermInputMeter {}
 
std::weak_ptr< MetermOutputMeter {}
 
bool mEmulateMixerOutputVol
 
bool mInputMixerWorks
 Can we control the hardware input level? More...
 
float mMixerOutputVol
 
std::vector< std::unique_ptr< AudioIOExtBase > > mAudioIOExt
 
- Static Protected Attributes inherited from AudioIoCallback
static double mCachedBestRateOut
 
static bool mCachedBestRatePlaying
 
static bool mCachedBestRateCapturing
 
- Static Protected Attributes inherited from AudioIOBase
static std::unique_ptr< AudioIOBaseugAudioIO
 
static int mCachedPlaybackIndex = -1
 
static std::vector< long > mCachedPlaybackRates
 
static int mCachedCaptureIndex = -1
 
static std::vector< long > mCachedCaptureRates
 
static std::vector< long > mCachedSampleRates
 
static double mCachedBestRateIn = 0.0
 
static const int RatesToTry []
 Array of audio sample rates to try to use. More...
 
static const int NumRatesToTry = WXSIZEOF(AudioIOBase::RatesToTry)
 How many sample rates to try. More...
 

Detailed Description

AudioIO uses the PortAudio library to play and record sound.

Great care and attention to detail are necessary for understanding and modifying this system. The code in this file is run from three different thread contexts: the UI thread, the disk thread (which this file creates and maintains; in the code, this is called the Audio Thread), and the PortAudio callback thread. To highlight this deliniation, the file is divided into three parts based on what thread context each function is intended to run in.

Todo:
run through all functions called from audio and portaudio threads to verify they are thread-safe. Note that synchronization of the style: "A sets flag to signal B, B clears flag to acknowledge completion" is not thread safe in a general multiple-CPU context. For example, B can write to a buffer and set a completion flag. The flag write can occur before the buffer write due to out-of-order execution. Then A can see the flag and read the buffer before buffer writes complete.

Definition at line 379 of file AudioIO.h.

Member Typedef Documentation

◆ PostRecordingAction

using AudioIO::PostRecordingAction = std::function<void()>

Definition at line 420 of file AudioIO.h.

Constructor & Destructor Documentation

◆ AudioIO()

AudioIO::AudioIO ( )
private

Definition at line 548 of file AudioIO.cpp.

549 {
550  if (!std::atomic<double>{}.is_lock_free()) {
551  // If this check fails, then the atomic<double> members in AudioIO.h
552  // might be changed to atomic<float> to be more efficient with some
553  // loss of precision. That could be conditionally compiled depending
554  // on the platform.
555  wxASSERT(false);
556  }
557 
558  // This ASSERT because of casting in the callback
559  // functions where we cast a tempFloats buffer to a (short*) buffer.
560  // We have to ASSERT in the GUI thread, if we are to see it properly.
561  wxASSERT( sizeof( short ) <= sizeof( float ));
562 
566  mPortStreamV19 = NULL;
567 
568  mNumPauseFrames = 0;
569 
570 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
571  mAILAActive = false;
572 #endif
573  mStreamToken = 0;
574 
575  mLastPaError = paNoError;
576 
577  mLastRecordingOffset = 0.0;
579  mPaused = false;
580  mSilenceLevel = 0.0;
581 
582  mUpdateMeters = false;
583  mUpdatingMeters = false;
584 
585  mOwningProject = NULL;
586  mOutputMeter.reset();
587 
588  PaError err = Pa_Initialize();
589 
590  if (err != paNoError) {
591  auto errStr = XO("Could not find any audio devices.\n");
592  errStr += XO("You will not be able to play or record audio.\n\n");
593  wxString paErrStr = LAT1CTOWX(Pa_GetErrorText(err));
594  if (!paErrStr.empty())
595  errStr += XO("Error: %s").Format( paErrStr );
596  // XXX: we are in libaudacity, popping up dialogs not allowed! A
597  // long-term solution will probably involve exceptions
599  errStr,
600  XO("Error Initializing Audio"),
601  wxICON_ERROR|wxOK);
602 
603  // Since PortAudio is not initialized, all calls to PortAudio
604  // functions will fail. This will give reasonable behavior, since
605  // the user will be able to do things not relating to audio i/o,
606  // but any attempt to play or record will simply fail.
607  }
608 
609  // Start thread
610  mThread = std::make_unique<AudioThread>();
611  mThread->Create();
612 
613 #if defined(USE_PORTMIXER)
614  mPortMixer = NULL;
615  mPreviousHWPlaythrough = -1.0;
617 #else
618  mEmulateMixerOutputVol = true;
619  mMixerOutputVol = 1.0;
620  mInputMixerWorks = false;
621 #endif
622 
624 
625 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
626  mScrubState = NULL;
627  mScrubDuration = 0;
628  mSilentScrub = false;
629 #endif
630 }

References AudacityMessageBox(), AudioIOBase::HandleDeviceChange(), LAT1CTOWX, AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopActive, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning, AudioIOBase::mEmulateMixerOutputVol, AudioIOBase::mInputMixerWorks, AudioIoCallback::mLastPaError, AudioIoCallback::mLastPlaybackTimeMillis, AudioIoCallback::mLastRecordingOffset, AudioIOBase::mMixerOutputVol, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPauseFrames, AudioIOBase::mOutputMeter, AudioIOBase::mOwningProject, AudioIOBase::mPaused, AudioIOBase::mPortStreamV19, AudioIoCallback::mSilenceLevel, AudioIOBase::mStreamToken, AudioIoCallback::mThread, AudioIoCallback::mUpdateMeters, AudioIoCallback::mUpdatingMeters, and XO.

Referenced by Init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ~AudioIO()

AudioIO::~AudioIO ( )
private

Definition at line 632 of file AudioIO.cpp.

633 {
634 #if defined(USE_PORTMIXER)
635  if (mPortMixer) {
636  #if __WXMAC__
637  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
638  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
639  mPreviousHWPlaythrough = -1.0;
640  #endif
641  Px_CloseMixer(mPortMixer);
642  mPortMixer = NULL;
643  }
644 #endif
645 
646  // FIXME: ? TRAP_ERR. Pa_Terminate probably OK if err without reporting.
647  Pa_Terminate();
648 
649  /* Delete is a "graceful" way to stop the thread.
650  (Kill is the not-graceful way.) */
651 
652  // This causes reentrancy issues during application shutdown
653  // wxTheApp->Yield();
654 
655  mThread->Delete();
656  mThread.reset();
657 }

References AudioIoCallback::mThread.

Member Function Documentation

◆ AllocateBuffers()

bool AudioIO::AllocateBuffers ( const AudioIOStartStreamOptions options,
const TransportTracks tracks,
double  t0,
double  t1,
double  sampleRate,
bool  scrubbing 
)
private

Allocate RingBuffer structures, and others, needed for playback and recording.

Returns true iff successful.

Definition at line 1364 of file AudioIO.cpp.

1368 {
1369  bool success = false;
1370  auto cleanup = finally([&]{
1371  if (!success) StartStreamCleanup( false );
1372  });
1373 
1374  //
1375  // The (audio) stream has been opened successfully (assuming we tried
1376  // to open it). We now proceed to
1377  // allocate the memory structures the stream will need.
1378  //
1379 
1380  //
1381  // The RingBuffer sizes, and the max amount of the buffer to
1382  // fill at a time, both grow linearly with the number of
1383  // tracks. This allows us to scale up to many tracks without
1384  // killing performance.
1385  //
1386 
1387  // real playback time to produce with each filling of the buffers
1388  // by the Audio thread (except at the end of playback):
1389  // usually, make fillings fewer and longer for less CPU usage.
1390  // But for useful scrubbing, we can't run too far ahead without checking
1391  // mouse input, so make fillings more and shorter.
1392  // What Audio thread produces for playback is then consumed by the PortAudio
1393  // thread, in many smaller pieces.
1394  double playbackTime = 4.0;
1395  if (scrubbing)
1396  // Specify a very short minimum batch for non-seek scrubbing, to allow
1397  // more frequent polling of the mouse
1398  playbackTime =
1399  lrint(options.pScrubbingOptions->delay * mRate) / mRate;
1400 
1401  wxASSERT( playbackTime >= 0 );
1402  mPlaybackSamplesToCopy = playbackTime * mRate;
1403 
1404  // Capacity of the playback buffer.
1405  mPlaybackRingBufferSecs = 10.0;
1406 
1408  4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.size());
1410  0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.size());
1411 
1414  bool bDone;
1415  do
1416  {
1417  bDone = true; // assume success
1418  try
1419  {
1420  if( mNumPlaybackChannels > 0 ) {
1421  // Allocate output buffers. For every output track we allocate
1422  // a ring buffer of ten seconds
1423  auto playbackBufferSize =
1424  (size_t)lrint(mRate * mPlaybackRingBufferSecs);
1425 
1426  // Always make at least one playback buffer
1428  std::max<size_t>(1, mPlaybackTracks.size()));
1430 
1431  const Mixer::WarpOptions &warpOptions =
1432 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1433  scrubbing
1437  :
1438 #endif
1439  Mixer::WarpOptions(mPlaybackSchedule.mEnvelope);
1440 
1442  if (scrubbing)
1443  // Specify enough playback RingBuffer latency so we can refill
1444  // once every seek stutter without falling behind the demand.
1445  // (Scrub might switch in and out of seeking with left mouse
1446  // presses in the ruler)
1448  2 * options.pScrubbingOptions->minStutterTime * mRate );
1450  std::min( mPlaybackQueueMinimum, playbackBufferSize );
1451 
1452  if (mPlaybackTracks.empty())
1453  // Make at least one playback buffer
1454  mPlaybackBuffers[0] =
1455  std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
1456 
1457  for (unsigned int i = 0; i < mPlaybackTracks.size(); i++)
1458  {
1459  // Bug 1763 - We must fade in from zero to avoid a click on starting.
1460  mPlaybackTracks[i]->SetOldChannelGain(0, 0.0);
1461  mPlaybackTracks[i]->SetOldChannelGain(1, 0.0);
1462 
1463  mPlaybackBuffers[i] =
1464  std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
1465 
1466  // use track time for the end time, not real time!
1467  WaveTrackConstArray mixTracks;
1468  mixTracks.push_back(mPlaybackTracks[i]);
1469 
1470  double endTime;
1472  .contains(mPlaybackTracks[i]))
1473  // Stop playing this track after pre-roll
1474  endTime = t0;
1475  else
1476  // Pass t1 -- not mT1 as may have been adjusted for latency
1477  // -- so that overdub recording stops playing back samples
1478  // at the right time, though transport may continue to record
1479  endTime = t1;
1480 
1481  mPlaybackMixers[i] = std::make_unique<Mixer>
1482  (mixTracks,
1483  // Don't throw for read errors, just play silence:
1484  false,
1485  warpOptions,
1487  endTime,
1488  1,
1490  false,
1491  mRate, floatSample,
1492  false, // low quality dithering and resampling
1493  nullptr,
1494  false // don't apply track gains
1495  );
1496  }
1497 
1498  const auto timeQueueSize = 1 +
1499  (playbackBufferSize + TimeQueueGrainSize - 1)
1501  mPlaybackSchedule.mTimeQueue.mData.reinit( timeQueueSize );
1502  mPlaybackSchedule.mTimeQueue.mSize = timeQueueSize;
1503  }
1504 
1505  if( mNumCaptureChannels > 0 )
1506  {
1507  // Allocate input buffers. For every input track we allocate
1508  // a ring buffer of five seconds
1509  auto captureBufferSize =
1510  (size_t)(mRate * mCaptureRingBufferSecs + 0.5);
1511 
1512  // In the extraordinarily rare case that we can't even afford
1513  // 100 samples, just give up.
1514  if(captureBufferSize < 100)
1515  {
1516  AudacityMessageBox( XO("Out of memory!") );
1517  return false;
1518  }
1519 
1522  mFactor = sampleRate / mRate;
1523 
1524  for( unsigned int i = 0; i < mCaptureTracks.size(); i++ )
1525  {
1526  mCaptureBuffers[i] = std::make_unique<RingBuffer>(
1527  mCaptureTracks[i]->GetSampleFormat(), captureBufferSize );
1528  mResample[i] =
1529  std::make_unique<Resample>(true, mFactor, mFactor);
1530  // constant rate resampling
1531  }
1532  }
1533  }
1534  catch(std::bad_alloc&)
1535  {
1536  // Oops! Ran out of memory. This is pretty rare, so we'll just
1537  // try deleting everything, halving our buffer size, and try again.
1538  StartStreamCleanup(true);
1539  mPlaybackRingBufferSecs *= 0.5;
1541  mCaptureRingBufferSecs *= 0.5;
1542  mMinCaptureSecsToCopy *= 0.5;
1543  bDone = false;
1544 
1545  // In the extraordinarily rare case that we can't even afford 100
1546  // samples, just give up.
1547  auto playbackBufferSize =
1548  (size_t)lrint(mRate * mPlaybackRingBufferSecs);
1549  if(playbackBufferSize < 100 || mPlaybackSamplesToCopy < 100)
1550  {
1551  AudacityMessageBox( XO("Out of memory!") );
1552  return false;
1553  }
1554  }
1555  } while(!bDone);
1556 
1557  success = true;
1558  return true;
1559 }

References AudacityMessageBox(), floatSample, lrint, make_iterator_range(), ScrubbingOptions::MaxAllowedScrubSpeed(), AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureRingBufferSecs, AudioIoCallback::mCaptureTracks, PlaybackSchedule::TimeQueue::mData, PlaybackSchedule::mEnvelope, AudioIoCallback::mFactor, PlaybackSchedule::TimeQueue::mHead, min(), ScrubbingOptions::MinAllowedScrubSpeed(), AudioIoCallback::mMinCaptureSecsToCopy, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPlaybackChannels, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackQueueMinimum, AudioIoCallback::mPlaybackRingBufferSecs, AudioIoCallback::mPlaybackSamplesToCopy, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIOBase::mRate, AudioIoCallback::mResample, PlaybackSchedule::TimeQueue::mSize, PlaybackSchedule::mT0, PlaybackSchedule::TimeQueue::mTail, PlaybackSchedule::mTimeQueue, TransportTracks::prerollTracks, ArrayOf< X >::reinit(), StartStreamCleanup(), TimeQueueGrainSize, and XO.

Referenced by StartStream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CallAfterRecording()

void AudioIO::CallAfterRecording ( PostRecordingAction  action)

Enqueue action for main thread idle time, not before the end of any recording in progress.

This may be called from non-main threads

Definition at line 1336 of file AudioIO.cpp.

1337 {
1338  if (!action)
1339  return;
1340 
1341  {
1342  std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
1343  if (mPostRecordingAction) {
1344  // Enqueue it, even if perhaps not still recording,
1345  // but it wasn't cleared yet
1347  prevAction = std::move(mPostRecordingAction),
1348  nextAction = std::move(action)
1349  ]{ prevAction(); nextAction(); };
1350  return;
1351  }
1352  else if (DelayingActions()) {
1353  mPostRecordingAction = std::move(action);
1354  return;
1355  }
1356  }
1357 
1358  // Don't delay it except until idle time.
1359  // (Recording might start between now and then, but won't go far before
1360  // the action is done. So the system isn't bulletproof yet.)
1361  wxTheApp->CallAfter(std::move(action));
1362 }

References DelayingActions(), mPostRecordingAction, and mPostRecordingActionMutex.

Here is the call graph for this function:

◆ Deinit()

void AudioIO::Deinit ( )
static

Definition at line 534 of file AudioIO.cpp.

535 {
536  ugAudioIO.reset();
537 }

References AudioIOBase::ugAudioIO.

Referenced by AudacityApp::OnExit().

Here is the caller graph for this function:

◆ DelayActions()

void AudioIO::DelayActions ( bool  recording)

For purposes of CallAfterRecording, treat time from now as if recording (when argument is true) or not necessarily so (false)

Definition at line 1326 of file AudioIO.cpp.

1327 {
1328  mDelayingActions = recording;
1329 }

References mDelayingActions.

Referenced by StopStream().

Here is the caller graph for this function:

◆ DelayingActions()

bool AudioIO::DelayingActions ( ) const
private

Definition at line 1331 of file AudioIO.cpp.

1332 {
1334 }

References mDelayingActions, AudioIoCallback::mNumCaptureChannels, and AudioIOBase::mPortStreamV19.

Referenced by CallAfterRecording().

Here is the caller graph for this function:

◆ DrainRecordBuffers()

void AudioIO::DrainRecordBuffers ( )
private

Second part of TrackBufferExchange.

Definition at line 2305 of file AudioIO.cpp.

2306 {
2307  if (mRecordingException || mCaptureTracks.empty())
2308  return;
2309 
2310  auto delayedHandler = [this] ( AudacityException * pException ) {
2311  // In the main thread, stop recording
2312  // This is one place where the application handles disk
2313  // exhaustion exceptions from wave track operations, without rolling
2314  // back to the last pushed undo state. Instead, partial recording
2315  // results are pushed as a NEW undo state. For this reason, as
2316  // commented elsewhere, we want an exception safety guarantee for
2317  // the output wave tracks, after the failed append operation, that
2318  // the tracks remain as they were after the previous successful
2319  // (block-level) appends.
2320 
2321  // Note that the Flush in StopStream() may throw another exception,
2322  // but StopStream() contains that exception, and the logic in
2323  // AudacityException::DelayedHandlerAction prevents redundant message
2324  // boxes.
2325  StopStream();
2326  DefaultDelayedHandlerAction{}( pException );
2327  };
2328 
2329  GuardedCall( [&] {
2330  // start record buffering
2331  const auto avail = GetCommonlyAvailCapture(); // samples
2332  const auto remainingTime =
2333  std::max(0.0, mRecordingSchedule.ToConsume());
2334  // This may be a very big double number:
2335  const auto remainingSamples = remainingTime * mRate;
2336  bool latencyCorrected = true;
2337 
2338  double deltat = avail / mRate;
2339 
2341  deltat >= mMinCaptureSecsToCopy)
2342  {
2343  // This scope may combine many appendings of wave tracks,
2344  // and also an autosave, into one transaction,
2345  // lessening the number of checkpoints
2347  if (mOwningProject) {
2348  auto &pIO = ProjectFileIO::Get(*mOwningProject);
2349  pScope.emplace(pIO.GetConnection(), "Recording");
2350  }
2351 
2352  bool newBlocks = false;
2353 
2354  // Append captured samples to the end of the WaveTracks.
2355  // The WaveTracks have their own buffering for efficiency.
2356  auto numChannels = mCaptureTracks.size();
2357 
2358  for( size_t i = 0; i < numChannels; i++ )
2359  {
2360  sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
2361 
2362  size_t discarded = 0;
2363 
2365  const auto correction = mRecordingSchedule.TotalCorrection();
2366  if (correction >= 0) {
2367  // Rightward shift
2368  // Once only (per track per recording), insert some initial
2369  // silence.
2370  size_t size = floor( correction * mRate * mFactor);
2371  SampleBuffer temp(size, trackFormat);
2372  ClearSamples(temp.ptr(), trackFormat, 0, size);
2373  mCaptureTracks[i]->Append(temp.ptr(), trackFormat, size, 1);
2374  }
2375  else {
2376  // Leftward shift
2377  // discard some samples from the ring buffers.
2378  size_t size = floor(
2380 
2381  // The ring buffer might have grown concurrently -- don't discard more
2382  // than the "avail" value noted above.
2383  discarded = mCaptureBuffers[i]->Discard(std::min(avail, size));
2384 
2385  if (discarded < size)
2386  // We need to visit this again to complete the
2387  // discarding.
2388  latencyCorrected = false;
2389  }
2390  }
2391 
2392  const float *pCrossfadeSrc = nullptr;
2393  size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2394  if (i < mRecordingSchedule.mCrossfadeData.size())
2395  {
2396  // Do crossfading
2397  // The supplied crossfade samples are at the same rate as the track
2398  const auto &data = mRecordingSchedule.mCrossfadeData[i];
2399  totalCrossfadeLength = data.size();
2400  if (totalCrossfadeLength) {
2401  crossfadeStart =
2402  floor(mRecordingSchedule.Consumed() * mCaptureTracks[i]->GetRate());
2403  if (crossfadeStart < totalCrossfadeLength)
2404  pCrossfadeSrc = data.data() + crossfadeStart;
2405  }
2406  }
2407 
2408  wxASSERT(discarded <= avail);
2409  size_t toGet = avail - discarded;
2410  SampleBuffer temp;
2411  size_t size;
2413  if( mFactor == 1.0 )
2414  {
2415  // Take captured samples directly
2416  size = toGet;
2417  if (pCrossfadeSrc)
2418  // Change to float for crossfade calculation
2419  format = floatSample;
2420  else
2421  format = trackFormat;
2422  temp.Allocate(size, format);
2423  const auto got =
2424  mCaptureBuffers[i]->Get(temp.ptr(), format, toGet);
2425  // wxASSERT(got == toGet);
2426  // but we can't assert in this thread
2427  wxUnusedVar(got);
2428  if (double(size) > remainingSamples)
2429  size = floor(remainingSamples);
2430  }
2431  else
2432  {
2433  size = lrint(toGet * mFactor);
2434  format = floatSample;
2435  SampleBuffer temp1(toGet, floatSample);
2436  temp.Allocate(size, format);
2437  const auto got =
2438  mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, toGet);
2439  // wxASSERT(got == toGet);
2440  // but we can't assert in this thread
2441  wxUnusedVar(got);
2442  /* we are re-sampling on the fly. The last resampling call
2443  * must flush any samples left in the rate conversion buffer
2444  * so that they get recorded
2445  */
2446  if (toGet > 0 ) {
2447  if (double(toGet) > remainingSamples)
2448  toGet = floor(remainingSamples);
2449  const auto results =
2450  mResample[i]->Process(mFactor, (float *)temp1.ptr(), toGet,
2451  !IsStreamActive(), (float *)temp.ptr(), size);
2452  size = results.second;
2453  }
2454  }
2455 
2456  if (pCrossfadeSrc) {
2457  wxASSERT(format == floatSample);
2458  size_t crossfadeLength = std::min(size, totalCrossfadeLength - crossfadeStart);
2459  if (crossfadeLength) {
2460  auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2461  auto ratioStep = 1.0 / totalCrossfadeLength;
2462  auto pCrossfadeDst = (float*)temp.ptr();
2463 
2464  // Crossfade loop here
2465  for (size_t ii = 0; ii < crossfadeLength; ++ii) {
2466  *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2467  ++pCrossfadeSrc, ++pCrossfadeDst;
2468  ratio += ratioStep;
2469  }
2470  }
2471  }
2472 
2473  // Now append
2474  // see comment in second handler about guarantee
2475  newBlocks = mCaptureTracks[i]->Append(temp.ptr(), format, size, 1)
2476  || newBlocks;
2477  } // end loop over capture channels
2478 
2479  // Now update the recording schedule position
2480  mRecordingSchedule.mPosition += avail / mRate;
2481  mRecordingSchedule.mLatencyCorrected = latencyCorrected;
2482 
2483  auto pListener = GetListener();
2484  if (pListener && newBlocks)
2485  pListener->OnAudioIONewBlocks(&mCaptureTracks);
2486 
2487  if (pScope)
2488  pScope->Commit();
2489  }
2490  // end of record buffering
2491  },
2492  // handler
2493  [this] ( AudacityException *pException ) {
2494  if ( pException ) {
2495  // So that we don't attempt to fill the recording buffer again
2496  // before the main thread stops recording
2498  return ;
2499  }
2500  else
2501  // Don't want to intercept other exceptions (?)
2502  throw;
2503  },
2504  delayedHandler );
2505 }

References SampleBuffer::Allocate(), ClearSamples(), TransactionScope::Commit(), RecordingSchedule::Consumed(), Optional< X >::emplace(), floatSample, format, ProjectFileIO::Get(), GetCommonlyAvailCapture(), AudioIoCallback::GetListener(), GuardedCall(), AudioIOBase::IsStreamActive(), lrint, AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, RecordingSchedule::mCrossfadeData, AudioIoCallback::mFactor, min(), RecordingSchedule::mLatencyCorrected, AudioIoCallback::mMinCaptureSecsToCopy, AudioIOBase::mOwningProject, RecordingSchedule::mPosition, AudioIOBase::mRate, AudioIoCallback::mRecordingException, AudioIoCallback::mRecordingSchedule, AudioIoCallback::mResample, SampleBuffer::ptr(), AudioIoCallback::SetRecordingException(), size, StopStream(), RecordingSchedule::ToConsume(), RecordingSchedule::ToDiscard(), and RecordingSchedule::TotalCorrection().

Referenced by TrackBufferExchange().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillPlayBuffers()

void AudioIO::FillPlayBuffers ( )
private

First part of TrackBufferExchange.

Definition at line 2096 of file AudioIO.cpp.

2097 {
2098  if (mNumPlaybackChannels == 0)
2099  return;
2100 
2101  // Though extremely unlikely, it is possible that some buffers
2102  // will have more samples available than others. This could happen
2103  // if we hit this code during the PortAudio callback. To keep
2104  // things simple, we only write as much data as is vacant in
2105  // ALL buffers, and advance the global time by that much.
2106  auto nAvailable = GetCommonlyFreePlayback();
2107 
2108  // Don't fill the buffers at all unless we can do the
2109  // full mMaxPlaybackSecsToCopy. This improves performance
2110  // by not always trying to process tiny chunks, eating the
2111  // CPU unnecessarily.
2112  if (nAvailable < mPlaybackSamplesToCopy)
2113  return;
2114 
2115  // More than mPlaybackSamplesToCopy might be copied:
2116  // May produce a larger amount when initially priming the buffer, or
2117  // perhaps again later in play to avoid underfilling the queue and falling
2118  // behind the real-time demand on the consumer side in the callback.
2119  auto nReady = GetCommonlyReadyPlayback();
2120  auto nNeeded =
2122 
2123  // wxASSERT( nNeeded <= nAvailable );
2124 
2125  // Limit maximum buffer size (increases performance)
2126  auto available = std::min( nAvailable,
2127  std::max( nNeeded, mPlaybackSamplesToCopy ) );
2128 
2129  // msmeyer: When playing a very short selection in looped
2130  // mode, the selection must be copied to the buffer multiple
2131  // times, to ensure, that the buffer has a reasonable size
2132  // This is the purpose of this loop.
2133  // PRL: or, when scrubbing, we may get work repeatedly from the
2134  // user interface.
2135  bool done = false;
2136  do {
2137  const auto [frames, toProduce, progress] = GetPlaybackSlice(available);
2138 
2139  // Update the time queue. This must be done before writing to the
2140  // ring buffers of samples, for proper synchronization with the
2141  // consumer side in the PortAudio thread, which reads the time
2142  // queue after reading the sample queues. The sample queues use
2143  // atomic variables, the time queue doesn't.
2145  (mPlaybackSchedule.Interactive() ? mScrubSpeed : 1.0),
2146  frames);
2147 
2148  for (size_t i = 0; i < mPlaybackTracks.size(); i++)
2149  {
2150  // The mixer here isn't actually mixing: it's just doing
2151  // resampling, format conversion, and possibly time track
2152  // warping
2153  if (frames > 0)
2154  {
2155  size_t produced = 0;
2156  if ( toProduce )
2157  produced = mPlaybackMixers[i]->Process( toProduce );
2158  //wxASSERT(produced <= toProduce);
2159  auto warpedSamples = mPlaybackMixers[i]->GetBuffer();
2160  const auto put = mPlaybackBuffers[i]->Put(
2161  warpedSamples, floatSample, produced, frames - produced);
2162  // wxASSERT(put == frames);
2163  // but we can't assert in this thread
2164  wxUnusedVar(put);
2165  }
2166  }
2167 
2168  if (mPlaybackTracks.empty())
2169  // Produce silence in the single ring buffer
2170  mPlaybackBuffers[0]->Put(nullptr, floatSample, 0, frames);
2171 
2172  available -= frames;
2173  // wxASSERT(available >= 0); // don't assert on this thread
2174 
2175  done = RepositionPlayback(frames, available, progress);
2176  } while (!done);
2177 }

References floatSample, GetCommonlyFreePlayback(), AudioIoCallback::GetCommonlyReadyPlayback(), GetPlaybackSlice(), PlaybackSchedule::Interactive(), min(), AudioIoCallback::mNumPlaybackChannels, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackQueueMinimum, AudioIoCallback::mPlaybackSamplesToCopy, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIOBase::mRate, PlaybackSchedule::mTimeQueue, PlaybackSchedule::TimeQueue::Producer(), and RepositionPlayback().

Referenced by TrackBufferExchange().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Get()

AudioIO * AudioIO::Get ( )
static

Definition at line 138 of file AudioIO.cpp.

139 {
140  return static_cast< AudioIO* >( AudioIOBase::Get() );
141 }

References AudioIOBase::Get().

Referenced by audacityAudioCallback(), ProjectAudioManager::CanStopAudioStream(), CaptureNotBusyFlag(), DefaultSpeedPlayOptions(), anonymous_namespace{SelectMenus.cpp}::DoBoundaryMove(), PlayIndicatorOverlayBase::DoGetRectangle(), ProjectAudioManager::DoPlayStopSelect(), ProjectAudioManager::DoRecord(), PlayIndicatorOverlayBase::Draw(), ControlToolBar::EnableDisableButtons(), TranscriptionToolBar::EnableDisableButtons(), AudioThread::Entry(), UpdateManager::GetUpdates(), Init(), EffectUIHost::Initialize(), ProjectManager::New(), LabelEditActions::Handler::OnAddLabelPlaying(), ProjectAudioManager::OnAudioIOStopRecording(), ProjectManager::OnCloseWindow(), SelectActions::Handler::OnCursorPositionStore(), PluginActions::Handler::OnDetectUpstreamDropouts(), EffectUIHost::OnFFwd(), SelectionBar::OnIdle(), TimeToolBar::OnIdle(), AudacityApp::OnKeyDown(), MeterPanel::OnMeterUpdate(), ProjectAudioManager::OnPause(), EffectUIHost::OnPlay(), EffectUIHost::OnRewind(), SelectActions::Handler::OnSelectCursorStoredCursor(), SelectActions::Handler::OnSetLeftSelection(), SelectActions::Handler::OnSetRightSelection(), PluginActions::Handler::OnSimulateRecordingErrors(), ProjectAudioManager::OnSoundActivationThreshold(), LyricsWindow::OnTimer(), MixerBoard::OnTimer(), ProjectWindow::PlaybackScroller::OnTimer(), PlayIndicatorOverlay::OnTimer(), ProjectManager::OnTimer(), TrackPanel::OnTimer(), ProjectAudioManager::Pause(), anonymous_namespace{TransportMenus.cpp}::PlayCurrentRegionAndWait(), ProjectAudioManager::Playing(), ProjectAudioManager::PlayPlayRegion(), anonymous_namespace{TransportMenus.cpp}::PlayPlayRegionAndWait(), MixerToolBar::Populate(), Effect::Preview(), anonymous_namespace{TransportMenus.cpp}::RecordAndWait(), ProjectAudioManager::Recording(), TimerRecordDialog::RunWaitDialog(), anonymous_namespace{SelectMenus.cpp}::SeekWhenAudioActive(), MixerToolBar::SetMixer(), MixerToolBar::SetToolTips(), MeterPanel::StartMonitoring(), StartMonitoring(), ControlToolBar::StartScrolling(), ProjectAudioManager::Stop(), MeterPanel::StopMonitoring(), anonymous_namespace{PluginMenus.cpp}::ToolsMenu(), AdornedRulerPanel::UpdateButtonStates(), MixerToolBar::UpdateControls(), MixerToolBar::UpdatePrefs(), and ProjectWindow::ZoomInByFactor().

Here is the call graph for this function:

◆ GetBestRate()

double AudioIO::GetBestRate ( bool  capturing,
bool  playing,
double  sampleRate 
)

Return a valid sample rate that is supported by the current I/O device(s).

The return from this function is used to determine the sample rate that audacity actually runs the audio I/O stream at. if there is no suitable rate available from the hardware, it returns 0. The sampleRate argument gives the desired sample rate (the rate of the audio to be handled, i.e. the currently Project Rate). capturing is true if the stream is capturing one or more audio channels, and playing is true if one or more channels are being played.

Definition at line 1929 of file AudioIO.cpp.

1930 {
1931  // Check if we can use the cached value
1932  if (mCachedBestRateIn != 0.0 && mCachedBestRateIn == sampleRate
1933  && mCachedBestRatePlaying == playing && mCachedBestRateCapturing == capturing) {
1934  return mCachedBestRateOut;
1935  }
1936 
1937  // In order to cache the value, all early returns should instead set retval
1938  // and jump to finished
1939  double retval;
1940 
1941  std::vector<long> rates;
1942  if (capturing) wxLogDebug(wxT("AudioIO::GetBestRate() for capture"));
1943  if (playing) wxLogDebug(wxT("AudioIO::GetBestRate() for playback"));
1944  wxLogDebug(wxT("GetBestRate() suggested rate %.0lf Hz"), sampleRate);
1945 
1946  if (capturing && !playing) {
1947  rates = GetSupportedCaptureRates(-1, sampleRate);
1948  }
1949  else if (playing && !capturing) {
1950  rates = GetSupportedPlaybackRates(-1, sampleRate);
1951  }
1952  else { // we assume capturing and playing - the alternative would be a
1953  // bit odd
1954  rates = GetSupportedSampleRates(-1, -1, sampleRate);
1955  }
1956  /* rem rates is the array of hardware-supported sample rates (in the current
1957  * configuration), sampleRate is the Project Rate (desired sample rate) */
1958  long rate = (long)sampleRate;
1959 
1960  if (make_iterator_range(rates).contains(rate)) {
1961  wxLogDebug(wxT("GetBestRate() Returning %.0ld Hz"), rate);
1962  retval = rate;
1963  goto finished;
1964  /* the easy case - the suggested rate (project rate) is in the list, and
1965  * we can just accept that and send back to the caller. This should be
1966  * the case for most users most of the time (all of the time on
1967  * Win MME as the OS does resampling) */
1968  }
1969 
1970  /* if we get here, there is a problem - the project rate isn't supported
1971  * on our hardware, so we can't us it. Need to come up with an alternative
1972  * rate to use. The process goes like this:
1973  * * If there are no rates to pick from, we're stuck and return 0 (error)
1974  * * If there are some rates, we pick the next one higher than the requested
1975  * rate to use.
1976  * * If there aren't any higher, we use the highest available rate */
1977 
1978  if (rates.empty()) {
1979  /* we're stuck - there are no supported rates with this hardware. Error */
1980  wxLogDebug(wxT("GetBestRate() Error - no supported sample rates"));
1981  retval = 0.0;
1982  goto finished;
1983  }
1984  int i;
1985  for (i = 0; i < (int)rates.size(); i++) // for each supported rate
1986  {
1987  if (rates[i] > rate) {
1988  // supported rate is greater than requested rate
1989  wxLogDebug(wxT("GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1990  retval = rates[i];
1991  goto finished;
1992  }
1993  }
1994 
1995  wxLogDebug(wxT("GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1996  retval = rates.back(); // the highest available rate
1997  goto finished;
1998 
1999 finished:
2000  mCachedBestRateIn = sampleRate;
2001  mCachedBestRateOut = retval;
2002  mCachedBestRatePlaying = playing;
2003  mCachedBestRateCapturing = capturing;
2004  return retval;
2005 }

References AudioIOBase::GetSupportedCaptureRates(), AudioIOBase::GetSupportedPlaybackRates(), AudioIOBase::GetSupportedSampleRates(), make_iterator_range(), AudioIoCallback::mCachedBestRateCapturing, AudioIOBase::mCachedBestRateIn, AudioIoCallback::mCachedBestRateOut, and AudioIoCallback::mCachedBestRatePlaying.

Referenced by StartPortAudioStream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetCaptureFormat()

sampleFormat AudioIO::GetCaptureFormat ( )
inline

Definition at line 484 of file AudioIO.h.

484 { return mCaptureFormat; }

References AudioIoCallback::mCaptureFormat.

◆ GetCommonlyAvailCapture()

size_t AudioIO::GetCommonlyAvailCapture ( )
private

Get the number of audio samples ready in all of the recording buffers.

Returns the smallest of the number of samples available for storage in the recording buffers (i.e. the number of samples that can be read from all record buffers without underflow).

Definition at line 2078 of file AudioIO.cpp.

2079 {
2080  auto commonlyAvail = mCaptureBuffers[0]->AvailForGet();
2081  for (unsigned i = 1; i < mCaptureTracks.size(); ++i)
2082  commonlyAvail = std::min(commonlyAvail,
2083  mCaptureBuffers[i]->AvailForGet());
2084  return commonlyAvail;
2085 }

References AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, and min().

Referenced by DrainRecordBuffers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetCommonlyFreePlayback()

size_t AudioIO::GetCommonlyFreePlayback ( )
private

Get the number of audio samples free in all of the playback buffers.

Returns the smallest of the buffer free space values in the event that they are different.

Definition at line 2058 of file AudioIO.cpp.

2059 {
2060  auto commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
2061  for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
2062  commonlyAvail = std::min(commonlyAvail,
2063  mPlaybackBuffers[i]->AvailForPut());
2064  // MB: subtract a few samples because the code in TrackBufferExchange has rounding
2065  // errors
2066  return commonlyAvail - std::min(size_t(10), commonlyAvail);
2067 }

References min(), AudioIoCallback::mPlaybackBuffers, and AudioIoCallback::mPlaybackTracks.

Referenced by FillPlayBuffers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetInputSourceNames()

wxArrayString AudioIO::GetInputSourceNames ( )

Get the list of inputs to the current mixer device.

Returns an array of strings giving the names of the inputs to the soundcard mixer (driven by PortMixer)

Definition at line 721 of file AudioIO.cpp.

722 {
723 #if defined(USE_PORTMIXER)
724 
725  wxArrayString deviceNames;
726 
727  if( mPortMixer )
728  {
729  int numSources = Px_GetNumInputSources(mPortMixer);
730  for( int source = 0; source < numSources; source++ )
731  deviceNames.push_back(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
732  }
733  else
734  {
735  wxLogDebug(wxT("AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
736  }
737 
738  return deviceNames;
739 
740 #else
741 
742  wxArrayString blank;
743 
744  return blank;
745 
746 #endif
747 }

◆ GetLastPlaybackTime()

wxLongLong AudioIO::GetLastPlaybackTime ( ) const
inline

Definition at line 446 of file AudioIO.h.

446 { return mLastPlaybackTimeMillis; }

References AudioIoCallback::mLastPlaybackTimeMillis.

◆ GetMixer()

void AudioIO::GetMixer ( int *  inputSource,
float *  inputVolume,
float *  playbackVolume 
)

Definition at line 680 of file AudioIO.cpp.

682 {
683 #if defined(USE_PORTMIXER)
684 
685  PxMixer *mixer = mPortMixer;
686 
687  if( mixer )
688  {
689  *recordDevice = Px_GetCurrentInputSource(mixer);
690 
691  if (mInputMixerWorks)
692  *recordVolume = Px_GetInputVolume(mixer);
693  else
694  *recordVolume = 1.0f;
695 
697  *playbackVolume = mMixerOutputVol;
698  else
699  *playbackVolume = Px_GetPCMOutputVolume(mixer);
700 
701  return;
702  }
703 
704 #endif
705 
706  *recordDevice = 0;
707  *recordVolume = 1.0f;
708  *playbackVolume = mMixerOutputVol;
709 }

References AudioIOBase::mEmulateMixerOutputVol, AudioIOBase::mInputMixerWorks, and AudioIOBase::mMixerOutputVol.

◆ GetNumCaptureChannels()

unsigned AudioIO::GetNumCaptureChannels ( ) const
inline

Definition at line 486 of file AudioIO.h.

486 { return mNumCaptureChannels; }

References AudioIoCallback::mNumCaptureChannels.

Referenced by IsCapturing().

Here is the caller graph for this function:

◆ GetNumPlaybackChannels()

unsigned AudioIO::GetNumPlaybackChannels ( ) const
inline

Definition at line 485 of file AudioIO.h.

485 { return mNumPlaybackChannels; }

References AudioIoCallback::mNumPlaybackChannels.

◆ GetOwningProject()

AudacityProject* AudioIO::GetOwningProject ( ) const
inline

Definition at line 447 of file AudioIO.h.

447 { return mOwningProject; }

References AudioIOBase::mOwningProject.

◆ GetPlaybackSlice()

PlaybackSlice AudioIO::GetPlaybackSlice ( size_t  available)
private

Called one or more times by FillPlayBuffers.

Parameters
availablehow many more samples may be buffered

Definition at line 2179 of file AudioIO.cpp.

2180 {
2181  // How many samples to produce for each channel.
2182  auto frames = available;
2183  bool progress = true;
2184  auto toProduce = frames;
2185 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2187  // scrubbing and play-at-speed are not limited by the real time
2188  // and length accumulators
2189  toProduce =
2190  frames = limitSampleBufferSize(frames, mScrubDuration);
2191  else
2192 #endif
2193  {
2194  double deltat = frames / mRate;
2195  const auto realTimeRemaining = mPlaybackSchedule.RealTimeRemaining();
2196  if (deltat > realTimeRemaining)
2197  {
2198  // Produce some extra silence so that the time queue consumer can
2199  // satisfy its end condition
2200  double extraRealTime = mPlaybackSchedule.PlayingStraight()
2201  ? (TimeQueueGrainSize + 1) / mRate
2202  : 0;
2203 
2204  auto extra = std::min( extraRealTime, deltat - realTimeRemaining );
2205  auto realTime = realTimeRemaining + extra;
2206  frames = realTime * mRate;
2207  toProduce = realTimeRemaining * mRate;
2208 
2209  // Don't fall into an infinite loop, if loop-playing a selection
2210  // that is so short, it has no samples: detect that case
2211  progress =
2212  !(mPlaybackSchedule.Looping() &&
2213  mPlaybackSchedule.mWarpedTime == 0.0 && frames == 0);
2214  mPlaybackSchedule.RealTimeAdvance( realTime );
2215  }
2216  else
2218  }
2219 
2220  if (!progress)
2221  frames = available, toProduce = 0;
2222 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2223  else if ( mPlaybackSchedule.Interactive() && mSilentScrub)
2224  toProduce = 0;
2225 #endif
2226 
2227  return { available, frames, toProduce, progress };
2228 }

References PlaybackSchedule::Interactive(), limitSampleBufferSize(), PlaybackSchedule::Looping(), min(), AudioIoCallback::mPlaybackSchedule, AudioIOBase::mRate, PlaybackSchedule::mWarpedTime, PlaybackSchedule::PlayingStraight(), PlaybackSchedule::RealTimeAdvance(), PlaybackSchedule::RealTimeRemaining(), and TimeQueueGrainSize.

Referenced by FillPlayBuffers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetStreamTime()

double AudioIO::GetStreamTime ( )

During playback, the track time most recently played.

When playing looped, this will start from t0 again, too. So the returned time should be always between t0 and t1

Definition at line 2007 of file AudioIO.cpp.

2008 {
2009  // Track time readout for the main thread
2010 
2011  if( !IsStreamActive() )
2012  return BAD_STREAM_TIME;
2013 
2015 }

References BAD_STREAM_TIME, AudioIOBase::IsStreamActive(), AudioIoCallback::mPlaybackSchedule, and PlaybackSchedule::NormalizeTrackTime().

Here is the call graph for this function:

◆ Init()

void AudioIO::Init ( )
static

Definition at line 507 of file AudioIO.cpp.

508 {
509  ugAudioIO.reset(safenew AudioIO());
510  Get()->mThread->Run();
511 
512  // Make sure device prefs are initialized
513  if (gPrefs->Read(wxT("AudioIO/RecordingDevice"), wxT("")).empty()) {
514  int i = getRecordDevIndex();
515  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
516  if (info) {
518  AudioIOHost.Write(HostName(info));
519  }
520  }
521 
522  if (gPrefs->Read(wxT("AudioIO/PlaybackDevice"), wxT("")).empty()) {
523  int i = getPlayDevIndex();
524  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
525  if (info) {
527  AudioIOHost.Write(HostName(info));
528  }
529  }
530 
531  gPrefs->Flush();
532 }

References AudioIO(), AudioIOHost, AudioIOPlaybackDevice, AudioIORecordingDevice, AudioIOBase::DeviceName(), FileConfig::Flush(), Get(), AudioIOBase::getPlayDevIndex(), AudioIOBase::getRecordDevIndex(), gPrefs, AudioIOBase::HostName(), AudioIoCallback::mThread, safenew, AudioIOBase::ugAudioIO, and Setting< T >::Write().

Referenced by AudacityApp::InitPart2().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ InputMixerWorks()

bool AudioIO::InputMixerWorks ( )

Find out if the input hardware level control is available.

Checks the mInputMixerWorks variable, which is set up in AudioIOBase::HandleDeviceChange(). External people care, because we want to disable the UI if it doesn't work.

Definition at line 711 of file AudioIO.cpp.

712 {
713  return mInputMixerWorks;
714 }

References AudioIOBase::mInputMixerWorks.

◆ IsAvailable()

bool AudioIO::IsAvailable ( AudacityProject projecT) const

Function to automatically set an acceptable volume.

Definition at line 1587 of file AudioIO.cpp.

1588 {
1589  return mOwningProject == NULL || mOwningProject == project;
1590 }

References AudioIOBase::mOwningProject.

◆ IsCapturing()

bool AudioIO::IsCapturing ( ) const

Definition at line 3553 of file AudioIO.cpp.

3554 {
3555  // Includes a test of mTime, used in the main thread
3556  return IsStreamActive() &&
3557  GetNumCaptureChannels() > 0 &&
3560 }

References GetNumCaptureChannels(), PlaybackSchedule::GetTrackTime(), AudioIOBase::IsStreamActive(), AudioIoCallback::mPlaybackSchedule, RecordingSchedule::mPreRoll, AudioIoCallback::mRecordingSchedule, and PlaybackSchedule::mT0.

Here is the call graph for this function:

◆ LastPaErrorString()

wxString AudioIO::LastPaErrorString ( )

Definition at line 950 of file AudioIO.cpp.

951 {
952  return wxString::Format(wxT("%d %s."), (int) mLastPaError, Pa_GetErrorText(mLastPaError));
953 }

References AudioIoCallback::mLastPaError.

Referenced by StartMonitoring().

Here is the caller graph for this function:

◆ OutputMixerEmulated()

bool AudioIO::OutputMixerEmulated ( )

Find out if the output level control is being emulated via software attenuation.

Checks the mEmulateMixerOutputVol variable, which is set up in AudioIOBase::HandleDeviceChange(). External classes care, because we want to modify the UI if it doesn't work.

Definition at line 716 of file AudioIO.cpp.

717 {
718  return mEmulateMixerOutputVol;
719 }

References AudioIOBase::mEmulateMixerOutputVol.

Referenced by MixerToolBar::SetToolTips().

Here is the caller graph for this function:

◆ RepositionPlayback()

bool AudioIO::RepositionPlayback ( size_t  frames,
size_t  available,
bool  progress 
)
private

FillPlayBuffers calls this to update its cursors into tracks for changes of position or speed.

Parameters
frameshow many samples were just now buffered for play
availablehow many more samples may be buffered

Definition at line 2230 of file AudioIO.cpp.

2231 {
2232  bool done = false;
2233  switch (mPlaybackSchedule.mPlayMode)
2234  {
2235  #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2236  case PlaybackSchedule::PLAY_SCRUB:
2237  case PlaybackSchedule::PLAY_AT_SPEED:
2238  case PlaybackSchedule::PLAY_KEYBOARD_SCRUB:
2239  {
2240  mScrubDuration -= frames;
2241  wxASSERT(mScrubDuration >= 0);
2242  done = (available == 0);
2243  if (!done && mScrubDuration <= 0)
2244  {
2245  sampleCount startSample, endSample;
2246  mScrubState->Get(
2247  startSample, endSample, available, mScrubDuration);
2248  if (mScrubDuration < 0)
2249  {
2250  // Can't play anything
2251  // Stop even if we don't fill up available
2252  mScrubDuration = 0;
2253  done = true;
2254  }
2255  else
2256  {
2257  mSilentScrub = (endSample == startSample);
2258  double startTime, endTime;
2259  startTime = startSample.as_double() / mRate;
2260  endTime = endSample.as_double() / mRate;
2261  auto diff = (endSample - startSample).as_long_long();
2262  if (mScrubDuration == 0)
2263  mScrubSpeed = 0;
2264  else
2265  mScrubSpeed =
2266  double(diff) / mScrubDuration.as_double();
2267  if (!mSilentScrub)
2268  {
2269  for (size_t i = 0; i < mPlaybackTracks.size(); i++) {
2270  if (mPlaybackSchedule.mPlayMode == PlaybackSchedule::PLAY_AT_SPEED)
2271  mPlaybackMixers[i]->SetSpeedForPlayAtSpeed(mScrubSpeed);
2272  else if (mPlaybackSchedule.mPlayMode == PlaybackSchedule::PLAY_KEYBOARD_SCRUB)
2273  mPlaybackMixers[i]->SetSpeedForKeyboardScrubbing(mScrubSpeed, startTime);
2274  else
2275  mPlaybackMixers[i]->SetTimesAndSpeed(
2276  startTime, endTime, fabs( mScrubSpeed ));
2277  }
2278  }
2280  }
2281  }
2282  }
2283  break;
2284  #endif
2286  {
2287  done = !progress || (available == 0);
2288  // msmeyer: If playing looped, check if we are at the end of the buffer
2289  // and if yes, restart from the beginning.
2291  {
2292  for (size_t i = 0; i < mPlaybackTracks.size(); i++)
2293  mPlaybackMixers[i]->Restart();
2295  }
2296  }
2297  break;
2298  default:
2299  done = true;
2300  break;
2301  }
2302  return done;
2303 }

References sampleCount::as_double(), PlaybackSchedule::TimeQueue::mLastTime, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIOBase::mRate, PlaybackSchedule::mTimeQueue, PlaybackSchedule::PLAY_LOOPED, PlaybackSchedule::RealTimeRemaining(), and PlaybackSchedule::RealTimeRestart().

Referenced by FillPlayBuffers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SeekStream()

void AudioIO::SeekStream ( double  seconds)
inline

Move the playback / recording position of the current stream by the specified amount from where it is now.

Definition at line 418 of file AudioIO.h.

418 { mSeek = seconds; }

◆ SetMeters()

void AudioIO::SetMeters ( )
private

Set the current VU meters - this should be done once after each call to StartStream currently.

Definition at line 1592 of file AudioIO.cpp.

1593 {
1594  if (auto pInputMeter = mInputMeter.lock())
1595  pInputMeter->Reset(mRate, true);
1596  if (auto pOutputMeter = mOutputMeter.lock())
1597  pOutputMeter->Reset(mRate, true);
1598 
1599  mUpdateMeters = true;
1600 }

References AudioIOBase::mInputMeter, AudioIOBase::mOutputMeter, AudioIOBase::mRate, and AudioIoCallback::mUpdateMeters.

Referenced by StartPortAudioStream().

Here is the caller graph for this function:

◆ SetMixer()

void AudioIO::SetMixer ( int  inputSource,
float  inputVolume,
float  playbackVolume 
)

Definition at line 659 of file AudioIO.cpp.

661 {
662  mMixerOutputVol = playbackVolume;
663 #if defined(USE_PORTMIXER)
664  PxMixer *mixer = mPortMixer;
665  if( !mixer )
666  return;
667 
668  float oldRecordVolume = Px_GetInputVolume(mixer);
669  float oldPlaybackVolume = Px_GetPCMOutputVolume(mixer);
670 
671  AudioIoCallback::SetMixer(inputSource);
672  if( oldRecordVolume != recordVolume )
673  Px_SetInputVolume(mixer, recordVolume);
674  if( oldPlaybackVolume != playbackVolume )
675  Px_SetPCMOutputVolume(mixer, playbackVolume);
676 
677 #endif
678 }

References AudioIOBase::mMixerOutputVol, and AudioIOBase::SetMixer().

Here is the call graph for this function:

◆ SetPaused()

void AudioIO::SetPaused ( bool  state)

Pause and un-pause playback and recording.

Definition at line 1885 of file AudioIO.cpp.

1886 {
1887  if (state != mPaused)
1888  {
1889  if (state)
1890  {
1892  }
1893  else
1894  {
1896  }
1897  }
1898 
1899  mPaused = state;
1900 }

References RealtimeEffectManager::Get(), AudioIOBase::mPaused, RealtimeEffectManager::RealtimeResume(), and RealtimeEffectManager::RealtimeSuspend().

Here is the call graph for this function:

◆ StartMonitoring()

void AudioIO::StartMonitoring ( const AudioIOStartStreamOptions options)

Start up Portaudio for capture and recording as needed for input monitoring and software playthrough only.

This uses the Default project sample format, current sample rate, and selected number of input channels to open the recording device and start reading input data. If software playthrough is enabled, it also opens the output device in stereo to play the data through

Definition at line 955 of file AudioIO.cpp.

956 {
957  if ( mPortStreamV19 || mStreamToken )
958  return;
959 
960  bool success;
961  auto captureFormat = QualitySettings::SampleFormatChoice();
962  auto captureChannels = AudioIORecordChannels.Read();
963  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
964  int playbackChannels = 0;
965 
967  playbackChannels = 2;
968 
969  // FIXME: TRAP_ERR StartPortAudioStream (a PaError may be present)
970  // but StartPortAudioStream function only returns true or false.
971  mUsingAlsa = false;
972  success = StartPortAudioStream(options, (unsigned int)playbackChannels,
973  (unsigned int)captureChannels,
974  captureFormat);
975 
976  if (!success) {
977  using namespace BasicUI;
978  auto msg = XO("Error opening recording device.\nError code: %s")
979  .Format( Get()->LastPaErrorString() );
981  XO("Error"), msg, wxT("Error_opening_sound_device"),
982  ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
983  return;
984  }
985 
986  wxCommandEvent e(EVT_AUDIOIO_MONITOR);
987  e.SetEventObject(mOwningProject);
988  e.SetInt(true);
989  wxTheApp->ProcessEvent(e);
990 
991  // FIXME: TRAP_ERR PaErrorCode 'noted' but not reported in StartMonitoring.
992  // Now start the PortAudio stream!
993  // TODO: ? Factor out and reuse error reporting code from end of
994  // AudioIO::StartStream?
995  mLastPaError = Pa_StartStream( mPortStreamV19 );
996 
997  // Update UI display only now, after all possibilities for error are past.
998  auto pListener = GetListener();
999  if ((mLastPaError == paNoError) && pListener) {
1000  // advertise the chosen I/O sample rate to the UI
1001  pListener->OnAudioIORate((int)mRate);
1002  }
1003 }

References AudioIORecordChannels, Get(), AudioIoCallback::GetListener(), gPrefs, LastPaErrorString(), AudioIoCallback::mLastPaError, AudioIOBase::mOwningProject, AudioIOBase::mPortStreamV19, AudioIOBase::mRate, AudioIoCallback::mSoftwarePlaythrough, AudioIOBase::mStreamToken, AudioIoCallback::mUsingAlsa, ProjectFramePlacement(), Setting< T >::Read(), QualitySettings::SampleFormatChoice(), BasicUI::ShowErrorDialog(), StartPortAudioStream(), and XO.

Here is the call graph for this function:

◆ StartPortAudioStream()

bool AudioIO::StartPortAudioStream ( const AudioIOStartStreamOptions options,
unsigned int  numPlaybackChannels,
unsigned int  numCaptureChannels,
sampleFormat  captureFormat 
)
private

Opens the portaudio stream(s) used to do playback or recording (or both) through.

The sampleRate passed is the Project Rate of the active project. It may or may not be actually supported by playback or recording hardware currently in use (for many reasons). The number of Capture and Playback channels requested includes an allocation for doing software playthrough if necessary. The captureFormat is used for recording only, the playback being floating point always. Returns true if the stream opened successfully and false if it did not.

Definition at line 762 of file AudioIO.cpp.

766 {
767  auto sampleRate = options.rate;
768  mNumPauseFrames = 0;
769  mOwningProject = options.pProject;
770 
771  // PRL: Protection from crash reported by David Bailes, involving starting
772  // and stopping with frequent changes of active window, hard to reproduce
773  if (!mOwningProject)
774  return false;
775 
776  mInputMeter.reset();
777  mOutputMeter.reset();
778 
779  mLastPaError = paNoError;
780  // pick a rate to do the audio I/O at, from those available. The project
781  // rate is suggested, but we may get something else if it isn't supported
782  mRate = GetBestRate(numCaptureChannels > 0, numPlaybackChannels > 0, sampleRate);
783 
784  // July 2016 (Carsten and Uwe)
785  // BUG 193: Tell PortAudio sound card will handle 24 bit (under DirectSound) using
786  // userData.
787  int captureFormat_saved = captureFormat;
788  // Special case: Our 24-bit sample format is different from PortAudio's
789  // 3-byte packed format. So just make PortAudio return float samples,
790  // since we need float values anyway to apply the gain.
791  // ANSWER-ME: So we *never* actually handle 24-bit?! This causes mCapture to
792  // be set to floatSample below.
793  // JKC: YES that's right. Internally Audacity uses float, and float has space for
794  // 24 bits as well as exponent. Actual 24 bit would require packing and
795  // unpacking unaligned bytes and would be inefficient.
796  // ANSWER ME: is floatSample 64 bit on 64 bit machines?
797  if (captureFormat == int24Sample)
798  captureFormat = floatSample;
799 
800  mNumPlaybackChannels = numPlaybackChannels;
801  mNumCaptureChannels = numCaptureChannels;
802 
803  bool usePlayback = false, useCapture = false;
804  PaStreamParameters playbackParameters{};
805  PaStreamParameters captureParameters{};
806 
807  auto latencyDuration = AudioIOLatencyDuration.Read();
808 
809  if( numPlaybackChannels > 0)
810  {
811  usePlayback = true;
812 
813  // this sets the device index to whatever is "right" based on preferences,
814  // then defaults
815  playbackParameters.device = getPlayDevIndex();
816 
817  const PaDeviceInfo *playbackDeviceInfo;
818  playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
819 
820  if( playbackDeviceInfo == NULL )
821  return false;
822 
823  // regardless of source formats, we always mix to float
824  playbackParameters.sampleFormat = paFloat32;
825  playbackParameters.hostApiSpecificStreamInfo = NULL;
826  playbackParameters.channelCount = mNumPlaybackChannels;
827 
829  playbackParameters.suggestedLatency =
830  playbackDeviceInfo->defaultLowOutputLatency;
831  else {
832  // When using WASAPI, the suggested latency does not affect
833  // the latency of the playback, but the position of playback is given as if
834  // there was the suggested latency. This results in the last "suggested latency"
835  // of a selection not being played. So for WASAPI use 0.0 for the suggested
836  // latency regardless of user setting. See bug 1949.
837  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
838  bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
839  playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
840  }
841 
842  mOutputMeter = options.playbackMeter;
843  }
844 
845  if( numCaptureChannels > 0)
846  {
847  useCapture = true;
848  mCaptureFormat = captureFormat;
849 
850  const PaDeviceInfo *captureDeviceInfo;
851  // retrieve the index of the device set in the prefs, or a sensible
852  // default if it isn't set/valid
853  captureParameters.device = getRecordDevIndex();
854 
855  captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
856 
857  if( captureDeviceInfo == NULL )
858  return false;
859 
860  captureParameters.sampleFormat =
862 
863  captureParameters.hostApiSpecificStreamInfo = NULL;
864  captureParameters.channelCount = mNumCaptureChannels;
865 
867  captureParameters.suggestedLatency =
868  captureDeviceInfo->defaultHighInputLatency;
869  else
870  captureParameters.suggestedLatency = latencyDuration/1000.0;
871 
873  }
874 
875  SetMeters();
876 
877 #ifdef USE_PORTMIXER
878 #ifdef __WXMSW__
879  //mchinen nov 30 2010. For some reason Pa_OpenStream resets the input volume on windows.
880  //so cache and restore after it.
881  //The actual problem is likely in portaudio's pa_win_wmme.c OpenStream().
882  float oldRecordVolume = Px_GetInputVolume(mPortMixer);
883 #endif
884 #endif
885 
886  // July 2016 (Carsten and Uwe)
887  // BUG 193: Possibly tell portAudio to use 24 bit with DirectSound.
888  int userData = 24;
889  int* lpUserData = (captureFormat_saved == int24Sample) ? &userData : NULL;
890 
891  // (Linux, bug 1885) After scanning devices it takes a little time for the
892  // ALSA device to be available, so allow retries.
893  // On my test machine, no more than 3 attempts are required.
894  unsigned int maxTries = 1;
895 #ifdef __WXGTK__
897  maxTries = 5;
898 #endif
899 
900  for (unsigned int tries = 0; tries < maxTries; tries++) {
901  mLastPaError = Pa_OpenStream( &mPortStreamV19,
902  useCapture ? &captureParameters : NULL,
903  usePlayback ? &playbackParameters : NULL,
904  mRate, paFramesPerBufferUnspecified,
905  paNoFlag,
906  audacityAudioCallback, lpUserData );
907  if (mLastPaError == paNoError) {
908  break;
909  }
910  wxLogDebug("Attempt %u to open capture stream failed with: %d", 1 + tries, mLastPaError);
911  wxMilliSleep(1000);
912  }
913 
914 
915 #if USE_PORTMIXER
916 #ifdef __WXMSW__
917  Px_SetInputVolume(mPortMixer, oldRecordVolume);
918 #endif
919  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
920 
921  #ifdef __WXMAC__
922  if (mPortMixer) {
923  if (Px_SupportsPlaythrough(mPortMixer)) {
924  bool playthrough = false;
925 
926  mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
927 
928  // Bug 388. Feature not supported.
929  //gPrefs->Read(wxT("/AudioIO/Playthrough"), &playthrough, false);
930  if (playthrough)
931  Px_SetPlaythrough(mPortMixer, 1.0);
932  else
933  Px_SetPlaythrough(mPortMixer, 0.0);
934  }
935  }
936  #endif
937  }
938 #endif
939 
940 #if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
941  // Don't want the system to sleep while audio I/O is active
942  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
943  wxPowerResource::Acquire(wxPOWER_RESOURCE_SCREEN, _("Audacity Audio"));
944  }
945 #endif
946 
947  return (mLastPaError == paNoError);
948 }

References _, audacityAudioCallback(), AudacityToPortAudioSampleFormat(), AudioIOLatencyDuration, AudioIOStartStreamOptions::captureMeter, floatSample, GetBestRate(), AudioIOBase::getPlayDevIndex(), AudioIOBase::getRecordDevIndex(), DeviceManager::GetTimeSinceRescan(), DeviceManager::Instance(), int24Sample, AudioIoCallback::mCaptureFormat, AudioIOBase::mInputMeter, AudioIoCallback::mLastPaError, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPauseFrames, AudioIoCallback::mNumPlaybackChannels, AudioIOBase::mOutputMeter, AudioIOBase::mOwningProject, AudioIOBase::mPortStreamV19, AudioIOBase::mRate, AudioIoCallback::mSoftwarePlaythrough, AudioIOStartStreamOptions::playbackMeter, AudioIOStartStreamOptions::pProject, AudioIOStartStreamOptions::rate, Setting< T >::Read(), AudioIOBase::SetCaptureMeter(), and SetMeters().

Referenced by StartMonitoring(), and StartStream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ StartStream()

int AudioIO::StartStream ( const TransportTracks tracks,
double  t0,
double  t1,
const AudioIOStartStreamOptions options 
)

Start recording or playing back audio.

Allocates buffers for recording and playback, gets the Audio thread to fill them, and sets the stream rolling. If successful, returns a token identifying this particular stream instance. For use with IsStreamActive()

Definition at line 1005 of file AudioIO.cpp.

1008 {
1009  mLostSamples = 0;
1010  mLostCaptureIntervals.clear();
1011  mDetectDropouts =
1012  gPrefs->Read( WarningDialogKey(wxT("DropoutDetected")), true ) != 0;
1013  auto cleanup = finally ( [this] { ClearRecordingException(); } );
1014 
1015  if( IsBusy() )
1016  return 0;
1017 
1018  // We just want to set mStreamToken to -1 - this way avoids
1019  // an extremely rare but possible race condition, if two functions
1020  // somehow called StartStream at the same time...
1021  mStreamToken--;
1022  if (mStreamToken != -1)
1023  return 0;
1024 
1025  // TODO: we don't really need to close and reopen stream if the
1026  // format matches; however it's kind of tricky to keep it open...
1027  //
1028  // if (sampleRate == mRate &&
1029  // playbackChannels == mNumPlaybackChannels &&
1030  // captureChannels == mNumCaptureChannels &&
1031  // captureFormat == mCaptureFormat) {
1032 
1033  if (mPortStreamV19) {
1034  StopStream();
1035  while(mPortStreamV19)
1036  wxMilliSleep( 50 );
1037  }
1038 
1039 #ifdef __WXGTK__
1040  // Detect whether ALSA is the chosen host, and do the various involved MIDI
1041  // timing compensations only then.
1042  mUsingAlsa = (AudioIOHost.Read() == L"ALSA");
1043 #endif
1044 
1045  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
1046  gPrefs->Read(wxT("/AudioIO/SoundActivatedRecord"), &mPauseRec, false);
1047  gPrefs->Read(wxT("/AudioIO/Microfades"), &mbMicroFades, false);
1048  int silenceLevelDB;
1049  gPrefs->Read(wxT("/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
1050  int dBRange = DecibelScaleCutoff.Read();
1051  if(silenceLevelDB < -dBRange)
1052  {
1053  silenceLevelDB = -dBRange + 3;
1054  // meter range was made smaller than SilenceLevel
1055  // so set SilenceLevel reasonable
1056 
1057  // PRL: update prefs, or correct it only in-session?
1058  // The behavior (as of 2.3.1) was the latter, the code suggested that
1059  // the intent was the former; I preserve the behavior, but uncomment
1060  // this if you disagree.
1061  // gPrefs->Write(wxT("/AudioIO/SilenceLevel"), silenceLevelDB);
1062  // gPrefs->Flush();
1063  }
1064  mSilenceLevel = DB_TO_LINEAR(silenceLevelDB); // meter goes -dBRange dB -> 0dB
1065 
1066  // Clamp pre-roll so we don't play before time 0
1067  const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
1068  mRecordingSchedule = {};
1069  mRecordingSchedule.mPreRoll = preRoll;
1071  AudioIOLatencyCorrection.Read() / 1000.0;
1072  mRecordingSchedule.mDuration = t1 - t0;
1073  if (options.pCrossfadeData)
1075 
1076  mListener = options.listener;
1077  mRate = options.rate;
1078 
1079  mSeek = 0;
1081  mCaptureTracks = tracks.captureTracks;
1083 
1084  bool commit = false;
1085  auto cleanupTracks = finally([&]{
1086  if (!commit) {
1087  // Don't keep unnecessary shared pointers to tracks
1088  mPlaybackTracks.clear();
1089  mCaptureTracks.clear();
1090  for(auto &ext : Extensions())
1091  ext.AbortOtherStream();
1092 
1093  // Don't cause a busy wait in the audio thread after stopping scrubbing
1095  }
1096  });
1097 
1098  mPlaybackBuffers.reset();
1099  mPlaybackMixers.reset();
1100  mCaptureBuffers.reset();
1101  mResample.reset();
1103 
1105  t0, t1, options, mCaptureTracks.empty() ? nullptr : &mRecordingSchedule );
1106  const bool scrubbing = mPlaybackSchedule.Interactive();
1107 
1108  unsigned int playbackChannels = 0;
1109  unsigned int captureChannels = 0;
1110  sampleFormat captureFormat = floatSample;
1111 
1112  auto pListener = GetListener();
1113 
1114  if (tracks.playbackTracks.size() > 0
1115  || tracks.otherPlayableTracks.size() > 0)
1116  playbackChannels = 2;
1117 
1119  playbackChannels = 2;
1120 
1121  if (tracks.captureTracks.size() > 0)
1122  {
1123  // For capture, every input channel gets its own track
1124  captureChannels = mCaptureTracks.size();
1125  // I don't deal with the possibility of the capture tracks
1126  // having different sample formats, since it will never happen
1127  // with the current code. This code wouldn't *break* if this
1128  // assumption was false, but it would be sub-optimal. For example,
1129  // if the first track was 16-bit and the second track was 24-bit,
1130  // we would set the sound card to capture in 16 bits and the second
1131  // track wouldn't get the benefit of all 24 bits the card is capable
1132  // of.
1133  captureFormat = mCaptureTracks[0]->GetSampleFormat();
1134 
1135  // Tell project that we are about to start recording
1136  if (pListener)
1137  pListener->OnAudioIOStartRecording();
1138  }
1139 
1140  bool successAudio;
1141 
1142  successAudio = StartPortAudioStream(options, playbackChannels,
1143  captureChannels, captureFormat);
1144 #ifdef EXPERIMENTAL_MIDI_OUT
1145  auto range = Extensions();
1146  successAudio = successAudio &&
1147  std::all_of(range.begin(), range.end(),
1148  [this, &tracks, t0](auto &ext){
1149  return ext.StartOtherStream( tracks,
1150  (mPortStreamV19 != NULL && mLastPaError == paNoError)
1151  ? Pa_GetStreamInfo(mPortStreamV19) : nullptr,
1152  t0, mRate ); });
1153 #endif
1154 
1155  if (!successAudio) {
1156  if (pListener && captureChannels > 0)
1157  pListener->OnAudioIOStopRecording();
1158  mStreamToken = 0;
1159 
1160  return 0;
1161  }
1162 
1163  if ( ! AllocateBuffers( options, tracks, t0, t1, options.rate, scrubbing ) )
1164  return 0;
1165 
1166  if (mNumPlaybackChannels > 0)
1167  {
1168  auto & em = RealtimeEffectManager::Get();
1169  // Setup for realtime playback at the rate of the realtime
1170  // stream, not the rate of the track.
1171  em.RealtimeInitialize(mRate);
1172 
1173  // The following adds a NEW effect processor for each logical track and the
1174  // group determination should mimic what is done in audacityAudioCallback()
1175  // when calling RealtimeProcess().
1176  int group = 0;
1177  for (size_t i = 0, cnt = mPlaybackTracks.size(); i < cnt;)
1178  {
1179  const WaveTrack *vt = mPlaybackTracks[i].get();
1180 
1181  // TODO: more-than-two-channels
1182  unsigned chanCnt = TrackList::Channels(vt).size();
1183  i += chanCnt;
1184 
1185  // Setup for realtime playback at the rate of the realtime
1186  // stream, not the rate of the track.
1187  em.RealtimeAddProcessor(group++, std::min(2u, chanCnt), mRate);
1188  }
1189  }
1190 
1191 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1192  AILASetStartTime();
1193 #endif
1194 
1195  if (options.pStartTime)
1196  {
1197  // Calculate the NEW time position
1198  const auto time = mPlaybackSchedule.ClampTrackTime( *options.pStartTime );
1199 
1200  // Main thread's initialization of mTime
1202 
1203  // Reset mixer positions for all playback tracks
1204  unsigned numMixers = mPlaybackTracks.size();
1205  for (unsigned ii = 0; ii < numMixers; ++ii)
1206  mPlaybackMixers[ii]->Reposition( time );
1208  }
1209 
1210  // Now that we are done with SetTrackTime():
1215  // else recording only without overdub
1216 
1217 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1218  if (scrubbing)
1219  {
1220  const auto &scrubOptions = *options.pScrubbingOptions;
1221  mScrubState =
1222  std::make_unique<ScrubState>(
1224  mRate,
1225  scrubOptions);
1226  mScrubDuration = 0;
1227  mSilentScrub = false;
1228  }
1229  else
1230  mScrubState.reset();
1231 #endif
1232 
1233  // We signal the audio thread to call TrackBufferExchange, to prime the RingBuffers
1234  // so that they will have data in them when the stream starts. Having the
1235  // audio thread call TrackBufferExchange here makes the code more predictable, since
1236  // TrackBufferExchange will ALWAYS get called from the Audio thread.
1238 
1240  auto interval = 50ull;
1241  if (options.playbackStreamPrimer) {
1242  interval = options.playbackStreamPrimer();
1243  }
1244  wxMilliSleep( interval );
1245  }
1246 
1247  if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) {
1248 
1249 #ifdef REALTIME_ALSA_THREAD
1250  // PRL: Do this in hope of less thread scheduling jitter in calls to
1251  // audacityAudioCallback.
1252  // Not needed to make audio playback work smoothly.
1253  // But needed in case we also play MIDI, so that the variable "offset"
1254  // in AudioIO::MidiTime() is a better approximation of the duration
1255  // between the call of audacityAudioCallback and the actual output of
1256  // the first audio sample.
1257  // (Which we should be able to determine from fields of
1258  // PaStreamCallbackTimeInfo, but that seems not to work as documented with
1259  // ALSA.)
1260  if (mUsingAlsa)
1261  // Perhaps we should do this only if also playing MIDI ?
1262  PaAlsa_EnableRealtimeScheduling( mPortStreamV19, 1 );
1263 #endif
1264 
1265  //
1266  // Generate a unique value each time, to be returned to
1267  // clients accessing the AudioIO API, so they can query if they
1268  // are the ones who have reserved AudioIO or not.
1269  //
1270  // It is important to set this before setting the portaudio stream in
1271  // motion -- otherwise it may play an unspecified number of leading
1272  // zeroes.
1274 
1275  // This affects the AudioThread (not the portaudio callback).
1276  // Probably not needed so urgently before portaudio thread start for usual
1277  // playback, since our ring buffers have been primed already with 4 sec
1278  // of audio, but then we might be scrubbing, so do it.
1280  mForceFadeOut.store(false, std::memory_order_relaxed);
1281 
1282  // Now start the PortAudio stream!
1283  PaError err;
1284  err = Pa_StartStream( mPortStreamV19 );
1285 
1286  if( err != paNoError )
1287  {
1288  mStreamToken = 0;
1290  if (pListener && mNumCaptureChannels > 0)
1291  pListener->OnAudioIOStopRecording();
1293  // PRL: PortAudio error messages are sadly not internationalized
1295  Verbatim( LAT1CTOWX(Pa_GetErrorText(err)) ) );
1296  return 0;
1297  }
1298  }
1299 
1300  // Update UI display only now, after all possibilities for error are past.
1301  if (pListener) {
1302  // advertise the chosen I/O sample rate to the UI
1303  pListener->OnAudioIORate((int)mRate);
1304  }
1305 
1306  if (mNumPlaybackChannels > 0)
1307  {
1308  wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
1309  e.SetEventObject(mOwningProject);
1310  e.SetInt(true);
1311  wxTheApp->ProcessEvent(e);
1312  }
1313 
1314  if (mNumCaptureChannels > 0)
1315  {
1316  wxCommandEvent e(EVT_AUDIOIO_CAPTURE);
1317  e.SetEventObject(mOwningProject);
1318  e.SetInt(true);
1319  wxTheApp->ProcessEvent(e);
1320  }
1321 
1322  commit = true;
1323  return mStreamToken;
1324 }

References AllocateBuffers(), AudacityMessageBox(), AudioIOHost, AudioIOLatencyCorrection, TransportTracks::captureTracks, TrackList::Channels(), PlaybackSchedule::ClampTrackTime(), AudioIoCallback::ClearRecordingException(), DB_TO_LINEAR(), DecibelScaleCutoff, AudioIoCallback::Extensions(), floatSample, RealtimeEffectManager::Get(), AudioIoCallback::GetListener(), PlaybackSchedule::GetTrackTime(), gPrefs, PlaybackSchedule::Init(), PlaybackSchedule::Interactive(), AudioIOBase::IsBusy(), LAT1CTOWX, AudioIOStartStreamOptions::listener, AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning, AudioIoCallback::mbMicroFades, AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, RecordingSchedule::mCrossfadeData, PlaybackSchedule::TimeQueue::mData, AudioIoCallback::mDetectDropouts, RecordingSchedule::mDuration, AudioIoCallback::mForceFadeOut, min(), AudioIoCallback::mLastRecordingOffset, PlaybackSchedule::TimeQueue::mLastTime, RecordingSchedule::mLatencyCorrection, AudioIoCallback::mListener, AudioIoCallback::mLostCaptureIntervals, AudioIoCallback::mLostSamples, AudioIoCallback::mNextStreamToken, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPlaybackChannels, AudioIOBase::mOwningProject, AudioIoCallback::mPauseRec, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIOBase::mPortStreamV19, RecordingSchedule::mPreRoll, AudioIOBase::mRate, AudioIoCallback::mRecordingSchedule, AudioIoCallback::mResample, AudioIoCallback::mSeek, AudioIoCallback::mSilenceLevel, AudioIoCallback::mSoftwarePlaythrough, AudioIOBase::mStreamToken, PlaybackSchedule::mT0, PlaybackSchedule::mTimeQueue, AudioIoCallback::mUsingAlsa, TransportTracks::otherPlayableTracks, AudioIOStartStreamOptions::pCrossfadeData, AudioIOStartStreamOptions::playbackStreamPrimer, TransportTracks::playbackTracks, AudioIOStartStreamOptions::preRoll, AudioIOStartStreamOptions::pStartTime, AudioIOStartStreamOptions::rate, Setting< T >::Read(), PlaybackSchedule::RealTimeInit(), PlaybackSchedule::ResetMode(), PlaybackSchedule::SetTrackTime(), StartPortAudioStream(), StartStreamCleanup(), StopStream(), Verbatim(), and WarningDialogKey().

Here is the call graph for this function:

◆ StartStreamCleanup()

void AudioIO::StartStreamCleanup ( bool  bOnlyBuffers = false)
private

Clean up after StartStream if it fails.

If bOnlyBuffers is specified, it only cleans up the buffers.

Definition at line 1561 of file AudioIO.cpp.

1562 {
1563  if (mNumPlaybackChannels > 0)
1564  {
1566  }
1567 
1568  mPlaybackBuffers.reset();
1569  mPlaybackMixers.reset();
1570  mCaptureBuffers.reset();
1571  mResample.reset();
1573 
1574  if(!bOnlyBuffers)
1575  {
1576  Pa_AbortStream( mPortStreamV19 );
1577  Pa_CloseStream( mPortStreamV19 );
1578  mPortStreamV19 = NULL;
1579  mStreamToken = 0;
1580  }
1581 
1582 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1583  mScrubState.reset();
1584 #endif
1585 }

References RealtimeEffectManager::Get(), AudioIoCallback::mCaptureBuffers, PlaybackSchedule::TimeQueue::mData, AudioIoCallback::mNumPlaybackChannels, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackSchedule, AudioIOBase::mPortStreamV19, AudioIoCallback::mResample, AudioIOBase::mStreamToken, PlaybackSchedule::mTimeQueue, and RealtimeEffectManager::RealtimeFinalize().

Referenced by AllocateBuffers(), and StartStream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ StopStream()

void AudioIO::StopStream ( )
overridevirtual

Stop recording, playback or input monitoring.

Does quite a bit of housekeeping, including switching off monitoring, flushing recording buffers out to wave tracks, and applies latency correction to recorded tracks if necessary

Implements AudioIOBase.

Definition at line 1602 of file AudioIO.cpp.

1603 {
1604  auto cleanup = finally ( [this] {
1606  mRecordingSchedule.mCrossfadeData.clear(); // free arrays
1607  } );
1608 
1609  if( mPortStreamV19 == NULL )
1610  return;
1611 
1612  // DV: This code seems to be unnecessary.
1613  // We do not leave mPortStreamV19 open in stopped
1614  // state. (Do we?)
1615  // This breaks WASAPI backend, as it sets the `running`
1616  // flag to `false` asynchronously.
1617  // Previously we have patched PortAudio and the patch
1618  // was breaking IsStreamStopped() == !IsStreamActive()
1619  // invariant.
1620  /*
1621  if ( Pa_IsStreamStopped(mPortStreamV19) )
1622  return;
1623  */
1624 
1625 #if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1626  // Re-enable system sleep
1627  wxPowerResource::Release(wxPOWER_RESOURCE_SCREEN);
1628 #endif
1629 
1631  {
1632  // PortAudio callback can use the information that we are stopping to fade
1633  // out the audio. Give PortAudio callback a chance to do so.
1634  mForceFadeOut.store(true, std::memory_order_relaxed);
1635  auto latency = static_cast<long>(AudioIOLatencyDuration.Read());
1636  // If we can gracefully fade out in 200ms, with the faded-out play buffers making it through
1637  // the sound card, then do so. If we can't, don't wait around. Just stop quickly and accept
1638  // there will be a click.
1639  if( mbMicroFades && (latency < 150 ))
1640  wxMilliSleep( latency + 50);
1641  }
1642 
1643  wxMutexLocker locker(mSuspendAudioThread);
1644 
1645  // No longer need effects processing
1646  if (mNumPlaybackChannels > 0)
1647  {
1649  }
1650 
1651  //
1652  // We got here in one of two ways:
1653  //
1654  // 1. The user clicked the stop button and we therefore want to stop
1655  // as quickly as possible. So we use AbortStream(). If this is
1656  // the case the portaudio stream is still in the Running state
1657  // (see PortAudio state machine docs).
1658  //
1659  // 2. The callback told PortAudio to stop the stream since it had
1660  // reached the end of the selection. The UI thread discovered
1661  // this by noticing that AudioIO::IsActive() returned false.
1662  // IsActive() (which calls Pa_GetStreamActive()) will not return
1663  // false until all buffers have finished playing, so we can call
1664  // AbortStream without losing any samples. If this is the case
1665  // we are in the "callback finished state" (see PortAudio state
1666  // machine docs).
1667  //
1668  // The moral of the story: We can call AbortStream safely, without
1669  // losing samples.
1670  //
1671  // DMM: This doesn't seem to be true; it seems to be necessary to
1672  // call StopStream if the callback brought us here, and AbortStream
1673  // if the user brought us here.
1674  //
1675  // DV: Seems that Pa_CloseStream calls Pa_AbortStream internally,
1676  // at least for PortAudio 19.7.0+
1677 
1679 
1680  // Audacity can deadlock if it tries to update meters while
1681  // we're stopping PortAudio (because the meter updating code
1682  // tries to grab a UI mutex while PortAudio tries to join a
1683  // pthread). So we tell the callback to stop updating meters,
1684  // and wait until the callback has left this part of the code
1685  // if it was already there.
1686  mUpdateMeters = false;
1687  while(mUpdatingMeters) {
1688  ::wxSafeYield();
1689  wxMilliSleep( 50 );
1690  }
1691 
1692  // Turn off HW playthrough if PortMixer is being used
1693 
1694  #if defined(USE_PORTMIXER)
1695  if( mPortMixer ) {
1696  #if __WXMAC__
1697  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1698  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1699  mPreviousHWPlaythrough = -1.0;
1700  #endif
1701  }
1702  #endif
1703 
1704  if (mPortStreamV19) {
1705  // DV: Pa_CloseStream will close Pa_AbortStream internally,
1706  // but it doesn't hurt to do it ourselves.
1707  // PA_AbortStream will silently fail if stream is stopped.
1708  if (!Pa_IsStreamStopped( mPortStreamV19 ))
1709  Pa_AbortStream( mPortStreamV19 );
1710 
1711  Pa_CloseStream( mPortStreamV19 );
1712 
1713  mPortStreamV19 = NULL;
1714  }
1715 
1716  for( auto &ext : Extensions() )
1717  ext.StopOtherStream();
1718 
1719  auto pListener = GetListener();
1720 
1721  // If there's no token, we were just monitoring, so we can
1722  // skip this next part...
1723  if (mStreamToken > 0) {
1724  // In either of the above cases, we want to make sure that any
1725  // capture data that made it into the PortAudio callback makes it
1726  // to the target WaveTrack. To do this, we ask the audio thread to
1727  // call TrackBufferExchange one last time (it normally would not do so since
1728  // Pa_GetStreamActive() would now return false
1730 
1732  {
1733  // LLL: Experienced recursive yield here...once.
1734  wxTheApp->Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error.
1735  wxMilliSleep( 50 );
1736  }
1737 
1738  //
1739  // Everything is taken care of. Now, just free all the resources
1740  // we allocated in StartStream()
1741  //
1742 
1743  if (mPlaybackTracks.size() > 0)
1744  {
1745  mPlaybackBuffers.reset();
1746  mPlaybackMixers.reset();
1748  }
1749 
1750  //
1751  // Offset all recorded tracks to account for latency
1752  //
1753  if (mCaptureTracks.size() > 0)
1754  {
1755  mCaptureBuffers.reset();
1756  mResample.reset();
1757 
1758  //
1759  // We only apply latency correction when we actually played back
1760  // tracks during the recording. If we did not play back tracks,
1761  // there's nothing we could be out of sync with. This also covers the
1762  // case that we do not apply latency correction when recording the
1763  // first track in a project.
1764  //
1765 
1766  for (unsigned int i = 0; i < mCaptureTracks.size(); i++) {
1767  // The calls to Flush
1768  // may cause exceptions because of exhaustion of disk space.
1769  // Stop those exceptions here, or else they propagate through too
1770  // many parts of Audacity that are not effects or editing
1771  // operations. GuardedCall ensures that the user sees a warning.
1772 
1773  // Also be sure to Flush each track, at the top of the guarded call,
1774  // relying on the guarantee that the track will be left in a flushed
1775  // state, though the append buffer may be lost.
1776 
1777  GuardedCall( [&] {
1778  WaveTrack* track = mCaptureTracks[i].get();
1779 
1780  // use No-fail-guarantee that track is flushed,
1781  // Partial-guarantee that some initial length of the recording
1782  // is saved.
1783  // See comments in TrackBufferExchange().
1784  track->Flush();
1785  } );
1786  }
1787 
1788 
1789  if (!mLostCaptureIntervals.empty())
1790  {
1791  // This scope may combine many splittings of wave tracks
1792  // into one transaction, lessening the number of checkpoints
1794  if (mOwningProject) {
1795  auto &pIO = ProjectFileIO::Get(*mOwningProject);
1796  pScope.emplace(pIO.GetConnection(), "Dropouts");
1797  }
1798  for (auto &interval : mLostCaptureIntervals) {
1799  auto &start = interval.first;
1800  auto duration = interval.second;
1801  for (auto &track : mCaptureTracks) {
1802  GuardedCall([&] {
1803  track->SyncLockAdjust(start, start + duration);
1804  });
1805  }
1806  }
1807  if (pScope)
1808  pScope->Commit();
1809  }
1810 
1811  if (pListener)
1812  pListener->OnCommitRecording();
1813  }
1814  }
1815 
1816  if (auto pInputMeter = mInputMeter.lock())
1817  pInputMeter->Reset(mRate, false);
1818 
1819  if (auto pOutputMeter = mOutputMeter.lock())
1820  pOutputMeter->Reset(mRate, false);
1821 
1822  mInputMeter.reset();
1823  mOutputMeter.reset();
1824  mOwningProject = nullptr;
1825 
1826  if (pListener && mNumCaptureChannels > 0)
1827  pListener->OnAudioIOStopRecording();
1828 
1829  wxTheApp->CallAfter([this]{
1831  // Recording was restarted between StopStream and idle time
1832  // So the actions can keep waiting
1833  return;
1834  // In case some other thread was waiting on the mutex too:
1835  std::this_thread::yield();
1836  std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
1837  if (mPostRecordingAction) {
1839  mPostRecordingAction = {};
1840  }
1841  DelayActions(false);
1842  });
1843 
1844  //
1845  // Only set token to 0 after we're totally finished with everything
1846  //
1847  bool wasMonitoring = mStreamToken == 0;
1848  mStreamToken = 0;
1849 
1850  if (mNumPlaybackChannels > 0)
1851  {
1852  wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
1853  e.SetEventObject(mOwningProject);
1854  e.SetInt(false);
1855  wxTheApp->ProcessEvent(e);
1856  }
1857 
1858  if (mNumCaptureChannels > 0)
1859  {
1860  wxCommandEvent e(wasMonitoring ? EVT_AUDIOIO_MONITOR : EVT_AUDIOIO_CAPTURE);
1861  e.SetEventObject(mOwningProject);
1862  e.SetInt(false);
1863  wxTheApp->ProcessEvent(e);
1864  }
1865 
1866  mNumCaptureChannels = 0;
1868 
1869  mPlaybackTracks.clear();
1870  mCaptureTracks.clear();
1871 
1872 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1873  mScrubState.reset();
1874 #endif
1875 
1876  if (pListener) {
1877  // Tell UI to hide sample rate
1878  pListener->OnAudioIORate(0);
1879  }
1880 
1881  // Don't cause a busy wait in the audio thread after stopping scrubbing
1883 }

References AudioIOLatencyDuration, AudioIoCallback::ClearRecordingException(), TransactionScope::Commit(), DelayActions(), Optional< X >::emplace(), AudioIoCallback::Extensions(), WaveTrack::Flush(), RealtimeEffectManager::Get(), ProjectFileIO::Get(), AudioIoCallback::GetListener(), GuardedCall(), AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning, AudioIoCallback::mbMicroFades, AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, RecordingSchedule::mCrossfadeData, PlaybackSchedule::TimeQueue::mData, AudioIoCallback::mForceFadeOut, AudioIOBase::mInputMeter, AudioIoCallback::mLostCaptureIntervals, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPlaybackChannels, AudioIOBase::mOutputMeter, AudioIOBase::mOwningProject, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIOBase::mPortStreamV19, mPostRecordingAction, mPostRecordingActionMutex, AudioIOBase::mRate, AudioIoCallback::mRecordingSchedule, AudioIoCallback::mResample, AudioIOBase::mStreamToken, AudioIoCallback::mSuspendAudioThread, PlaybackSchedule::mTimeQueue, AudioIoCallback::mUpdateMeters, AudioIoCallback::mUpdatingMeters, Setting< T >::Read(), RealtimeEffectManager::RealtimeFinalize(), KeyboardCapture::Release(), and PlaybackSchedule::ResetMode().

Referenced by DrainRecordBuffers(), and StartStream().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TrackBufferExchange()

void AudioIO::TrackBufferExchange ( )
private

Called in a loop from another worker thread that does not have the low-latency constraints of the PortAudio callback thread. Does less frequent and larger batches of work that may include memory allocations and database operations. RingBuffer objects mediate the transfer between threads, to overcome the mismatch of their batch sizes.

Definition at line 2090 of file AudioIO.cpp.

2091 {
2092  FillPlayBuffers();
2094 }

References DrainRecordBuffers(), and FillPlayBuffers().

Referenced by AudioThread::Entry().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ValidateDeviceNames()

bool AudioIO::ValidateDeviceNames ( const wxString &  play,
const wxString &  rec 
)
static

Ensure selected device names are valid.

Definition at line 539 of file AudioIO.cpp.

540 {
541  const PaDeviceInfo *pInfo = Pa_GetDeviceInfo(getPlayDevIndex(play));
542  const PaDeviceInfo *rInfo = Pa_GetDeviceInfo(getRecordDevIndex(rec));
543 
544  // Valid iff both defined and the same api.
545  return pInfo != nullptr && rInfo != nullptr && pInfo->hostApi == rInfo->hostApi;
546 }

References AudioIOBase::getPlayDevIndex(), and AudioIOBase::getRecordDevIndex().

Here is the call graph for this function:

Friends And Related Function Documentation

◆ AudioThread

friend class AudioThread
friend

Definition at line 530 of file AudioIO.h.

Member Data Documentation

◆ mDelayingActions

bool AudioIO::mDelayingActions { false }
private

Definition at line 618 of file AudioIO.h.

Referenced by DelayActions(), and DelayingActions().

◆ mPostRecordingAction

PostRecordingAction AudioIO::mPostRecordingAction
private

Definition at line 617 of file AudioIO.h.

Referenced by CallAfterRecording(), and StopStream().

◆ mPostRecordingActionMutex

std::mutex AudioIO::mPostRecordingActionMutex
private

Definition at line 616 of file AudioIO.h.

Referenced by CallAfterRecording(), and StopStream().


The documentation for this class was generated from the following files:
AudioIORecordingDevice
StringSetting AudioIORecordingDevice
Definition: AudioIOBase.cpp:974
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
AudioIoCallback::mPlaybackQueueMinimum
size_t mPlaybackQueueMinimum
Occupancy of the queue we try to maintain, with bigger batches if needed.
Definition: AudioIO.h:271
AudioIOLatencyCorrection
DoubleSetting AudioIOLatencyCorrection
Definition: AudioIOBase.cpp:966
Optional::emplace
X & emplace(Args &&... args)
Definition: MemoryX.h:193
AudioIOPlaybackDevice
StringSetting AudioIOPlaybackDevice
Definition: AudioIOBase.cpp:970
AudioIoCallback::mCaptureFormat
sampleFormat mCaptureFormat
Definition: AudioIO.h:280
ClearSamples
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
Definition: SampleFormat.cpp:77
RecordingSchedule::mLatencyCorrection
double mLatencyCorrection
Definition: PlaybackSchedule.h:130
WaveTrackConstArray
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:49
TransportTracks::playbackTracks
WaveTrackArray playbackTracks
Definition: AudioIO.h:65
WaveTrack::Flush
void Flush()
Flush must be called after last Append.
Definition: WaveTrack.cpp:1699
SampleBuffer::Allocate
SampleBuffer & Allocate(size_t count, sampleFormat format)
Definition: SampleFormat.h:84
AudioIOStartStreamOptions::playbackMeter
std::weak_ptr< Meter > playbackMeter
Definition: AudioIOBase.h:88
AudioIoCallback::mPlaybackTracks
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:256
AudioIOStartStreamOptions::rate
double rate
Definition: AudioIOBase.h:91
ProjectFramePlacement
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
Definition: ProjectWindows.cpp:101
AudioIoCallback::mbMicroFades
bool mbMicroFades
Definition: AudioIO.h:262
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
RecordingSchedule::mPosition
double mPosition
Definition: PlaybackSchedule.h:136
AudioIOBase::DeviceName
static wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:71
GuardedCall
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), std::function< void(AudacityException *)> delayedHandler=DefaultDelayedHandlerAction{})
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
Definition: AudacityException.h:202
AudioIO::AllocateBuffers
bool AllocateBuffers(const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate, bool scrubbing)
Allocate RingBuffer structures, and others, needed for playback and recording.
Definition: AudioIO.cpp:1364
DB_TO_LINEAR
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:551
AudioIoCallback::mForceFadeOut
std::atomic< bool > mForceFadeOut
Definition: AudioIO.h:286
AudioIO::LastPaErrorString
wxString LastPaErrorString()
Definition: AudioIO.cpp:950
PlaybackSchedule::SetTrackTime
void SetTrackTime(double time)
Set current track time value, unadjusted.
Definition: PlaybackSchedule.h:268
AudioIOStartStreamOptions::listener
std::shared_ptr< AudioIOListener > listener
Definition: AudioIOBase.h:90
Optional
Like a smart pointer, allows for object to not exist (nullptr)
Definition: MemoryX.h:144
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
AudioIO::RepositionPlayback
bool RepositionPlayback(size_t frames, size_t available, bool progress)
FillPlayBuffers calls this to update its cursors into tracks for changes of position or speed.
Definition: AudioIO.cpp:2230
AudioIoCallback::mThread
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:250
AudioIOBase::mOwningProject
AudacityProject * mOwningProject
Definition: AudioIOBase.h:282
ScrubbingOptions::MaxAllowedScrubSpeed
static double MaxAllowedScrubSpeed()
Definition: AudioIOBase.h:66
KeyboardCapture::Release
void Release(wxWindow *handler)
Definition: KeyboardCapture.cpp:75
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
AudioIOBase::mPortStreamV19
PaStream * mPortStreamV19
Definition: AudioIOBase.h:292
AudacityToPortAudioSampleFormat
static PaSampleFormat AudacityToPortAudioSampleFormat(sampleFormat format)
Definition: AudioIO.cpp:749
BasicUI::ShowErrorDialog
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:233
TransportTracks::captureTracks
WaveTrackArray captureTracks
Definition: AudioIO.h:66
AudioIoCallback::mNumPlaybackChannels
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:279
AudioIOBase::mInputMixerWorks
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIOBase.h:310
AudioIoCallback::mNumCaptureChannels
unsigned int mNumCaptureChannels
Definition: AudioIO.h:278
PlaybackSchedule::mT0
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: PlaybackSchedule.h:148
AudioIOBase::getPlayDevIndex
static int getPlayDevIndex(const wxString &devName={})
get the index of the device selected in the preferences.
Definition: AudioIOBase.cpp:595
PlaybackSchedule::mWarpedTime
double mWarpedTime
Definition: PlaybackSchedule.h:160
Mixer::WarpOptions
Definition: Mix.h:81
Setting::Write
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:172
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1484
AudioIO::GetBestRate
double GetBestRate(bool capturing, bool playing, double sampleRate)
Return a valid sample rate that is supported by the current I/O device(s).
Definition: AudioIO.cpp:1929
AudioIoCallback::mUpdatingMeters
volatile bool mUpdatingMeters
Definition: AudioIO.h:296
ArrayOf::reinit
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
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:650
AudioIoCallback::mPlaybackSamplesToCopy
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
Definition: AudioIO.h:269
XO
#define XO(s)
Definition: Internat.h:31
AudioIO::GetPlaybackSlice
PlaybackSlice GetPlaybackSlice(size_t available)
Called one or more times by FillPlayBuffers.
Definition: AudioIO.cpp:2179
ProjectFileIO::Get
static ProjectFileIO & Get(AudacityProject &project)
Definition: ProjectFileIO.cpp:265
PlaybackSchedule::TimeQueue::mSize
size_t mSize
Definition: PlaybackSchedule.h:197
PlaybackSchedule::PlayingStraight
bool PlayingStraight() const
Definition: PlaybackSchedule.h:294
AudioIOBase::IsStreamActive
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIOBase.cpp:354
AudioIO::DelayActions
void DelayActions(bool recording)
Definition: AudioIO.cpp:1326
int24Sample
@ int24Sample
Definition: SampleFormat.h:33
ScrubbingOptions::MinAllowedScrubSpeed
static double MinAllowedScrubSpeed()
Definition: AudioIOBase.h:68
AudioIOStartStreamOptions::preRoll
double preRoll
Definition: AudioIOBase.h:96
PlaybackSchedule::Init
void Init(double t0, double t1, const AudioIOStartStreamOptions &options, const RecordingSchedule *pRecordingSchedule)
Definition: PlaybackSchedule.cpp:16
AudioIoCallback::mPlaybackBuffers
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:255
PlaybackSchedule::TimeQueue::mLastTime
double mLastTime
Definition: PlaybackSchedule.h:198
PlaybackSchedule::NormalizeTrackTime
double NormalizeTrackTime() const
Normalizes mTime, clamping it and handling gaps from cut preview.
Definition: PlaybackSchedule.cpp:99
PlaybackSchedule::Interactive
bool Interactive() const
Definition: PlaybackSchedule.h:298
AudioIOStartStreamOptions::captureMeter
std::weak_ptr< Meter > captureMeter
Definition: AudioIOBase.h:88
AudioIoCallback::mUpdateMeters
bool mUpdateMeters
Definition: AudioIO.h:295
AudioIoCallback::mDetectDropouts
bool mDetectDropouts
Definition: AudioIO.h:333
AudioIoCallback::mRecordingException
wxAtomicInt mRecordingException
Definition: AudioIO.h:326
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:382
AudioIO::GetNumCaptureChannels
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:486
AudioIOBase::ugAudioIO
static std::unique_ptr< AudioIOBase > ugAudioIO
Definition: AudioIOBase.h:278
RecordingSchedule::TotalCorrection
double TotalCorrection() const
Definition: PlaybackSchedule.h:139
TransportTracks::otherPlayableTracks
PlayableTrackConstArray otherPlayableTracks
Definition: AudioIO.h:67
PlaybackSchedule::Looping
bool Looping() const
Definition: PlaybackSchedule.h:295
AudioIOBase::IsBusy
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIOBase.cpp:346
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
AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce
volatile bool mAudioThreadShouldCallTrackBufferExchangeOnce
Definition: AudioIO.h:282
AudioIO::mDelayingActions
bool mDelayingActions
Definition: AudioIO.h:618
AudioIOLatencyDuration
DoubleSetting AudioIOLatencyDuration
Definition: AudioIOBase.cpp:968
floatSample
@ floatSample
Definition: SampleFormat.h:34
AudioIoCallback::Extensions
AudioIOExtRange Extensions()
Definition: AudioIO.h:155
AudacityException
Base class for exceptions specially processed by the application.
Definition: AudacityException.h:33
AudioIO::mPostRecordingAction
PostRecordingAction mPostRecordingAction
Definition: AudioIO.h:617
RecordingSchedule::ToConsume
double ToConsume() const
Definition: PlaybackSchedule.cpp:252
AudioIoCallback::mSoftwarePlaythrough
bool mSoftwarePlaythrough
Definition: AudioIO.h:274
WaveTrack::SyncLockAdjust
void SyncLockAdjust(double oldT1, double newT1) override
Definition: WaveTrack.cpp:1218
PlaybackSchedule::ResetMode
void ResetMode()
Definition: PlaybackSchedule.h:292
AudioIOBase::mPaused
bool mPaused
True if audio playback is paused.
Definition: AudioIOBase.h:285
AudioIOBase::SetCaptureMeter
void SetCaptureMeter(AudacityProject *project, const std::weak_ptr< Meter > &meter)
Definition: AudioIOBase.cpp:309
sampleCount::as_double
double as_double() const
Definition: SampleCount.h:45
AudioIoCallback::mPauseRec
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:276
RealtimeEffectManager::RealtimeFinalize
void RealtimeFinalize()
Definition: RealtimeEffectManager.cpp:197
AudioIoCallback::mCaptureBuffers
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:253
AudioIO::GetCommonlyAvailCapture
size_t GetCommonlyAvailCapture()
Get the number of audio samples ready in all of the recording buffers.
Definition: AudioIO.cpp:2078
AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning
volatile bool mAudioThreadTrackBufferExchangeLoopRunning
Definition: AudioIO.h:283
AudioIOBase::mMixerOutputVol
float mMixerOutputVol
Definition: AudioIOBase.h:311
AudioIoCallback::mLastPlaybackTimeMillis
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:288
AudioIOBase::mInputMeter
std::weak_ptr< Meter > mInputMeter
Definition: AudioIOBase.h:294
PlaybackSchedule::ClampTrackTime
double ClampTrackTime(double trackTime) const
Clamps argument to be between mT0 and mT1.
Definition: PlaybackSchedule.cpp:91
PaError
int PaError
Definition: AudioIO.h:53
AudioIoCallback::mRecordingSchedule
RecordingSchedule mRecordingSchedule
Definition: AudioIO.h:348
RecordingSchedule::mCrossfadeData
PRCrossfadeData mCrossfadeData
Definition: PlaybackSchedule.h:132
PlaybackSchedule::mTimeQueue
struct PlaybackSchedule::TimeQueue mTimeQueue
format
int format
Definition: ExportPCM.cpp:56
DeviceManager::GetTimeSinceRescan
float GetTimeSinceRescan()
Definition: DeviceManager.cpp:308
AudioIoCallback::mLostSamples
unsigned long long mLostSamples
Definition: AudioIO.h:281
AudioIOBase::Get
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:89
AudioIoCallback::mPlaybackMixers
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:258
AudioIOBase::mRate
double mRate
Audio playback rate in samples per second.
Definition: AudioIOBase.h:290
AudioIoCallback::mSuspendAudioThread
wxMutex mSuspendAudioThread
Definition: AudioIO.h:311
AudioIoCallback::mLastRecordingOffset
volatile double mLastRecordingOffset
Definition: AudioIO.h:290
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:516
AudioIOBase::SetMixer
void SetMixer(int inputSource)
Definition: AudioIOBase.cpp:98
BAD_STREAM_TIME
#define BAD_STREAM_TIME
Definition: AudioIOBase.h:38
PlaybackSchedule::PLAY_LOOPED
@ PLAY_LOOPED
Definition: PlaybackSchedule.h:218
AudioIOBase::HostName
static wxString HostName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:78
AudioIoCallback::mNextStreamToken
static int mNextStreamToken
Definition: AudioIO.h:259
AudioIoCallback::mCachedBestRateCapturing
static bool mCachedBestRateCapturing
Definition: AudioIO.h:307
audacityAudioCallback
int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
Definition: AudioIO.cpp:2707
AudioIO::StartPortAudioStream
bool StartPortAudioStream(const AudioIOStartStreamOptions &options, unsigned int numPlaybackChannels, unsigned int numCaptureChannels, sampleFormat captureFormat)
Opens the portaudio stream(s) used to do playback or recording (or both) through.
Definition: AudioIO.cpp:762
DecibelScaleCutoff
IntSetting DecibelScaleCutoff
Negation of this value is the lowest dB level that should be shown in dB scales.
Definition: Decibels.cpp:12
RealtimeEffectManager::Get
static RealtimeEffectManager & Get()
Definition: RealtimeEffectManager.cpp:43
RealtimeEffectManager::RealtimeSuspend
void RealtimeSuspend()
Definition: RealtimeEffectManager.cpp:217
BasicUI::ErrorDialogOptions
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:49
AudioIoCallback::ClearRecordingException
void ClearRecordingException()
Definition: AudioIO.h:329
SampleBuffer
Definition: SampleFormat.h:69
AudioIOStartStreamOptions::pStartTime
double * pStartTime
Definition: AudioIOBase.h:95
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
AudioIO::DelayingActions
bool DelayingActions() const
Definition: AudioIO.cpp:1331
LAT1CTOWX
#define LAT1CTOWX(X)
Definition: Internat.h:160
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
AudioIoCallback::mCaptureRingBufferSecs
double mCaptureRingBufferSecs
Definition: AudioIO.h:266
AudioIO::mPostRecordingActionMutex
std::mutex mPostRecordingActionMutex
Definition: AudioIO.h:616
PlaybackSchedule::TimeQueue::mData
ArrayOf< double > mData
Definition: PlaybackSchedule.h:196
BasicUI
Definition: Export.h:39
AudioIoCallback::GetCommonlyReadyPlayback
size_t GetCommonlyReadyPlayback()
Get the number of audio samples ready in all of the playback buffers.
Definition: AudioIO.cpp:2069
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
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:447
PlaybackSchedule::RealTimeAdvance
void RealTimeAdvance(double increment)
Definition: PlaybackSchedule.cpp:234
AudioIOStartStreamOptions::pCrossfadeData
PRCrossfadeData * pCrossfadeData
Definition: AudioIOBase.h:108
TimeQueueGrainSize
constexpr size_t TimeQueueGrainSize
Definition: PlaybackSchedule.h:22
AudioIoCallback::mUsingAlsa
bool mUsingAlsa
Definition: AudioIO.h:302
AudioIO::StartStreamCleanup
void StartStreamCleanup(bool bOnlyBuffers=false)
Clean up after StartStream if it fails.
Definition: AudioIO.cpp:1561
_
#define _(s)
Definition: Internat.h:75
AudioIoCallback::mSilenceLevel
float mSilenceLevel
Definition: AudioIO.h:277
sampleCount
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
QualitySettings::SampleFormatChoice
PROJECT_RATE_API sampleFormat SampleFormatChoice()
Definition: QualitySettings.cpp:38
AudioIoCallback::mSeek
double mSeek
Definition: AudioIO.h:264
AudioIO::StopStream
void StopStream() override
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:1602
AudioIOHost
StringSetting AudioIOHost
Definition: AudioIOBase.cpp:964
AudioIoCallback::mAudioThreadTrackBufferExchangeLoopActive
volatile bool mAudioThreadTrackBufferExchangeLoopActive
Definition: AudioIO.h:284
AudioIO::SetMeters
void SetMeters()
Set the current VU meters - this should be done once after each call to StartStream currently.
Definition: AudioIO.cpp:1592
WarningDialogKey
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Prefs.cpp:415
AudioIoCallback::mLostCaptureIntervals
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:332
AudioIoCallback::mCachedBestRatePlaying
static bool mCachedBestRatePlaying
Definition: AudioIO.h:306
DeviceManager::Instance
static DeviceManager * Instance()
Gets the singleton instance.
Definition: DeviceManager.cpp:35
AudioIOBase::mOutputMeter
std::weak_ptr< Meter > mOutputMeter
Definition: AudioIOBase.h:295
PlaybackSchedule::GetTrackTime
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: PlaybackSchedule.h:263
AudioIoCallback::mLastPaError
PaError mLastPaError
Definition: AudioIO.h:291
AudioIoCallback::GetListener
std::shared_ptr< AudioIOListener > GetListener() const
Definition: AudioIO.h:163
AudioIOBase::mCachedBestRateIn
static double mCachedBestRateIn
Definition: AudioIOBase.h:319
RealtimeEffectManager::RealtimeResume
void RealtimeResume()
Definition: RealtimeEffectManager.cpp:250
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
PlaybackSchedule::RealTimeInit
void RealTimeInit(double trackTime)
Definition: PlaybackSchedule.cpp:239
RecordingSchedule::ToDiscard
double ToDiscard() const
Definition: PlaybackSchedule.cpp:262
PlaybackSchedule::TimeQueue::mTail
NonInterfering< Cursor > mTail
Definition: PlaybackSchedule.h:204
AudioIoCallback::mResample
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:252
AudioIoCallback::mPlaybackSchedule
PlaybackSchedule mPlaybackSchedule
Definition: AudioIO.h:349
AudioIOBase::mStreamToken
volatile int mStreamToken
Definition: AudioIOBase.h:287
AudioIoCallback::mListener
std::weak_ptr< AudioIOListener > mListener
Definition: AudioIO.h:298
DefaultDelayedHandlerAction
A default template parameter for GuardedCall.
Definition: AudacityException.h:124
AudioIOStartStreamOptions::pProject
AudacityProject * pProject
Definition: AudioIOBase.h:87
AudioIO::FillPlayBuffers
void FillPlayBuffers()
First part of TrackBufferExchange.
Definition: AudioIO.cpp:2096
AudioIoCallback::mNumPauseFrames
long mNumPauseFrames
How many frames of zeros were output due to pauses?
Definition: AudioIO.h:231
AudioIO::GetCommonlyFreePlayback
size_t GetCommonlyFreePlayback()
Get the number of audio samples free in all of the playback buffers.
Definition: AudioIO.cpp:2058
AudioIOStartStreamOptions::playbackStreamPrimer
std::function< unsigned long() > playbackStreamPrimer
Definition: AudioIOBase.h:113
TransactionScope::Commit
bool Commit()
Definition: DBConnection.cpp:658
AudioIO
AudioIO uses the PortAudio library to play and record sound.
Definition: AudioIO.h:381
AudioIOBase::HandleDeviceChange
void HandleDeviceChange()
update state after changing what audio devices are selected
Definition: AudioIOBase.cpp:107
AudioIO::DrainRecordBuffers
void DrainRecordBuffers()
Second part of TrackBufferExchange.
Definition: AudioIO.cpp:2305
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:138
safenew
#define safenew
Definition: MemoryX.h:10
RecordingSchedule::Consumed
double Consumed() const
Definition: PlaybackSchedule.cpp:257
lrint
#define lrint(dbl)
Definition: float_cast.h:169
AudioIoCallback::mMinCaptureSecsToCopy
double mMinCaptureSecsToCopy
Definition: AudioIO.h:273
limitSampleBufferSize
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:23
RecordingSchedule::mLatencyCorrected
bool mLatencyCorrected
Definition: PlaybackSchedule.h:137
PlaybackSchedule::TimeQueue::Producer
void Producer(const PlaybackSchedule &schedule, double rate, double scrubSpeed, size_t nSamples)
Definition: PlaybackSchedule.cpp:267
TransportTracks::prerollTracks
WaveTrackConstArray prerollTracks
Definition: AudioIO.h:70
Mixer
Functions for doing the mixdown of the tracks.
Definition: Mix.h:76
RecordingSchedule::mDuration
double mDuration
Definition: PlaybackSchedule.h:131
PlaybackSchedule::RealTimeRestart
void RealTimeRestart()
Definition: PlaybackSchedule.cpp:247
PlaybackSchedule::RealTimeRemaining
double RealTimeRemaining() const
Definition: PlaybackSchedule.cpp:229
AudioIoCallback::SetRecordingException
void SetRecordingException()
Definition: AudioIO.h:327
AudioIoCallback::mCaptureTracks
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:254
AudioIO::AudioIO
AudioIO()
Definition: AudioIO.cpp:548
AudioIORecordChannels
IntSetting AudioIORecordChannels
Definition: AudioIOBase.cpp:972
PlaybackSchedule::TimeQueue::mHead
NonInterfering< Cursor > mHead
Aligned to avoid false sharing.
Definition: PlaybackSchedule.h:204
AudioIoCallback::mFactor
double mFactor
Definition: AudioIO.h:260
RecordingSchedule::mPreRoll
double mPreRoll
Definition: PlaybackSchedule.h:129
SampleBuffer::ptr
samplePtr ptr() const
Definition: SampleFormat.h:98
AudioIoCallback::mCachedBestRateOut
static double mCachedBestRateOut
Definition: AudioIO.h:305
AudioIoCallback::mPlaybackRingBufferSecs
double mPlaybackRingBufferSecs
Definition: AudioIO.h:265
AudioIOBase::mEmulateMixerOutputVol
bool mEmulateMixerOutputVol
Definition: AudioIOBase.h:302