Audacity  2.2.0
AudioIO.h
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  AudioIO.h
6 
7  Dominic Mazzoni
8 
9  Use the PortAudio library to play and record sound
10 
11 **********************************************************************/
12 
13 #ifndef __AUDACITY_AUDIO_IO__
14 #define __AUDACITY_AUDIO_IO__
15 
16 #include "portaudio.h"
17 #include "Audacity.h"
18 #include "Experimental.h"
19 
20 #include "MemoryX.h"
21 #include <vector>
22 #include <wx/atomic.h>
23 
24 #ifdef USE_MIDI
25 
26 // TODO: Put the relative paths into automake.
27 
28 #ifdef EXPERIMENTAL_MIDI_OUT
29 #include "../lib-src/portmidi/pm_common/portmidi.h"
30 #include "../lib-src/portmidi/porttime/porttime.h"
31 #include <cstring> // Allegro include fails if this header isn't included do to no memcpy
32 #include "../lib-src/portsmf/allegro.h"
33 
34 class NoteTrack;
35 using NoteTrackArray = std::vector < NoteTrack* >;
36 
37 #endif // EXPERIMENTAL_MIDI_OUT
38 
39 #endif // USE_MIDI
40 
41 #if USE_PORTMIXER
42 #include "../lib-src/portmixer/include/portmixer.h"
43 #endif
44 
45 #include <wx/event.h>
46 #include <wx/string.h>
47 #include <wx/thread.h>
48 
49 #include "SampleFormat.h"
50 
51 class AudioIO;
52 class RingBuffer;
53 class Mixer;
54 class Resample;
55 class TimeTrack;
56 class AudioThread;
57 class Meter;
58 class SelectedRegion;
59 
60 class AudacityProject;
61 
62 class WaveTrack;
63 using WaveTrackArray = std::vector < WaveTrack* >;
64 using ConstWaveTrackArray = std::vector < const WaveTrack* >;
65 
66 extern AUDACITY_DLL_API AudioIO *gAudioIO;
67 
68 void InitAudioIO();
69 void DeinitAudioIO();
70 wxString DeviceName(const PaDeviceInfo* info);
71 wxString HostName(const PaDeviceInfo* info);
72 bool ValidateDeviceNames();
73 
74 class AudioIOListener;
75 
76 // #include <cfloat> if you need this constant
77 #define BAD_STREAM_TIME (-DBL_MAX)
78 
79 #define MAX_MIDI_BUFFER_SIZE 5000
80 #define DEFAULT_SYNTH_LATENCY 5
81 
82 #define DEFAULT_LATENCY_DURATION 100.0
83 #define DEFAULT_LATENCY_CORRECTION -130.0
84 
85 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
86  #define AILA_DEF_TARGET_PEAK 92
87  #define AILA_DEF_DELTA_PEAK 2
88  #define AILA_DEF_ANALYSIS_TIME 1000
89  #define AILA_DEF_NUMBER_ANALYSIS 5
90 #endif
91 
92 DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_PLAYBACK, -1);
93 DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_CAPTURE, -1);
94 DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_MONITOR, -1);
95 
96 // PRL:
97 // If we always run a portaudio output stream (even just to produce silence)
98 // whenever we play Midi, then we might use just one thread for both.
99 // I thought this would improve MIDI synch problems on Linux/ALSA, but RBD
100 // convinced me it was neither a necessary nor sufficient fix. Perhaps too the
101 // MIDI thread might block in some error situations but we should then not
102 // also block the audio thread.
103 // So leave the separate thread ENABLED.
104 #define USE_MIDI_THREAD
105 
106 struct ScrubbingOptions;
107 
108 // To avoid growing the argument list of StartStream, add fields here
110 {
111  explicit
113  : timeTrack(NULL)
114  , listener(NULL)
115  , rate(rate_)
116  , playLooped(false)
117  , cutPreviewGapStart(0.0)
118  , cutPreviewGapLen(0.0)
119  , pStartTime(NULL)
120  {}
121 
124  double rate;
128  double * pStartTime;
129 
130 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
131  // Non-null value indicates that scrubbing will happen
132  // (do not specify a time track, looping, or recording, which
133  // are all incompatible with scrubbing):
135 #endif
136 };
137 
138 // This workaround makes pause and stop work when output is to GarageBand,
139 // which seems not to implement the notes-off message correctly.
140 #define AUDIO_IO_GB_MIDI_WORKAROUND
141 
142 class AUDACITY_DLL_API AudioIO final {
143 
144  public:
145  AudioIO();
146  ~AudioIO();
147 
148  AudioIOListener* GetListener() { return mListener; }
149  void SetListener(AudioIOListener* listener);
150 
158  void StartMonitoring(double sampleRate);
159 
167  int StartStream(const ConstWaveTrackArray &playbackTracks, const WaveTrackArray &captureTracks,
168 #ifdef EXPERIMENTAL_MIDI_OUT
169  const NoteTrackArray &midiTracks,
170 #endif
171  double t0, double t1,
172  const AudioIOStartStreamOptions &options);
173 
179  void StopStream();
182  void SeekStream(double seconds) { mSeek = seconds; }
183 
184 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
185  bool IsScrubbing() { return IsBusy() && mScrubQueue != 0; }
186 
197  bool EnqueueScrub(double endTimeOrSpeed, const ScrubbingOptions &options);
198 
201  double GetLastTimeInScrubQueue() const;
202 #endif
203 
208  bool IsBusy();
209 
216  bool IsStreamActive();
217  bool IsStreamActive(int token);
218 
219  wxLongLong GetLastPlaybackTime() const { return mLastPlaybackTimeMillis; }
220  AudacityProject *GetOwningProject() const { return mOwningProject; }
221 
222 #ifdef EXPERIMENTAL_MIDI_OUT
223 
227  PmTimestamp MidiTime();
228 
229  // Note: audio code solves the problem of soloing/muting tracks by scanning
230  // all playback tracks on every call to the audio buffer fill routine.
231  // We do the same for Midi, but it seems wasteful for at least two
232  // threads to be frequently polling to update status. This could be
233  // eliminated (also with a reduction in code I think) by updating mHasSolo
234  // each time a solo button is activated or deactivated. For now, I'm
235  // going to do this polling in the FillMidiBuffer routine to localize
236  // changes for midi to the midi code, but I'm declaring the variable
237  // here so possibly in the future, Audio code can use it too. -RBD
238  private:
239  bool mHasSolo; // is any playback solo button pressed?
240  public:
241  bool SetHasSolo(bool hasSolo);
242  bool GetHasSolo() { return mHasSolo; }
243 #endif
244 
250  bool IsAudioTokenActive(int token);
251 
254  bool IsMonitoring();
255 
257  void SetPaused(bool state);
259  bool IsPaused();
260 
261  /* Mixer services are always available. If no stream is running, these
262  * methods use whatever device is specified by the preferences. If a
263  * stream *is* running, naturally they manipulate the mixer associated
264  * with that stream. If no mixer is available, output is emulated and
265  * input is stuck at 1.0f (a gain is applied to output samples).
266  */
267  void SetMixer(int inputSource);
268  void SetMixer(int inputSource, float inputVolume,
269  float playbackVolume);
270  void GetMixer(int *inputSource, float *inputVolume,
271  float *playbackVolume);
278  bool InputMixerWorks();
279 
286  bool OutputMixerEmulated();
287 
292  wxArrayString GetInputSourceNames();
293 
302  void HandleDeviceChange();
303 
316  static wxArrayLong GetSupportedPlaybackRates(int DevIndex = -1,
317  double rate = 0.0);
318 
331  static wxArrayLong GetSupportedCaptureRates(int devIndex = -1,
332  double rate = 0.0);
333 
348  static wxArrayLong GetSupportedSampleRates(int playDevice = -1,
349  int recDevice = -1,
350  double rate = 0.0);
351 
360  static int GetOptimalSupportedSampleRate();
361 
368  double GetStreamTime();
369 
370  sampleFormat GetCaptureFormat() { return mCaptureFormat; }
371  unsigned GetNumPlaybackChannels() const { return mNumPlaybackChannels; }
372  unsigned GetNumCaptureChannels() const { return mNumCaptureChannels; }
373 
378  static const int StandardRates[];
380  static const int NumStandardRates;
381 
385  wxString GetDeviceInfo();
386 
387 #ifdef EXPERIMENTAL_MIDI_OUT
388 
389  wxString GetMidiDeviceInfo();
390 #endif
391 
395  static bool ValidateDeviceNames(const wxString &play, const wxString &rec);
396 
400  #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
401  void AILAInitialize();
402  void AILADisable();
403  bool AILAIsActive();
404  void AILAProcess(double maxPeak);
405  void AILASetStartTime();
406  double AILAGetLastDecisionTime();
407  #endif
408 
409  bool IsAvailable(AudacityProject *projecT);
410  void SetCaptureMeter(AudacityProject *project, Meter *meter);
411  void SetPlaybackMeter(AudacityProject *project, Meter *meter);
412  Meter * GetCaptureMeter();
413 
414 private:
417  void SetMeters();
418 
429  double GetBestRate(bool capturing, bool playing, double sampleRate);
430 
441  bool StartPortAudioStream(double sampleRate,
442  unsigned int numPlaybackChannels,
443  unsigned int numCaptureChannels,
444  sampleFormat captureFormat);
445  void FillBuffers();
446 
447 #ifdef EXPERIMENTAL_MIDI_OUT
448  void PrepareMidiIterator(bool send = true, double offset = 0);
449  bool StartPortMidiStream();
450 
451  // Compute nondecreasing time stamps, accounting for pauses, but not the
452  // synth latency.
453  double UncorrectedMidiEventTime();
454 
455  void OutputEvent();
456  void FillMidiBuffers();
457  void GetNextEvent();
458  double AudioTime() { return mT0 + mNumFrames / mRate; }
459  double PauseTime();
460  void AllNotesOff(bool looping = false);
461 #endif
462 
468  size_t GetCommonlyAvailPlayback();
469 
476  size_t GetCommonlyAvailCapture();
477 
485  static int getRecordDevIndex(const wxString &devName = wxEmptyString);
490 #if USE_PORTMIXER
491  static int getRecordSourceIndex(PxMixer *portMixer);
492 #endif
493 
501  static int getPlayDevIndex(const wxString &devName = wxEmptyString);
502 
507  static const int RatesToTry[];
509  static const int NumRatesToTry;
510 
512  bool ReversedTime() const
513  {
514  return mT1 < mT0;
515  }
522  double LimitStreamTime(double absoluteTime) const;
523 
530  double NormalizeStreamTime(double absoluteTime) const;
531 
535  void StartStreamCleanup(bool bOnlyBuffers = false);
536 
537 #ifdef EXPERIMENTAL_MIDI_OUT
538  // MIDI_PLAYBACK:
539  PmStream *mMidiStream;
540  PmError mLastPmError;
541 
543  long mSynthLatency; // ms
544 
545  // These fields are used to synchronize MIDI with audio:
546 
548  volatile double mAudioCallbackClockTime;
549 
551  volatile long mNumFrames;
553  volatile long mNumPauseFrames;
555  volatile int mMidiLoopPasses;
556  inline double MidiLoopOffset() { return mMidiLoopPasses * (mT1 - mT0); }
557 
558  volatile long mAudioFramesPerBuffer;
561  volatile bool mMidiPaused;
564  PmTimestamp mMaxMidiTimestamp;
565 
569  double mSystemMinusAudioTime;
572  double mAudioOutLatency;
573 
574  // Next two are used to adjust the previous two, if
575  // PortAudio does not provide the info (using ALSA):
576 
579  double mStartTime;
581  long mCallbackCount;
582 
585  volatile double mSystemMinusAudioTimePlusLatency;
586 
587  Alg_seq_ptr mSeq;
588  std::unique_ptr<Alg_iterator> mIterator;
590  Alg_event_ptr mNextEvent;
591 
592 #ifdef AUDIO_IO_GB_MIDI_WORKAROUND
593  std::vector< std::pair< int, int > > mPendingNotesOff;
594 #endif
595 
598  double mNextEventTime;
600  NoteTrack *mNextEventTrack;
602  bool mMidiOutputComplete{ true };
604  bool mNextIsNoteOn;
606  bool mMidiStreamActive;
609  bool mSendMidiState;
610  NoteTrackArray mMidiPlaybackTracks;
611 #endif
612 
613 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
614  bool mAILAActive;
615  bool mAILAClipped;
616  int mAILATotalAnalysis;
617  int mAILAAnalysisCounter;
618  double mAILAMax;
619  double mAILAGoalPoint;
620  double mAILAGoalDelta;
621  double mAILAAnalysisTime;
622  double mAILALastStartTime;
623  double mAILAChangeFactor;
624  double mAILATopLevel;
625  double mAILAAnalysisEndTime;
626  double mAILAAbsolutStartTime;
627  unsigned short mAILALastChangeType; //0 - no change, 1 - increase change, 2 - decrease change
628 #endif
629 
630  std::unique_ptr<AudioThread> mThread;
631 #ifdef EXPERIMENTAL_MIDI_OUT
632 #ifdef USE_MIDI_THREAD
633  std::unique_ptr<AudioThread> mMidiThread;
634 #endif
635 #endif
641 
643  volatile int mStreamToken;
644  static int mNextStreamToken;
645  double mFactor;
647  double mRate;
649  double mT0;
651  double mT1;
653  double mTime;
654 
658  double mWarpedTime;
659 
664 
665  double mSeek;
671  bool mPaused;
672  PaStream *mPortStreamV19;
675  bool mPauseRec;
677  unsigned int mNumCaptureChannels;
678  unsigned int mNumPlaybackChannels;
679  sampleFormat mCaptureFormat;
684 
686 
687 #ifdef EXPERIMENTAL_MIDI_OUT
688  volatile bool mMidiThreadFillBuffersLoopRunning;
689  volatile bool mMidiThreadFillBuffersLoopActive;
690 #endif
691 
692  volatile double mLastRecordingOffset;
693  PaError mLastPaError;
694 
699  volatile bool mUpdatingMeters;
700 
701  #if USE_PORTMIXER
702  PxMixer *mPortMixer;
703  float mPreviousHWPlaythrough;
704  #endif /* USE_PORTMIXER */
705 
716 
717  volatile enum {
720 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
722 #endif
723  } mPlayMode;
726 
728 
730 
731  friend class AudioThread;
732 #ifdef EXPERIMENTAL_MIDI_OUT
733  friend class MidiThread;
734 #endif
735 
736  friend void InitAudioIO();
737 
739 
740  bool mUsingAlsa { false };
741 
742  // For cacheing supported sample rates
744  static wxArrayLong mCachedPlaybackRates;
746  static wxArrayLong mCachedCaptureRates;
747  static wxArrayLong mCachedSampleRates;
748  static double mCachedBestRateIn;
749  static double mCachedBestRateOut;
750 
773  friend int audacityAudioCallback(
774  const void *inputBuffer, void *outputBuffer,
775  unsigned long framesPerBuffer,
776  const PaStreamCallbackTimeInfo *timeInfo,
777  PaStreamCallbackFlags statusFlags, void *userData );
778 
779  // Serialize main thread and PortAudio thread's attempts to pause and change
780  // the state used by the third, Audio thread.
782 
783 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
784  struct ScrubQueue;
785  std::unique_ptr<ScrubQueue> mScrubQueue;
786 
788  sampleCount mScrubDuration;
789 #endif
790 
791  // A flag tested and set in one thread, cleared in another. Perhaps
792  // this guarantee of atomicity is more cautious than necessary.
793  wxAtomicInt mRecordingException {};
795  { wxAtomicInc( mRecordingException ); }
797  { if (mRecordingException) wxAtomicDec( mRecordingException ); }
798 };
799 
800 #endif
AudioIO uses the PortAudio library to play and record sound.
Definition: AudioIO.h:142
static wxArrayLong mCachedPlaybackRates
Definition: AudioIO.h:744
double mMinCaptureSecsToCopy
Definition: AudioIO.h:669
TimeTrack * timeTrack
Definition: AudioIO.h:122
double rate
Definition: AudioIO.h:124
static double mCachedBestRateIn
Definition: AudioIO.h:748
static int mNextStreamToken
Definition: AudioIO.h:644
wxLongLong GetLastPlaybackTime() const
Definition: AudioIO.h:219
double cutPreviewGapStart
Definition: AudioIO.h:126
Meter * mInputMeter
Definition: AudioIO.h:696
sampleCount mScrubDuration
Definition: AudioIO.h:788
VU Meter, for displaying recording/playback level.
Definition: Meter.h:88
volatile bool mUpdatingMeters
Definition: AudioIO.h:699
float mMixerOutputVol
Definition: AudioIO.h:715
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:372
double mTime
Current time position during playback, in seconds. Between mT0 and mT1.
Definition: AudioIO.h:653
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:714
bool mSoftwarePlaythrough
Definition: AudioIO.h:673
Definition: AudioIO.h:721
void DeinitAudioIO()
Definition: AudioIO.cpp:1133
AudioIOStartStreamOptions(double rate_)
Definition: AudioIO.h:112
const TimeTrack * mTimeTrack
Definition: AudioIO.h:738
int mLostSamples
Definition: AudioIO.h:680
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:639
ScrubbingOptions * pScrubbingOptions
Definition: AudioIO.h:134
AudioIOListener * GetListener()
Definition: AudioIO.h:148
bool ValidateDeviceNames()
float mSilenceLevel
Definition: AudioIO.h:676
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:636
AUDACITY_DLL_API AudioIO * gAudioIO
Definition: AudioIO.cpp:468
sampleFormat mCaptureFormat
Definition: AudioIO.h:679
static wxArrayLong mCachedSampleRates
Definition: AudioIO.h:747
GrowableSampleBuffer mSilentBuf
Definition: AudioIO.h:727
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:642
std::vector< const WaveTrack * > ConstWaveTrackArray
Definition: AudioIO.h:64
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:784
double mWarpedTime
Definition: AudioIO.h:658
static int mCachedPlaybackIndex
Definition: AudioIO.h:743
wxMutex mSuspendAudioThread
Definition: AudioIO.h:781
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:161
bool playLooped
Definition: AudioIO.h:125
A kind of Track used to 'warp time'.
Definition: TimeTrack.h:29
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:671
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:637
bool ReversedTime() const
True if the end time is before the start time.
Definition: AudioIO.h:512
volatile int mStreamToken
Definition: AudioIO.h:643
Definition: AudioIO.h:719
Defines a selected portion of a project.
Definition: SelectedRegion.h:37
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:638
bool mEmulateMixerOutputVol
Definition: AudioIO.h:706
PaStream * mPortStreamV19
Definition: AudioIO.h:672
Definition: AudioIO.h:109
void ClearRecordingException()
Definition: AudioIO.h:796
double mCaptureRingBufferSecs
Definition: AudioIO.h:667
int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
A Track that contains audio waveform data.
Definition: WaveTrack.h:76
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1138
AudacityProject * GetOwningProject() const
Definition: AudioIO.h:220
AudacityProject * mOwningProject
Definition: AudioIO.h:695
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:685
AudioIOListener * mListener
Definition: AudioIO.h:729
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:681
bool IsScrubbing()
Definition: AudioIO.h:185
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:678
double mSeek
Definition: AudioIO.h:665
std::vector< WaveTrack * > WaveTrackArray
Definition: AudioIO.h:63
unsigned int mNumCaptureChannels
Definition: AudioIO.h:677
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:630
wxString HostName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1145
Definition: AudioIO.h:718
ConstWaveTrackArray mPlaybackTracks
Definition: AudioIO.h:640
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:647
Definition: AudioIOListener.h:20
bool mUpdateMeters
Definition: AudioIO.h:698
Holds streamed audio samples.
Definition: RingBuffer.h:16
volatile double mLastRecordingOffset
Definition: AudioIO.h:692
Interface to libsoxr.
Definition: Resample.h:30
Definition: Scrubbing.h:35
static int mCachedCaptureIndex
Definition: AudioIO.h:745
static const int NumStandardRates
How many standard sample rates there are.
Definition: AudioIO.h:380
Definition: MemoryX.h:439
sampleFormat GetCaptureFormat()
Definition: AudioIO.h:370
void InitAudioIO()
Definition: AudioIO.cpp:1100
double mWarpedLength
Definition: AudioIO.h:663
double mCutPreviewGapLen
Definition: AudioIO.h:725
std::vector< NoteTrack * > NoteTrackArray
Definition: Track.h:71
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:649
double mCutPreviewGapStart
Definition: AudioIO.h:724
Meter * mOutputMeter
Definition: AudioIO.h:697
static double mCachedBestRateOut
Definition: AudioIO.h:749
AudioIOListener * listener
Definition: AudioIO.h:123
Definition: SampleFormat.h:88
static const int NumRatesToTry
How many sample rates to try.
Definition: AudioIO.h:509
volatile bool mAudioThreadFillBuffersLoopActive
Definition: AudioIO.h:683
Functions for doing the mixdown of the tracks.
Definition: Mix.h:71
double mFactor
Definition: AudioIO.h:645
PaError mLastPaError
Definition: AudioIO.h:693
size_t mPlaybackSamplesToCopy
Definition: AudioIO.h:668
void SeekStream(double seconds)
Move the playback / recording position of the current stream by the specified amount from where it is...
Definition: AudioIO.h:182
double cutPreviewGapLen
Definition: AudioIO.h:127
double * pStartTime
Definition: AudioIO.h:128
unsigned GetNumPlaybackChannels() const
Definition: AudioIO.h:371
Definition: AudioIO.cpp:531
double mT1
Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 duri...
Definition: AudioIO.h:651
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_AUDIOIO_PLAYBACK,-1)
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:682
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:675
void SetRecordingException()
Definition: AudioIO.h:794
bool mSilentScrub
Definition: AudioIO.h:787
static wxArrayLong mCachedCaptureRates
Definition: AudioIO.h:746
A Track that is used for Midi notes. (Somewhat old code).
double mPlaybackRingBufferSecs
Definition: AudioIO.h:666
Defined different on Mac and other platforms (on Mac it does not use wxWidgets wxThread), this class sits in a thread loop reading and writing audio.
Definition: AudioIO.cpp:1078