Audacity  3.2.0
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 Types inherited from Observer::Publisher< AudioIOEvent >
using message_type = AudioIOEvent
 
using CallbackReturn = std::conditional_t< true, void, bool >
 
using Callback = std::function< CallbackReturn(const AudioIOEvent &) >
 Type of functions that can be connected to the Publisher. More...
 

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, double mixerLimit, 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
 
std::shared_ptr< 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...
 
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 (const std::shared_ptr< AudacityProject > &project, const std::weak_ptr< Meter > &meter)
 
void SetPlaybackMeter (const std::shared_ptr< 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)
 
- Public Member Functions inherited from Observer::Publisher< AudioIOEvent >
 Publisher (ExceptionPolicy *pPolicy=nullptr, Alloc a={})
 Constructor supporting type-erased custom allocation/deletion. More...
 
 Publisher (Publisher &&)=default
 
Publisheroperator= (Publisher &&)=default
 
Subscription Subscribe (Callback callback)
 Connect a callback to the Publisher; later-connected are called earlier. More...
 
Subscription Subscribe (Object &obj, Return(Object::*callback)(Args...))
 Overload of Subscribe takes an object and pointer-to-member-function. More...
 

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 SetOwningProject (const std::shared_ptr< AudacityProject > &pProject)
 
void ResetOwningProject ()
 
void TrackBufferExchange ()
 
void FillPlayBuffers ()
 First part of TrackBufferExchange. 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)
 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
 
std::vector< std::unique_ptr< Mixer > > mPlaybackMixers
 
float mMixerOutputVol { 1.0 }
 
double mFactor
 
unsigned long mMaxFramesOutput
 
bool mbMicroFades
 
double mSeek
 
PlaybackPolicy::Duration 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...
 
- Static Public Attributes inherited from Observer::Publisher< AudioIOEvent >
static constexpr bool notifies_all
 
- Protected Member Functions inherited from AudioIoCallback
void SetRecordingException ()
 
void ClearRecordingException ()
 
- Protected Member Functions inherited from Observer::Publisher< AudioIOEvent >
CallbackReturn Publish (const AudioIOEvent &message)
 Send a message to connected callbacks. More...
 
- 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
std::weak_ptr< 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 mInputMixerWorks
 Can we control the hardware input level? More...
 
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 359 of file AudioIO.h.

Member Typedef Documentation

◆ PostRecordingAction

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

Definition at line 402 of file AudioIO.h.

Constructor & Destructor Documentation

◆ AudioIO()

AudioIO::AudioIO ( )
private

Definition at line 273 of file AudioIO.cpp.

274 {
275  if (!std::atomic<double>{}.is_lock_free()) {
276  // If this check fails, then the atomic<double> members in AudioIO.h
277  // might be changed to atomic<float> to be more efficient with some
278  // loss of precision. That could be conditionally compiled depending
279  // on the platform.
280  wxASSERT(false);
281  }
282 
283  // This ASSERT because of casting in the callback
284  // functions where we cast a tempFloats buffer to a (short*) buffer.
285  // We have to ASSERT in the GUI thread, if we are to see it properly.
286  wxASSERT( sizeof( short ) <= sizeof( float ));
287 
291  mPortStreamV19 = NULL;
292 
293  mNumPauseFrames = 0;
294 
295 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
296  mAILAActive = false;
297 #endif
298  mStreamToken = 0;
299 
300  mLastPaError = paNoError;
301 
302  mLastRecordingOffset = 0.0;
304  mPaused = false;
305  mSilenceLevel = 0.0;
306 
307  mUpdateMeters = false;
308  mUpdatingMeters = false;
309 
310  mOutputMeter.reset();
311 
312  PaError err = Pa_Initialize();
313 
314  if (err != paNoError) {
315  auto errStr = XO("Could not find any audio devices.\n");
316  errStr += XO("You will not be able to play or record audio.\n\n");
317  wxString paErrStr = LAT1CTOWX(Pa_GetErrorText(err));
318  if (!paErrStr.empty())
319  errStr += XO("Error: %s").Format( paErrStr );
320  // XXX: we are in libaudacity, popping up dialogs not allowed! A
321  // long-term solution will probably involve exceptions
323  errStr,
324  XO("Error Initializing Audio"),
325  wxICON_ERROR|wxOK);
326 
327  // Since PortAudio is not initialized, all calls to PortAudio
328  // functions will fail. This will give reasonable behavior, since
329  // the user will be able to do things not relating to audio i/o,
330  // but any attempt to play or record will simply fail.
331  }
332 
333  // Start thread
334  mThread = std::make_unique<AudioThread>();
335  mThread->Create();
336 
337 #if defined(USE_PORTMIXER)
338  mPortMixer = NULL;
339  mPreviousHWPlaythrough = -1.0;
341 #else
342  mEmulateMixerOutputVol = true;
343  mInputMixerWorks = false;
344 #endif
345 
347 
349 }

References AudacityMessageBox(), AudioIOPlaybackVolume, AudioIOBase::HandleDeviceChange(), LAT1CTOWX, AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopActive, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning, AudioIOBase::mInputMixerWorks, AudioIoCallback::mLastPaError, AudioIoCallback::mLastPlaybackTimeMillis, AudioIoCallback::mLastRecordingOffset, AudioIoCallback::mMixerOutputVol, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPauseFrames, AudioIOBase::mOutputMeter, AudioIOBase::mPaused, AudioIOBase::mPortStreamV19, AudioIoCallback::mSilenceLevel, AudioIOBase::mStreamToken, AudioIoCallback::mThread, AudioIoCallback::mUpdateMeters, AudioIoCallback::mUpdatingMeters, Setting< T >::Read(), 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 351 of file AudioIO.cpp.

352 {
353  if ( !mOwningProject.expired() )
354  // Unlikely that this will be destroyed earlier than any projects, but
355  // be prepared anyway
357 
358 #if defined(USE_PORTMIXER)
359  if (mPortMixer) {
360  #if __WXMAC__
361  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
362  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
363  mPreviousHWPlaythrough = -1.0;
364  #endif
365  Px_CloseMixer(mPortMixer);
366  mPortMixer = NULL;
367  }
368 #endif
369 
370  // FIXME: ? TRAP_ERR. Pa_Terminate probably OK if err without reporting.
371  Pa_Terminate();
372 
373  /* Delete is a "graceful" way to stop the thread.
374  (Kill is the not-graceful way.) */
375 
376  // This causes reentrancy issues during application shutdown
377  // wxTheApp->Yield();
378 
379  mThread->Delete();
380  mThread.reset();
381 }

References AudioIOBase::mOwningProject, AudioIoCallback::mThread, and ResetOwningProject().

Here is the call graph for this function:

Member Function Documentation

◆ AllocateBuffers()

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

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

Returns true iff successful.

Definition at line 1090 of file AudioIO.cpp.

1093 {
1094  bool success = false;
1095  auto cleanup = finally([&]{
1096  if (!success) StartStreamCleanup( false );
1097  });
1098 
1099  auto &policy = mPlaybackSchedule.GetPolicy();
1100  auto times = policy.SuggestedBufferTimes(mPlaybackSchedule);
1101 
1102  //
1103  // The (audio) stream has been opened successfully (assuming we tried
1104  // to open it). We now proceed to
1105  // allocate the memory structures the stream will need.
1106  //
1107 
1108  //
1109  // The RingBuffer sizes, and the max amount of the buffer to
1110  // fill at a time, both grow linearly with the number of
1111  // tracks. This allows us to scale up to many tracks without
1112  // killing performance.
1113  //
1114 
1115  // real playback time to produce with each filling of the buffers
1116  // by the Audio thread (except at the end of playback):
1117  // usually, make fillings fewer and longer for less CPU usage.
1118  // What Audio thread produces for playback is then consumed by the PortAudio
1119  // thread, in many smaller pieces.
1120  double playbackTime = lrint(times.batchSize.count() * mRate) / mRate;
1121 
1122  wxASSERT( playbackTime >= 0 );
1123  mPlaybackSamplesToCopy = playbackTime * mRate;
1124 
1125  // Capacity of the playback buffer.
1126  mPlaybackRingBufferSecs = times.ringBufferDelay;
1127 
1129  4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.size());
1131  0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.size());
1132 
1133  bool bDone;
1134  do
1135  {
1136  bDone = true; // assume success
1137  try
1138  {
1139  if( mNumPlaybackChannels > 0 ) {
1140  // Allocate output buffers. For every output track we allocate
1141  // a ring buffer of ten seconds
1142  auto playbackBufferSize =
1143  (size_t)lrint(mRate * mPlaybackRingBufferSecs.count());
1144 
1145  // Always make at least one playback buffer
1147  std::max<size_t>(1, mPlaybackTracks.size()));
1148  mPlaybackMixers.clear();
1149  mPlaybackMixers.resize(mPlaybackTracks.size());
1150 
1151  const auto &warpOptions =
1152  policy.MixerWarpOptions(mPlaybackSchedule);
1153 
1154  mPlaybackQueueMinimum = lrint( mRate * times.latency.count() );
1156  std::min( mPlaybackQueueMinimum, playbackBufferSize );
1157 
1158  if (mPlaybackTracks.empty())
1159  // Make at least one playback buffer
1160  mPlaybackBuffers[0] =
1161  std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
1162 
1163  for (unsigned int i = 0; i < mPlaybackTracks.size(); i++)
1164  {
1165  // Bug 1763 - We must fade in from zero to avoid a click on starting.
1166  mPlaybackTracks[i]->SetOldChannelGain(0, 0.0);
1167  mPlaybackTracks[i]->SetOldChannelGain(1, 0.0);
1168 
1169  mPlaybackBuffers[i] =
1170  std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
1171 
1172  // use track time for the end time, not real time!
1173  SampleTrackConstArray mixTracks;
1174  mixTracks.push_back(mPlaybackTracks[i]);
1175 
1176  double startTime, endTime;
1178  .contains(mPlaybackTracks[i])) {
1179  // Stop playing this track after pre-roll
1180  startTime = mPlaybackSchedule.mT0;
1181  endTime = t0;
1182  }
1183  else {
1184  // Pass t1 -- not mT1 as may have been adjusted for latency
1185  // -- so that overdub recording stops playing back samples
1186  // at the right time, though transport may continue to record
1187  startTime = t0;
1188  endTime = t1;
1189  }
1190 
1191  mPlaybackMixers[i] = std::make_unique<Mixer>
1192  (mixTracks,
1193  // Don't throw for read errors, just play silence:
1194  false,
1195  warpOptions,
1196  startTime,
1197  endTime,
1198  1,
1200  false,
1201  mRate, floatSample,
1202  false, // low quality dithering and resampling
1203  nullptr,
1204  false // don't apply track gains
1205  );
1206  }
1207 
1208  const auto timeQueueSize = 1 +
1209  (playbackBufferSize + TimeQueueGrainSize - 1)
1211  mPlaybackSchedule.mTimeQueue.Resize( timeQueueSize );
1212  }
1213 
1214  if( mNumCaptureChannels > 0 )
1215  {
1216  // Allocate input buffers. For every input track we allocate
1217  // a ring buffer of five seconds
1218  auto captureBufferSize =
1219  (size_t)(mRate * mCaptureRingBufferSecs + 0.5);
1220 
1221  // In the extraordinarily rare case that we can't even afford
1222  // 100 samples, just give up.
1223  if(captureBufferSize < 100)
1224  {
1225  AudacityMessageBox( XO("Out of memory!") );
1226  return false;
1227  }
1228 
1231  mFactor = sampleRate / mRate;
1232 
1233  for( unsigned int i = 0; i < mCaptureTracks.size(); i++ )
1234  {
1235  mCaptureBuffers[i] = std::make_unique<RingBuffer>(
1236  mCaptureTracks[i]->GetSampleFormat(), captureBufferSize );
1237  mResample[i] =
1238  std::make_unique<Resample>(true, mFactor, mFactor);
1239  // constant rate resampling
1240  }
1241  }
1242  }
1243  catch(std::bad_alloc&)
1244  {
1245  // Oops! Ran out of memory. This is pretty rare, so we'll just
1246  // try deleting everything, halving our buffer size, and try again.
1247  StartStreamCleanup(true);
1248  mPlaybackRingBufferSecs *= 0.5;
1250  mCaptureRingBufferSecs *= 0.5;
1251  mMinCaptureSecsToCopy *= 0.5;
1252  bDone = false;
1253 
1254  // In the extraordinarily rare case that we can't even afford 100
1255  // samples, just give up.
1256  auto playbackBufferSize =
1257  (size_t)lrint(mRate * mPlaybackRingBufferSecs.count());
1258  if(playbackBufferSize < 100 || mPlaybackSamplesToCopy < 100)
1259  {
1260  AudacityMessageBox( XO("Out of memory!") );
1261  return false;
1262  }
1263  }
1264  } while(!bDone);
1265 
1266  success = true;
1267  return true;
1268 }

