Audacity  2.2.0
AudioIO Class Referencefinal

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

#include <AudioIO.h>

Classes

struct  ScrubQueue
 

Public Member Functions

 AudioIO ()
 
 ~AudioIO ()
 
AudioIOListenerGetListener ()
 
void SetListener (AudioIOListener *listener)
 
void StartMonitoring (double sampleRate)
 Start up Portaudio for capture and recording as needed for input monitoring and software playthrough only. More...
 
int StartStream (const ConstWaveTrackArray &playbackTracks, const WaveTrackArray &captureTracks, double t0, double t1, const AudioIOStartStreamOptions &options)
 Start recording or playing back audio. More...
 
void StopStream ()
 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...
 
bool IsScrubbing ()
 
bool EnqueueScrub (double endTimeOrSpeed, const ScrubbingOptions &options)
 enqueue a NEW scrub play interval, using the last end as the NEW start, to be played over the same duration, as between this and the last enqueuing (or the starting of the stream). Except, we do not exceed maximum scrub speed, so may need to adjust either the start or the end. If options.adjustStart is true, then when mouse movement exceeds maximum scrub speed, adjust the beginning of the scrub interval rather than the end, so that the scrub skips or "stutters" to stay near the cursor. Return true if some sound was really enqueued. But if the "stutter" is too short for the minimum, enqueue nothing and return false. More...
 
double GetLastTimeInScrubQueue () const
 return the ending time of the last enqueued scrub interval. More...
 
bool IsBusy ()
 Returns true if audio i/o is busy starting, stopping, playing, or recording. More...
 
bool IsStreamActive ()
 Returns true if the audio i/o is running at all, but not during cleanup. More...
 
bool IsStreamActive (int token)
 
wxLongLong GetLastPlaybackTime () const
 
AudacityProjectGetOwningProject () const
 
bool IsAudioTokenActive (int token)
 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 ()
 Returns true if we're monitoring input (but not recording or playing actual audio) More...
 
void SetPaused (bool state)
 Pause and un-pause playback and recording. More...
 
bool IsPaused ()
 Find out if playback / recording is currently paused. More...
 
void SetMixer (int inputSource)
 
void SetMixer (int inputSource, float inputVolume, float playbackVolume)
 
void GetMixer (int *inputSource, float *inputVolume, float *playbackVolume)
 
bool InputMixerWorks ()
 Find out if the input hardware level control is available. More...
 
bool OutputMixerEmulated ()
 Find out if the output level control is being emulated via software attenuation. More...
 
wxArrayString GetInputSourceNames ()
 Get the list of inputs to the current mixer device. More...
 
void HandleDeviceChange ()
 update state after changing what audio devices are selected More...
 
double GetStreamTime ()
 During playback, the (unwarped) track time most recently played. More...
 
sampleFormat GetCaptureFormat ()
 
unsigned GetNumPlaybackChannels () const
 
unsigned GetNumCaptureChannels () const
 
wxString GetDeviceInfo ()
 Get diagnostic information on all the available audio I/O devices. More...
 
bool IsAvailable (AudacityProject *projecT)
 Function to automatically set an acceptable volume. More...
 
void SetCaptureMeter (AudacityProject *project, Meter *meter)
 
void SetPlaybackMeter (AudacityProject *project, Meter *meter)
 
MeterGetCaptureMeter ()
 

Static Public Member Functions

static wxArrayLong GetSupportedPlaybackRates (int DevIndex=-1, double rate=0.0)
 Get a list of sample rates the output (playback) device supports. More...
 
static wxArrayLong GetSupportedCaptureRates (int devIndex=-1, double rate=0.0)
 Get a list of sample rates the input (recording) device supports. More...
 
static wxArrayLong 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...
 
static bool ValidateDeviceNames (const wxString &play, const wxString &rec)
 Ensure selected device names are valid. More...
 

Static Public Attributes

static const int StandardRates []
 Array of common audio sample rates. More...
 
static const int NumStandardRates
 How many standard sample rates there are. More...
 

Private Types

enum  { PLAY_STRAIGHT, PLAY_LOOPED, PLAY_SCRUB }
 

Private Member Functions

void SetMeters ()
 Set the current VU meters - this should be done once after each call to StartStream currently. 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...
 
bool StartPortAudioStream (double sampleRate, unsigned int numPlaybackChannels, unsigned int numCaptureChannels, sampleFormat captureFormat)
 Opens the portaudio stream(s) used to do playback or recording (or both) through. More...
 
void FillBuffers ()
 
size_t GetCommonlyAvailPlayback ()
 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 ReversedTime () const
 True if the end time is before the start time. More...
 
double LimitStreamTime (double absoluteTime) const
 Clamps the given time to be between mT0 and mT1. More...
 
double NormalizeStreamTime (double absoluteTime) const
 Normalizes the given time, clamping it and handling gaps from cut preview. More...
 
void StartStreamCleanup (bool bOnlyBuffers=false)
 Clean up after StartStream if it fails. More...
 
void SetRecordingException ()
 
void ClearRecordingException ()
 

Static Private Member Functions

static int getRecordDevIndex (const wxString &devName=wxEmptyString)
 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=wxEmptyString)
 get the index of the device selected in the preferences. More...
 

Private Attributes

std::unique_ptr< AudioThreadmThread
 
ArrayOf< std::unique_ptr
< Resample > > 
mResample
 
ArrayOf< std::unique_ptr
< RingBuffer > > 
mCaptureBuffers
 
WaveTrackArray mCaptureTracks
 
ArrayOf< std::unique_ptr
< RingBuffer > > 
mPlaybackBuffers
 
ConstWaveTrackArray mPlaybackTracks
 
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
 
volatile int mStreamToken
 
double mFactor
 
double mRate
 Audio playback rate in samples per second. More...
 
double mT0
 Playback starts at offset of mT0, which is measured in seconds. More...
 
double mT1
 Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 during scrubbing. More...
 