References AudacityMessageBox(), floatSample, PlaybackSchedule::GetPolicy(), lrint, make_iterator_range(), AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureRingBufferSecs, AudioIoCallback::mCaptureTracks, AudioIoCallback::mFactor, min(), 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::mT0, PlaybackSchedule::mTimeQueue, TransportTracks::prerollTracks, ArrayOf< X >::reinit(), PlaybackSchedule::TimeQueue::Resize(), StartStreamCleanup(), PlaybackPolicy::SuggestedBufferTimes(), 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 1062 of file AudioIO.cpp.

1063 {
1064  if (!action)
1065  return;
1066 
1067  {
1068  std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
1069  if (mPostRecordingAction) {
1070  // Enqueue it, even if perhaps not still recording,
1071  // but it wasn't cleared yet
1073  prevAction = std::move(mPostRecordingAction),
1074  nextAction = std::move(action)
1075  ]{ prevAction(); nextAction(); };
1076  return;
1077  }
1078  else if (DelayingActions()) {
1079  mPostRecordingAction = std::move(action);
1080  return;
1081  }
1082  }
1083 
1084  // Don't delay it except until idle time.
1085  // (Recording might start between now and then, but won't go far before
1086  // the action is done. So the system isn't bulletproof yet.)
1087  wxTheApp->CallAfter(std::move(action));
1088 }

References DelayingActions(), mPostRecordingAction, and mPostRecordingActionMutex.

Here is the call graph for this function:

◆ Deinit()

void AudioIO::Deinit ( )
static

Definition at line 259 of file AudioIO.cpp.

260 {
261  ugAudioIO.reset();
262 }

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 1052 of file AudioIO.cpp.

1053 {
1054  mDelayingActions = recording;
1055 }

References mDelayingActions.

Referenced by StopStream().

Here is the caller graph for this function:

◆ DelayingActions()

bool AudioIO::DelayingActions ( ) const
private

Definition at line 1057 of file AudioIO.cpp.

1058 {
1060 }

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 1858 of file AudioIO.cpp.

1859 {
1860  if (mRecordingException || mCaptureTracks.empty())
1861  return;
1862 
1863  auto delayedHandler = [this] ( AudacityException * pException ) {
1864  // In the main thread, stop recording
1865  // This is one place where the application handles disk
1866  // exhaustion exceptions from wave track operations, without rolling
1867  // back to the last pushed undo state. Instead, partial recording
1868  // results are pushed as a NEW undo state. For this reason, as
1869  // commented elsewhere, we want an exception safety guarantee for
1870  // the output wave tracks, after the failed append operation, that
1871  // the tracks remain as they were after the previous successful
1872  // (block-level) appends.
1873 
1874  // Note that the Flush in StopStream() may throw another exception,
1875  // but StopStream() contains that exception, and the logic in
1876  // AudacityException::DelayedHandlerAction prevents redundant message
1877  // boxes.
1878  StopStream();
1879  DefaultDelayedHandlerAction( pException );
1880  };
1881 
1882  GuardedCall( [&] {
1883  // start record buffering
1884  const auto avail = GetCommonlyAvailCapture(); // samples
1885  const auto remainingTime =
1886  std::max(0.0, mRecordingSchedule.ToConsume());
1887  // This may be a very big double number:
1888  const auto remainingSamples = remainingTime * mRate;
1889  bool latencyCorrected = true;
1890 
1891  double deltat = avail / mRate;
1892 
1894  deltat >= mMinCaptureSecsToCopy)
1895  {
1896  // This scope may combine many appendings of wave tracks,
1897  // and also an autosave, into one transaction,
1898  // lessening the number of checkpoints
1899  std::optional<TransactionScope> pScope;
1900  if (auto pOwningProject = mOwningProject.lock())
1901  pScope.emplace(*pOwningProject, "Recording");
1902 
1903  bool newBlocks = false;
1904 
1905  // Append captured samples to the end of the WaveTracks.
1906  // The WaveTracks have their own buffering for efficiency.
1907  auto numChannels = mCaptureTracks.size();
1908 
1909  for( size_t i = 0; i < numChannels; i++ )
1910  {
1911  sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
1912 
1913  size_t discarded = 0;
1914 
1916  const auto correction = mRecordingSchedule.TotalCorrection();
1917  if (correction >= 0) {
1918  // Rightward shift
1919  // Once only (per track per recording), insert some initial
1920  // silence.
1921  size_t size = floor( correction * mRate * mFactor);
1922  SampleBuffer temp(size, trackFormat);
1923  ClearSamples(temp.ptr(), trackFormat, 0, size);
1924  mCaptureTracks[i]->Append(temp.ptr(), trackFormat, size, 1);
1925  }
1926  else {
1927  // Leftward shift
1928  // discard some samples from the ring buffers.
1929  size_t size = floor(
1931 
1932  // The ring buffer might have grown concurrently -- don't discard more
1933  // than the "avail" value noted above.
1934  discarded = mCaptureBuffers[i]->Discard(std::min(avail, size));
1935 
1936  if (discarded < size)
1937  // We need to visit this again to complete the
1938  // discarding.
1939  latencyCorrected = false;
1940  }
1941  }
1942 
1943  const float *pCrossfadeSrc = nullptr;
1944  size_t crossfadeStart = 0, totalCrossfadeLength = 0;
1945  if (i < mRecordingSchedule.mCrossfadeData.size())
1946  {
1947  // Do crossfading
1948  // The supplied crossfade samples are at the same rate as the track
1949  const auto &data = mRecordingSchedule.mCrossfadeData[i];
1950  totalCrossfadeLength = data.size();
1951  if (totalCrossfadeLength) {
1952  crossfadeStart =
1953  floor(mRecordingSchedule.Consumed() * mCaptureTracks[i]->GetRate());
1954  if (crossfadeStart < totalCrossfadeLength)
1955  pCrossfadeSrc = data.data() + crossfadeStart;
1956  }
1957  }
1958 
1959  wxASSERT(discarded <= avail);
1960  size_t toGet = avail - discarded;
1961  SampleBuffer temp;
1962  size_t size;
1964  if( mFactor == 1.0 )
1965  {
1966  // Take captured samples directly
1967  size = toGet;
1968  if (pCrossfadeSrc)
1969  // Change to float for crossfade calculation
1970  format = floatSample;
1971  else
1972  format = trackFormat;
1973  temp.Allocate(size, format);
1974  const auto got =
1975  mCaptureBuffers[i]->Get(temp.ptr(), format, toGet);
1976  // wxASSERT(got == toGet);
1977  // but we can't assert in this thread
1978  wxUnusedVar(got);
1979  if (double(size) > remainingSamples)
1980  size = floor(remainingSamples);
1981  }
1982  else
1983  {
1984  size = lrint(toGet * mFactor);
1985  format = floatSample;
1986  SampleBuffer temp1(toGet, floatSample);
1987  temp.Allocate(size, format);
1988  const auto got =
1989  mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, toGet);
1990  // wxASSERT(got == toGet);
1991  // but we can't assert in this thread
1992  wxUnusedVar(got);
1993  /* we are re-sampling on the fly. The last resampling call
1994  * must flush any samples left in the rate conversion buffer
1995  * so that they get recorded
1996  */
1997  if (toGet > 0 ) {
1998  if (double(toGet) > remainingSamples)
1999  toGet = floor(remainingSamples);
2000  const auto results =
2001  mResample[i]->Process(mFactor, (float *)temp1.ptr(), toGet,
2002  !IsStreamActive(), (float *)temp.ptr(), size);
2003  size = results.second;
2004  }
2005  }
2006 
2007  if (pCrossfadeSrc) {
2008  wxASSERT(format == floatSample);
2009  size_t crossfadeLength = std::min(size, totalCrossfadeLength - crossfadeStart);
2010  if (crossfadeLength) {
2011  auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2012  auto ratioStep = 1.0 / totalCrossfadeLength;
2013  auto pCrossfadeDst = (float*)temp.ptr();
2014 
2015  // Crossfade loop here
2016  for (size_t ii = 0; ii < crossfadeLength; ++ii) {
2017  *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2018  ++pCrossfadeSrc, ++pCrossfadeDst;
2019  ratio += ratioStep;
2020  }
2021  }
2022  }
2023 
2024  // Now append
2025  // see comment in second handler about guarantee
2026  newBlocks = mCaptureTracks[i]->Append(temp.ptr(), format, size, 1)
2027  || newBlocks;
2028  } // end loop over capture channels
2029 
2030  // Now update the recording schedule position
2031  mRecordingSchedule.mPosition += avail / mRate;
2032  mRecordingSchedule.mLatencyCorrected = latencyCorrected;
2033 
2034  auto pListener = GetListener();
2035  if (pListener && newBlocks)
2036  pListener->OnAudioIONewBlocks(&mCaptureTracks);
2037 
2038  if (pScope)
2039  pScope->Commit();
2040  }
2041  // end of record buffering
2042  },
2043  // handler
2044  [this] ( AudacityException *pException ) {
2045  if ( pException ) {
2046  // So that we don't attempt to fill the recording buffer again
2047  // before the main thread stops recording
2049  return ;
2050  }
2051  else
2052  // Don't want to intercept other exceptions (?)
2053  throw;
2054  },
2055  delayedHandler );
2056 }

References SampleBuffer::Allocate(), ClearSamples(), RecordingSchedule::Consumed(), DefaultDelayedHandlerAction(), floatSample, format, 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 1772 of file AudioIO.cpp.