double mTime
 Current time position during playback, in seconds. Between mT0 and mT1. More...
 
double mWarpedTime
 
double mWarpedLength
 
double mSeek
 
double mPlaybackRingBufferSecs
 
double mCaptureRingBufferSecs
 
size_t mPlaybackSamplesToCopy
 
double mMinCaptureSecsToCopy
 
bool mPaused
 True if audio playback is paused. More...
 
PaStream * mPortStreamV19
 
bool mSoftwarePlaythrough
 
bool mPauseRec
 True if Sound Activated Recording is enabled. More...
 
float mSilenceLevel
 
unsigned int mNumCaptureChannels
 
unsigned int mNumPlaybackChannels
 
sampleFormat mCaptureFormat
 
int mLostSamples
 
volatile bool mAudioThreadShouldCallFillBuffersOnce
 
volatile bool mAudioThreadFillBuffersLoopRunning
 
volatile bool mAudioThreadFillBuffersLoopActive
 
wxLongLong mLastPlaybackTimeMillis
 
volatile double mLastRecordingOffset
 
PaError mLastPaError
 
AudacityProjectmOwningProject
 
MetermInputMeter
 
MetermOutputMeter
 
bool mUpdateMeters
 
volatile bool mUpdatingMeters
 
bool mEmulateMixerOutputVol
 
bool mInputMixerWorks
 Can we control the hardware input level? More...
 
float mMixerOutputVol
 
enum AudioIO:: { ... }  mPlayMode
 
double mCutPreviewGapStart
 
double mCutPreviewGapLen
 
GrowableSampleBuffer mSilentBuf
 
AudioIOListenermListener
 
const TimeTrackmTimeTrack
 
bool mUsingAlsa { false }
 
wxMutex mSuspendAudioThread
 
std::unique_ptr< ScrubQueuemScrubQueue
 
bool mSilentScrub
 
sampleCount mScrubDuration
 
wxAtomicInt mRecordingException {}
 

Static Private Attributes

static const int RatesToTry []
 Array of audio sample rates to try to use. More...
 
static const int NumRatesToTry
 How many sample rates to try. More...
 
static int mNextStreamToken = 0
 
static int mCachedPlaybackIndex = -1
 
static wxArrayLong mCachedPlaybackRates
 
static int mCachedCaptureIndex = -1
 
static wxArrayLong mCachedCaptureRates
 
static wxArrayLong mCachedSampleRates
 
static double mCachedBestRateIn = 0.0
 
static double mCachedBestRateOut
 

Friends

class AudioThread
 
void InitAudioIO ()
 