1773 {
1774  if (mNumPlaybackChannels == 0)
1775  return;
1776 
1777  // Though extremely unlikely, it is possible that some buffers
1778  // will have more samples available than others. This could happen
1779  // if we hit this code during the PortAudio callback. To keep
1780  // things simple, we only write as much data as is vacant in
1781  // ALL buffers, and advance the global time by that much.
1782  auto nAvailable = GetCommonlyFreePlayback();
1783 
1784  // Don't fill the buffers at all unless we can do the
1785  // full mMaxPlaybackSecsToCopy. This improves performance
1786  // by not always trying to process tiny chunks, eating the
1787  // CPU unnecessarily.
1788  if (nAvailable < mPlaybackSamplesToCopy)
1789  return;
1790 
1791  auto &policy = mPlaybackSchedule.GetPolicy();
1792 
1793  // More than mPlaybackSamplesToCopy might be copied:
1794  // May produce a larger amount when initially priming the buffer, or
1795  // perhaps again later in play to avoid underfilling the queue and falling
1796  // behind the real-time demand on the consumer side in the callback.
1797  auto nReady = GetCommonlyReadyPlayback();
1798  auto nNeeded =
1800 
1801  // wxASSERT( nNeeded <= nAvailable );
1802 
1803  // Limit maximum buffer size (increases performance)
1804  auto available = std::min( nAvailable,
1805  std::max( nNeeded, mPlaybackSamplesToCopy ) );
1806 
1807  // msmeyer: When playing a very short selection in looped
1808  // mode, the selection must be copied to the buffer multiple
1809  // times, to ensure, that the buffer has a reasonable size
1810  // This is the purpose of this loop.
1811  // PRL: or, when scrubbing, we may get work repeatedly from the
1812  // user interface.
1813  bool done = false;
1814  do {
1815  const auto slice =
1816  policy.GetPlaybackSlice(mPlaybackSchedule, available);
1817  const auto &[frames, toProduce] = slice;
1818 
1819  // Update the time queue. This must be done before writing to the
1820  // ring buffers of samples, for proper synchronization with the
1821  // consumer side in the PortAudio thread, which reads the time
1822  // queue after reading the sample queues. The sample queues use
1823  // atomic variables, the time queue doesn't.
1825 
1826  for (size_t i = 0; i < mPlaybackTracks.size(); i++)
1827  {
1828  // The mixer here isn't actually mixing: it's just doing
1829  // resampling, format conversion, and possibly time track
1830  // warping
1831  if (frames > 0)
1832  {
1833  size_t produced = 0;
1834  if ( toProduce )
1835  produced = mPlaybackMixers[i]->Process( toProduce );
1836  //wxASSERT(produced <= toProduce);
1837  auto warpedSamples = mPlaybackMixers[i]->GetBuffer();
1838  const auto put = mPlaybackBuffers[i]->Put(
1839  warpedSamples, floatSample, produced, frames - produced);
1840  // wxASSERT(put == frames);
1841  // but we can't assert in this thread
1842  wxUnusedVar(put);
1843  }
1844  }
1845 
1846  if (mPlaybackTracks.empty())
1847  // Produce silence in the single ring buffer
1848  mPlaybackBuffers[0]->Put(nullptr, floatSample, 0, frames);
1849 
1850  available -= frames;
1851  // wxASSERT(available >= 0); // don't assert on this thread
1852 
1853  done = policy.RepositionPlayback( mPlaybackSchedule, mPlaybackMixers,
1854  frames, available );
1855  } while (available && !done);
1856 }

References floatSample, GetCommonlyFreePlayback(), AudioIoCallback::GetCommonlyReadyPlayback(), PlaybackSchedule::GetPolicy(), min(), AudioIoCallback::mNumPlaybackChannels, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackQueueMinimum, AudioIoCallback::mPlaybackSamplesToCopy, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, PlaybackSchedule::mTimeQueue, and PlaybackSchedule::TimeQueue::Producer().

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 140 of file AudioIO.cpp.

141 {
142  return static_cast< AudioIO* >( AudioIOBase::Get() );
143 }

References AudioIOBase::Get().

Referenced by AdornedRulerPanel::AdornedRulerPanel(), audacityAudioCallback(), ProjectAudioManager::CanStopAudioStream(), CaptureNotBusyFlag(), DefaultSpeedPlayOptions(), anonymous_namespace{SelectMenus.cpp}::DoBoundaryMove(), PlayIndicatorOverlayBase::DoGetRectangle(), ProjectAudioManager::DoPlayStopSelect(), ProjectAudioManager::DoRecord(), PlayIndicatorOverlayBase::Draw(), ControlToolBar::EnableDisableButtons(), TranscriptionToolBar::EnableDisableButtons(), AudioThread::Entry(), ScrubbingPlaybackPolicy::GetPlaybackSlice(), UpdateManager::GetUpdates(), HistoryDialog::HistoryDialog(), Init(), EffectUIHost::Initialize(), EffectUIHost::InitializeRealtime(), LyricsPanel::LyricsPanel(), MixerBoard::MixerBoard(), 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(), SelectUtilities::OnSetRegion(), PluginActions::Handler::OnSimulateRecordingErrors(), ProjectAudioManager::OnSoundActivationThreshold(), ProjectWindow::PlaybackScroller::OnTimer(), LyricsWindow::OnTimer(), MixerBoard::OnTimer(), PlayIndicatorOverlay::OnTimer(), ProjectManager::OnTimer(), TrackPanel::OnTimer(), ProjectAudioManager::Pause(), TransportUtilities::PlayCurrentRegionAndWait(), ProjectAudioManager::Playing(), ProjectAudioManager::PlayPlayRegion(), TransportUtilities::PlayPlayRegionAndWait(), MixerToolBar::Populate(), Effect::Preview(), TransportUtilities::RecordAndWait(), ProjectAudioManager::Recording(), ScrubbingPlaybackPolicy::RepositionPlayback(), TimerRecordDialog::RunWaitDialog(), anonymous_namespace{SelectMenus.cpp}::SeekWhenAudioActive(), MixerToolBar::SetMixer(), MeterPanel::StartMonitoring(), StartMonitoring(), ControlToolBar::StartScrolling(), ProjectAudioManager::Stop(), MeterPanel::StopMonitoring(), anonymous_namespace{PluginMenus.cpp}::ToolsMenu(), TrackPanel::TrackPanel(), 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 1608 of file AudioIO.cpp.

1609 {
1610  // Check if we can use the cached value
1611  if (mCachedBestRateIn != 0.0 && mCachedBestRateIn == sampleRate
1612  && mCachedBestRatePlaying == playing && mCachedBestRateCapturing == capturing) {
1613  return mCachedBestRateOut;
1614  }
1615 
1616  // In order to cache the value, all early returns should instead set retval
1617  // and jump to finished
1618  double retval;
1619 
1620  std::vector<long> rates;
1621  if (capturing) wxLogDebug(wxT("AudioIO::GetBestRate() for capture"));
1622  if (playing) wxLogDebug(wxT("AudioIO::GetBestRate() for playback"));
1623  wxLogDebug(wxT("GetBestRate() suggested rate %.0lf Hz"), sampleRate);
1624 
1625  if (capturing && !playing) {
1626  rates = GetSupportedCaptureRates(-1, sampleRate);
1627  }
1628  else if (playing && !capturing) {
1629  rates = GetSupportedPlaybackRates(-1, sampleRate);
1630  }
1631  else { // we assume capturing and playing - the alternative would be a
1632  // bit odd
1633  rates = GetSupportedSampleRates(-1, -1, sampleRate);
1634  }
1635  /* rem rates is the array of hardware-supported sample rates (in the current
1636  * configuration), sampleRate is the Project Rate (desired sample rate) */
1637  long rate = (long)sampleRate;
1638 
1639  if (make_iterator_range(rates).contains(rate)) {
1640  wxLogDebug(wxT("GetBestRate() Returning %.0ld Hz"), rate);
1641  retval = rate;
1642  goto finished;
1643  /* the easy case - the suggested rate (project rate) is in the list, and
1644  * we can just accept that and send back to the caller. This should be
1645  * the case for most users most of the time (all of the time on
1646  * Win MME as the OS does resampling) */
1647  }
1648 
1649  /* if we get here, there is a problem - the project rate isn't supported
1650  * on our hardware, so we can't us it. Need to come up with an alternative
1651  * rate to use. The process goes like this:
1652  * * If there are no rates to pick from, we're stuck and return 0 (error)
1653  * * If there are some rates, we pick the next one higher than the requested
1654  * rate to use.
1655  * * If there aren't any higher, we use the highest available rate */
1656 
1657  if (rates.empty()) {
1658  /* we're stuck - there are no supported rates with this hardware. Error */
1659  wxLogDebug(wxT("GetBestRate() Error - no supported sample rates"));
1660  retval = 0.0;
1661  goto finished;
1662  }
1663  int i;
1664  for (i = 0; i < (int)rates.size(); i++) // for each supported rate
1665  {
1666  if (rates[i] > rate) {
1667  // supported rate is greater than requested rate
1668  wxLogDebug(wxT("GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1669  retval = rates[i];
1670  goto finished;
1671  }
1672  }
1673 
1674  wxLogDebug(wxT("GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1675  retval = rates.back(); // the highest available rate
1676  goto finished;
1677 
1678 finished:
1679  mCachedBestRateIn = sampleRate;
1680  mCachedBestRateOut = retval;
1681  mCachedBestRatePlaying = playing;
1682  mCachedBestRateCapturing = capturing;
1683  return retval;
1684 }

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 442 of file AudioIO.h.

442 { 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 1754 of file AudioIO.cpp.

1755 {
1756  auto commonlyAvail = mCaptureBuffers[0]->AvailForGet();
1757  for (unsigned i = 1; i < mCaptureTracks.size(); ++i)
1758  commonlyAvail = std::min(commonlyAvail,
1759  mCaptureBuffers[i]->AvailForGet());
1760  return commonlyAvail;
1761 }

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 1734 of file AudioIO.cpp.

1735 {
1736  auto commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
1737  for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
1738  commonlyAvail = std::min(commonlyAvail,
1739  mPlaybackBuffers[i]->AvailForPut());
1740  // MB: subtract a few samples because the code in TrackBufferExchange has rounding
1741  // errors
1742  return commonlyAvail - std::min(size_t(10), commonlyAvail);
1743 }

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 435 of file AudioIO.cpp.

436 {
437 #if defined(USE_PORTMIXER)
438 
439  wxArrayString deviceNames;
440 
441  if( mPortMixer )
442  {
443  int numSources = Px_GetNumInputSources(mPortMixer);
444  for( int source = 0; source < numSources; source++ )
445  deviceNames.push_back(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
446  }
447  else
448  {
449  wxLogDebug(wxT("AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
450  }
451 
452  return deviceNames;
453 
454 #else
455 
456  wxArrayString blank;
457 
458  return blank;
459 
460 #endif
461 }

◆ GetLastPlaybackTime()

wxLongLong AudioIO::GetLastPlaybackTime ( ) const
inline

Definition at line 411 of file AudioIO.h.

411 { return mLastPlaybackTimeMillis; }

References AudioIoCallback::mLastPlaybackTimeMillis.

◆ GetMixer()

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

Definition at line 403 of file AudioIO.cpp.

405 {
406  *playbackVolume = mMixerOutputVol;
407 
408 #if defined(USE_PORTMIXER)
409 
410  PxMixer *mixer = mPortMixer;
411 
412  if( mixer )
413  {
414  *recordDevice = Px_GetCurrentInputSource(mixer);
415 
416  if (mInputMixerWorks)
417  *recordVolume = Px_GetInputVolume(mixer);
418  else
419  *recordVolume = 1.0f;
420 
421  return;
422  }
423 
424 #endif
425 
426  *recordDevice = 0;
427  *recordVolume = 1.0f;
428 }

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

◆ GetNumCaptureChannels()

unsigned AudioIO::GetNumCaptureChannels ( ) const
inline

Definition at line 444 of file AudioIO.h.

444 { 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 443 of file AudioIO.h.

443 { return mNumPlaybackChannels; }

References AudioIoCallback::mNumPlaybackChannels.

◆ GetOwningProject()

std::shared_ptr<AudacityProject> AudioIO::GetOwningProject ( ) const
inline

Definition at line 412 of file AudioIO.h.

413  { return mOwningProject.lock(); }

◆ 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 1686 of file AudioIO.cpp.

1687 {
1688  // Track time readout for the main thread
1689 
1690  if( !IsStreamActive() )
1691  return BAD_STREAM_TIME;
1692 
1694 }

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

Here is the call graph for this function:

◆ Init()

void AudioIO::Init ( )
static

Definition at line 232 of file AudioIO.cpp.

233 {
234  ugAudioIO.reset(safenew AudioIO());
235  Get()->mThread->Run();
236 
237  // Make sure device prefs are initialized
238  if (gPrefs->Read(wxT("AudioIO/RecordingDevice"), wxT("")).empty()) {
239  int i = getRecordDevIndex();
240  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
241  if (info) {
243  AudioIOHost.Write(HostName(info));
244  }
245  }
246 
247  if (gPrefs->Read(wxT("AudioIO/PlaybackDevice"), wxT("")).empty()) {
248  int i = getPlayDevIndex();
249  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
250  if (info) {
252  AudioIOHost.Write(HostName(info));
253  }
254  }
255 
256  gPrefs->Flush();
257 }

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 430 of file AudioIO.cpp.

431 {
432  return mInputMixerWorks;
433 }

References AudioIOBase::mInputMixerWorks.

◆ IsAvailable()

bool AudioIO::IsAvailable ( AudacityProject project) const

Function to automatically set an acceptable volume.

Definition at line 1295 of file AudioIO.cpp.

1296 {
1297  auto pOwningProject = mOwningProject.lock();
1298  return !pOwningProject || pOwningProject.get() == &project;
1299 }

References AudioIOBase::mOwningProject.

◆ IsCapturing()

bool AudioIO::IsCapturing ( ) const

Definition at line 3099 of file AudioIO.cpp.

3100 {
3101  // Includes a test of mTime, used in the main thread
3102  return IsStreamActive() &&
3103  GetNumCaptureChannels() > 0 &&
3106 }

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 673 of file AudioIO.cpp.

674 {
675  return wxString::Format(wxT("%d %s."), (int) mLastPaError, Pa_GetErrorText(mLastPaError));
676 }

References AudioIoCallback::mLastPaError.

Referenced by StartMonitoring().

Here is the caller graph for this function:

◆ ResetOwningProject()

void AudioIO::ResetOwningProject ( )
private

Definition at line 689 of file AudioIO.cpp.

690 {
691  mOwningProject.reset();
692 }

References AudioIOBase::mOwningProject.

Referenced by SetOwningProject(), StartPortAudioStream(), StopStream(), and ~AudioIO().

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 400 of file AudioIO.h.

400 { 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 1301 of file AudioIO.cpp.

1302 {
1303  if (auto pInputMeter = mInputMeter.lock())
1304  pInputMeter->Reset(mRate, true);
1305  if (auto pOutputMeter = mOutputMeter.lock())
1306  pOutputMeter->Reset(mRate, true);
1307 
1308  mUpdateMeters = true;
1309 }

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 383 of file AudioIO.cpp.

385 {
386  mMixerOutputVol = playbackVolume;
388 
389 #if defined(USE_PORTMIXER)
390  PxMixer *mixer = mPortMixer;
391  if( !mixer )
392  return;
393 
394  float oldRecordVolume = Px_GetInputVolume(mixer);
395 
396  AudioIoCallback::SetMixer(inputSource);
397  if( oldRecordVolume != recordVolume )
398  Px_SetInputVolume(mixer, recordVolume);
399 
400 #endif
401 }

References AudioIOPlaybackVolume, AudioIoCallback::mMixerOutputVol, AudioIOBase::SetMixer(), and Setting< T >::Write().

Here is the call graph for this function:

◆ SetOwningProject()

void AudioIO::SetOwningProject ( const std::shared_ptr< AudacityProject > &  pProject)
private

Definition at line 678 of file AudioIO.cpp.

680 {
681  if ( !mOwningProject.expired() ) {
682  wxASSERT(false);
684  }
685 
686  mOwningProject = pProject;
687 }

References AudioIOBase::mOwningProject, and ResetOwningProject().

Referenced by StartPortAudioStream().

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

◆ SetPaused()

void AudioIO::SetPaused ( bool  state)

Pause and un-pause playback and recording.

Definition at line 1592 of file AudioIO.cpp.

1593 {
1594  if (state != mPaused)
1595  {
1596  if (auto pOwningProject = mOwningProject.lock()) {
1597  auto &em = RealtimeEffectManager::Get(*pOwningProject);
1598  if (state)
1599  em.RealtimeSuspend();
1600  else
1601  em.RealtimeResume();
1602  }
1603  }
1604 
1605  mPaused = state;
1606 }

References RealtimeEffectManager::Get(), AudioIOBase::mOwningProject, and AudioIOBase::mPaused.

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 694 of file AudioIO.cpp.

695 {
696  if ( mPortStreamV19 || mStreamToken )
697  return;
698 
699  bool success;
700  auto captureFormat = QualitySettings::SampleFormatChoice();
701  auto captureChannels = AudioIORecordChannels.Read();
702  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
703  int playbackChannels = 0;
704 
706  playbackChannels = 2;
707 
708  // FIXME: TRAP_ERR StartPortAudioStream (a PaError may be present)
709  // but StartPortAudioStream function only returns true or false.
710  mUsingAlsa = false;
711  success = StartPortAudioStream(options, (unsigned int)playbackChannels,
712  (unsigned int)captureChannels,
713  captureFormat);
714 
715  auto pOwningProject = mOwningProject.lock();
716  if (!success) {
717  using namespace BasicUI;
718  auto msg = XO("Error opening recording device.\nError code: %s")
719  .Format( Get()->LastPaErrorString() );
720  ShowErrorDialog( *ProjectFramePlacement( pOwningProject.get() ),
721  XO("Error"), msg, wxT("Error_opening_sound_device"),
722  ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
723  return;
724  }
725 
726  Publish({ pOwningProject.get(), AudioIOEvent::MONITOR, true });
727 
728  // FIXME: TRAP_ERR PaErrorCode 'noted' but not reported in StartMonitoring.
729  // Now start the PortAudio stream!
730  // TODO: ? Factor out and reuse error reporting code from end of
731  // AudioIO::StartStream?
732  mLastPaError = Pa_StartStream( mPortStreamV19 );
733 
734  // Update UI display only now, after all possibilities for error are past.
735  auto pListener = GetListener();
736  if ((mLastPaError == paNoError) && pListener) {
737  // advertise the chosen I/O sample rate to the UI
738  pListener->OnAudioIORate((int)mRate);
739  }
740 }

References AudioIORecordChannels, Get(), AudioIoCallback::GetListener(), gPrefs, LastPaErrorString(), AudioIoCallback::mLastPaError, AudioIOEvent::MONITOR, AudioIOBase::mOwningProject, AudioIOBase::mPortStreamV19, AudioIOBase::mRate, AudioIoCallback::mSoftwarePlaythrough, AudioIOBase::mStreamToken, AudioIoCallback::mUsingAlsa, ProjectFramePlacement(), Observer::Publisher< AudioIOEvent >::Publish(), 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 476 of file AudioIO.cpp.

480 {
481  auto sampleRate = options.rate;
482  mNumPauseFrames = 0;
483  SetOwningProject( options.pProject );
484  bool success = false;
485  auto cleanup = finally([&]{
486  if (!success)
488  });
489 
490  // PRL: Protection from crash reported by David Bailes, involving starting
491  // and stopping with frequent changes of active window, hard to reproduce
492  if (mOwningProject.expired())
493  return false;
494 
495  mInputMeter.reset();
496  mOutputMeter.reset();
497 
498  mLastPaError = paNoError;
499  // pick a rate to do the audio I/O at, from those available. The project
500  // rate is suggested, but we may get something else if it isn't supported
501  mRate = GetBestRate(numCaptureChannels > 0, numPlaybackChannels > 0, sampleRate);
502 
503  // July 2016 (Carsten and Uwe)
504  // BUG 193: Tell PortAudio sound card will handle 24 bit (under DirectSound) using
505  // userData.
506  int captureFormat_saved = captureFormat;
507  // Special case: Our 24-bit sample format is different from PortAudio's
508  // 3-byte packed format. So just make PortAudio return float samples,
509  // since we need float values anyway to apply the gain.
510  // ANSWER-ME: So we *never* actually handle 24-bit?! This causes mCapture to
511  // be set to floatSample below.
512  // JKC: YES that's right. Internally Audacity uses float, and float has space for
513  // 24 bits as well as exponent. Actual 24 bit would require packing and
514  // unpacking unaligned bytes and would be inefficient.
515  // ANSWER ME: is floatSample 64 bit on 64 bit machines?
516  if (captureFormat == int24Sample)
517  captureFormat = floatSample;
518 
519  mNumPlaybackChannels = numPlaybackChannels;
520  mNumCaptureChannels = numCaptureChannels;
521 
522  bool usePlayback = false, useCapture = false;
523  PaStreamParameters playbackParameters{};
524  PaStreamParameters captureParameters{};
525 
526  auto latencyDuration = AudioIOLatencyDuration.Read();
527 
528  if( numPlaybackChannels > 0)
529  {
530  usePlayback = true;
531 
532  // this sets the device index to whatever is "right" based on preferences,
533  // then defaults
534  playbackParameters.device = getPlayDevIndex();
535 
536  const PaDeviceInfo *playbackDeviceInfo;
537  playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
538 
539  if( playbackDeviceInfo == NULL )
540  return false;
541 
542  // regardless of source formats, we always mix to float
543  playbackParameters.sampleFormat = paFloat32;
544  playbackParameters.hostApiSpecificStreamInfo = NULL;
545  playbackParameters.channelCount = mNumPlaybackChannels;
546 
548  playbackParameters.suggestedLatency =
549  playbackDeviceInfo->defaultLowOutputLatency;
550  else {
551  // When using WASAPI, the suggested latency does not affect
552  // the latency of the playback, but the position of playback is given as if
553  // there was the suggested latency. This results in the last "suggested latency"
554  // of a selection not being played. So for WASAPI use 0.0 for the suggested
555  // latency regardless of user setting. See bug 1949.
556  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
557  bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
558  playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
559  }
560 
561  mOutputMeter = options.playbackMeter;
562  }
563 
564  if( numCaptureChannels > 0)
565  {
566  useCapture = true;
567  mCaptureFormat = captureFormat;
568 
569  const PaDeviceInfo *captureDeviceInfo;
570  // retrieve the index of the device set in the prefs, or a sensible
571  // default if it isn't set/valid
572  captureParameters.device = getRecordDevIndex();
573 
574  captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
575 
576  if( captureDeviceInfo == NULL )
577  return false;
578 
579  captureParameters.sampleFormat =
581 
582  captureParameters.hostApiSpecificStreamInfo = NULL;
583  captureParameters.channelCount = mNumCaptureChannels;
584 
586  captureParameters.suggestedLatency =
587  captureDeviceInfo->defaultHighInputLatency;
588  else
589  captureParameters.suggestedLatency = latencyDuration/1000.0;
590 
591  SetCaptureMeter( mOwningProject.lock(), options.captureMeter );
592  }
593 
594  SetMeters();
595 
596 #ifdef USE_PORTMIXER
597 #ifdef __WXMSW__
598  //mchinen nov 30 2010. For some reason Pa_OpenStream resets the input volume on windows.
599  //so cache and restore after it.
600  //The actual problem is likely in portaudio's pa_win_wmme.c OpenStream().
601  float oldRecordVolume = Px_GetInputVolume(mPortMixer);
602 #endif
603 #endif
604 
605  // July 2016 (Carsten and Uwe)
606  // BUG 193: Possibly tell portAudio to use 24 bit with DirectSound.
607  int userData = 24;
608  int* lpUserData = (captureFormat_saved == int24Sample) ? &userData : NULL;
609 
610  // (Linux, bug 1885) After scanning devices it takes a little time for the
611  // ALSA device to be available, so allow retries.
612  // On my test machine, no more than 3 attempts are required.
613  unsigned int maxTries = 1;
614 #ifdef __WXGTK__
615  {
616  using namespace std::chrono;
618  maxTries = 5;
619  }
620 #endif
621 
622  for (unsigned int tries = 0; tries < maxTries; tries++) {
623  mLastPaError = Pa_OpenStream( &mPortStreamV19,
624  useCapture ? &captureParameters : NULL,
625  usePlayback ? &playbackParameters : NULL,
626  mRate, paFramesPerBufferUnspecified,
627  paNoFlag,
628  audacityAudioCallback, lpUserData );
629  if (mLastPaError == paNoError) {
630  break;
631  }
632  wxLogDebug("Attempt %u to open capture stream failed with: %d", 1 + tries, mLastPaError);
633  using namespace std::chrono;
634  std::this_thread::sleep_for(1s);
635  }
636 
637 
638 #if USE_PORTMIXER
639 #ifdef __WXMSW__
640  Px_SetInputVolume(mPortMixer, oldRecordVolume);
641 #endif
642  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
643 
644  #ifdef __WXMAC__
645  if (mPortMixer) {
646  if (Px_SupportsPlaythrough(mPortMixer)) {
647  bool playthrough = false;
648 
649  mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
650 
651  // Bug 388. Feature not supported.
652  //gPrefs->Read(wxT("/AudioIO/Playthrough"), &playthrough, false);
653  if (playthrough)
654  Px_SetPlaythrough(mPortMixer, 1.0);
655  else
656  Px_SetPlaythrough(mPortMixer, 0.0);
657  }
658  }
659  #endif
660  }
661 #endif
662 
663 #if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
664  // Don't want the system to sleep while audio I/O is active
665  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
666  wxPowerResource::Acquire(wxPOWER_RESOURCE_SCREEN, _("Audacity Audio"));
667  }
668 #endif
669 
670  return (success = (mLastPaError == paNoError));
671 }

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(), ResetOwningProject(), AudioIOBase::SetCaptureMeter(), SetMeters(), and SetOwningProject().

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,
double  mixerLimit,
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()

Parameters
mixerLimitTime at which mixer stops producing, maybe > t1

Definition at line 742 of file AudioIO.cpp.

745 {
746  const auto &pStartTime = options.pStartTime;
747  t1 = std::min(t1, mixerLimit);
748 
749  mLostSamples = 0;
750  mLostCaptureIntervals.clear();
752  gPrefs->Read( WarningDialogKey(wxT("DropoutDetected")), true ) != 0;
753  auto cleanup = finally ( [this] { ClearRecordingException(); } );
754 
755  if( IsBusy() )
756  return 0;
757 
758  // We just want to set mStreamToken to -1 - this way avoids
759  // an extremely rare but possible race condition, if two functions
760  // somehow called StartStream at the same time...
761  mStreamToken--;
762  if (mStreamToken != -1)
763  return 0;
764 
765  // TODO: we don't really need to close and reopen stream if the
766  // format matches; however it's kind of tricky to keep it open...
767  //
768  // if (sampleRate == mRate &&
769  // playbackChannels == mNumPlaybackChannels &&
770  // captureChannels == mNumCaptureChannels &&
771  // captureFormat == mCaptureFormat) {
772 
773  if (mPortStreamV19) {
774  StopStream();
775  while(mPortStreamV19) {
776  using namespace std::chrono;
777  std::this_thread::sleep_for(50ms);
778  }
779  }
780 
781 #ifdef __WXGTK__
782  // Detect whether ALSA is the chosen host, and do the various involved MIDI
783  // timing compensations only then.
784  mUsingAlsa = (AudioIOHost.Read() == L"ALSA");
785 #endif
786 
787  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
788  gPrefs->Read(wxT("/AudioIO/SoundActivatedRecord"), &mPauseRec, false);
789  gPrefs->Read(wxT("/AudioIO/Microfades"), &mbMicroFades, false);
790  int silenceLevelDB;
791  gPrefs->Read(wxT("/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
792  int dBRange = DecibelScaleCutoff.Read();
793  if(silenceLevelDB < -dBRange)
794  {
795  silenceLevelDB = -dBRange + 3;
796  // meter range was made smaller than SilenceLevel
797  // so set SilenceLevel reasonable
798 
799  // PRL: update prefs, or correct it only in-session?
800  // The behavior (as of 2.3.1) was the latter, the code suggested that
801  // the intent was the former; I preserve the behavior, but uncomment
802  // this if you disagree.
803  // gPrefs->Write(wxT("/AudioIO/SilenceLevel"), silenceLevelDB);
804  // gPrefs->Flush();
805  }
806  mSilenceLevel = DB_TO_LINEAR(silenceLevelDB); // meter goes -dBRange dB -> 0dB
807 
808  // Clamp pre-roll so we don't play before time 0
809  const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
810  mRecordingSchedule = {};
811  mRecordingSchedule.mPreRoll = preRoll;
813  AudioIOLatencyCorrection.Read() / 1000.0;
814  mRecordingSchedule.mDuration = t1 - t0;
815  if (options.pCrossfadeData)
817 
818  mListener = options.listener;
819  mRate = options.rate;
820 
821  mSeek = 0;
823  mCaptureTracks = tracks.captureTracks;
825 
826  bool commit = false;
827  auto cleanupTracks = finally([&]{
828  if (!commit) {
829  // Don't keep unnecessary shared pointers to tracks
830  mPlaybackTracks.clear();
831  mCaptureTracks.clear();
832  for(auto &ext : Extensions())
833  ext.AbortOtherStream();
834 
835  // Don't cause a busy wait in the audio thread after stopping scrubbing
837  }
838  });
839 
840  mPlaybackBuffers.reset();
841  mPlaybackMixers.clear();
842  mCaptureBuffers.reset();
843  mResample.reset();
845 
847  t0, t1, options, mCaptureTracks.empty() ? nullptr : &mRecordingSchedule );
848 
849  unsigned int playbackChannels = 0;
850  unsigned int captureChannels = 0;
851  sampleFormat captureFormat = floatSample;
852 
853  auto pListener = GetListener();
854 
855  if (tracks.playbackTracks.size() > 0
856  || tracks.otherPlayableTracks.size() > 0)
857  playbackChannels = 2;
858 
860  playbackChannels = 2;
861 
862  if (tracks.captureTracks.size() > 0)
863  {
864  // For capture, every input channel gets its own track
865  captureChannels = mCaptureTracks.size();
866  // I don't deal with the possibility of the capture tracks
867  // having different sample formats, since it will never happen
868  // with the current code. This code wouldn't *break* if this
869  // assumption was false, but it would be sub-optimal. For example,
870  // if the first track was 16-bit and the second track was 24-bit,
871  // we would set the sound card to capture in 16 bits and the second
872  // track wouldn't get the benefit of all 24 bits the card is capable
873  // of.
874  captureFormat = mCaptureTracks[0]->GetSampleFormat();
875 
876  // Tell project that we are about to start recording
877  if (pListener)
878  pListener->OnAudioIOStartRecording();
879  }
880 
881  bool successAudio;
882 
883  successAudio = StartPortAudioStream(options, playbackChannels,
884  captureChannels, captureFormat);
885 
886  // Call this only after reassignment of mRate that might happen in the
887  // previous call.
889 
890 #ifdef EXPERIMENTAL_MIDI_OUT
891  auto range = Extensions();
892  successAudio = successAudio &&
893  std::all_of(range.begin(), range.end(),
894  [this, &tracks, t0](auto &ext){
895  return ext.StartOtherStream( tracks,
896  (mPortStreamV19 != NULL && mLastPaError == paNoError)
897  ? Pa_GetStreamInfo(mPortStreamV19) : nullptr,
898  t0, mRate ); });
899 #endif
900 
901  if (!successAudio) {
902  if (pListener && captureChannels > 0)
903  pListener->OnAudioIOStopRecording();
904  mStreamToken = 0;
905 
906  return 0;
907  }
908 
909  {
910  double mixerStart = t0;
911  if (pStartTime)
912  mixerStart = std::min( mixerStart, *pStartTime );
913  if ( ! AllocateBuffers( options, tracks,
914  mixerStart, mixerLimit, options.rate ) )
915  return 0;
916  }
917 
918  if (mNumPlaybackChannels > 0)
919  {
920  if (auto pOwningProject = mOwningProject.lock()) {
921  auto & em = RealtimeEffectManager::Get(*pOwningProject);
922  // Setup for realtime playback at the rate of the realtime
923  // stream, not the rate of the track.
924  em.RealtimeInitialize(mRate);
925 
926  // The following adds a NEW effect processor for each logical track and the
927  // group determination should mimic what is done in audacityAudioCallback()
928  // when calling RealtimeProcess().
929  int group = 0;
930  for (size_t i = 0, cnt = mPlaybackTracks.size(); i < cnt;)
931  {
932  const WaveTrack *vt = mPlaybackTracks[i].get();
933 
934  // TODO: more-than-two-channels
935  unsigned chanCnt = TrackList::Channels(vt).size();
936  i += chanCnt;
937 
938  // Setup for realtime playback at the rate of the realtime
939  // stream, not the rate of the track.
940  em.RealtimeAddProcessor(group++, std::min(2u, chanCnt), mRate);
941  }
942  }
943  }
944 
945 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
946  AILASetStartTime();
947 #endif
948 
949  if (pStartTime)
950  {
951  // Calculate the NEW time position
952  const auto time = *pStartTime;
953 
954  // Main thread's initialization of mTime
957 
958  // Reset mixer positions for all playback tracks
959  unsigned numMixers = mPlaybackTracks.size();
960  for (unsigned ii = 0; ii < numMixers; ++ii)
961  mPlaybackMixers[ii]->Reposition( time );
962  }
963 
964  // Now that we are done with AllocateBuffers() and SetTrackTime():
966  // else recording only without overdub
967 
968  // We signal the audio thread to call TrackBufferExchange, to prime the RingBuffers
969  // so that they will have data in them when the stream starts. Having the
970  // audio thread call TrackBufferExchange here makes the code more predictable, since
971  // TrackBufferExchange will ALWAYS get called from the Audio thread.
973 
975  using namespace std::chrono;
976  auto interval = 50ms;
977  if (options.playbackStreamPrimer) {
978  interval = options.playbackStreamPrimer();
979  }
980  std::this_thread::sleep_for(interval);
981  }
982 
984 
985 #ifdef REALTIME_ALSA_THREAD
986  // PRL: Do this in hope of less thread scheduling jitter in calls to
987  // audacityAudioCallback.
988  // Not needed to make audio playback work smoothly.
989  // But needed in case we also play MIDI, so that the variable "offset"
990  // in AudioIO::MidiTime() is a better approximation of the duration
991  // between the call of audacityAudioCallback and the actual output of
992  // the first audio sample.
993  // (Which we should be able to determine from fields of
994  // PaStreamCallbackTimeInfo, but that seems not to work as documented with
995  // ALSA.)
996  if (mUsingAlsa)
997  // Perhaps we should do this only if also playing MIDI ?
998  PaAlsa_EnableRealtimeScheduling( mPortStreamV19, 1 );
999 #endif
1000 
1001  //
1002  // Generate a unique value each time, to be returned to
1003  // clients accessing the AudioIO API, so they can query if they
1004  // are the ones who have reserved AudioIO or not.
1005  //
1006  // It is important to set this before setting the portaudio stream in
1007  // motion -- otherwise it may play an unspecified number of leading
1008  // zeroes.
1010 
1011  // This affects the AudioThread (not the portaudio callback).
1012  // Probably not needed so urgently before portaudio thread start for usual
1013  // playback, since our ring buffers have been primed already with 4 sec
1014  // of audio, but then we might be scrubbing, so do it.
1016  mForceFadeOut.store(false, std::memory_order_relaxed);
1017 
1018  // Now start the PortAudio stream!
1019  PaError err;
1020  err = Pa_StartStream( mPortStreamV19 );
1021 
1022  if( err != paNoError )
1023  {
1024  mStreamToken = 0;
1026  if (pListener && mNumCaptureChannels > 0)
1027  pListener->OnAudioIOStopRecording();
1029  // PRL: PortAudio error messages are sadly not internationalized
1031  Verbatim( LAT1CTOWX(Pa_GetErrorText(err)) ) );
1032  return 0;
1033  }
1034  }
1035 
1036  // Update UI display only now, after all possibilities for error are past.
1037  if (pListener) {
1038  // advertise the chosen I/O sample rate to the UI
1039  pListener->OnAudioIORate((int)mRate);
1040  }
1041 
1042  auto pOwningProject = mOwningProject.lock();
1043  if (mNumPlaybackChannels > 0)
1044  Publish({ pOwningProject.get(), AudioIOEvent::PLAYBACK, true });
1045  if (mNumCaptureChannels > 0)
1046  Publish({ pOwningProject.get(), AudioIOEvent::CAPTURE, true });
1047 
1048  commit = true;
1049  return mStreamToken;
1050 }

References AllocateBuffers(), AudacityMessageBox(), AudioIOHost, AudioIOLatencyCorrection, AudioIOEvent::CAPTURE, TransportTracks::captureTracks, TrackList::Channels(), PlaybackSchedule::TimeQueue::Clear(), AudioIoCallback::ClearRecordingException(), DB_TO_LINEAR(), DecibelScaleCutoff, AudioIoCallback::Extensions(), floatSample, RealtimeEffectManager::Get(), AudioIoCallback::GetListener(), PlaybackSchedule::GetPolicy(), PlaybackSchedule::GetTrackTime(), gPrefs, PlaybackSchedule::Init(), PlaybackPolicy::Initialize(), AudioIOBase::IsBusy(), LAT1CTOWX, AudioIOStartStreamOptions::listener, AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning, AudioIoCallback::mbMicroFades, AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, RecordingSchedule::mCrossfadeData, AudioIoCallback::mDetectDropouts, RecordingSchedule::mDuration, AudioIoCallback::mForceFadeOut, min(), AudioIoCallback::mLastRecordingOffset, 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::mTimeQueue, AudioIoCallback::mUsingAlsa, PlaybackPolicy::OffsetTrackTime(), TransportTracks::otherPlayableTracks, AudioIOStartStreamOptions::pCrossfadeData, AudioIOEvent::PLAYBACK, AudioIOStartStreamOptions::playbackStreamPrimer, TransportTracks::playbackTracks, AudioIOStartStreamOptions::preRoll, PlaybackSchedule::TimeQueue::Prime(), AudioIOStartStreamOptions::pStartTime, Observer::Publisher< AudioIOEvent >::Publish(), AudioIOStartStreamOptions::rate, Setting< T >::Read(), 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 1270 of file AudioIO.cpp.

1271 {
1272  if (mNumPlaybackChannels > 0)
1273  {
1274  if (auto pOwningProject = mOwningProject.lock())
1275  RealtimeEffectManager::Get(*pOwningProject).RealtimeFinalize();
1276  }
1277 
1278  mPlaybackBuffers.reset();
1279  mPlaybackMixers.clear();
1280  mCaptureBuffers.reset();
1281  mResample.reset();
1283 
1284  if(!bOnlyBuffers)
1285  {
1286  Pa_AbortStream( mPortStreamV19 );
1287  Pa_CloseStream( mPortStreamV19 );
1288  mPortStreamV19 = NULL;
1289  mStreamToken = 0;
1290  }
1291 
1293 }

References PlaybackSchedule::TimeQueue::Clear(), PlaybackPolicy::Finalize(), RealtimeEffectManager::Get(), PlaybackSchedule::GetPolicy(), AudioIoCallback::mCaptureBuffers, AudioIoCallback::mNumPlaybackChannels, AudioIOBase::mOwningProject, 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 1311 of file AudioIO.cpp.

1312 {
1313  auto cleanup = finally ( [this] {
1315  mRecordingSchedule.mCrossfadeData.clear(); // free arrays
1316  } );
1317 
1318  if( mPortStreamV19 == NULL )
1319  return;
1320 
1321  // DV: This code seems to be unnecessary.
1322  // We do not leave mPortStreamV19 open in stopped
1323  // state. (Do we?)
1324  // This breaks WASAPI backend, as it sets the `running`
1325  // flag to `false` asynchronously.
1326  // Previously we have patched PortAudio and the patch
1327  // was breaking IsStreamStopped() == !IsStreamActive()
1328  // invariant.
1329  /*
1330  if ( Pa_IsStreamStopped(mPortStreamV19) )
1331  return;
1332  */
1333 
1334 #if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1335  // Re-enable system sleep
1336  wxPowerResource::Release(wxPOWER_RESOURCE_SCREEN);
1337 #endif
1338 
1340  {
1341  // PortAudio callback can use the information that we are stopping to fade
1342  // out the audio. Give PortAudio callback a chance to do so.
1343  mForceFadeOut.store(true, std::memory_order_relaxed);
1344  auto latency = static_cast<long>(AudioIOLatencyDuration.Read());
1345  // If we can gracefully fade out in 200ms, with the faded-out play buffers making it through
1346  // the sound card, then do so. If we can't, don't wait around. Just stop quickly and accept
1347  // there will be a click.
1348  if( mbMicroFades && (latency < 150 )) {
1349  using namespace std::chrono;
1350  std::this_thread::sleep_for(milliseconds{latency + 50});
1351  }
1352  }
1353 
1354  wxMutexLocker locker(mSuspendAudioThread);
1355 
1356  // No longer need effects processing
1357  if (mNumPlaybackChannels > 0)
1358  {
1359  if (auto pOwningProject = mOwningProject.lock())
1360  RealtimeEffectManager::Get(*pOwningProject).RealtimeFinalize();
1361  }
1362 
1363  //
1364  // We got here in one of two ways:
1365  //
1366  // 1. The user clicked the stop button and we therefore want to stop
1367  // as quickly as possible. So we use AbortStream(). If this is
1368  // the case the portaudio stream is still in the Running state
1369  // (see PortAudio state machine docs).
1370  //
1371  // 2. The callback told PortAudio to stop the stream since it had
1372  // reached the end of the selection. The UI thread discovered
1373  // this by noticing that AudioIO::IsActive() returned false.
1374  // IsActive() (which calls Pa_GetStreamActive()) will not return
1375  // false until all buffers have finished playing, so we can call
1376  // AbortStream without losing any samples. If this is the case
1377  // we are in the "callback finished state" (see PortAudio state
1378  // machine docs).
1379  //
1380  // The moral of the story: We can call AbortStream safely, without
1381  // losing samples.
1382  //
1383  // DMM: This doesn't seem to be true; it seems to be necessary to
1384  // call StopStream if the callback brought us here, and AbortStream
1385  // if the user brought us here.
1386  //
1387  // DV: Seems that Pa_CloseStream calls Pa_AbortStream internally,
1388  // at least for PortAudio 19.7.0+
1389 
1391 
1392  // Audacity can deadlock if it tries to update meters while
1393  // we're stopping PortAudio (because the meter updating code
1394  // tries to grab a UI mutex while PortAudio tries to join a
1395  // pthread). So we tell the callback to stop updating meters,
1396  // and wait until the callback has left this part of the code
1397  // if it was already there.
1398  mUpdateMeters = false;
1399  while(mUpdatingMeters) {
1400  ::wxSafeYield();
1401  using namespace std::chrono;
1402  std::this_thread::sleep_for(50ms);
1403  }
1404 
1405  // Turn off HW playthrough if PortMixer is being used
1406 
1407  #if defined(USE_PORTMIXER)
1408  if( mPortMixer ) {
1409  #if __WXMAC__
1410  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1411  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1412  mPreviousHWPlaythrough = -1.0;
1413  #endif
1414  }
1415  #endif
1416 
1417  if (mPortStreamV19) {
1418  // DV: Pa_CloseStream will close Pa_AbortStream internally,
1419  // but it doesn't hurt to do it ourselves.
1420  // PA_AbortStream will silently fail if stream is stopped.
1421  if (!Pa_IsStreamStopped( mPortStreamV19 ))
1422  Pa_AbortStream( mPortStreamV19 );
1423 
1424  Pa_CloseStream( mPortStreamV19 );
1425 
1426  mPortStreamV19 = NULL;
1427  }
1428 
1429  for( auto &ext : Extensions() )
1430  ext.StopOtherStream();
1431 
1432  auto pListener = GetListener();
1433 
1434  // If there's no token, we were just monitoring, so we can
1435  // skip this next part...
1436  if (mStreamToken > 0) {
1437  // In either of the above cases, we want to make sure that any
1438  // capture data that made it into the PortAudio callback makes it
1439  // to the target WaveTrack. To do this, we ask the audio thread to
1440  // call TrackBufferExchange one last time (it normally would not do so since
1441  // Pa_GetStreamActive() would now return false
1443 
1445  {
1446  //FIXME: Seems like this block of the UI thread isn't bounded,
1447  //but we cannot allow event handlers to see incompletely terminated
1448  //AudioIO state with wxYield (or similar functions)
1449  using namespace std::chrono;
1450  std::this_thread::sleep_for(50ms);
1451  }
1452 
1453  //
1454  // Everything is taken care of. Now, just free all the resources
1455  // we allocated in StartStream()
1456  //
1457 
1458  if (mPlaybackTracks.size() > 0)
1459  {
1460  mPlaybackBuffers.reset();
1461  mPlaybackMixers.clear();
1463  }
1464 
1465  //
1466  // Offset all recorded tracks to account for latency
1467  //
1468  if (mCaptureTracks.size() > 0)
1469  {
1470  mCaptureBuffers.reset();
1471  mResample.reset();
1472 
1473  //
1474  // We only apply latency correction when we actually played back
1475  // tracks during the recording. If we did not play back tracks,
1476  // there's nothing we could be out of sync with. This also covers the
1477  // case that we do not apply latency correction when recording the
1478  // first track in a project.
1479  //
1480 
1481  for (unsigned int i = 0; i < mCaptureTracks.size(); i++) {
1482  // The calls to Flush
1483  // may cause exceptions because of exhaustion of disk space.
1484  // Stop those exceptions here, or else they propagate through too
1485  // many parts of Audacity that are not effects or editing
1486  // operations. GuardedCall ensures that the user sees a warning.
1487 
1488  // Also be sure to Flush each track, at the top of the guarded call,
1489  // relying on the guarantee that the track will be left in a flushed
1490  // state, though the append buffer may be lost.
1491 
1492  GuardedCall( [&] {
1493  WaveTrack* track = mCaptureTracks[i].get();
1494 
1495  // use No-fail-guarantee that track is flushed,
1496  // Partial-guarantee that some initial length of the recording
1497  // is saved.
1498  // See comments in TrackBufferExchange().
1499  track->Flush();
1500  } );
1501  }
1502 
1503 
1504  if (!mLostCaptureIntervals.empty())
1505  {
1506  // This scope may combine many splittings of wave tracks
1507  // into one transaction, lessening the number of checkpoints
1508  std::optional<TransactionScope> pScope;
1509  if (auto pOwningProject = mOwningProject.lock())
1510  pScope.emplace(*pOwningProject, "Dropouts");
1511  for (auto &interval : mLostCaptureIntervals) {
1512  auto &start = interval.first;
1513  auto duration = interval.second;
1514  for (auto &track : mCaptureTracks) {
1515  GuardedCall([&] {
1516  track->SyncLockAdjust(start, start + duration);
1517  });
1518  }
1519  }
1520  if (pScope)
1521  pScope->Commit();
1522  }
1523 
1524  if (pListener)
1525  pListener->OnCommitRecording();
1526  }
1527  }
1528 
1529  if (auto pInputMeter = mInputMeter.lock())
1530  pInputMeter->Reset(mRate, false);
1531 
1532  if (auto pOutputMeter = mOutputMeter.lock())
1533  pOutputMeter->Reset(mRate, false);
1534 
1535  mInputMeter.reset();
1536  mOutputMeter.reset();
1538 
1539  if (pListener && mNumCaptureChannels > 0)
1540  pListener->OnAudioIOStopRecording();
1541 
1542  wxTheApp->CallAfter([this]{
1544  // Recording was restarted between StopStream and idle time
1545  // So the actions can keep waiting
1546  return;
1547  // In case some other thread was waiting on the mutex too:
1548  std::this_thread::yield();
1549  std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
1550  if (mPostRecordingAction) {
1552  mPostRecordingAction = {};
1553  }
1554  DelayActions(false);
1555  });
1556 
1557  //
1558  // Only set token to 0 after we're totally finished with everything
1559  //
1560  bool wasMonitoring = mStreamToken == 0;
1561  mStreamToken = 0;
1562 
1563  {
1564  auto pOwningProject = mOwningProject.lock();
1565  if (mNumPlaybackChannels > 0)
1566  Publish({ pOwningProject.get(), AudioIOEvent::PLAYBACK, false });
1567  if (mNumCaptureChannels > 0)
1568  Publish({ pOwningProject.get(),
1569  wasMonitoring
1572  false });
1573  }
1574 
1575  mNumCaptureChannels = 0;
1577 
1578  mPlaybackTracks.clear();
1579  mCaptureTracks.clear();
1580 
1582 
1583  if (pListener) {
1584  // Tell UI to hide sample rate
1585  pListener->OnAudioIORate(0);
1586  }
1587 
1588  // Don't cause a busy wait in the audio thread after stopping scrubbing
1590 }

References AudioIOLatencyDuration, AudioIOEvent::CAPTURE, PlaybackSchedule::TimeQueue::Clear(), AudioIoCallback::ClearRecordingException(), DelayActions(), AudioIoCallback::Extensions(), PlaybackPolicy::Finalize(), WaveTrack::Flush(), RealtimeEffectManager::Get(), AudioIoCallback::GetListener(), PlaybackSchedule::GetPolicy(), GuardedCall(), AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce, AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning, AudioIoCallback::mbMicroFades, AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, RecordingSchedule::mCrossfadeData, AudioIoCallback::mForceFadeOut, AudioIOBase::mInputMeter, AudioIoCallback::mLostCaptureIntervals, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPlaybackChannels, AudioIOEvent::MONITOR, 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, AudioIOEvent::PLAYBACK, Observer::Publisher< AudioIOEvent >::Publish(), Setting< T >::Read(), RealtimeEffectManager::RealtimeFinalize(), KeyboardCapture::Release(), PlaybackSchedule::ResetMode(), and ResetOwningProject().

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 1766 of file AudioIO.cpp.

1767 {
1768  FillPlayBuffers();
1770 }

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 264 of file AudioIO.cpp.

265 {
266  const PaDeviceInfo *pInfo = Pa_GetDeviceInfo(getPlayDevIndex(play));
267  const PaDeviceInfo *rInfo = Pa_GetDeviceInfo(getRecordDevIndex(rec));
268 
269  // Valid iff both defined and the same api.
270  return pInfo != nullptr && rInfo != nullptr && pInfo->hostApi == rInfo->hostApi;
271 }

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 488 of file AudioIO.h.

Member Data Documentation

◆ mDelayingActions

bool AudioIO::mDelayingActions { false }
private

Definition at line 569 of file AudioIO.h.

Referenced by DelayActions(), and DelayingActions().

◆ mPostRecordingAction

PostRecordingAction AudioIO::mPostRecordingAction
private

Definition at line 567 of file AudioIO.h.

Referenced by CallAfterRecording(), and StopStream().

◆ mPostRecordingActionMutex

std::mutex AudioIO::mPostRecordingActionMutex
private

Definition at line 566 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:945
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:278
AudioIOLatencyCorrection
DoubleSetting AudioIOLatencyCorrection
Definition: AudioIOBase.cpp:935
AudioIOPlaybackDevice
StringSetting AudioIOPlaybackDevice
Definition: AudioIOBase.cpp:939
AudioIoCallback::mCaptureFormat
sampleFormat mCaptureFormat
Definition: AudioIO.h:287
ClearSamples
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
Definition: SampleFormat.cpp:77
RecordingSchedule::mLatencyCorrection
double mLatencyCorrection
Definition: PlaybackSchedule.h:137
AudioIO::AllocateBuffers
bool AllocateBuffers(const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate)
Allocate RingBuffer structures, and others, needed for playback and recording.
Definition: AudioIO.cpp:1090
TransportTracks::playbackTracks
WaveTrackArray playbackTracks
Definition: AudioIO.h:70
SampleBuffer::Allocate
SampleBuffer & Allocate(size_t count, sampleFormat format)
Definition: SampleFormat.h:84
AudioIOStartStreamOptions::playbackMeter
std::weak_ptr< Meter > playbackMeter
Definition: AudioIOBase.h:54
AudioIoCallback::mPlaybackTracks
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:261
AudioIOStartStreamOptions::rate
double rate
Definition: AudioIOBase.h:57
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:269
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:75
RecordingSchedule::mPosition
double mPosition
Definition: PlaybackSchedule.h:143
AudioIOBase::DeviceName
static wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:71
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:423
AudioIoCallback::mForceFadeOut
std::atomic< bool > mForceFadeOut
Definition: AudioIO.h:293
AudioIO::LastPaErrorString
wxString LastPaErrorString()
Definition: AudioIO.cpp:673
PlaybackSchedule::SetTrackTime
void SetTrackTime(double time)
Set current track time value, unadjusted.
Definition: PlaybackSchedule.h:403
AudioIOStartStreamOptions::listener
std::shared_ptr< AudioIOListener > listener
Definition: AudioIOBase.h:56
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
AudioIoCallback::mThread
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:255
PlaybackSchedule::GetPolicy
PlaybackPolicy & GetPolicy()
Definition: PlaybackSchedule.cpp:139
KeyboardCapture::Release
void Release(wxWindow *handler)
Definition: KeyboardCapture.cpp:65
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:71
AudioIOBase::mPortStreamV19
PaStream * mPortStreamV19
Definition: AudioIOBase.h:255
AudacityToPortAudioSampleFormat
static PaSampleFormat AudacityToPortAudioSampleFormat(sampleFormat format)
Definition: AudioIO.cpp:463
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:241
SampleTrackConstArray
std::vector< std::shared_ptr< const SampleTrack > > SampleTrackConstArray
Definition: Mix.h:33
TransportTracks::captureTracks
WaveTrackArray captureTracks
Definition: AudioIO.h:71
WaveTrack::Flush
void Flush() override
Definition: WaveTrack.cpp:1841
AudioIoCallback::mNumPlaybackChannels
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:286
AudioIoCallback::mPlaybackMixers
std::vector< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:263
AudioIOBase::mInputMixerWorks
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIOBase.h:272
AudioIoCallback::mNumCaptureChannels
unsigned int mNumCaptureChannels
Definition: AudioIO.h:285
PlaybackSchedule::mT0
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: PlaybackSchedule.h:268
AudioIOBase::getPlayDevIndex
static int getPlayDevIndex(const wxString &devName={})
get the index of the device selected in the preferences.
Definition: AudioIOBase.cpp:581
AudioIoCallback::mMixerOutputVol
float mMixerOutputVol
Definition: AudioIO.h:265
Setting::Write
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:171
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1483
PlaybackSchedule::TimeQueue::Prime
void Prime(double time)
Empty the queue and reassign the last produced time.
Definition: PlaybackSchedule.cpp:618
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:1608
AudioIoCallback::mUpdatingMeters
volatile bool mUpdatingMeters
Definition: AudioIO.h:303
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:636
AudioIoCallback::mPlaybackSamplesToCopy
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
Definition: AudioIO.h:276
AudioIOStartStreamOptions::playbackStreamPrimer
std::function< std::chrono::milliseconds() > playbackStreamPrimer
Definition: AudioIOBase.h:69
XO
#define XO(s)
Definition: Internat.h:31
AudioIOBase::IsStreamActive
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIOBase.cpp:340
AudioIO::DelayActions
void DelayActions(bool recording)
Definition: AudioIO.cpp:1052
int24Sample
@ int24Sample
Definition: SampleFormat.h:33
AudioIOStartStreamOptions::preRoll
double preRoll
Definition: AudioIOBase.h:59
PlaybackSchedule::Init
void Init(double t0, double t1, const AudioIOStartStreamOptions &options, const RecordingSchedule *pRecordingSchedule)
Definition: PlaybackSchedule.cpp:416
AudioIoCallback::mPlaybackBuffers
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:260
AudioIOStartStreamOptions::captureMeter
std::weak_ptr< Meter > captureMeter
Definition: AudioIOBase.h:54
AudioIoCallback::mUpdateMeters
bool mUpdateMeters
Definition: AudioIO.h:302
PlaybackSchedule::TimeQueue::Resize
void Resize(size_t size)
Definition: PlaybackSchedule.cpp:523
AudioIoCallback::mDetectDropouts
bool mDetectDropouts
Definition: AudioIO.h:330
AudioIoCallback::mRecordingException
wxAtomicInt mRecordingException
Definition: AudioIO.h:323
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:368
AudioIO::GetNumCaptureChannels
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:444
AudioIOBase::ugAudioIO
static std::unique_ptr< AudioIOBase > ugAudioIO
Definition: AudioIOBase.h:241
RecordingSchedule::TotalCorrection
double TotalCorrection() const
Definition: PlaybackSchedule.h:146
TransportTracks::otherPlayableTracks
PlayableTrackConstArray otherPlayableTracks
Definition: AudioIO.h:72
AudioIOBase::IsBusy
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIOBase.cpp:332
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:127
PlaybackSchedule::mTimeQueue
class PlaybackSchedule::TimeQueue mTimeQueue
AudioIoCallback::mAudioThreadShouldCallTrackBufferExchangeOnce
volatile bool mAudioThreadShouldCallTrackBufferExchangeOnce
Definition: AudioIO.h:289
AudioIO::mDelayingActions
bool mDelayingActions
Definition: AudioIO.h:569
AudioIOLatencyDuration
DoubleSetting AudioIOLatencyDuration
Definition: AudioIOBase.cpp:937
floatSample
@ floatSample
Definition: SampleFormat.h:34
AudioIoCallback::Extensions
AudioIOExtRange Extensions()
Definition: AudioIO.h:160
AudioIOBase::mOwningProject
std::weak_ptr< AudacityProject > mOwningProject
Definition: AudioIOBase.h:245
DefaultDelayedHandlerAction
void DefaultDelayedHandlerAction(AudacityException *pException)
A default template parameter for GuardedCall.
Definition: AudacityException.h:123
AudacityException
Base class for exceptions specially processed by the application.
Definition: AudacityException.h:33
AudioIO::mPostRecordingAction
PostRecordingAction mPostRecordingAction
Definition: AudioIO.h:567
RecordingSchedule::ToConsume
double ToConsume() const
Definition: PlaybackSchedule.cpp:501
AudioIoCallback::mSoftwarePlaythrough
bool mSoftwarePlaythrough
Definition: AudioIO.h:281
WaveTrack::SyncLockAdjust
void SyncLockAdjust(double oldT1, double newT1) override
Definition: WaveTrack.cpp:1368
PlaybackSchedule::ResetMode
void ResetMode()
Definition: PlaybackSchedule.h:406
AudioIOBase::mPaused
bool mPaused
True if audio playback is paused.
Definition: AudioIOBase.h:248
AudioIOEvent::CAPTURE
@ CAPTURE
Definition: AudioIO.h:63
AudioIoCallback::mPauseRec
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:283
Observer::Publisher< AudioIOEvent >::Publish
CallbackReturn Publish(const AudioIOEvent &message)
Send a message to connected callbacks.
Definition: Observer.h:207
AudioIOEvent::PLAYBACK
@ PLAYBACK
Definition: AudioIO.h:62
PlaybackPolicy::OffsetTrackTime
virtual double OffsetTrackTime(PlaybackSchedule &schedule, double offset)
Called when the play head needs to jump a certain distance.
Definition: PlaybackSchedule.cpp:61
RealtimeEffectManager::RealtimeFinalize
void RealtimeFinalize()
Definition: RealtimeEffectManager.cpp:133
AudioIoCallback::mCaptureBuffers
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:258
AudioIO::GetCommonlyAvailCapture
size_t GetCommonlyAvailCapture()
Get the number of audio samples ready in all of the recording buffers.
Definition: AudioIO.cpp:1754
AudioIoCallback::mAudioThreadTrackBufferExchangeLoopRunning
volatile bool mAudioThreadTrackBufferExchangeLoopRunning
Definition: AudioIO.h:290
AudioIoCallback::mLastPlaybackTimeMillis
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:295
AudioIOBase::mInputMeter
std::weak_ptr< Meter > mInputMeter
Definition: AudioIOBase.h:257
AudioIO::ResetOwningProject
void ResetOwningProject()
Definition: AudioIO.cpp:689
PaError
int PaError
Definition: AudioIO.h:51
PlaybackSchedule::TimeQueue::Clear
void Clear()
Definition: PlaybackSchedule.cpp:516
AudioIoCallback::mRecordingSchedule
RecordingSchedule mRecordingSchedule
Definition: AudioIO.h:345
AudioIoCallback::mPlaybackRingBufferSecs
PlaybackPolicy::Duration mPlaybackRingBufferSecs
Definition: AudioIO.h:272
RecordingSchedule::mCrossfadeData
PRCrossfadeData mCrossfadeData
Definition: PlaybackSchedule.h:139
format
int format
Definition: ExportPCM.cpp:56
PlaybackPolicy::Initialize
virtual void Initialize(PlaybackSchedule &schedule, double rate)
Called before starting an audio stream.
Definition: PlaybackSchedule.cpp:25
AudioIoCallback::mLostSamples
unsigned long long mLostSamples
Definition: AudioIO.h:288
AudioIOBase::Get
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:89
AudioIOBase::mRate
double mRate
Audio playback rate in samples per second.
Definition: AudioIOBase.h:253
AudioIoCallback::mSuspendAudioThread
wxMutex mSuspendAudioThread
Definition: AudioIO.h:318
AudioIoCallback::mLastRecordingOffset
volatile double mLastRecordingOffset
Definition: AudioIO.h:297
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:502
AudioIOBase::SetMixer
void SetMixer(int inputSource)
Definition: AudioIOBase.cpp:98
BAD_STREAM_TIME
#define BAD_STREAM_TIME
Definition: AudioIOBase.h:37
AudioIOBase::HostName
static wxString HostName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:78
AudioIoCallback::mNextStreamToken
static int mNextStreamToken
Definition: AudioIO.h:266
PlaybackPolicy::SuggestedBufferTimes
virtual BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule)
Provide hints for construction of playback RingBuffer objects.
Definition: PlaybackSchedule.cpp:38
AudioIoCallback::mCachedBestRateCapturing
static bool mCachedBestRateCapturing
Definition: AudioIO.h:314
audacityAudioCallback
int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
Definition: AudioIO.cpp:2258
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:476
DecibelScaleCutoff
IntSetting DecibelScaleCutoff
Negation of this value is the lowest dB level that should be shown in dB scales.
Definition: Decibels.cpp:12
BasicUI::ErrorDialogOptions
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:49
AudioIOStartStreamOptions::pStartTime
std::optional< double > pStartTime
Definition: AudioIOBase.h:58
AudioIoCallback::ClearRecordingException
void ClearRecordingException()
Definition: AudioIO.h:326
SampleBuffer
Definition: SampleFormat.h:69
sampleFormat
sampleFormat
Definition: SampleFormat.h:29
AudioIO::DelayingActions
bool DelayingActions() const
Definition: AudioIO.cpp:1057
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:273
AudioIO::SetOwningProject
void SetOwningProject(const std::shared_ptr< AudacityProject > &pProject)
Definition: AudioIO.cpp:678
AudioIOPlaybackVolume
DoubleSetting AudioIOPlaybackVolume
Definition: AudioIOBase.cpp:941
AudioIO::mPostRecordingActionMutex
std::mutex mPostRecordingActionMutex
Definition: AudioIO.h:566
RealtimeEffectManager::Get
static RealtimeEffectManager & Get(AudacityProject &project)
Definition: RealtimeEffectManager.cpp:30
BasicUI
Definition: Effect.h:47
AudioIoCallback::GetCommonlyReadyPlayback
size_t GetCommonlyReadyPlayback()
Get the number of audio samples ready in all of the playback buffers.
Definition: AudioIO.cpp:1745
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:433
AudioIOStartStreamOptions::pCrossfadeData
PRCrossfadeData * pCrossfadeData
Definition: AudioIOBase.h:64
TimeQueueGrainSize
constexpr size_t TimeQueueGrainSize
Definition: PlaybackSchedule.h:29
AudioIoCallback::mUsingAlsa
bool mUsingAlsa
Definition: AudioIO.h:309
AudioIOBase::SetCaptureMeter
void SetCaptureMeter(const std::shared_ptr< AudacityProject > &project, const std::weak_ptr< Meter > &meter)
Definition: AudioIOBase.cpp:293
AudioIO::StartStreamCleanup
void StartStreamCleanup(bool bOnlyBuffers=false)
Clean up after StartStream if it fails.
Definition: AudioIO.cpp:1270
DeviceManager::GetTimeSinceRescan
std::chrono::duration< float > GetTimeSinceRescan()
Definition: DeviceManager.cpp:297
_
#define _(s)
Definition: Internat.h:75
AudioIoCallback::mSilenceLevel
float mSilenceLevel
Definition: AudioIO.h:284
QualitySettings::SampleFormatChoice
PROJECT_RATE_API sampleFormat SampleFormatChoice()
Definition: QualitySettings.cpp:38
AudioIoCallback::mSeek
double mSeek
Definition: AudioIO.h:271
AudioIO::StopStream
void StopStream() override
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:1311
AudioIOHost
StringSetting AudioIOHost
Definition: AudioIOBase.cpp:933
AudioIoCallback::mAudioThreadTrackBufferExchangeLoopActive
volatile bool mAudioThreadTrackBufferExchangeLoopActive
Definition: AudioIO.h:291
AudioIO::SetMeters
void SetMeters()
Set the current VU meters - this should be done once after each call to StartStream currently.
Definition: AudioIO.cpp:1301
WarningDialogKey
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Prefs.cpp:410
AudioIoCallback::mLostCaptureIntervals
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:329
AudioIoCallback::mCachedBestRatePlaying
static bool mCachedBestRatePlaying
Definition: AudioIO.h:313
DeviceManager::Instance
static DeviceManager * Instance()
Gets the singleton instance.
Definition: DeviceManager.cpp:33
AudioIOBase::mOutputMeter
std::weak_ptr< Meter > mOutputMeter
Definition: AudioIOBase.h:258
PlaybackSchedule::GetTrackTime
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: PlaybackSchedule.h:398
AudioIoCallback::mLastPaError
PaError mLastPaError
Definition: AudioIO.h:298
AudioIoCallback::GetListener
std::shared_ptr< AudioIOListener > GetListener() const
Definition: AudioIO.h:168
AudioIOBase::mCachedBestRateIn
static double mCachedBestRateIn
Definition: AudioIOBase.h:280
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
RecordingSchedule::ToDiscard
double ToDiscard() const
Definition: PlaybackSchedule.cpp:511
AudioIoCallback::mResample
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:257
PlaybackSchedule::TimeQueue::Producer
void Producer(PlaybackSchedule &schedule, PlaybackSlice slice)
Enqueue track time value advanced by the slice according to schedule's PlaybackPolicy.
Definition: PlaybackSchedule.cpp:528
AudioIoCallback::mPlaybackSchedule
PlaybackSchedule mPlaybackSchedule
Definition: AudioIO.h:346
AudioIOBase::mStreamToken
volatile int mStreamToken
Definition: AudioIOBase.h:250
AudioIoCallback::mListener
std::weak_ptr< AudioIOListener > mListener
Definition: AudioIO.h:305
AudioIOEvent::MONITOR
@ MONITOR
Definition: AudioIO.h:64
AudioIO::FillPlayBuffers
void FillPlayBuffers()
First part of TrackBufferExchange.
Definition: AudioIO.cpp:1772
AudioIoCallback::mNumPauseFrames
long mNumPauseFrames
How many frames of zeros were output due to pauses?
Definition: AudioIO.h:236
GuardedCall
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
Definition: AudacityException.h:207
AudioIO::GetCommonlyFreePlayback
size_t GetCommonlyFreePlayback()
Get the number of audio samples free in all of the playback buffers.
Definition: AudioIO.cpp:1734
AudioIO
AudioIO uses the PortAudio library to play and record sound.
Definition: AudioIO.h:362
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:1858
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:140
safenew
#define safenew
Definition: MemoryX.h:10
RecordingSchedule::Consumed
double Consumed() const
Definition: PlaybackSchedule.cpp:506
lrint
#define lrint(dbl)
Definition: float_cast.h:169
PlaybackPolicy::Finalize
virtual void Finalize(PlaybackSchedule &schedule)
Called after stopping of an audio stream or an unsuccessful start.
Definition: PlaybackSchedule.cpp:30
AudioIoCallback::mMinCaptureSecsToCopy
double mMinCaptureSecsToCopy
Definition: AudioIO.h:280
RecordingSchedule::mLatencyCorrected
bool mLatencyCorrected
Definition: PlaybackSchedule.h:144
TransportTracks::prerollTracks
WaveTrackConstArray prerollTracks
Definition: AudioIO.h:75
RecordingSchedule::mDuration
double mDuration
Definition: PlaybackSchedule.h:138
AudioIoCallback::SetRecordingException
void SetRecordingException()
Definition: AudioIO.h:324
AudioIoCallback::mCaptureTracks
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:259
AudioIO::AudioIO
AudioIO()
Definition: AudioIO.cpp:273
AudioIORecordChannels
IntSetting AudioIORecordChannels
Definition: AudioIOBase.cpp:943
AudioIoCallback::mFactor
double mFactor
Definition: AudioIO.h:267
RecordingSchedule::mPreRoll
double mPreRoll
Definition: PlaybackSchedule.h:136
AudioIOStartStreamOptions::pProject
std::shared_ptr< AudacityProject > pProject
Definition: AudioIOBase.h:53
SampleBuffer::ptr
samplePtr ptr() const
Definition: SampleFormat.h:98
AudioIoCallback::mCachedBestRateOut
static double mCachedBestRateOut
Definition: AudioIO.h:312