int audacityAudioCallback (const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
 

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.

EXPERIMENTAL_MIDI_OUT
If EXPERIMENTAL_MIDI_OUT is defined, this class also manages MIDI playback. The reason for putting MIDI here rather than in, say, class MidiIO, is that there is no high-level synchronization and transport architecture, so Audio and MIDI must be coupled in order to start/stop/pause and synchronize them.
MIDI With Audio
When Audio and MIDI play simultaneously, MIDI synchronizes to Audio. This is necessary because the Audio sample clock is not the same hardware as the system time used to schedule MIDI messages. MIDI is synchronized to Audio because it is simple to pause or rush the dispatch of MIDI messages, but generally impossible to pause or rush synchronous audio samples (without distortion).
MIDI output is driven by yet another thread. In principle, we could output timestamped MIDI data at the same time we fill audio buffers from disk, but audio buffers are filled far in advance of playback time, and there is a lower latency thread (PortAudio's callback) that actually sends samples to the output device. The relatively low latency to the output device allows Audacity to stop audio output quickly. We want the same behavior for MIDI, but there is not periodic callback from PortMidi (because MIDI is asynchronous), so this function is performed by the MidiThread class.
When Audio is running, MIDI is synchronized to Audio. Globals are set in the Audio callback (audacityAudioCallback) for use by a time function that reports milliseconds to PortMidi. (Details below.)
MIDI Without Audio
When Audio is not running, PortMidi uses its own millisecond timer since there is no audio to synchronize to. (Details below.)
Implementation Notes and Details for MIDI
When opening devices, successAudio and successMidi indicate errors if false, so normally both are true. Use playbackChannels, captureChannels and mMidiPlaybackTracks.IsEmpty() to determine if Audio or MIDI is actually in use.
Audio Time
Normally, the current time during playback is given by the variable mTime. mTime normally advances by frames / samplerate each time an audio buffer is output by the audio callback. However, Audacity has a speed control that can perform continuously variable time stretching on audio. This is achieved in two places: the playback "mixer" that generates the samples for output processes the audio according to the speed control. In a separate algorithm, the audio callback updates mTime by (frames / samplerate) * factor, where factor reflects the speed at mTime. This effectively integrates speed to get position. Negative speeds are allowed too, for instance in scrubbing.
The Big Picture
Sample
Time (in seconds, = total_sample_count / sample_rate)
  ^
  |                                             /         /
  |             y=x-mSystemTimeMinusAudioTime /         /
  |                                         /     #   /
  |                                       /         /
  |                                     /   # <- callbacks (#) showing
  |                                   /#        /   lots of timing jitter.
  |       top line is "full buffer" /         /     Some are later,
  |                     condition /         /       indicating buffer is
  |                             /         /         getting low. Plot
  |                           /     #   /           shows sample time
  |                         /    #    /             (based on how many
  |                       /    #    /               samples previously
  |                     /         /                 *written*) vs. real
  |                   / #       /                   time.
  |                 /<------->/ audio latency
  |               /#       v/
  |             /         / bottom line is "empty buffer"
  |           /   #     /      condition = DAC output time =
  |         /         /
  |       /      # <-- rapid callbacks as buffer is filled
  |     /         /
0 +...+---------#---------------------------------------------------->
  0 ^ |         |                                            real time
    | |         first callback time
    | mSystemMinusAudioTime
    |
    Probably the actual real times shown in this graph are very large
    in practice (> 350,000 sec.), so the X "origin" might be when
    the computer was booted or 1970 or something.

To estimate the true DAC time (needed to synchronize MIDI), we need a mapping from track time to DAC time. The estimate is the theoretical time of the full buffer (top diagonal line) + audio latency. To estimate the top diagonal line, we "draw" the line to be at least as high as any sample time corresponding to a callback (#), and we slowly lower the line in case the sample clock is slow or the system clock is fast, preventing the estimated line from drifting too far from the actual callback observations. The line is occasionally "bumped" up by new callback observations, but continuously "lowered" at a very low rate. All adjustment is accomplished by changing mSystemMinusAudioTime, shown here as the X-intercept.
theoreticalFullBufferTime = realTime - mSystemMinusAudioTime
To estimate audio latency, notice that the first callback happens on an empty buffer, but the buffer soon fills up. This will cause a rapid re-estimation of mSystemMinusAudioTime. (The first estimate of mSystemMinusAudioTime will simply be the real time of the first callback time.) By watching these changes, which happen within ms of starting, we can estimate the buffer size and thus audio latency. So, to map from track time to real time, we compute:
DACoutputTime = trackTime + mSystemMinusAudioTime
There are some additional details to avoid counting samples while paused or while waiting for initialization, MIDI latency, etc. Also, in the code, track time is measured with respect to the track origin, so there's an extra term to add (mT0) if you start somewhere in the middle of the track. Finally, when a callback occurs, you might expect there is room in the output buffer for the requested frames, so maybe the "full buffer" sample time should be based not on the first sample of the callback, but the last sample time + 1 sample. I suspect, at least on Linux, that the callback occurs as soon as the last callback completes, so the buffer is really full, and the callback thread is going to block waiting for space in the output buffer.

Midi Time
MIDI is not warped according to the speed control. This might be something that should be changed. (Editorial note: Wouldn't it make more sense to display audio at the correct time and allow users to stretch audio the way they can stretch MIDI?) For now, MIDI plays at 1 second per second, so it requires an unwarped clock. In fact, MIDI time synchronization requires a millisecond clock that does not pause. Note that mTime will stop progress when the Pause button is pressed, even though audio samples (zeros) continue to be output.
Therefore, we define the following interface for MIDI timing:
  • AudioTime() is the time based on all samples written so far, including zeros output during pauses. AudioTime() is based on the start location mT0, not zero.
  • PauseTime() is the amount of time spent paused, based on a count of zero-padding samples output.
  • MidiTime() is an estimate in milliseconds of the current audio output time + 1s. In other words, what audacity track time corresponds to the audio (plus pause insertions) at the DAC output?
AudioTime() and PauseTime() computation
AudioTime() is simply mT0 + mNumFrames / mRate. mNumFrames is incremented in each audio callback. Similarly, PauseTime() is mNumPauseFrames / mRate. mNumPauseFrames is also incremented in each audio callback when a pause is in effect or audio output is ready to start.
MidiTime() computation
MidiTime() is computed based on information from PortAudio's callback, which estimates the system time at which the current audio buffer will be output. Consider the (unimplemented) function RealToTrack() that maps real audio write time to track time. If writeTime is the system time for the first sample of the current output buffer, and if we are in the callback, so AudioTime() also refers to the first sample of the buffer, then
RealToTrack(writeTime) = AudioTime() - PauseTime()
We want to know RealToTrack of the current time (when we are not in the callback, so we use this approximation for small d:
RealToTrack(t + d) = RealToTrack(t) + d, or
Letting t = writeTime and d = (systemTime - writeTime), we can substitute to get:
RealToTrack(systemTime) = RealToTrack(writeTime) + systemTime - writeTime
= AudioTime() - PauseTime() + (systemTime - writeTime)
MidiTime() should include pause time, so that it increases smoothly, and audioLatency so that MidiTime() corresponds to the time of audio output rather than audio write times. Also MidiTime() is offset by 1 second to avoid negative time at startup, so add 1:
MidiTime(systemTime) in seconds
= RealToTrack(systemTime) + PauseTime() - audioLatency + 1
= AudioTime() + (systemTime - writeTime) - audioLatency + 1
(Note that audioLatency is called mAudioOutLatency in the code.) When we schedule a MIDI event with track time TT, we need to map TT to a PortMidi timestamp. The PortMidi timestamp is exactly MidiTime(systemTime) in ms units, and
MidiTime(x) = RealToTrack(x) + PauseTime() + 1, so
timestamp = TT + PauseTime() + 1 - midiLatency
Note 1: The timestamp is incremented by the PortMidi stream latency (midiLatency) so we subtract midiLatency here for the timestamp passed to PortMidi.
Note 2: Here, we're setting x to the time at which RealToTrack(x) = TT, so then MidiTime(x) is the desired timestamp. To be completely correct, we should assume that MidiTime(x + d) = MidiTime(x) + d, and consider that we compute MidiTime(systemTime) based on the current* system time, but we really want the MidiTime(x) for some future time corresponding when MidiTime(x) = TT.)
Also, we should assume PortMidi was opened with mMidiLatency, and that MIDI messages become sound with a delay of mSynthLatency. Therefore, the final timestamp calculation is:
timestamp = TT + PauseTime() + 1 - (mMidiLatency + mSynthLatency)
(All units here are seconds; some conversion is needed in the code.)
The difference AudioTime() - PauseTime() is the time "cursor" for MIDI. When the speed control is used, MIDI and Audio will become unsynchronized. In particular, MIDI will not be synchronized with the visual cursor, which moves with scaled time reported in mTime.
Timing in Linux
It seems we cannot get much info from Linux. We can read the time when we get a callback, and we get a variable frame count (it changes from one callback to the next). Returning to the RealToTrack() equations above:
RealToTrack(outputTime) = AudioTime() - PauseTime() - bufferDuration
where outputTime should be PortAudio's estimate for the most recent output buffer, but at least on my Dell Latitude E7450, PortAudio is getting zero from ALSA, so we need to find a proxy for this.
Estimating outputTime (Plan A, assuming double-buffered, fixed-size buffers, please skip to Plan B)
One can expect the audio callback to happen as soon as there is room in the output for another block of samples, so we could just measure system time at the top of the callback. Then we could add the maximum delay buffered in the system. E.g. if there is simple double buffering and the callback is computing one of the buffers, the callback happens just as one of the buffers empties, meaning the other buffer is full, so we have exactly one buffer delay before the next computed sample is output.

If computation falls behind a bit, the callback will be later, so the delay to play the next computed sample will be less. I think a reasonable way to estimate the actual output time is to assume that the computer is mostly keeping up and that most callbacks will occur immediately when there is space. Note that the most likely reason for the high-priority audio thread to fall behind is the callback itself, but the start of the callback should be pretty consistently keeping up.

Also, we do not have to have a perfect estimate of the time. Suppose we estimate a linear mapping from sample count to system time by saying that the sample count maps to the system time at the most recent callback, and set the slope to 1% slower than real time (as if the sample clock is slow). Now, at each callback, if the callback seems to occur earlier than expected, we can adjust the mapping to be earlier. The earlier the callback, the more accurate it must be. On the other hand, if the callback is later than predicted, it must be a delayed callback (or else the sample clock is more than 1% slow, which is really a hardware problem.) How bad can this be? Assuming callbacks every 30ms (this seems to be what I'm observing in a default setup), you'll be a maximum of 1ms off even if 2 out of 3 callbacks are late. This is pretty reasonable given that PortMIDI clock precision is 1ms. If buffers are larger and callback timing is more erratic, errors will be larger, but even a few ms error is probably OK.

Estimating outputTime (Plan B, variable framesPerBuffer in callback, please skip to Plan C)
ALSA is complicated because we get varying values of framesPerBuffer from callback to callback. Assume you get more frames when the callback is later (because there is more accumulated input to deliver and more more accumulated room in the output buffers). So take the current time and subtract the duration of the frame count in the current callback. This should be a time position that is relatively jitter free (because we estimated the lateness by frame count and subtracted that out). This time position intuitively represents the current ADC time, or if no input, the time of the tail of the output buffer. If we wanted DAC time, we'd have to add the total output buffer duration, which should be reported by PortAudio. (If PortAudio is wrong, we'll be systematically shifted in time by the error.)

Since there is still bound to be jitter, we can smooth these estimates. First, we will assume a linear mapping from system time to audio time with slope = 1, so really it's just the offset we need, which is going to be a double that we can read/write atomically without locks or anything fancy. (Maybe it should be "volatile".)

To improve the estimate, we get a new offset every callback, so we can create a "smooth" offset by using a simple regression model (also this could be seen as a first order filter). The following formula updates smooth_offset with a new offset estimate in the callback: smooth_offset = smooth_offset * 0.9 + new_offset_estimate * 0.1 Since this is smooth, we'll have to be careful to give it a good initial value to avoid a long convergence.

Estimating outputTime (Plan C)
ALSA is complicated because we get varying values of framesPerBuffer from callback to callback. It seems there is a lot of variation in callback times and buffer space. One solution would be to go to fixed size double buffer, but Audacity seems to work better as is, so Plan C is to rely on one invariant which is that the output buffer cannot overflow, so there's a limit to how far ahead of the DAC time we can be writing samples into the buffer. Therefore, we'll assume that the audio clock runs slow by about 0.2% and we'll assume we're computing at that rate. If the actual output position is ever ahead of the computed position, we'll increase the computed position to the actual position. Thus whenever the buffer is less than near full, we'll stay ahead of DAC time, falling back at a rate of about 0.2% until eventually there's another near-full buffer callback that will push the time back ahead.
Interaction between MIDI, Audio, and Pause
When Pause is used, PauseTime() will increase at the same rate as AudioTime(), and no more events will be output. Because of the time advance of mAudioOutputLatency + MIDI_SLEEP + latency and the fact that AudioTime() advances stepwise by mAudioBufferDuration, some extra MIDI might be output, but the same is true of audio: something like mAudioOutputLatency audio samples will be in the output buffer (with up to mAudioBufferDuration additional samples, depending on when the Pause takes effect). When playback is resumed, there will be a slight delay corresponding to the extra data previously sent. Again, the same is true of audio. Audio and MIDI will not pause and resume at exactly the same times, but their pause and resume times will be within the low tens of milliseconds, and the streams will be synchronized in any case. I.e. if audio pauses 10ms earlier than MIDI, it will resume 10ms earlier as well.
PortMidi Latency Parameter
PortMidi has a "latency" parameter that is added to all timestamps. This value must be greater than zero to enable timestamp-based timing, but serves no other function, so we will set it to 1. All timestamps must then be adjusted down by 1 before messages are sent. This adjustment is on top of all the calculations described above. It just seem too complicated to describe everything in complete detail in one place.
Midi with a time track
When a variable-speed time track is present, MIDI events are output with the times used by the time track (rather than the raw times). This ensures MIDI is synchronized with audio.
Midi While Recording Only or Without Audio Playback
To reduce duplicate code and to ensure recording is synchronised with MIDI, a portaudio stream will always be used, even when there is no actual audio output. For recording, this ensures that the recorded audio will by synchronized with the MIDI (otherwise, it gets out-of- sync if played back with correct timing).
NoteTrack PlayLooped
When mPlayLooped is true, output is supposed to loop from mT0 to mT1. For NoteTracks, we interpret this to mean that any note-on or control change in the range mT0 <= t < mT1 is sent (notes that start before mT0 are not played even if they extend beyond mT0). Then, all notes are turned off. Events in the range mT0 <= t < mT1 are then repeated, offset by (mT1 - mT0), etc. We do NOT go back to the beginning and play all control changes (update events) up to mT0, nor do we "undo" any state changes between mT0 and mT1.
NoteTrack PlayLooped Implementation
The mIterator object (an Alg_iterator) returns NULL when there are no more events scheduled before mT1. At mT1, we want to output all notes off messages, but the FillMidiBuffers() loop will exit if mNextEvent is NULL, so we create a "fake" mNextEvent for this special "event" of sending all notes off. After that, we destroy the iterator and use PrepareMidiIterator() to set up a NEW one. At each iteration, time must advance by (mT1 - mT0), so the accumulated complete loop time (in "unwarped," track time) is computed by MidiLoopOffset().
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.

Member Enumeration Documentation

anonymous enum
private
Enumerator
PLAY_STRAIGHT 
PLAY_LOOPED 
PLAY_SCRUB 

Constructor & Destructor Documentation

AudioIO::~AudioIO ( )

References gAudioIO, and mThread.

Member Function Documentation

void AudioIO::ClearRecordingException ( )
inlineprivate

Referenced by StartStream(), and StopStream().

bool AudioIO::EnqueueScrub ( double  endTimeOrSpeed,
const ScrubbingOptions options 
)

enqueue a NEW scrub play interval, using the last end as the NEW start, to be played over the same duration, as between this and the last enqueuing (or the starting of the stream). Except, we do not exceed maximum scrub speed, so may need to adjust either the start or the end. If options.adjustStart is true, then when mouse movement exceeds maximum scrub speed, adjust the beginning of the scrub interval rather than the end, so that the scrub skips or "stutters" to stay near the cursor. Return true if some sound was really enqueued. But if the "stutter" is too short for the minimum, enqueue nothing and return false.

Referenced by Scrubber::ContinueScrubbingPoll().

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

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 handeled, 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.

References GetSupportedCaptureRates(), GetSupportedPlaybackRates(), GetSupportedSampleRates(), mCachedBestRateIn, and mCachedBestRateOut.

Referenced by StartPortAudioStream().

sampleFormat AudioIO::GetCaptureFormat ( )
inline
Meter * AudioIO::GetCaptureMeter ( )

References mInputMeter.

Referenced by Meter::~Meter().

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).

References mCaptureBuffers, mCaptureTracks, and min().

Referenced by FillBuffers().

size_t AudioIO::GetCommonlyAvailPlayback ( )
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.

References min(), mPlaybackBuffers, and mPlaybackTracks.

Referenced by FillBuffers().

wxString AudioIO::GetDeviceInfo ( )
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)

wxLongLong AudioIO::GetLastPlaybackTime ( ) const
inline
double AudioIO::GetLastTimeInScrubQueue ( ) const

return the ending time of the last enqueued scrub interval.

References mScrubQueue.

Referenced by Scrubber::ContinueScrubbingPoll().

AudioIOListener* AudioIO::GetListener ( )
inline
void AudioIO::GetMixer ( int *  inputSource,
float *  inputVolume,
float *  playbackVolume 
)
unsigned AudioIO::GetNumPlaybackChannels ( ) const
inline
int AudioIO::GetOptimalSupportedSampleRate ( )
static

Get a supported sample rate which can be used a an optimal default.

Currently, this uses the first supported rate in the list [44100, 48000, highest sample rate]. Used in Project as a default value for project rates if one cannot be retrieved from the preferences. So all in all not that useful or important really

Todo:
: should this take into account PortAudio's value for PaDeviceInfo::defaultSampleRate? In principal this should let us work out which rates are "real" and which resampled in the drivers, and so prefer the real rates.

References GetSupportedSampleRates().

Referenced by EVT_COMMAND_RANGE(), QualityPrefs::PopulateOrExchange(), SelectionBar::UpdatePrefs(), and AudacityProject::UpdatePrefsVariables().

AudacityProject* AudioIO::GetOwningProject ( ) const
inline
int AudioIO::getPlayDevIndex ( const wxString &  devName = wxEmptyString)
staticprivate

get the index of the device selected in the preferences.

If the device isn't found, returns -1get the index of the supplied (named) playback device, or the device selected in the preferences if none given.

Pure utility function, but it comes round a number of times in the code and would be neater done once. If the device isn't found, return the default device index.

References DeviceName(), and gPrefs.

Referenced by GetSupportedPlaybackRates(), GetSupportedSampleRates(), HandleDeviceChange(), InitAudioIO(), StartPortAudioStream(), and ValidateDeviceNames().

int AudioIO::getRecordDevIndex ( const wxString &  devName = wxEmptyString)
staticprivate

get the index of the supplied (named) recording device, or the device selected in the preferences if none given.

Pure utility function, but it comes round a number of times in the code and would be neater done once. If the device isn't found, return the default device index.

References DeviceName(), and gPrefs.

Referenced by GetSupportedCaptureRates(), GetSupportedSampleRates(), HandleDeviceChange(), InitAudioIO(), StartPortAudioStream(), and ValidateDeviceNames().

wxArrayLong AudioIO::GetSupportedCaptureRates ( int  devIndex = -1,
double  rate = 0.0 
)
static

Get a list of sample rates the input (recording) device supports.

If no information about available sample rates can be fetched, an empty list is returned.

You can explicitely give the index of the device. If you don't give it, the currently selected device from the preferences will be used.

You may also specify a rate for which to check in addition to the standard rates.

References DEFAULT_LATENCY_DURATION, getRecordDevIndex(), gPrefs, mCachedCaptureIndex, mCachedCaptureRates, NumRatesToTry, and RatesToTry.

Referenced by GetBestRate(), GetSupportedSampleRates(), and HandleDeviceChange().

wxArrayLong AudioIO::GetSupportedPlaybackRates ( int  DevIndex = -1,
double  rate = 0.0 
)
static

Get a list of sample rates the output (playback) device supports.

If no information about available sample rates can be fetched, an empty list is returned.

You can explicitely give the index of the device. If you don't give it, the currently selected device from the preferences will be used.

You may also specify a rate for which to check in addition to the standard rates.

References getPlayDevIndex(), mCachedPlaybackIndex, mCachedPlaybackRates, NumRatesToTry, and RatesToTry.

Referenced by GetBestRate(), GetDeviceInfo(), GetSupportedSampleRates(), and HandleDeviceChange().

wxArrayLong AudioIO::GetSupportedSampleRates ( int  playDevice = -1,
int  recDevice = -1,
double  rate = 0.0 
)
static

Get a list of sample rates the current input/output device combination supports.

Since there is no concept (yet) for different input/output sample rates, this currently returns only sample rates that are supported on both the output and input device. If no information about available sample rates can be fetched, it returns a default list. You can explicitely give the indexes of the playDevice/recDevice. If you don't give them, the selected devices from the preferences will be used. You may also specify a rate for which to check in addition to the standard rates.

References getPlayDevIndex(), getRecordDevIndex(), GetSupportedCaptureRates(), GetSupportedPlaybackRates(), mCachedCaptureIndex, mCachedPlaybackIndex, and mCachedSampleRates.

Referenced by GetBestRate(), GetDeviceInfo(), GetOptimalSupportedSampleRate(), and HandleDeviceChange().

void AudioIO::HandleDeviceChange ( )

update state after changing what audio devices are selected

Called when the devices stored in the preferences are changed to update the audio mixer capabilities

Todo:
: Make this do a sample rate query and store the result in the AudioIO object to avoid doing it later? Would simplify the GetSupported*Rate functions considerably

References audacityAudioCallback, DEFAULT_LATENCY_CORRECTION, getPlayDevIndex(), getRecordDevIndex(), GetSupportedCaptureRates(), GetSupportedPlaybackRates(), GetSupportedSampleRates(), gPrefs, IsStreamActive(), mCachedBestRateIn, mCachedCaptureIndex, mCachedCaptureRates, mCachedPlaybackIndex, mCachedPlaybackRates, mCachedSampleRates, mEmulateMixerOutputVol, mInputMixerWorks, mMixerOutputVol, and SetMixer().

Referenced by AudioIO(), DeviceToolBar::OnChoice(), and PrefsDialog::OnOK().

bool AudioIO::InputMixerWorks ( )

Find out if the input hardware level control is available.

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

References mInputMixerWorks.

Referenced by MixerToolBar::Populate(), MixerToolBar::UpdateControls(), and MixerToolBar::UpdatePrefs().

bool AudioIO::IsAudioTokenActive ( int  token)

Returns true if the stream is active, or even if audio I/O is busy cleaning up its data or writing to disk.

This is used by TrackPanel to determine when a track has been completely recorded, and it's safe to flush to disk.

References mStreamToken.

Referenced by AudacityProject::GetUpdateFlags(), IsStreamActive(), AudacityApp::OnKeyDown(), and TrackPanel::OnTimer().

bool AudioIO::IsAvailable ( AudacityProject projecT)

Function to automatically set an acceptable volume.

References mOwningProject.

Referenced by EffectUIHost::Initialize().

bool AudioIO::IsPaused ( )
bool AudioIO::IsScrubbing ( )
inline

Referenced by ControlToolBar::OnPause().

bool AudioIO::IsStreamActive ( int  token)
double AudioIO::LimitStreamTime ( double  absoluteTime) const
private

Clamps the given time to be between mT0 and mT1.

Returns the bound if the value is out of bounds; does not wrap. Returns a time in seconds.

Parameters
absoluteTimeA time in seconds, usually mTime

References min(), mT0, mT1, and ReversedTime().

Referenced by audacityAudioCallback(), and NormalizeStreamTime().

double AudioIO::NormalizeStreamTime ( double  absoluteTime) const
private

Normalizes the given time, clamping it and handling gaps from cut preview.

Clamps the time (unless scrubbing), and skips over the cut section. Returns a time in seconds.

Parameters
absoluteTimeA time in seconds, usually mTime

References LimitStreamTime(), mCutPreviewGapLen, mCutPreviewGapStart, mPlayMode, and PLAY_SCRUB.

Referenced by GetStreamTime().

bool AudioIO::OutputMixerEmulated ( )

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

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

References mEmulateMixerOutputVol.

Referenced by MixerToolBar::SetToolTips().

bool AudioIO::ReversedTime ( ) const
inlineprivate

True if the end time is before the start time.

Referenced by audacityAudioCallback(), and LimitStreamTime().

void AudioIO::SeekStream ( double  seconds)
inline

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

Referenced by EffectUIHost::OnFFwd(), EffectUIHost::OnRewind(), ControlToolBar::PlayPlayRegion(), and AudacityProject::SeekLeftOrRight().

void AudioIO::SetCaptureMeter ( AudacityProject project,
Meter meter 
)
void AudioIO::SetListener ( AudioIOListener listener)
void AudioIO::SetMeters ( )
private

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

References GetActiveProject(), AudacityProject::GetMixerBoard(), mInputMeter, mOutputMeter, mRate, mUpdateMeters, Meter::Reset(), and MixerBoard::ResetMeters().

Referenced by StartPortAudioStream().

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

References mMixerOutputVol, and SetMixer().

void AudioIO::SetPaused ( bool  state)
void AudioIO::SetPlaybackMeter ( AudacityProject project,
Meter meter 
)
void AudioIO::SetRecordingException ( )
inlineprivate

Referenced by FillBuffers().

void AudioIO::StartMonitoring ( double  sampleRate)

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

References gPrefs, mLastPaError, mListener, mOwningProject, mPortStreamV19, mRate, mSoftwarePlaythrough, mStreamToken, mUsingAlsa, AudioIOListener::OnAudioIORate(), and StartPortAudioStream().

Referenced by Meter::StartMonitoring().

bool AudioIO::StartPortAudioStream ( double  sampleRate,
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 sucessfully and false if it did not.

References audacityAudioCallback, AudacityToPortAudioSampleFormat(), DEFAULT_LATENCY_DURATION, GetActiveProject(), GetBestRate(), AudacityProject::GetCaptureMeter(), AudacityProject::GetPlaybackMeter(), getPlayDevIndex(), getRecordDevIndex(), gPrefs, mCaptureFormat, mInputMeter, mLastPaError, mNumCaptureChannels, mNumPlaybackChannels, mOutputMeter, mOwningProject, mPortStreamV19, mRate, mSoftwarePlaythrough, mUsingAlsa, SetMeters(), and SystemTime().

Referenced by StartMonitoring(), and StartStream().

int AudioIO::StartStream ( const ConstWaveTrackArray playbackTracks,
const WaveTrackArray captureTracks,
double  t0,
double  t1,
const AudioIOStartStreamOptions options 
)

Start recording or playing back audio.

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

References _(), ClearRecordingException(), TimeTrack::ComputeWarpedLength(), AudioIOStartStreamOptions::cutPreviewGapLen, AudioIOStartStreamOptions::cutPreviewGapStart, ENV_DB_KEY, ENV_DB_RANGE, gAudioIO, EffectManager::Get(), Track::GetLinked(), gPrefs, IsBusy(), LAT1CTOWX, AudioIOStartStreamOptions::listener, lrint, mAudioThreadFillBuffersLoopRunning, mAudioThreadShouldCallFillBuffersOnce, ScrubbingOptions::MaxAllowedScrubSpeed(), mCaptureBuffers, mCaptureRingBufferSecs, mCaptureTracks, mCutPreviewGapLen, mCutPreviewGapStart, mFactor, min(), ScrubbingOptions::MinAllowedScrubSpeed(), mLastRecordingOffset, mListener, mMinCaptureSecsToCopy, mNextStreamToken, mNumCaptureChannels, mNumPlaybackChannels, mOwningProject, mPauseRec, mPlaybackBuffers, mPlaybackMixers, mPlaybackRingBufferSecs, mPlaybackSamplesToCopy, mPlaybackTracks, mPlayMode, mPortStreamV19, mRate, mResample, mScrubDuration, mScrubQueue, mSeek, mSilenceLevel, mSilentScrub, mSoftwarePlaythrough, mStreamToken, mT0, mT1, mTime, mTimeTrack, mUsingAlsa, mWarpedLength, mWarpedTime, AudioIOListener::OnAudioIORate(), AudioIOListener::OnAudioIOStartRecording(), AudioIOListener::OnAudioIOStopRecording(), PLAY_LOOPED, PLAY_SCRUB, PLAY_STRAIGHT, AudioIOStartStreamOptions::playLooped, AudioIOStartStreamOptions::pScrubbingOptions, AudioIOStartStreamOptions::pStartTime, AudioIOStartStreamOptions::rate, EffectManager::RealtimeAddProcessor(), EffectManager::RealtimeInitialize(), ArrayOf< X >::reinit(), AudacityApp::SetMissingAliasedFileWarningShouldShow(), StartPortAudioStream(), StartStreamCleanup(), StopStream(), SystemTime(), AudioIOStartStreamOptions::timeTrack, and wxGetApp().

Referenced by ControlToolBar::OnRecord(), ControlToolBar::PlayPlayRegion(), and Effect::Preview().

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

Clean up after StartStream if it fails.

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

References EffectManager::Get(), mCaptureBuffers, mNumPlaybackChannels, mPlaybackBuffers, mPlaybackMixers, mPlayMode, mPortStreamV19, mResample, mScrubQueue, mStreamToken, PLAY_STRAIGHT, and EffectManager::RealtimeFinalize().

Referenced by StartStream().

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

Ensure selected device names are valid.

References getPlayDevIndex(), and getRecordDevIndex().

Friends And Related Function Documentation

int audacityAudioCallback ( const void *  inputBuffer,
void *  outputBuffer,
unsigned long  framesPerBuffer,
const PaStreamCallbackTimeInfo *  timeInfo,
PaStreamCallbackFlags  statusFlags,
void *  userData 
)
friend

brief The function which is called from PortAudio's callback thread context to collect and deliver audio for / from the sound device.

This covers recording, playback, and doing both simultaneously. It is also invoked to do monitoring and software playthrough. Note that dealing with the two buffers needs some care to ensure that the right things happen for all possible cases.

Parameters
inputBufferBuffer of length framesPerBuffer containing samples from the sound card, or null if not capturing audio. Note that the data type will depend on the format of audio data that was chosen when the stream was created (so could be floats or various integers)
outputBufferUninitialised buffer of length framesPerBuffer which will be sent to the sound card after the callback, or null if not playing audio back.
framesPerBufferThe length of the playback and recording buffers
PaStreamCallbackTimeInfoPointer to PortAudio time information structure, which tells us how long we have been playing / recording
statusFlagsPortAudio stream status flags
userDatapointer to user-defined data structure. Provided for flexibility by PortAudio, but not used by Audacity - the data is stored in the AudioIO class instead.

Referenced by GetDeviceInfo(), HandleDeviceChange(), and StartPortAudioStream().

friend class AudioThread
friend
void InitAudioIO ( )
friend

Member Data Documentation

volatile bool AudioIO::mAudioThreadFillBuffersLoopActive
private
volatile bool AudioIO::mAudioThreadFillBuffersLoopRunning
private
volatile bool AudioIO::mAudioThreadShouldCallFillBuffersOnce
private
double AudioIO::mCachedBestRateIn = 0.0
staticprivate

Referenced by GetBestRate(), and HandleDeviceChange().

double AudioIO::mCachedBestRateOut
staticprivate

Referenced by GetBestRate().

int AudioIO::mCachedCaptureIndex = -1
staticprivate
wxArrayLong AudioIO::mCachedCaptureRates
staticprivate
int AudioIO::mCachedPlaybackIndex = -1
staticprivate
wxArrayLong AudioIO::mCachedPlaybackRates
staticprivate
wxArrayLong AudioIO::mCachedSampleRates
staticprivate
ArrayOf<std::unique_ptr<RingBuffer> > AudioIO::mCaptureBuffers
private
sampleFormat AudioIO::mCaptureFormat
private
double AudioIO::mCaptureRingBufferSecs
private

Referenced by StartStream().

WaveTrackArray AudioIO::mCaptureTracks
private
double AudioIO::mCutPreviewGapLen
private

Referenced by NormalizeStreamTime(), and StartStream().

double AudioIO::mCutPreviewGapStart
private

Referenced by NormalizeStreamTime(), and StartStream().

bool AudioIO::mEmulateMixerOutputVol
private
double AudioIO::mFactor
private

Referenced by FillBuffers(), and StartStream().

bool AudioIO::mInputMixerWorks
private

Can we control the hardware input level?

This flag is set to true if using portmixer to control the input volume seems to be working (and so we offer the user the control), and to false (locking the control out) otherwise. This avoids stupid scaled clipping problems when trying to do software emulated input volume control

Referenced by AudioIO(), GetMixer(), HandleDeviceChange(), and InputMixerWorks().

PaError AudioIO::mLastPaError
private
wxLongLong AudioIO::mLastPlaybackTimeMillis
private

Referenced by audacityAudioCallback(), and AudioIO().

volatile double AudioIO::mLastRecordingOffset
private
int AudioIO::mLostSamples
private

Referenced by audacityAudioCallback().

double AudioIO::mMinCaptureSecsToCopy
private

Referenced by FillBuffers(), and StartStream().

float AudioIO::mMixerOutputVol
private
int AudioIO::mNextStreamToken = 0
staticprivate

Referenced by StartStream().

unsigned int AudioIO::mNumCaptureChannels
private
unsigned int AudioIO::mNumPlaybackChannels
private
bool AudioIO::mPaused
private

True if audio playback is paused.

Referenced by audacityAudioCallback(), AudioIO(), IsPaused(), and SetPaused().

bool AudioIO::mPauseRec
private

True if Sound Activated Recording is enabled.

Referenced by audacityAudioCallback(), and StartStream().

ArrayOf<std::unique_ptr<RingBuffer> > AudioIO::mPlaybackBuffers
private
ArrayOf<std::unique_ptr<Mixer> > AudioIO::mPlaybackMixers
private
double AudioIO::mPlaybackRingBufferSecs
private

Referenced by StartStream().

size_t AudioIO::mPlaybackSamplesToCopy
private

Referenced by FillBuffers(), and StartStream().

double AudioIO::mRate
private
wxAtomicInt AudioIO::mRecordingException {}
private

Referenced by FillBuffers().

ArrayOf<std::unique_ptr<Resample> > AudioIO::mResample
private
sampleCount AudioIO::mScrubDuration
private

Referenced by AudioIO(), FillBuffers(), and StartStream().

double AudioIO::mSeek
private
float AudioIO::mSilenceLevel
private
GrowableSampleBuffer AudioIO::mSilentBuf
private

Referenced by FillBuffers().

bool AudioIO::mSilentScrub
private

Referenced by AudioIO(), FillBuffers(), and StartStream().

bool AudioIO::mSoftwarePlaythrough
private
wxMutex AudioIO::mSuspendAudioThread
private
double AudioIO::mT0
private

Playback starts at offset of mT0, which is measured in seconds.

Referenced by audacityAudioCallback(), LimitStreamTime(), StartStream(), and StopStream().

double AudioIO::mT1
private

Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 during scrubbing.

Referenced by audacityAudioCallback(), LimitStreamTime(), and StartStream().

std::unique_ptr<AudioThread> AudioIO::mThread
private

Referenced by AudioIO(), InitAudioIO(), and ~AudioIO().

double AudioIO::mTime
private

Current time position during playback, in seconds. Between mT0 and mT1.

Referenced by audacityAudioCallback(), GetStreamTime(), and StartStream().

const TimeTrack* AudioIO::mTimeTrack
private
bool AudioIO::mUpdateMeters
private
volatile bool AudioIO::mUpdatingMeters
private
bool AudioIO::mUsingAlsa { false }
private
double AudioIO::mWarpedLength
private

Real length to be played (if looping, for each pass) after warping via a time track, computed just once when starting the stream. Length in real seconds between mT0 and mT1. Always positive.

Referenced by FillBuffers(), and StartStream().

double AudioIO::mWarpedTime
private

Accumulated real time (not track position), starting at zero (unlike mTime), and wrapping back to zero each time around looping play. Thus, it is the length in real seconds between mT0 and mTime.

Referenced by audacityAudioCallback(), FillBuffers(), and StartStream().

const int AudioIO::NumRatesToTry
staticprivate
Initial value:

How many sample rates to try.

Referenced by GetSupportedCaptureRates(), and GetSupportedPlaybackRates().

const int AudioIO::NumStandardRates
static
Initial value:

How many standard sample rates there are.

Referenced by QualityPrefs::GetNamesAndLabels(), and SelectionBar::UpdateRates().

const int AudioIO::RatesToTry
staticprivate
Initial value:
= {
8000,
9600,
11025,
12000,
15000,
16000,
22050,
24000,
32000,
44100,
48000,
88200,
96000,
176400,
192000,
352800,
384000
}

Array of audio sample rates to try to use.

These are the rates we will check if a device supports, and is as long as I can think of (to try and work out what the card can do)

Referenced by GetSupportedCaptureRates(), and GetSupportedPlaybackRates().

const int AudioIO::StandardRates
static
Initial value:
= {
8000,
11025,
16000,
22050,
32000,
44100,
48000,
88200,
96000,
176400,
192000,
352800,
384000
}

Array of common audio sample rates.

These are the rates we will always support, regardless of hardware support for them (by resampling in audacity if needed)

Referenced by QualityPrefs::GetNamesAndLabels(), and SelectionBar::UpdateRates().


The documentation for this class was generated from the following files: