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

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

#include <AudioIO.h>

Classes

struct  RecordingSchedule
 
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 TransportTracks &tracks, 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
 
bool IsCapturing () 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, MeterPanel *meter)
 
void SetPlaybackMeter (AudacityProject *project, MeterPanel *meter)
 
const std::vector< std::pair
< double, double > > & 
LostCaptureIntervals ()
 

Static Public Member Functions

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...
 
static bool ValidateDeviceNames (const wxString &play, const wxString &rec)
 Ensure selected device names are valid. More...
 

Public Attributes

bool mSimulateRecordingErrors { false }
 
bool mDetectUpstreamDropouts { true }
 

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

PRCrossfadeData mCrossfadeData {}
 
std::unique_ptr< AudioThreadmThread
 
ArrayOf< std::unique_ptr
< Resample > > 
mResample
 
ArrayOf< std::unique_ptr
< RingBuffer > > 
mCaptureBuffers
 
WaveTrackArray mCaptureTracks
 
ArrayOf< std::unique_ptr
< RingBuffer > > 
mPlaybackBuffers
 
WaveTrackConstArray 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
 
unsigned long long mLostSamples { 0 }
 
volatile bool mAudioThreadShouldCallFillBuffersOnce
 
volatile bool mAudioThreadFillBuffersLoopRunning
 
volatile bool mAudioThreadFillBuffersLoopActive
 
wxLongLong mLastPlaybackTimeMillis
 
volatile double mLastRecordingOffset
 
PaError mLastPaError
 
AudacityProjectmOwningProject
 
wxWeakRef< MeterPanelmInputMeter {}
 
MeterPanelmOutputMeter
 
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 {}
 
std::vector< std::pair< double,
double > > 
mLostCaptureIntervals
 
bool mDetectDropouts { true }
 
struct AudioIO::RecordingSchedule mRecordingSchedule
 

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 std::vector< long > mCachedPlaybackRates
 
static int mCachedCaptureIndex = -1
 
static std::vector< long > mCachedCaptureRates
 
static std::vector< long > 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.

Definition at line 172 of file AudioIO.h.

Member Enumeration Documentation

anonymous enum
private
Enumerator
PLAY_STRAIGHT 
PLAY_LOOPED 
PLAY_SCRUB 

Definition at line 748 of file AudioIO.h.

748  {
750  PLAY_LOOPED,
751 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
752  PLAY_SCRUB,
753 #endif
754  } mPlayMode;
enum AudioIO::@3 mPlayMode

Constructor & Destructor Documentation

AudioIO::AudioIO ( )

Definition at line 1180 of file AudioIO.cpp.

References _(), AudacityMessageBox(), HandleDeviceChange(), LAT1CTOWX, mAudioThreadFillBuffersLoopActive, mAudioThreadFillBuffersLoopRunning, mAudioThreadShouldCallFillBuffersOnce, mEmulateMixerOutputVol, mInputMixerWorks, mLastPaError, mLastPlaybackTimeMillis, mLastRecordingOffset, mListener, mMixerOutputVol, mNumCaptureChannels, mOutputMeter, mOwningProject, mPaused, mPlayMode, mPortStreamV19, mScrubDuration, mScrubQueue, mSilentScrub, mStreamToken, mThread, mUpdateMeters, mUpdatingMeters, and PLAY_STRAIGHT.

1181 {
1185  mPortStreamV19 = NULL;
1186 
1187 #ifdef EXPERIMENTAL_MIDI_OUT
1188  mMidiStream = NULL;
1189  mMidiThreadFillBuffersLoopRunning = false;
1190  mMidiThreadFillBuffersLoopActive = false;
1191  mMidiStreamActive = false;
1192  mSendMidiState = false;
1193  mIterator = NULL;
1194 
1195  mNumFrames = 0;
1196  mNumPauseFrames = 0;
1197 #endif
1198 
1199 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1200  mAILAActive = false;
1201 #endif
1202  mStreamToken = 0;
1203 
1204  mLastPaError = paNoError;
1205 
1206  mLastRecordingOffset = 0.0;
1207  mNumCaptureChannels = 0;
1208  mPaused = false;
1210 
1211  mListener = NULL;
1212  mUpdateMeters = false;
1213  mUpdatingMeters = false;
1214 
1215  mOwningProject = NULL;
1216  mOutputMeter = NULL;
1217 
1218  PaError err = Pa_Initialize();
1219 
1220  if (err != paNoError) {
1221  wxString errStr = _("Could not find any audio devices.\n");
1222  errStr += _("You will not be able to play or record audio.\n\n");
1223  wxString paErrStr = LAT1CTOWX(Pa_GetErrorText(err));
1224  if (!paErrStr.IsEmpty())
1225  errStr += _("Error: ")+paErrStr;
1226  // XXX: we are in libaudacity, popping up dialogs not allowed! A
1227  // long-term solution will probably involve exceptions
1228  AudacityMessageBox(errStr, _("Error Initializing Audio"), wxICON_ERROR|wxOK);
1229 
1230  // Since PortAudio is not initialized, all calls to PortAudio
1231  // functions will fail. This will give reasonable behavior, since
1232  // the user will be able to do things not relating to audio i/o,
1233  // but any attempt to play or record will simply fail.
1234  }
1235 
1236 #ifdef EXPERIMENTAL_MIDI_OUT
1237  PmError pmErr = Pm_Initialize();
1238 
1239  if (pmErr != pmNoError) {
1240  wxString errStr =
1241  _("There was an error initializing the midi i/o layer.\n");
1242  errStr += _("You will not be able to play midi.\n\n");
1243  wxString pmErrStr = LAT1CTOWX(Pm_GetErrorText(pmErr));
1244  if (!pmErrStr.empty())
1245  errStr += _("Error: ") + pmErrStr;
1246  // XXX: we are in libaudacity, popping up dialogs not allowed! A
1247  // long-term solution will probably involve exceptions
1248  AudacityMessageBox(errStr, _("Error Initializing Midi"), wxICON_ERROR|wxOK);
1249 
1250  // Same logic for PortMidi as described above for PortAudio
1251  }
1252 
1253 #ifdef USE_MIDI_THREAD
1254  mMidiThread = std::make_unique<MidiThread>();
1255  mMidiThread->Create();
1256 #endif
1257 
1258 #endif
1259 
1260  // Start thread
1261  mThread = std::make_unique<AudioThread>();
1262  mThread->Create();
1263 
1264 #if defined(USE_PORTMIXER)
1265  mPortMixer = NULL;
1266  mPreviousHWPlaythrough = -1.0;
1268 #else
1269  mEmulateMixerOutputVol = true;
1270  mMixerOutputVol = 1.0;
1271  mInputMixerWorks = false;
1272 #endif
1273 
1275 
1276 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1277  mScrubQueue = NULL;
1278  mScrubDuration = 0;
1279  mSilentScrub = false;
1280 #endif
1281 }
enum AudioIO::@3 mPlayMode
sampleCount mScrubDuration
Definition: AudioIO.h:819
volatile bool mUpdatingMeters
Definition: AudioIO.h:730
float mMixerOutputVol
Definition: AudioIO.h:746
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:745
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
MeterPanel * mOutputMeter
Definition: AudioIO.h:728
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:702
volatile int mStreamToken
Definition: AudioIO.h:674
bool mEmulateMixerOutputVol
Definition: AudioIO.h:737
PaStream * mPortStreamV19
Definition: AudioIO.h:703
void HandleDeviceChange()
update state after changing what audio devices are selected
Definition: AudioIO.cpp:1426
AudacityProject * mOwningProject
Definition: AudioIO.h:726
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:716
AudioIOListener * mListener
Definition: AudioIO.h:760
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:712
#define LAT1CTOWX(X)
Definition: Internat.h:180
unsigned int mNumCaptureChannels
Definition: AudioIO.h:708
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:661
bool mUpdateMeters
Definition: AudioIO.h:729
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
volatile double mLastRecordingOffset
Definition: AudioIO.h:723
volatile bool mAudioThreadFillBuffersLoopActive
Definition: AudioIO.h:714
PaError mLastPaError
Definition: AudioIO.h:724
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:713
bool mSilentScrub
Definition: AudioIO.h:818
AudioIO::~AudioIO ( )

Definition at line 1283 of file AudioIO.cpp.

References gAudioIO, and mThread.

1284 {
1285 #if defined(USE_PORTMIXER)
1286  if (mPortMixer) {
1287  #if __WXMAC__
1288  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1289  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1290  mPreviousHWPlaythrough = -1.0;
1291  #endif
1292  Px_CloseMixer(mPortMixer);
1293  mPortMixer = NULL;
1294  }
1295 #endif
1296 
1297  // FIXME: ? TRAP_ERR. Pa_Terminate probably OK if err without reporting.
1298  Pa_Terminate();
1299 
1300 #ifdef EXPERIMENTAL_MIDI_OUT
1301  Pm_Terminate();
1302 
1303  /* Delete is a "graceful" way to stop the thread.
1304  (Kill is the not-graceful way.) */
1305 
1306 #ifdef USE_MIDI_THREAD
1307  mMidiThread->Delete();
1308  mMidiThread.reset();
1309 #endif
1310 
1311 #endif
1312 
1313  /* Delete is a "graceful" way to stop the thread.
1314  (Kill is the not-graceful way.) */
1315 
1316  // This causes reentrancy issues during application shutdown
1317  // wxTheApp->Yield();
1318 
1319  mThread->Delete();
1320  mThread.reset();
1321 
1322  gAudioIO = nullptr;
1323 }
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:661
AudioIO * gAudioIO
Definition: AudioIO.cpp:482

Member Function Documentation

void AudioIO::ClearRecordingException ( )
inlineprivate

Definition at line 827 of file AudioIO.h.

Referenced by StartStream(), and StopStream().

828  { if (mRecordingException) wxAtomicDec( mRecordingException ); }
wxAtomicInt mRecordingException
Definition: AudioIO.h:824
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.

Definition at line 2864 of file AudioIO.cpp.

Referenced by Scrubber::ContinueScrubbingPoll().

2865 {
2866  if (mScrubQueue)
2867  return mScrubQueue->Producer(endTimeOrSpeed, options);
2868  else
2869  return false;
2870 }
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
void AudioIO::FillBuffers ( )
private

Definition at line 3789 of file AudioIO.cpp.

References SampleBuffer::Allocate(), sampleCount::as_double(), ClearSamples(), AudioIO::RecordingSchedule::Consumed(), AutoSaveFile::EndTag(), floatSample, format, GetCommonlyAvailCapture(), GetCommonlyAvailPlayback(), GuardedCall(), AutoSaveFile::IsEmpty(), IsStreamActive(), limitSampleBufferSize(), lrint, mAudioThreadShouldCallFillBuffersOnce, mCaptureBuffers, mCaptureTracks, AudioIO::RecordingSchedule::mCrossfadeData, mFactor, min(), AudioIO::RecordingSchedule::mLatencyCorrected, mListener, mMinCaptureSecsToCopy, mPlaybackBuffers, mPlaybackMixers, mPlaybackSamplesToCopy, mPlaybackTracks, mPlayMode, AudioIO::RecordingSchedule::mPosition, mRate, mRecordingException, mRecordingSchedule, mResample, mScrubDuration, mScrubQueue, mSilentBuf, mSilentScrub, mWarpedLength, mWarpedTime, AudioIOListener::OnAudioIONewBlockFiles(), PLAY_LOOPED, PLAY_SCRUB, PLAY_STRAIGHT, SampleBuffer::ptr(), GrowableSampleBuffer::Resize(), SetRecordingException(), AutoSaveFile::StartTag(), StopStream(), AudioIO::RecordingSchedule::ToConsume(), AudioIO::RecordingSchedule::ToDiscard(), AudioIO::RecordingSchedule::TotalCorrection(), AutoSaveFile::WriteAttr(), and AutoSaveFile::WriteSubTree().

Referenced by AudioThread::Entry().

3790 {
3791  unsigned int i;
3792 
3793  auto delayedHandler = [this] ( AudacityException * pException ) {
3794  // In the main thread, stop recording
3795  // This is one place where the application handles disk
3796  // exhaustion exceptions from wave track operations, without rolling
3797  // back to the last pushed undo state. Instead, partial recording
3798  // results are pushed as a NEW undo state. For this reason, as
3799  // commented elsewhere, we want an exception safety guarantee for
3800  // the output wave tracks, after the failed append operation, that
3801  // the tracks remain as they were after the previous successful
3802  // (block-level) appends.
3803 
3804  // Note that the Flush in StopStream() may throw another exception,
3805  // but StopStream() contains that exception, and the logic in
3806  // AudacityException::DelayedHandlerAction prevents redundant message
3807  // boxes.
3808  StopStream();
3809  DefaultDelayedHandlerAction{}( pException );
3810  };
3811 
3812  if (mPlaybackTracks.size() > 0)
3813  {
3814  // Though extremely unlikely, it is possible that some buffers
3815  // will have more samples available than others. This could happen
3816  // if we hit this code during the PortAudio callback. To keep
3817  // things simple, we only write as much data as is vacant in
3818  // ALL buffers, and advance the global time by that much.
3819  // MB: subtract a few samples because the code below has rounding errors
3820  auto nAvailable = (int)GetCommonlyAvailPlayback() - 10;
3821 
3822  //
3823  // Don't fill the buffers at all unless we can do the
3824  // full mMaxPlaybackSecsToCopy. This improves performance
3825  // by not always trying to process tiny chunks, eating the
3826  // CPU unnecessarily.
3827  //
3828  // The exception is if we're at the end of the selected
3829  // region - then we should just fill the buffer.
3830  //
3831  if (nAvailable >= (int)mPlaybackSamplesToCopy ||
3832  (mPlayMode == PLAY_STRAIGHT &&
3833  nAvailable > 0 &&
3834  mWarpedTime+(nAvailable/mRate) >= mWarpedLength))
3835  {
3836  // Limit maximum buffer size (increases performance)
3837  auto available =
3838  std::min<size_t>( nAvailable, mPlaybackSamplesToCopy );
3839 
3840  // msmeyer: When playing a very short selection in looped
3841  // mode, the selection must be copied to the buffer multiple
3842  // times, to ensure, that the buffer has a reasonable size
3843  // This is the purpose of this loop.
3844  // PRL: or, when scrubbing, we may get work repeatedly from the
3845  // scrub queue.
3846  bool done = false;
3847  Maybe<wxMutexLocker> cleanup;
3848  do {
3849  // How many samples to produce for each channel.
3850  auto frames = available;
3851  bool progress = true;
3852 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
3853  if (mPlayMode == PLAY_SCRUB)
3854  // scrubbing does not use warped time and length
3855  frames = limitSampleBufferSize(frames, mScrubDuration);
3856  else
3857 #endif
3858  {
3859  double deltat = frames / mRate;
3860  if (mWarpedTime + deltat > mWarpedLength)
3861  {
3862  frames = (mWarpedLength - mWarpedTime) * mRate;
3863  // Don't fall into an infinite loop, if loop-playing a selection
3864  // that is so short, it has no samples: detect that case
3865  progress =
3866  !(mPlayMode == PLAY_LOOPED &&
3867  mWarpedTime == 0.0 && frames == 0);
3868  mWarpedTime = mWarpedLength;
3869  }
3870  else
3871  mWarpedTime += deltat;
3872  }
3873 
3874  if (!progress)
3875  frames = available;
3876 
3877  for (i = 0; i < mPlaybackTracks.size(); i++)
3878  {
3879  // The mixer here isn't actually mixing: it's just doing
3880  // resampling, format conversion, and possibly time track
3881  // warping
3882  decltype(mPlaybackMixers[i]->Process(frames))
3883  processed = 0;
3884  samplePtr warpedSamples;
3885  //don't do anything if we have no length. In particular, Process() will fail an wxAssert
3886  //that causes a crash since this is not the GUI thread and wxASSERT is a GUI call.
3887 
3888  // don't generate either if scrubbing at zero speed.
3889 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
3890  const bool silent = (mPlayMode == PLAY_SCRUB) && mSilentScrub;
3891 #else
3892  const bool silent = false;
3893 #endif
3894 
3895  if (progress && !silent && frames > 0)
3896  {
3897  processed = mPlaybackMixers[i]->Process(frames);
3898  wxASSERT(processed <= frames);
3899  warpedSamples = mPlaybackMixers[i]->GetBuffer();
3900  const auto put = mPlaybackBuffers[i]->Put
3901  (warpedSamples, floatSample, processed);
3902  // wxASSERT(put == processed);
3903  // but we can't assert in this thread
3904  wxUnusedVar(put);
3905  }
3906 
3907  //if looping and processed is less than the full chunk/block/buffer that gets pulled from
3908  //other longer tracks, then we still need to advance the ring buffers or
3909  //we'll trip up on ourselves when we start them back up again.
3910  //if not looping we never start them up again, so its okay to not do anything
3911  // If scrubbing, we may be producing some silence. Otherwise this should not happen,
3912  // but makes sure anyway that we produce equal
3913  // numbers of samples for all channels for this pass of the do-loop.
3914  if(processed < frames && mPlayMode != PLAY_STRAIGHT)
3915  {
3916  mSilentBuf.Resize(frames, floatSample);
3917  ClearSamples(mSilentBuf.ptr(), floatSample, 0, frames);
3918  const auto put = mPlaybackBuffers[i]->Put
3919  (mSilentBuf.ptr(), floatSample, frames - processed);
3920  // wxASSERT(put == frames - processed);
3921  // but we can't assert in this thread
3922  wxUnusedVar(put);
3923  }
3924  }
3925 
3926  available -= frames;
3927  wxASSERT(available >= 0);
3928 
3929  switch (mPlayMode)
3930  {
3931 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
3932  case PLAY_SCRUB:
3933  {
3934  mScrubDuration -= frames;
3935  wxASSERT(mScrubDuration >= 0);
3936  done = (available == 0);
3937  if (!done && mScrubDuration <= 0)
3938  {
3939  sampleCount startSample, endSample;
3940  mScrubQueue->Transformer(startSample, endSample, mScrubDuration, cleanup);
3941  if (mScrubDuration < 0)
3942  {
3943  // Can't play anything
3944  // Stop even if we don't fill up available
3945  mScrubDuration = 0;
3946  done = true;
3947  }
3948  else
3949  {
3950  mSilentScrub = (endSample == startSample);
3951  if (!mSilentScrub)
3952  {
3953  double startTime, endTime, speed;
3954  startTime = startSample.as_double() / mRate;
3955  endTime = endSample.as_double() / mRate;
3956  auto diff = (endSample - startSample).as_long_long();
3957  speed = double(std::abs(diff)) / mScrubDuration.as_double();
3958  for (i = 0; i < mPlaybackTracks.size(); i++)
3959  mPlaybackMixers[i]->SetTimesAndSpeed(startTime, endTime, speed);
3960  }
3961  }
3962  }
3963  }
3964  break;
3965 #endif
3966  case PLAY_LOOPED:
3967  {
3968  done = !progress || (available == 0);
3969  // msmeyer: If playing looped, check if we are at the end of the buffer
3970  // and if yes, restart from the beginning.
3971  if (mWarpedTime >= mWarpedLength)
3972  {
3973  for (i = 0; i < mPlaybackTracks.size(); i++)
3974  mPlaybackMixers[i]->Restart();
3975  mWarpedTime = 0.0;
3976  }
3977  }
3978  break;
3979  default:
3980  done = true;
3981  break;
3982  }
3983  } while (!done);
3984  }
3985  } // end of playback buffering
3986 
3987  if (!mRecordingException &&
3988  mCaptureTracks.size() > 0)
3989  GuardedCall( [&] {
3990  // start record buffering
3991  const auto avail = GetCommonlyAvailCapture(); // samples
3992  const auto remainingTime =
3993  std::max(0.0, mRecordingSchedule.ToConsume());
3994  // This may be a very big double number:
3995  const auto remainingSamples = remainingTime * mRate;
3996  bool latencyCorrected = true;
3997 
3998  double deltat = avail / mRate;
3999 
4001  deltat >= mMinCaptureSecsToCopy)
4002  {
4003  // Append captured samples to the end of the WaveTracks.
4004  // The WaveTracks have their own buffering for efficiency.
4005  AutoSaveFile blockFileLog;
4006  auto numChannels = mCaptureTracks.size();
4007 
4008  for( i = 0; i < numChannels; i++ )
4009  {
4010  sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
4011 
4012  AutoSaveFile appendLog;
4013  size_t discarded = 0;
4014 
4016  const auto correction = mRecordingSchedule.TotalCorrection();
4017  if (correction >= 0) {
4018  // Rightward shift
4019  // Once only (per track per recording), insert some initial
4020  // silence.
4021  size_t size = floor( correction * mRate * mFactor);
4022  SampleBuffer temp(size, trackFormat);
4023  ClearSamples(temp.ptr(), trackFormat, 0, size);
4024  mCaptureTracks[i]->Append(temp.ptr(), trackFormat,
4025  size, 1, &appendLog);
4026  }
4027  else {
4028  // Leftward shift
4029  // discard some samples from the ring buffers.
4030  size_t size = floor(
4032 
4033  // The ring buffer might have grown concurrently -- don't discard more
4034  // than the "avail" value noted above.
4035  discarded = mCaptureBuffers[i]->Discard(std::min(avail, size));
4036 
4037  if (discarded < size)
4038  // We need to visit this again to complete the
4039  // discarding.
4040  latencyCorrected = false;
4041  }
4042  }
4043 
4044  const float *pCrossfadeSrc = nullptr;
4045  size_t crossfadeStart = 0, totalCrossfadeLength = 0;
4046  if (i < mRecordingSchedule.mCrossfadeData.size())
4047  {
4048  // Do crossfading
4049  // The supplied crossfade samples are at the same rate as the track
4050  const auto &data = mRecordingSchedule.mCrossfadeData[i];
4051  totalCrossfadeLength = data.size();
4052  if (totalCrossfadeLength) {
4053  crossfadeStart =
4054  floor(mRecordingSchedule.Consumed() * mCaptureTracks[i]->GetRate());
4055  if (crossfadeStart < totalCrossfadeLength)
4056  pCrossfadeSrc = data.data() + crossfadeStart;
4057  }
4058  }
4059 
4060  wxASSERT(discarded <= avail);
4061  size_t toGet = avail - discarded;
4062  SampleBuffer temp;
4063  size_t size;
4065  if( mFactor == 1.0 )
4066  {
4067  // Take captured samples directly
4068  size = toGet;
4069  if (pCrossfadeSrc)
4070  // Change to float for crossfade calculation
4071  format = floatSample;
4072  else
4073  format = trackFormat;
4074  temp.Allocate(size, format);
4075  const auto got =
4076  mCaptureBuffers[i]->Get(temp.ptr(), format, toGet);
4077  // wxASSERT(got == toGet);
4078  // but we can't assert in this thread
4079  wxUnusedVar(got);
4080  if (double(size) > remainingSamples)
4081  size = floor(remainingSamples);
4082  }
4083  else
4084  {
4085  size = lrint(toGet * mFactor);
4086  format = floatSample;
4087  SampleBuffer temp1(toGet, floatSample);
4088  temp.Allocate(size, format);
4089  const auto got =
4090  mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, toGet);
4091  // wxASSERT(got == toGet);
4092  // but we can't assert in this thread
4093  wxUnusedVar(got);
4094  /* we are re-sampling on the fly. The last resampling call
4095  * must flush any samples left in the rate conversion buffer
4096  * so that they get recorded
4097  */
4098  if (toGet > 0 ) {
4099  if (double(toGet) > remainingSamples)
4100  toGet = floor(remainingSamples);
4101  const auto results =
4102  mResample[i]->Process(mFactor, (float *)temp1.ptr(), toGet,
4103  !IsStreamActive(), (float *)temp.ptr(), size);
4104  size = results.second;
4105  }
4106  }
4107 
4108  if (pCrossfadeSrc) {
4109  wxASSERT(format == floatSample);
4110  size_t crossfadeLength = std::min(size, totalCrossfadeLength - crossfadeStart);
4111  if (crossfadeLength) {
4112  auto ratio = double(crossfadeStart) / totalCrossfadeLength;
4113  auto ratioStep = 1.0 / totalCrossfadeLength;
4114  auto pCrossfadeDst = (float*)temp.ptr();
4115 
4116  // Crossfade loop here
4117  for (size_t ii = 0; ii < crossfadeLength; ++ii) {
4118  *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
4119  ++pCrossfadeSrc, ++pCrossfadeDst;
4120  ratio += ratioStep;
4121  }
4122  }
4123  }
4124 
4125  // Now append
4126  // see comment in second handler about guarantee
4127  mCaptureTracks[i]->Append(temp.ptr(), format,
4128  size, 1,
4129  &appendLog);
4130 
4131  if (!appendLog.IsEmpty())
4132  {
4133  blockFileLog.StartTag(wxT("recordingrecovery"));
4134  blockFileLog.WriteAttr(wxT("id"), mCaptureTracks[i]->GetAutoSaveIdent());
4135  blockFileLog.WriteAttr(wxT("channel"), (int)i);
4136  blockFileLog.WriteAttr(wxT("numchannels"), numChannels);
4137  blockFileLog.WriteSubTree(appendLog);
4138  blockFileLog.EndTag(wxT("recordingrecovery"));
4139  }
4140  } // end loop over capture channels
4141 
4142  // Now update the recording shedule position
4143  mRecordingSchedule.mPosition += avail / mRate;
4144  mRecordingSchedule.mLatencyCorrected = latencyCorrected;
4145 
4146  if (mListener && !blockFileLog.IsEmpty())
4147  mListener->OnAudioIONewBlockFiles(blockFileLog);
4148  }
4149  // end of record buffering
4150  },
4151  // handler
4152  [this] ( AudacityException *pException ) {
4153  if ( pException ) {
4154  // So that we don't attempt to fill the recording buffer again
4155  // before the main thread stops recording
4157  return ;
4158  }
4159  else
4160  // Don't want to intercept other exceptions (?)
4161  throw;
4162  },
4163  delayedHandler
4164  );
4165 }
size_t GetCommonlyAvailCapture()
Get the number of audio samples ready in all of the recording buffers.
Definition: AudioIO.cpp:3305
void StartTag(const wxString &name) override
void StopStream()
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:2562
GrowableSampleBuffer & Resize(size_t count, sampleFormat format)
Definition: SampleFormat.h:101
double mMinCaptureSecsToCopy
Definition: AudioIO.h:700
root of a hierarchy of classes that are thrown and caught by Audacity.
void WriteAttr(const wxString &name, const wxString &value) override
bool IsEmpty() const
double TotalCorrection() const
Definition: AudioIO.h:857
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2890
enum AudioIO::@3 mPlayMode
sampleCount mScrubDuration
Definition: AudioIO.h:819
SampleBuffer & Allocate(size_t count, sampleFormat format)
Definition: SampleFormat.h:67
double as_double() const
Definition: Types.h:88
struct AudioIO::RecordingSchedule mRecordingSchedule
Definition: MemoryX.h:204
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:670
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:667
void WriteSubTree(const AutoSaveFile &value)
GrowableSampleBuffer mSilentBuf
Definition: AudioIO.h:758
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:673
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
double mWarpedTime
Definition: AudioIO.h:689
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:178
wxAtomicInt mRecordingException
Definition: AudioIO.h:824
void EndTag(const wxString &name) override
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:668
int format
Definition: ExportPCM.cpp:56
double Consumed() const
Definition: AudioIO.cpp:5471
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:669
double ToDiscard() const
Definition: AudioIO.cpp:5476
sampleFormat
Definition: Types.h:188
double ToConsume() const
Definition: AudioIO.cpp:5466
#define lrint(dbl)
Definition: float_cast.h:136
char * samplePtr
Definition: Types.h:203
int min(int a, int b)
AudioIOListener * mListener
Definition: AudioIO.h:760
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:712
samplePtr ptr() const
Definition: SampleFormat.h:81
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
size_t GetCommonlyAvailPlayback()
Get the number of audio samples free in all of the playback buffers.
Definition: AudioIO.cpp:3296
PRCrossfadeData mCrossfadeData
Definition: AudioIO.h:850
virtual void OnAudioIONewBlockFiles(const AutoSaveFile &blockFileLog)=0
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
double mWarpedLength
Definition: AudioIO.h:694
double mFactor
Definition: AudioIO.h:676
size_t mPlaybackSamplesToCopy
Definition: AudioIO.h:699
void SetRecordingException()
Definition: AudioIO.h:825
bool mSilentScrub
Definition: AudioIO.h:818
WaveTrackConstArray mPlaybackTracks
Definition: AudioIO.h:671
a class wrapping reading and writing of arbitrary data in text or binary format to a file...
Definition: AutoRecovery.h:76
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.

Definition at line 3161 of file AudioIO.cpp.

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

Referenced by StartPortAudioStream().

3162 {
3163  // Check if we can use the cached value
3164  if (mCachedBestRateIn != 0.0 && mCachedBestRateIn == sampleRate) {
3165  return mCachedBestRateOut;
3166  }
3167 
3168  // In order to cache the value, all early returns should instead set retval
3169  // and jump to finished
3170  double retval;
3171 
3172  std::vector<long> rates;
3173  if (capturing) wxLogDebug(wxT("AudioIO::GetBestRate() for capture"));
3174  if (playing) wxLogDebug(wxT("AudioIO::GetBestRate() for playback"));
3175  wxLogDebug(wxT("GetBestRate() suggested rate %.0lf Hz"), sampleRate);
3176 
3177  if (capturing && !playing) {
3178  rates = GetSupportedCaptureRates(-1, sampleRate);
3179  }
3180  else if (playing && !capturing) {
3181  rates = GetSupportedPlaybackRates(-1, sampleRate);
3182  }
3183  else { // we assume capturing and playing - the alternative would be a
3184  // bit odd
3185  rates = GetSupportedSampleRates(-1, -1, sampleRate);
3186  }
3187  /* rem rates is the array of hardware-supported sample rates (in the current
3188  * configuration), sampleRate is the Project Rate (desired sample rate) */
3189  long rate = (long)sampleRate;
3190 
3191  if (make_iterator_range(rates).contains(rate)) {
3192  wxLogDebug(wxT("GetBestRate() Returning %.0ld Hz"), rate);
3193  retval = rate;
3194  goto finished;
3195  /* the easy case - the suggested rate (project rate) is in the list, and
3196  * we can just accept that and send back to the caller. This should be
3197  * the case for most users most of the time (all of the time on
3198  * Win MME as the OS does resampling) */
3199  }
3200 
3201  /* if we get here, there is a problem - the project rate isn't supported
3202  * on our hardware, so we can't us it. Need to come up with an alternative
3203  * rate to use. The process goes like this:
3204  * * If there are no rates to pick from, we're stuck and return 0 (error)
3205  * * If there are some rates, we pick the next one higher than the requested
3206  * rate to use.
3207  * * If there aren't any higher, we use the highest available rate */
3208 
3209  if (rates.empty()) {
3210  /* we're stuck - there are no supported rates with this hardware. Error */
3211  wxLogDebug(wxT("GetBestRate() Error - no supported sample rates"));
3212  retval = 0.0;
3213  goto finished;
3214  }
3215  int i;
3216  for (i = 0; i < (int)rates.size(); i++) // for each supported rate
3217  {
3218  if (rates[i] > rate) {
3219  // supported rate is greater than requested rate
3220  wxLogDebug(wxT("GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
3221  retval = rates[i];
3222  goto finished;
3223  }
3224  }
3225 
3226  wxLogDebug(wxT("GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
3227  retval = rates.back(); // the highest available rate
3228  goto finished;
3229 
3230 finished:
3231  mCachedBestRateIn = sampleRate;
3232  mCachedBestRateOut = retval;
3233  return retval;
3234 }
static double mCachedBestRateIn
Definition: AudioIO.h:779
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: AudioIO.cpp:3097
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:677
static std::vector< long > GetSupportedCaptureRates(int devIndex=-1, double rate=0.0)
Get a list of sample rates the input (recording) device supports.
Definition: AudioIO.cpp:3031
static double mCachedBestRateOut
Definition: AudioIO.h:780
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
Definition: AudioIO.cpp:2969
sampleFormat AudioIO::GetCaptureFormat ( )
inline

Definition at line 397 of file AudioIO.h.

397 { return mCaptureFormat; }
sampleFormat mCaptureFormat
Definition: AudioIO.h:710
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 3305 of file AudioIO.cpp.

References mCaptureBuffers, mCaptureTracks, and min().

Referenced by FillBuffers().

3306 {
3307  auto commonlyAvail = mCaptureBuffers[0]->AvailForGet();
3308  for (unsigned i = 1; i < mCaptureTracks.size(); ++i)
3309  commonlyAvail = std::min(commonlyAvail,
3310  mCaptureBuffers[i]->AvailForGet());
3311  return commonlyAvail;
3312 }
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:668
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:669
int min(int a, int b)
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.

Definition at line 3296 of file AudioIO.cpp.

References min(), mPlaybackBuffers, and mPlaybackTracks.

Referenced by FillBuffers().

3297 {
3298  auto commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
3299  for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
3300  commonlyAvail = std::min(commonlyAvail,
3301  mPlaybackBuffers[i]->AvailForPut());
3302  return commonlyAvail;
3303 }
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:670
int min(int a, int b)
WaveTrackConstArray mPlaybackTracks
Definition: AudioIO.h:671
wxString AudioIO::GetDeviceInfo ( )

Get diagnostic information on all the available audio I/O devices.

Definition at line 3444 of file AudioIO.cpp.

References audacityAudioCallback, DEFAULT_LATENCY_CORRECTION, DeviceName(), GetSupportedPlaybackRates(), GetSupportedSampleRates(), gPrefs, HostName(), and IsStreamActive().

Referenced by AudacityProject::OnAudioDeviceInfo().

3445 {
3446  wxStringOutputStream o;
3447  wxTextOutputStream s(o, wxEOL_UNIX);
3448  wxString e(wxT("\n"));
3449 
3450  if (IsStreamActive()) {
3451  return wxT("Stream is active ... unable to gather information.");
3452  }
3453 
3454 
3455  // FIXME: TRAP_ERR PaErrorCode not handled. 3 instances in GetDeviceInfo().
3456  int recDeviceNum = Pa_GetDefaultInputDevice();
3457  int playDeviceNum = Pa_GetDefaultOutputDevice();
3458  int cnt = Pa_GetDeviceCount();
3459 
3460  wxLogDebug(wxT("Portaudio reports %d audio devices"),cnt);
3461 
3462  s << wxT("==============================") << e;
3463  s << wxT("Default recording device number: ") << recDeviceNum << e;
3464  s << wxT("Default playback device number: ") << playDeviceNum << e;
3465 
3466  wxString recDevice = gPrefs->Read(wxT("/AudioIO/RecordingDevice"), wxT(""));
3467  wxString playDevice = gPrefs->Read(wxT("/AudioIO/PlaybackDevice"), wxT(""));
3468  int j;
3469 
3470  // This gets info on all available audio devices (input and output)
3471  if (cnt <= 0) {
3472  s << wxT("No devices found\n");
3473  return o.GetString();
3474  }
3475 
3476  const PaDeviceInfo* info;
3477 
3478  for (j = 0; j < cnt; j++) {
3479  s << wxT("==============================") << e;
3480 
3481  info = Pa_GetDeviceInfo(j);
3482  if (!info) {
3483  s << wxT("Device info unavailable for: ") << j << wxT("\n");
3484  continue;
3485  }
3486 
3487  wxString name = DeviceName(info);
3488  s << wxT("Device ID: ") << j << e;
3489  s << wxT("Device name: ") << name << e;
3490  s << wxT("Host name: ") << HostName(info) << e;
3491  s << wxT("Recording channels: ") << info->maxInputChannels << e;
3492  s << wxT("Playback channels: ") << info->maxOutputChannels << e;
3493  s << wxT("Low Recording Latency: ") << info->defaultLowInputLatency << e;
3494  s << wxT("Low Playback Latency: ") << info->defaultLowOutputLatency << e;
3495  s << wxT("High Recording Latency: ") << info->defaultHighInputLatency << e;
3496  s << wxT("High Playback Latency: ") << info->defaultHighOutputLatency << e;
3497 
3498  auto rates = GetSupportedPlaybackRates(j, 0.0);
3499 
3500  s << wxT("Supported Rates:") << e;
3501  for (int k = 0; k < (int) rates.size(); k++) {
3502  s << wxT(" ") << (int)rates[k] << e;
3503  }
3504 
3505  if (name == playDevice && info->maxOutputChannels > 0)
3506  playDeviceNum = j;
3507 
3508  if (name == recDevice && info->maxInputChannels > 0)
3509  recDeviceNum = j;
3510 
3511  // Sometimes PortAudio returns -1 if it cannot find a suitable default
3512  // device, so we just use the first one available
3513  if (recDeviceNum < 0 && info->maxInputChannels > 0){
3514  recDeviceNum = j;
3515  }
3516  if (playDeviceNum < 0 && info->maxOutputChannels > 0){
3517  playDeviceNum = j;
3518  }
3519  }
3520 
3521  bool haveRecDevice = (recDeviceNum >= 0);
3522  bool havePlayDevice = (playDeviceNum >= 0);
3523 
3524  s << wxT("==============================") << e;
3525  if(haveRecDevice){
3526  s << wxT("Selected recording device: ") << recDeviceNum << wxT(" - ") << recDevice << e;
3527  }else{
3528  s << wxT("No recording device found for '") << recDevice << wxT("'.") << e;
3529  }
3530  if(havePlayDevice){
3531  s << wxT("Selected playback device: ") << playDeviceNum << wxT(" - ") << playDevice << e;
3532  }else{
3533  s << wxT("No playback device found for '") << playDevice << wxT("'.") << e;
3534  }
3535 
3536  std::vector<long> supportedSampleRates;
3537 
3538  if(havePlayDevice && haveRecDevice){
3539  supportedSampleRates = GetSupportedSampleRates(playDeviceNum, recDeviceNum);
3540 
3541  s << wxT("Supported Rates:") << e;
3542  for (int k = 0; k < (int) supportedSampleRates.size(); k++) {
3543  s << wxT(" ") << (int)supportedSampleRates[k] << e;
3544  }
3545  }else{
3546  s << wxT("Cannot check mutual sample rates without both devices.") << e;
3547  return o.GetString();
3548  }
3549 
3550 #if defined(USE_PORTMIXER)
3551  if (supportedSampleRates.size() > 0)
3552  {
3553  int highestSampleRate = supportedSampleRates.back();
3554  bool EmulateMixerInputVol = true;
3555  bool EmulateMixerOutputVol = true;
3556  float MixerInputVol = 1.0;
3557  float MixerOutputVol = 1.0;
3558 
3559  int error;
3560 
3561  PaStream *stream;
3562 
3563  PaStreamParameters playbackParameters;
3564 
3565  playbackParameters.device = playDeviceNum;
3566  playbackParameters.sampleFormat = paFloat32;
3567  playbackParameters.hostApiSpecificStreamInfo = NULL;
3568  playbackParameters.channelCount = 1;
3569  if (Pa_GetDeviceInfo(playDeviceNum)){
3570  playbackParameters.suggestedLatency =
3571  Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
3572  }
3573  else{
3574  playbackParameters.suggestedLatency = DEFAULT_LATENCY_CORRECTION/1000.0;
3575  }
3576 
3577  PaStreamParameters captureParameters;
3578 
3579  captureParameters.device = recDeviceNum;
3580  captureParameters.sampleFormat = paFloat32;;
3581  captureParameters.hostApiSpecificStreamInfo = NULL;
3582  captureParameters.channelCount = 1;
3583  if (Pa_GetDeviceInfo(recDeviceNum)){
3584  captureParameters.suggestedLatency =
3585  Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
3586  }else{
3587  captureParameters.suggestedLatency = DEFAULT_LATENCY_CORRECTION/1000.0;
3588  }
3589 
3590  error = Pa_OpenStream(&stream,
3591  &captureParameters, &playbackParameters,
3592  highestSampleRate, paFramesPerBufferUnspecified,
3593  paClipOff | paDitherOff,
3594  audacityAudioCallback, NULL);
3595 
3596  if (error) {
3597  error = Pa_OpenStream(&stream,
3598  &captureParameters, NULL,
3599  highestSampleRate, paFramesPerBufferUnspecified,
3600  paClipOff | paDitherOff,
3601  audacityAudioCallback, NULL);
3602  }
3603 
3604  if (error) {
3605  s << wxT("Received ") << error << wxT(" while opening devices") << e;
3606  return o.GetString();
3607  }
3608 
3609  PxMixer *PortMixer = Px_OpenMixer(stream, 0);
3610 
3611  if (!PortMixer) {
3612  s << wxT("Unable to open Portmixer") << e;
3613  Pa_CloseStream(stream);
3614  return o.GetString();
3615  }
3616 
3617  s << wxT("==============================") << e;
3618  s << wxT("Available mixers:") << e;
3619 
3620  // FIXME: ? PortMixer errors on query not reported in GetDeviceInfo
3621  cnt = Px_GetNumMixers(stream);
3622  for (int i = 0; i < cnt; i++) {
3623  wxString name = wxSafeConvertMB2WX(Px_GetMixerName(stream, i));
3624  s << i << wxT(" - ") << name << e;
3625  }
3626 
3627  s << wxT("==============================") << e;
3628  s << wxT("Available recording sources:") << e;
3629  cnt = Px_GetNumInputSources(PortMixer);
3630  for (int i = 0; i < cnt; i++) {
3631  wxString name = wxSafeConvertMB2WX(Px_GetInputSourceName(PortMixer, i));
3632  s << i << wxT(" - ") << name << e;
3633  }
3634 
3635  s << wxT("==============================") << e;
3636  s << wxT("Available playback volumes:") << e;
3637  cnt = Px_GetNumOutputVolumes(PortMixer);
3638  for (int i = 0; i < cnt; i++) {
3639  wxString name = wxSafeConvertMB2WX(Px_GetOutputVolumeName(PortMixer, i));
3640  s << i << wxT(" - ") << name << e;
3641  }
3642 
3643  // Determine mixer capabilities - it it doesn't support either
3644  // input or output, we emulate them (by multiplying this value
3645  // by all incoming/outgoing samples)
3646 
3647  MixerOutputVol = Px_GetPCMOutputVolume(PortMixer);
3648  EmulateMixerOutputVol = false;
3649  Px_SetPCMOutputVolume(PortMixer, 0.0);
3650  if (Px_GetPCMOutputVolume(PortMixer) > 0.1)
3651  EmulateMixerOutputVol = true;
3652  Px_SetPCMOutputVolume(PortMixer, 0.2f);
3653  if (Px_GetPCMOutputVolume(PortMixer) < 0.1 ||
3654  Px_GetPCMOutputVolume(PortMixer) > 0.3)
3655  EmulateMixerOutputVol = true;
3656  Px_SetPCMOutputVolume(PortMixer, MixerOutputVol);
3657 
3658  MixerInputVol = Px_GetInputVolume(PortMixer);
3659  EmulateMixerInputVol = false;
3660  Px_SetInputVolume(PortMixer, 0.0);
3661  if (Px_GetInputVolume(PortMixer) > 0.1)
3662  EmulateMixerInputVol = true;
3663  Px_SetInputVolume(PortMixer, 0.2f);
3664  if (Px_GetInputVolume(PortMixer) < 0.1 ||
3665  Px_GetInputVolume(PortMixer) > 0.3)
3666  EmulateMixerInputVol = true;
3667  Px_SetInputVolume(PortMixer, MixerInputVol);
3668 
3669  Pa_CloseStream(stream);
3670 
3671  s << wxT("==============================") << e;
3672  s << wxT("Recording volume is ") << (EmulateMixerInputVol? wxT("emulated"): wxT("native")) << e;
3673  s << wxT("Playback volume is ") << (EmulateMixerOutputVol? wxT("emulated"): wxT("native")) << e;
3674 
3675  Px_CloseMixer(PortMixer);
3676 
3677  } //end of massive if statement if a valid sample rate has been found
3678 #endif
3679  return o.GetString();
3680 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2890
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: AudioIO.cpp:3097
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1154
wxString HostName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1161
#define DEFAULT_LATENCY_CORRECTION
Definition: AudioIO.h:86
const wxChar * name
Definition: Distortion.cpp:94
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
Definition: AudioIO.cpp:2969
friend int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
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 1398 of file AudioIO.cpp.

1399 {
1400 #if defined(USE_PORTMIXER)
1401 
1402  wxArrayString deviceNames;
1403 
1404  if( mPortMixer )
1405  {
1406  int numSources = Px_GetNumInputSources(mPortMixer);
1407  for( int source = 0; source < numSources; source++ )
1408  deviceNames.Add(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
1409  }
1410  else
1411  {
1412  wxLogDebug(wxT("AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
1413  }
1414 
1415  return deviceNames;
1416 
1417 #else
1418 
1419  wxArrayString blank;
1420 
1421  return blank;
1422 
1423 #endif
1424 }
wxLongLong AudioIO::GetLastPlaybackTime ( ) const
inline

Definition at line 246 of file AudioIO.h.

Referenced by AudacityProject::SeekWhenAudioActive().

246 { return mLastPlaybackTimeMillis; }
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:716
double AudioIO::GetLastTimeInScrubQueue ( ) const

return the ending time of the last enqueued scrub interval.

Definition at line 2872 of file AudioIO.cpp.

References mScrubQueue.

Referenced by Scrubber::ContinueScrubbingPoll().

2873 {
2874  if (mScrubQueue)
2875  return mScrubQueue->LastTimeInQueue();
2876  else
2877  return -1.0;
2878 }
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
AudioIOListener* AudioIO::GetListener ( )
inline

Definition at line 178 of file AudioIO.h.

Referenced by AudacityProject::OnCloseWindow().

178 { return mListener; }
AudioIOListener * mListener
Definition: AudioIO.h:760
void AudioIO::GetMixer ( int *  inputSource,
float *  inputVolume,
float *  playbackVolume 
)

Definition at line 1357 of file AudioIO.cpp.

References mEmulateMixerOutputVol, mInputMixerWorks, and mMixerOutputVol.

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

1359 {
1360 #if defined(USE_PORTMIXER)
1361 
1362  PxMixer *mixer = mPortMixer;
1363 
1364  if( mixer )
1365  {
1366  *recordDevice = Px_GetCurrentInputSource(mixer);
1367 
1368  if (mInputMixerWorks)
1369  *recordVolume = Px_GetInputVolume(mixer);
1370  else
1371  *recordVolume = 1.0f;
1372 
1374  *playbackVolume = mMixerOutputVol;
1375  else
1376  *playbackVolume = Px_GetPCMOutputVolume(mixer);
1377 
1378  return;
1379  }
1380 
1381 #endif
1382 
1383  *recordDevice = 0;
1384  *recordVolume = 1.0f;
1385  *playbackVolume = mMixerOutputVol;
1386 }
float mMixerOutputVol
Definition: AudioIO.h:746
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:745
bool mEmulateMixerOutputVol
Definition: AudioIO.h:737
unsigned AudioIO::GetNumCaptureChannels ( ) const
inline
unsigned AudioIO::GetNumPlaybackChannels ( ) const
inline

Definition at line 398 of file AudioIO.h.

Referenced by ControlToolBar::StartScrolling().

398 { return mNumPlaybackChannels; }
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:709
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.

Definition at line 3141 of file AudioIO.cpp.

References GetSupportedSampleRates(), and make_iterator_range().

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

3142 {
3143  auto rates = GetSupportedSampleRates();
3144 
3145  if (make_iterator_range(rates).contains(44100))
3146  return 44100;
3147 
3148  if (make_iterator_range(rates).contains(48000))
3149  return 48000;
3150 
3151  // if there are no supported rates, the next bit crashes. So check first,
3152  // and give them a "sensible" value if there are no valid values. They
3153  // will still get an error later, but with any luck may have changed
3154  // something by then. It's no worse than having an invalid default rate
3155  // stored in the preferences, which we don't check for
3156  if (rates.empty()) return 44100;
3157 
3158  return rates.back();
3159 }
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: AudioIO.cpp:3097
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:677
AudacityProject* AudioIO::GetOwningProject ( ) const
inline

Definition at line 247 of file AudioIO.h.

Referenced by ControlToolBar::CanStopAudioStream().

247 { return mOwningProject; }
AudacityProject * mOwningProject
Definition: AudioIO.h:726
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.

Definition at line 3328 of file AudioIO.cpp.

References DeviceName(), and gPrefs.

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

3329 {
3330  wxString devName(devNameArg);
3331  // if we don't get given a device, look up the preferences
3332  if (devName.IsEmpty())
3333  {
3334  devName = gPrefs->Read(wxT("/AudioIO/PlaybackDevice"), wxT(""));
3335  }
3336 
3337  wxString hostName = gPrefs->Read(wxT("/AudioIO/Host"), wxT(""));
3338  PaHostApiIndex hostCnt = Pa_GetHostApiCount();
3339  PaHostApiIndex hostNum;
3340  for (hostNum = 0; hostNum < hostCnt; hostNum++)
3341  {
3342  const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
3343  if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
3344  {
3345  for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
3346  {
3347  PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
3348 
3349  const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
3350  if (dinfo && DeviceName(dinfo) == devName && dinfo->maxOutputChannels > 0 )
3351  {
3352  // this device name matches the stored one, and works.
3353  // So we say this is the answer and return it
3354  return deviceNum;
3355  }
3356  }
3357 
3358  // The device wasn't found so use the default for this host.
3359  // LL: At this point, preferences and active no longer match.
3360  return hinfo->defaultOutputDevice;
3361  }
3362  }
3363 
3364  // The host wasn't found, so use the default output device.
3365  // FIXME: TRAP_ERR PaErrorCode not handled well (this code is similar to input code
3366  // and the input side has more comments.)
3367 
3368  PaDeviceIndex deviceNum = Pa_GetDefaultOutputDevice();
3369 
3370  // Sometimes PortAudio returns -1 if it cannot find a suitable default
3371  // device, so we just use the first one available
3372  //
3373  // LL: At this point, preferences and active no longer match
3374  //
3375  // And I can't imagine how far we'll get specifying an "invalid" index later
3376  // on...are we certain "0" even exists?
3377  if (deviceNum < 0) {
3378  wxASSERT(false);
3379  deviceNum = 0;
3380  }
3381 
3382  return deviceNum;
3383 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1154
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.

Definition at line 3385 of file AudioIO.cpp.

References DeviceName(), and gPrefs.

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

3386 {
3387  wxString devName(devNameArg);
3388  // if we don't get given a device, look up the preferences
3389  if (devName.IsEmpty())
3390  {
3391  devName = gPrefs->Read(wxT("/AudioIO/RecordingDevice"), wxT(""));
3392  }
3393 
3394  wxString hostName = gPrefs->Read(wxT("/AudioIO/Host"), wxT(""));
3395  PaHostApiIndex hostCnt = Pa_GetHostApiCount();
3396  PaHostApiIndex hostNum;
3397  for (hostNum = 0; hostNum < hostCnt; hostNum++)
3398  {
3399  const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
3400  if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
3401  {
3402  for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
3403  {
3404  PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
3405 
3406  const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
3407  if (dinfo && DeviceName(dinfo) == devName && dinfo->maxInputChannels > 0 )
3408  {
3409  // this device name matches the stored one, and works.
3410  // So we say this is the answer and return it
3411  return deviceNum;
3412  }
3413  }
3414 
3415  // The device wasn't found so use the default for this host.
3416  // LL: At this point, preferences and active no longer match.
3417  return hinfo->defaultInputDevice;
3418  }
3419  }
3420 
3421  // The host wasn't found, so use the default input device.
3422  // FIXME: TRAP_ERR PaErrorCode not handled well in getRecordDevIndex()
3423  PaDeviceIndex deviceNum = Pa_GetDefaultInputDevice();
3424 
3425  // Sometimes PortAudio returns -1 if it cannot find a suitable default
3426  // device, so we just use the first one available
3427  // PortAudio has an error reporting function. We should log/report the error?
3428  //
3429  // LL: At this point, preferences and active no longer match
3430  //
3431  // And I can't imagine how far we'll get specifying an "invalid" index later
3432  // on...are we certain "0" even exists?
3433  if (deviceNum < 0) {
3434  // JKC: This ASSERT will happen if you run with no config file
3435  // This happens once. Config file will exist on the next run.
3436  // TODO: Look into this a bit more. Could be relevant to blank Device Toolbar.
3437  wxASSERT(false);
3438  deviceNum = 0;
3439  }
3440 
3441  return deviceNum;
3442 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1154
double AudioIO::GetStreamTime ( )

During playback, the (unwarped) 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 2960 of file AudioIO.cpp.

References BAD_STREAM_TIME, IsStreamActive(), mTime, and NormalizeStreamTime().

Referenced by AudacityProject::DoPlayStopSelect(), AudacityProject::OnAddLabelPlaying(), AudacityProject::OnBoundaryMove(), AudacityProject::OnCursorPositionStore(), EffectUIHost::OnFFwd(), EffectUIHost::OnPlay(), EffectUIHost::OnRewind(), AudacityProject::OnSelectCursorStoredCursor(), AudacityProject::OnSetLeftSelection(), AudacityProject::OnSetRightSelection(), AudacityProject::OnStopSelect(), LyricsWindow::OnTimer(), ViewInfo::OnTimer(), MixerBoard::OnTimer(), Effect::Preview(), AudacityProject::TP_DisplaySelection(), and AudacityProject::ZoomInByFactor().

2961 {
2962  if( !IsStreamActive() )
2963  return BAD_STREAM_TIME;
2964 
2965  return NormalizeStreamTime(mTime);
2966 }
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2890
double mTime
Current time position during playback, in seconds. Between mT0 and mT1.
Definition: AudioIO.h:684
double NormalizeStreamTime(double absoluteTime) const
Normalizes the given time, clamping it and handling gaps from cut preview.
Definition: AudioIO.cpp:2928
#define BAD_STREAM_TIME
Definition: AudioIO.h:80
std::vector< long > 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.

Definition at line 3031 of file AudioIO.cpp.

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

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

3032 {
3033  if (devIndex == -1)
3034  { // not given a device, look up in prefs / default
3035  devIndex = getRecordDevIndex();
3036  }
3037 
3038  // Check if we can use the cached rates
3039  if (mCachedCaptureIndex != -1 && devIndex == mCachedCaptureIndex
3040  && (rate == 0.0 || make_iterator_range(mCachedCaptureRates).contains(rate)))
3041  {
3042  return mCachedCaptureRates;
3043  }
3044 
3045  std::vector<long> supported;
3046  int irate = (int)rate;
3047  const PaDeviceInfo* devInfo = NULL;
3048  int i;
3049 
3050  devInfo = Pa_GetDeviceInfo(devIndex);
3051 
3052  if (!devInfo)
3053  {
3054  wxLogDebug(wxT("GetSupportedCaptureRates() Could not get device info!"));
3055  return supported;
3056  }
3057 
3058  double latencyDuration = DEFAULT_LATENCY_DURATION;
3059  long recordChannels = 1;
3060  gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration);
3061  gPrefs->Read(wxT("/AudioIO/RecordChannels"), &recordChannels);
3062 
3063  // LLL: Remove when a proper method of determining actual supported
3064  // DirectSound rate is devised.
3065  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
3066  bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
3067 
3068  PaStreamParameters pars;
3069 
3070  pars.device = devIndex;
3071  pars.channelCount = recordChannels;
3072  pars.sampleFormat = paFloat32;
3073  pars.suggestedLatency = latencyDuration / 1000.0;
3074  pars.hostApiSpecificStreamInfo = NULL;
3075 
3076  for (i = 0; i < NumRatesToTry; i++)
3077  {
3078  // LLL: Remove when a proper method of determining actual supported
3079  // DirectSound rate is devised.
3080  if (!(isDirectSound && RatesToTry[i] > 200000))
3081  if (Pa_IsFormatSupported(&pars, NULL, RatesToTry[i]) == 0)
3082  supported.push_back(RatesToTry[i]);
3083  }
3084 
3085  if (irate != 0 && !make_iterator_range(supported).contains(irate))
3086  {
3087  // LLL: Remove when a proper method of determining actual supported
3088  // DirectSound rate is devised.
3089  if (!(isDirectSound && RatesToTry[i] > 200000))
3090  if (Pa_IsFormatSupported(&pars, NULL, irate) == 0)
3091  supported.push_back(irate);
3092  }
3093 
3094  return supported;
3095 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
static std::vector< long > mCachedCaptureRates
Definition: AudioIO.h:777
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:677
static int mCachedCaptureIndex
Definition: AudioIO.h:776
static const int NumRatesToTry
How many sample rates to try.
Definition: AudioIO.h:538
#define DEFAULT_LATENCY_DURATION
Definition: AudioIO.h:85
static const int RatesToTry[]
Array of audio sample rates to try to use.
Definition: AudioIO.h:536
static int getRecordDevIndex(const wxString &devName=wxEmptyString)
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIO.cpp:3385
std::vector< long > 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.

Definition at line 2969 of file AudioIO.cpp.

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

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

2970 {
2971  if (devIndex == -1)
2972  { // weren't given a device index, get the prefs / default one
2973  devIndex = getPlayDevIndex();
2974  }
2975 
2976  // Check if we can use the cached rates
2977  if (mCachedPlaybackIndex != -1 && devIndex == mCachedPlaybackIndex
2978  && (rate == 0.0 || make_iterator_range(mCachedPlaybackRates).contains(rate)))
2979  {
2980  return mCachedPlaybackRates;
2981  }
2982 
2983  std::vector<long> supported;
2984  int irate = (int)rate;
2985  const PaDeviceInfo* devInfo = NULL;
2986  int i;
2987 
2988  devInfo = Pa_GetDeviceInfo(devIndex);
2989 
2990  if (!devInfo)
2991  {
2992  wxLogDebug(wxT("GetSupportedPlaybackRates() Could not get device info!"));
2993  return supported;
2994  }
2995 
2996  // LLL: Remove when a proper method of determining actual supported
2997  // DirectSound rate is devised.
2998  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
2999  bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
3000 
3001  PaStreamParameters pars;
3002 
3003  pars.device = devIndex;
3004  pars.channelCount = 1;
3005  pars.sampleFormat = paFloat32;
3006  pars.suggestedLatency = devInfo->defaultHighOutputLatency;
3007  pars.hostApiSpecificStreamInfo = NULL;
3008 
3009  // JKC: PortAudio Errors handled OK here. No need to report them
3010  for (i = 0; i < NumRatesToTry; i++)
3011  {
3012  // LLL: Remove when a proper method of determining actual supported
3013  // DirectSound rate is devised.
3014  if (!(isDirectSound && RatesToTry[i] > 200000))
3015  if (Pa_IsFormatSupported(NULL, &pars, RatesToTry[i]) == 0)
3016  supported.push_back(RatesToTry[i]);
3017  }
3018 
3019  if (irate != 0 && !make_iterator_range(supported).contains(irate))
3020  {
3021  // LLL: Remove when a proper method of determining actual supported
3022  // DirectSound rate is devised.
3023  if (!(isDirectSound && RatesToTry[i] > 200000))
3024  if (Pa_IsFormatSupported(NULL, &pars, irate) == 0)
3025  supported.push_back(irate);
3026  }
3027 
3028  return supported;
3029 }
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3328
static int mCachedPlaybackIndex
Definition: AudioIO.h:774
static std::vector< long > mCachedPlaybackRates
Definition: AudioIO.h:775
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:677
static const int NumRatesToTry
How many sample rates to try.
Definition: AudioIO.h:538
static const int RatesToTry[]
Array of audio sample rates to try to use.
Definition: AudioIO.h:536
std::vector< long > 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.

Definition at line 3097 of file AudioIO.cpp.

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

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

3098 {
3099  // Not given device indices, look up prefs
3100  if (playDevice == -1) {
3101  playDevice = getPlayDevIndex();
3102  }
3103  if (recDevice == -1) {
3104  recDevice = getRecordDevIndex();
3105  }
3106 
3107  // Check if we can use the cached rates
3108  if (mCachedPlaybackIndex != -1 && mCachedCaptureIndex != -1 &&
3109  playDevice == mCachedPlaybackIndex &&
3110  recDevice == mCachedCaptureIndex &&
3111  (rate == 0.0 || make_iterator_range(mCachedSampleRates).contains(rate)))
3112  {
3113  return mCachedSampleRates;
3114  }
3115 
3116  auto playback = GetSupportedPlaybackRates(playDevice, rate);
3117  auto capture = GetSupportedCaptureRates(recDevice, rate);
3118  int i;
3119 
3120  // Return only sample rates which are in both arrays
3121  std::vector<long> result;
3122 
3123  for (i = 0; i < (int)playback.size(); i++)
3124  if (make_iterator_range(capture).contains(playback[i]))
3125  result.push_back(playback[i]);
3126 
3127  // If this yields no results, use the default sample rates nevertheless
3128 /* if (result.IsEmpty())
3129  {
3130  for (i = 0; i < NumStandardRates; i++)
3131  result.Add(StandardRates[i]);
3132  }*/
3133 
3134  return result;
3135 }
static std::vector< long > mCachedSampleRates
Definition: AudioIO.h:778
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3328
static int mCachedPlaybackIndex
Definition: AudioIO.h:774
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:677
static int mCachedCaptureIndex
Definition: AudioIO.h:776
static std::vector< long > GetSupportedCaptureRates(int devIndex=-1, double rate=0.0)
Get a list of sample rates the input (recording) device supports.
Definition: AudioIO.cpp:3031
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
Definition: AudioIO.cpp:2969
static int getRecordDevIndex(const wxString &devName=wxEmptyString)
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIO.cpp:3385
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

Definition at line 1426 of file AudioIO.cpp.

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

1427 {
1428  // This should not happen, but it would screw things up if it did.
1429  // Vaughan, 2010-10-08: But it *did* happen, due to a bug, and nobody
1430  // caught it because this method just returned. Added wxASSERT().
1431  wxASSERT(!IsStreamActive());
1432  if (IsStreamActive())
1433  return;
1434 
1435  // get the selected record and playback devices
1436  const int playDeviceNum = getPlayDevIndex();
1437  const int recDeviceNum = getRecordDevIndex();
1438 
1439  // If no change needed, return
1440  if (mCachedPlaybackIndex == playDeviceNum &&
1441  mCachedCaptureIndex == recDeviceNum)
1442  return;
1443 
1444  // cache playback/capture rates
1447  mCachedSampleRates = GetSupportedSampleRates(playDeviceNum, recDeviceNum);
1448  mCachedPlaybackIndex = playDeviceNum;
1449  mCachedCaptureIndex = recDeviceNum;
1450  mCachedBestRateIn = 0.0;
1451 
1452 #if defined(USE_PORTMIXER)
1453 
1454  // if we have a PortMixer object, close it down
1455  if (mPortMixer) {
1456  #if __WXMAC__
1457  // on the Mac we must make sure that we restore the hardware playthrough
1458  // state of the sound device to what it was before, because there isn't
1459  // a UI for this (!)
1460  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1461  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1462  mPreviousHWPlaythrough = -1.0;
1463  #endif
1464  Px_CloseMixer(mPortMixer);
1465  mPortMixer = NULL;
1466  }
1467 
1468  // that might have given us no rates whatsoever, so we have to guess an
1469  // answer to do the next bit
1470  int numrates = mCachedSampleRates.size();
1471  int highestSampleRate;
1472  if (numrates > 0)
1473  {
1474  highestSampleRate = mCachedSampleRates[numrates - 1];
1475  }
1476  else
1477  { // we don't actually have any rates that work for Rec and Play. Guess one
1478  // to use for messing with the mixer, which doesn't actually do either
1479  highestSampleRate = 44100;
1480  // mCachedSampleRates is still empty, but it's not used again, so
1481  // can ignore
1482  }
1483  mInputMixerWorks = false;
1484  mEmulateMixerOutputVol = true;
1485  mMixerOutputVol = 1.0;
1486 
1487  int error;
1488  // This tries to open the device with the samplerate worked out above, which
1489  // will be the highest available for play and record on the device, or
1490  // 44.1kHz if the info cannot be fetched.
1491 
1492  PaStream *stream;
1493 
1494  PaStreamParameters playbackParameters;
1495 
1496  playbackParameters.device = playDeviceNum;
1497  playbackParameters.sampleFormat = paFloat32;
1498  playbackParameters.hostApiSpecificStreamInfo = NULL;
1499  playbackParameters.channelCount = 1;
1500  if (Pa_GetDeviceInfo(playDeviceNum))
1501  playbackParameters.suggestedLatency =
1502  Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
1503  else
1504  playbackParameters.suggestedLatency = DEFAULT_LATENCY_CORRECTION/1000.0;
1505 
1506  PaStreamParameters captureParameters;
1507 
1508  captureParameters.device = recDeviceNum;
1509  captureParameters.sampleFormat = paFloat32;;
1510  captureParameters.hostApiSpecificStreamInfo = NULL;
1511  captureParameters.channelCount = 1;
1512  if (Pa_GetDeviceInfo(recDeviceNum))
1513  captureParameters.suggestedLatency =
1514  Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
1515  else
1516  captureParameters.suggestedLatency = DEFAULT_LATENCY_CORRECTION/1000.0;
1517 
1518  // try opening for record and playback
1519  error = Pa_OpenStream(&stream,
1520  &captureParameters, &playbackParameters,
1521  highestSampleRate, paFramesPerBufferUnspecified,
1522  paClipOff | paDitherOff,
1523  audacityAudioCallback, NULL);
1524 
1525  if (!error) {
1526  // Try portmixer for this stream
1527  mPortMixer = Px_OpenMixer(stream, 0);
1528  if (!mPortMixer) {
1529  Pa_CloseStream(stream);
1530  error = true;
1531  }
1532  }
1533 
1534  // if that failed, try just for record
1535  if( error ) {
1536  error = Pa_OpenStream(&stream,
1537  &captureParameters, NULL,
1538  highestSampleRate, paFramesPerBufferUnspecified,
1539  paClipOff | paDitherOff,
1540  audacityAudioCallback, NULL);
1541 
1542  if (!error) {
1543  mPortMixer = Px_OpenMixer(stream, 0);
1544  if (!mPortMixer) {
1545  Pa_CloseStream(stream);
1546  error = true;
1547  }
1548  }
1549  }
1550 
1551  // finally, try just for playback
1552  if ( error ) {
1553  error = Pa_OpenStream(&stream,
1554  NULL, &playbackParameters,
1555  highestSampleRate, paFramesPerBufferUnspecified,
1556  paClipOff | paDitherOff,
1557  audacityAudioCallback, NULL);
1558 
1559  if (!error) {
1560  mPortMixer = Px_OpenMixer(stream, 0);
1561  if (!mPortMixer) {
1562  Pa_CloseStream(stream);
1563  error = true;
1564  }
1565  }
1566  }
1567 
1568  // FIXME: TRAP_ERR errors in HandleDeviceChange not reported.
1569  // if it's still not working, give up
1570  if( error )
1571  return;
1572 
1573  // Set input source
1574 #if USE_PORTMIXER
1575  int sourceIndex;
1576  if (gPrefs->Read(wxT("/AudioIO/RecordingSourceIndex"), &sourceIndex)) {
1577  if (sourceIndex >= 0) {
1578  //the current index of our source may be different because the stream
1579  //is a combination of two devices, so update it.
1580  sourceIndex = getRecordSourceIndex(mPortMixer);
1581  if (sourceIndex >= 0)
1582  SetMixer(sourceIndex);
1583  }
1584  }
1585 #endif
1586 
1587  // Determine mixer capabilities - if it doesn't support control of output
1588  // signal level, we emulate it (by multiplying this value by all outgoing
1589  // samples)
1590 
1591  mMixerOutputVol = Px_GetPCMOutputVolume(mPortMixer);
1592  mEmulateMixerOutputVol = false;
1593  Px_SetPCMOutputVolume(mPortMixer, 0.0);
1594  if (Px_GetPCMOutputVolume(mPortMixer) > 0.1)
1595  mEmulateMixerOutputVol = true;
1596  Px_SetPCMOutputVolume(mPortMixer, 0.2f);
1597  if (Px_GetPCMOutputVolume(mPortMixer) < 0.1 ||
1598  Px_GetPCMOutputVolume(mPortMixer) > 0.3)
1599  mEmulateMixerOutputVol = true;
1600  Px_SetPCMOutputVolume(mPortMixer, mMixerOutputVol);
1601 
1602  float inputVol = Px_GetInputVolume(mPortMixer);
1603  mInputMixerWorks = true; // assume it works unless proved wrong
1604  Px_SetInputVolume(mPortMixer, 0.0);
1605  if (Px_GetInputVolume(mPortMixer) > 0.1)
1606  mInputMixerWorks = false; // can't set to zero
1607  Px_SetInputVolume(mPortMixer, 0.2f);
1608  if (Px_GetInputVolume(mPortMixer) < 0.1 ||
1609  Px_GetInputVolume(mPortMixer) > 0.3)
1610  mInputMixerWorks = false; // can't set level accurately
1611  Px_SetInputVolume(mPortMixer, inputVol);
1612 
1613  Pa_CloseStream(stream);
1614 
1615 
1616  #if 0
1617  wxPrintf("PortMixer: Playback: %s Recording: %s\n",
1618  mEmulateMixerOutputVol? "emulated": "native",
1619  mInputMixerWorks? "hardware": "no control");
1620  #endif
1621 
1622  mMixerOutputVol = 1.0;
1623 
1624 #endif // USE_PORTMIXER
1625 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
static std::vector< long > mCachedSampleRates
Definition: AudioIO.h:778
static double mCachedBestRateIn
Definition: AudioIO.h:779
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2890
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: AudioIO.cpp:3097
float mMixerOutputVol
Definition: AudioIO.h:746
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:745
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3328
static int mCachedPlaybackIndex
Definition: AudioIO.h:774
#define DEFAULT_LATENCY_CORRECTION
Definition: AudioIO.h:86
static std::vector< long > mCachedPlaybackRates
Definition: AudioIO.h:775
bool mEmulateMixerOutputVol
Definition: AudioIO.h:737
static std::vector< long > mCachedCaptureRates
Definition: AudioIO.h:777
void SetMixer(int inputSource)
Definition: AudioIO.cpp:1325
static int mCachedCaptureIndex
Definition: AudioIO.h:776
static std::vector< long > GetSupportedCaptureRates(int devIndex=-1, double rate=0.0)
Get a list of sample rates the input (recording) device supports.
Definition: AudioIO.cpp:3031
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
Definition: AudioIO.cpp:2969
static int getRecordDevIndex(const wxString &devName=wxEmptyString)
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIO.cpp:3385
friend int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
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.

Definition at line 1388 of file AudioIO.cpp.

References mInputMixerWorks.

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

1389 {
1390  return mInputMixerWorks;
1391 }
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:745
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.

Definition at line 2909 of file AudioIO.cpp.

References mStreamToken.

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

2910 {
2911  return ( token > 0 && token == mStreamToken );
2912 }
volatile int mStreamToken
Definition: AudioIO.h:674
bool AudioIO::IsAvailable ( AudacityProject projecT)

Function to automatically set an acceptable volume.

Definition at line 2516 of file AudioIO.cpp.

References mOwningProject.

Referenced by EffectUIHost::Initialize().

2517 {
2518  return mOwningProject == NULL || mOwningProject == project;
2519 }
AudacityProject * mOwningProject
Definition: AudioIO.h:726
bool AudioIO::IsBusy ( )
bool AudioIO::IsCapturing ( ) const

Definition at line 5481 of file AudioIO.cpp.

References GetNumCaptureChannels(), AudioIO::RecordingSchedule::mPreRoll, mRecordingSchedule, mT0, and mTime.

Referenced by PlayIndicatorOverlayBase::Draw().

5482 {
5483  return GetNumCaptureChannels() > 0 &&
5485 }
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:399
double mTime
Current time position during playback, in seconds. Between mT0 and mT1.
Definition: AudioIO.h:684
struct AudioIO::RecordingSchedule mRecordingSchedule
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:680
bool AudioIO::IsMonitoring ( )

Returns true if we're monitoring input (but not recording or playing actual audio)

Definition at line 2914 of file AudioIO.cpp.

References mPortStreamV19, and mStreamToken.

Referenced by ControlToolBar::CanStopAudioStream(), DeviceToolBar::EnableDisableButtons(), DeviceToolBar::OnChoice(), AudacityProject::OnCloseWindow(), PrefsDialog::OnOK(), DeviceManager::Rescan(), MeterPanel::StartMonitoring(), and MeterPanel::StopMonitoring().

2915 {
2916  return ( mPortStreamV19 && mStreamToken==0 );
2917 }
volatile int mStreamToken
Definition: AudioIO.h:674
PaStream * mPortStreamV19
Definition: AudioIO.h:703
bool AudioIO::IsPaused ( )

Find out if playback / recording is currently paused.

Definition at line 2857 of file AudioIO.cpp.

References mPaused.

Referenced by audacityAudioCallback(), AudacityProject::GetUpdateFlags(), PlayIndicatorOverlay::OnTimer(), ControlToolBar::Pause(), and AudacityProject::ZoomInByFactor().

2858 {
2859  return mPaused;
2860 }
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:702
bool AudioIO::IsScrubbing ( )
inline

Definition at line 212 of file AudioIO.h.

Referenced by ControlToolBar::OnPause().

212 { return IsBusy() && mScrubQueue != 0; }
bool IsBusy()
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2882
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
bool AudioIO::IsStreamActive ( )

Returns true if the audio i/o is running at all, but not during cleanup.

Doesn't return true if the device has been closed but some disk i/o or cleanup is still going on. If you want to know if it's safe to start a NEW stream, use IsBusy()

Definition at line 2890 of file AudioIO.cpp.

References mPortStreamV19.

Referenced by ControlToolBar::CanStopAudioStream(), LabelTrack::DoCaptureKey(), AudacityProject::DoPlayStopSelect(), DeviceToolBar::EnableDisableButtons(), FillBuffers(), GetDeviceInfo(), GetStreamTime(), HandleDeviceChange(), EffectUIHost::Initialize(), AudacityProject::IsAudioActive(), IsStreamActive(), AudacityProject::MakeReadyToPlay(), AudacityProject::OnAddLabelPlaying(), AudacityProject::OnCloseWindow(), ControlToolBar::OnKeyEvent(), AudacityProject::OnPlayStop(), AudacityProject::OnSetLeftSelection(), AudacityProject::OnSetRightSelection(), AudacityProject::OnStopSelect(), TrackPanel::OnTimer(), Effect::Preview(), AudacityProject::PushState(), and AudacityProject::ZoomInByFactor().

2891 {
2892  bool isActive = false;
2893  // JKC: Not reporting any Pa error, but that looks OK.
2894  if( mPortStreamV19 )
2895  isActive = (Pa_IsStreamActive( mPortStreamV19 ) > 0);
2896 
2897 #ifdef EXPERIMENTAL_MIDI_OUT
2898  if( mMidiStreamActive && !mMidiOutputComplete )
2899  isActive = true;
2900 #endif
2901  return isActive;
2902 }
PaStream * mPortStreamV19
Definition: AudioIO.h:703
bool AudioIO::IsStreamActive ( int  token)

Definition at line 2904 of file AudioIO.cpp.

References IsAudioTokenActive(), and IsStreamActive().

2905 {
2906  return (this->IsStreamActive() && this->IsAudioTokenActive(token));
2907 }
bool IsStreamActive()
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2890
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...
Definition: AudioIO.cpp:2909
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

Definition at line 2919 of file AudioIO.cpp.

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

Referenced by audacityAudioCallback(), and NormalizeStreamTime().

2920 {
2921  // Allows for forward or backward play
2922  if (ReversedTime())
2923  return std::max(mT1, std::min(mT0, absoluteTime));
2924  else
2925  return std::max(mT0, std::min(mT1, absoluteTime));
2926 }
bool ReversedTime() const
True if the end time is before the start time.
Definition: AudioIO.h:541
int min(int a, int b)
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:680
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:682
const std::vector< std::pair<double, double> >& AudioIO::LostCaptureIntervals ( )
inline

Definition at line 835 of file AudioIO.h.

Referenced by AudacityProject::OnAudioIOStopRecording().

836  { return mLostCaptureIntervals; }
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:830
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

Definition at line 2928 of file AudioIO.cpp.

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

Referenced by GetStreamTime().

2929 {
2930  // dmazzoni: This function is needed for two reasons:
2931  // One is for looped-play mode - this function makes sure that the
2932  // position indicator keeps wrapping around. The other reason is
2933  // more subtle - it's because PortAudio can query the hardware for
2934  // the current stream time, and this query is not always accurate.
2935  // Sometimes it's a little behind or ahead, and so this function
2936  // makes sure that at least we clip it to the selection.
2937  //
2938  // msmeyer: There is also the possibility that we are using "cut preview"
2939  // mode. In this case, we should jump over a defined "gap" in the
2940  // audio.
2941 
2942 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2943  // Limit the time between t0 and t1 if not scrubbing.
2944  // Should the limiting be necessary in any play mode if there are no bugs?
2945  if (mPlayMode != PLAY_SCRUB)
2946 #endif
2947  absoluteTime = LimitStreamTime(absoluteTime);
2948 
2949  if (mCutPreviewGapLen > 0)
2950  {
2951  // msmeyer: We're in cut preview mode, so if we are on the right
2952  // side of the gap, we jump over it.
2953  if (absoluteTime > mCutPreviewGapStart)
2954  absoluteTime += mCutPreviewGapLen;
2955  }
2956 
2957  return absoluteTime;
2958 }
double LimitStreamTime(double absoluteTime) const
Clamps the given time to be between mT0 and mT1.
Definition: AudioIO.cpp:2919
enum AudioIO::@3 mPlayMode
double mCutPreviewGapLen
Definition: AudioIO.h:756
double mCutPreviewGapStart
Definition: AudioIO.h:755
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.

Definition at line 1393 of file AudioIO.cpp.

References mEmulateMixerOutputVol.

Referenced by MixerToolBar::SetToolTips().

1394 {
1395  return mEmulateMixerOutputVol;
1396 }
bool mEmulateMixerOutputVol
Definition: AudioIO.h:737
bool AudioIO::ReversedTime ( ) const
inlineprivate

True if the end time is before the start time.

Definition at line 541 of file AudioIO.h.

Referenced by audacityAudioCallback(), and LimitStreamTime().

542  {
543  return mT1 < mT0;
544  }
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:680
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:682
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 209 of file AudioIO.h.

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

209 { mSeek = seconds; }
double mSeek
Definition: AudioIO.h:696
void AudioIO::SetCaptureMeter ( AudacityProject project,
MeterPanel meter 
)

Definition at line 2521 of file AudioIO.cpp.

References mInputMeter, mOwningProject, and mRate.

Referenced by AudacityProject::SetCaptureMeter(), and StartPortAudioStream().

2522 {
2523  if (!mOwningProject || mOwningProject == project)
2524  {
2525  if (meter)
2526  {
2527  mInputMeter = meter;
2528  mInputMeter->Reset(mRate, true);
2529  }
2530  else
2531  mInputMeter.Release();
2532  }
2533 }
AudacityProject * mOwningProject
Definition: AudioIO.h:726
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:727
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
void AudioIO::SetListener ( AudioIOListener listener)

Definition at line 4167 of file AudioIO.cpp.

References IsBusy(), and mListener.

Referenced by CreateNewAudacityProject(), and AudacityProject::OnCloseWindow().

4168 {
4169  if (IsBusy())
4170  return;
4171 
4172  mListener = listener;
4173 }
bool IsBusy()
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2882
AudioIOListener * mListener
Definition: AudioIO.h:760
void AudioIO::SetMeters ( )
private

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

Definition at line 2547 of file AudioIO.cpp.

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

Referenced by StartPortAudioStream().

2548 {
2549  if (mInputMeter)
2550  mInputMeter->Reset(mRate, true);
2551  if (mOutputMeter)
2552  mOutputMeter->Reset(mRate, true);
2553 
2554  AudacityProject* pProj = GetActiveProject();
2555  MixerBoard* pMixerBoard = pProj->GetMixerBoard();
2556  if (pMixerBoard)
2557  pMixerBoard->ResetMeters(true);
2558 
2559  mUpdateMeters = true;
2560 }
MeterPanel * mOutputMeter
Definition: AudioIO.h:728
MixerBoard * GetMixerBoard()
Definition: Project.h:516
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:727
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
void Reset(double sampleRate, bool resetClipping)
This method is thread-safe! Feel free to call from a different thread (like from an audio I/O callbac...
Definition: Meter.cpp:826
bool mUpdateMeters
Definition: AudioIO.h:729
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
void ResetMeters(const bool bResetClipping)
void AudioIO::SetMixer ( int  inputSource)

Definition at line 1325 of file AudioIO.cpp.

Referenced by HandleDeviceChange(), MixerToolBar::SetMixer(), and SetMixer().

1326 {
1327 #if defined(USE_PORTMIXER)
1328  int oldRecordSource = Px_GetCurrentInputSource(mPortMixer);
1329  if ( inputSource != oldRecordSource )
1330  Px_SetCurrentInputSource(mPortMixer, inputSource);
1331 #endif
1332 }
void AudioIO::SetMixer ( int  inputSource,
float  inputVolume,
float  playbackVolume 
)

Definition at line 1333 of file AudioIO.cpp.

References mMixerOutputVol, and SetMixer().

1335 {
1336  mMixerOutputVol = playbackVolume;
1337 
1338 #if defined(USE_PORTMIXER)
1339  PxMixer *mixer = mPortMixer;
1340 
1341  if( mixer )
1342  {
1343  float oldRecordVolume = Px_GetInputVolume(mixer);
1344  float oldPlaybackVolume = Px_GetPCMOutputVolume(mixer);
1345 
1346  SetMixer(inputSource);
1347  if( oldRecordVolume != recordVolume )
1348  Px_SetInputVolume(mixer, recordVolume);
1349  if( oldPlaybackVolume != playbackVolume )
1350  Px_SetPCMOutputVolume(mixer, playbackVolume);
1351 
1352  return;
1353  }
1354 #endif
1355 }
float mMixerOutputVol
Definition: AudioIO.h:746
void SetMixer(int inputSource)
Definition: AudioIO.cpp:1325
void AudioIO::SetPaused ( bool  state)

Pause and un-pause playback and recording.

Definition at line 2840 of file AudioIO.cpp.

References EffectManager::Get(), mPaused, EffectManager::RealtimeResume(), and EffectManager::RealtimeSuspend().

Referenced by ControlToolBar::OnPause(), ControlToolBar::Pause(), and ControlToolBar::StopPlaying().

2841 {
2842  if (state != mPaused)
2843  {
2844  if (state)
2845  {
2847  }
2848  else
2849  {
2851  }
2852  }
2853 
2854  mPaused = state;
2855 }
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:702
static EffectManager & Get()
void RealtimeSuspend()
void AudioIO::SetPlaybackMeter ( AudacityProject project,
MeterPanel meter 
)

Definition at line 2535 of file AudioIO.cpp.

References mOutputMeter, mOwningProject, mRate, and MeterPanel::Reset().

Referenced by AudacityProject::SetPlaybackMeter().

2536 {
2537  if (!mOwningProject || mOwningProject == project)
2538  {
2539  mOutputMeter = meter;
2540  if (mOutputMeter)
2541  {
2542  mOutputMeter->Reset(mRate, true);
2543  }
2544  }
2545 }
MeterPanel * mOutputMeter
Definition: AudioIO.h:728
AudacityProject * mOwningProject
Definition: AudioIO.h:726
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
void Reset(double sampleRate, bool resetClipping)
This method is thread-safe! Feel free to call from a different thread (like from an audio I/O callbac...
Definition: Meter.cpp:826
void AudioIO::SetRecordingException ( )
inlineprivate

Definition at line 825 of file AudioIO.h.

Referenced by FillBuffers().

826  { wxAtomicInc( mRecordingException ); }
wxAtomicInt mRecordingException
Definition: AudioIO.h:824
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

Definition at line 1822 of file AudioIO.cpp.

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

Referenced by MeterPanel::StartMonitoring().

1823 {
1824  if ( mPortStreamV19 || mStreamToken )
1825  return;
1826 
1827  bool success;
1828  long captureChannels;
1829  auto captureFormat = QualityPrefs::SampleFormatChoice();
1830  gPrefs->Read(wxT("/AudioIO/RecordChannels"), &captureChannels, 2L);
1831  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
1832  int playbackChannels = 0;
1833 
1835  playbackChannels = 2;
1836 
1837  // FIXME: TRAP_ERR StartPortAudioStream (a PaError may be present)
1838  // but StartPortAudioStream function only returns true or false.
1839  mUsingAlsa = false;
1840  success = StartPortAudioStream(sampleRate, (unsigned int)playbackChannels,
1841  (unsigned int)captureChannels,
1842  captureFormat);
1843  // TODO: Check return value of success.
1844  (void)success;
1845 
1846  wxCommandEvent e(EVT_AUDIOIO_MONITOR);
1847  e.SetEventObject(mOwningProject);
1848  e.SetInt(true);
1849  wxTheApp->ProcessEvent(e);
1850 
1851  // FIXME: TRAP_ERR PaErrorCode 'noted' but not reported in StartMonitoring.
1852  // Now start the PortAudio stream!
1853  // TODO: ? Factor out and reuse error reporting code from end of
1854  // AudioIO::StartStream?
1855  mLastPaError = Pa_StartStream( mPortStreamV19 );
1856 
1857  // Update UI display only now, after all possibilities for error are past.
1858  if ((mLastPaError == paNoError) && mListener) {
1859  // advertise the chosen I/O sample rate to the UI
1860  mListener->OnAudioIORate((int)mRate);
1861  }
1862 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
bool mSoftwarePlaythrough
Definition: AudioIO.h:704
volatile int mStreamToken
Definition: AudioIO.h:674
PaStream * mPortStreamV19
Definition: AudioIO.h:703
AudacityProject * mOwningProject
Definition: AudioIO.h:726
AudioIOListener * mListener
Definition: AudioIO.h:760
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
bool mUsingAlsa
Definition: AudioIO.h:771
virtual void OnAudioIORate(int rate)=0
static sampleFormat SampleFormatChoice()
PaError mLastPaError
Definition: AudioIO.h:724
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. ...
Definition: AudioIO.cpp:1640
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.

Definition at line 1640 of file AudioIO.cpp.

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

Referenced by StartMonitoring(), and StartStream().

1644 {
1645 #ifdef EXPERIMENTAL_MIDI_OUT
1646  mNumFrames = 0;
1647  mNumPauseFrames = 0;
1648  // we want this initial value to be way high. It should be
1649  // sufficient to assume AudioTime is zero and therefore
1650  // mSystemMinusAudioTime is SystemTime(), but we'll add 1000s
1651  // for good measure. On the first callback, this should be
1652  // reduced to SystemTime() - mT0, and note that mT0 is always
1653  // positive.
1654  mSystemMinusAudioTimePlusLatency =
1655  mSystemMinusAudioTime = SystemTime(mUsingAlsa) + 1000;
1656  mAudioOutLatency = 0.0; // set when stream is opened
1657  mCallbackCount = 0;
1658  mAudioFramesPerBuffer = 0;
1659 #endif
1661 
1662  // PRL: Protection from crash reported by David Bailes, involving starting
1663  // and stopping with frequent changes of active window, hard to reproduce
1664  if (!mOwningProject)
1665  return false;
1666 
1667  mInputMeter.Release();
1668  mOutputMeter = NULL;
1669 
1670  mLastPaError = paNoError;
1671  // pick a rate to do the audio I/O at, from those available. The project
1672  // rate is suggested, but we may get something else if it isn't supported
1673  mRate = GetBestRate(numCaptureChannels > 0, numPlaybackChannels > 0, sampleRate);
1674 
1675  // July 2016 (Carsten and Uwe)
1676  // BUG 193: Tell PortAudio sound card will handle 24 bit (under DirectSound) using
1677  // userData.
1678  int captureFormat_saved = captureFormat;
1679  // Special case: Our 24-bit sample format is different from PortAudio's
1680  // 3-byte packed format. So just make PortAudio return float samples,
1681  // since we need float values anyway to apply the gain.
1682  // ANSWER-ME: So we *never* actually handle 24-bit?! This causes mCapture to
1683  // be set to floatSample below.
1684  // JKC: YES that's right. Internally Audacity uses float, and float has space for
1685  // 24 bits as well as exponent. Actual 24 bit would require packing and
1686  // unpacking unaligned bytes and would be inefficient.
1687  // ANSWER ME: is floatSample 64 bit on 64 bit machines?
1688  if (captureFormat == int24Sample)
1689  captureFormat = floatSample;
1690 
1691  mNumPlaybackChannels = numPlaybackChannels;
1692  mNumCaptureChannels = numCaptureChannels;
1693 
1694  bool usePlayback = false, useCapture = false;
1695  PaStreamParameters playbackParameters{};
1696  PaStreamParameters captureParameters{};
1697 
1698  double latencyDuration = DEFAULT_LATENCY_DURATION;
1699  gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration);
1700 
1701  if( numPlaybackChannels > 0)
1702  {
1703  usePlayback = true;
1704 
1705  // this sets the device index to whatever is "right" based on preferences,
1706  // then defaults
1707  playbackParameters.device = getPlayDevIndex();
1708 
1709  const PaDeviceInfo *playbackDeviceInfo;
1710  playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
1711 
1712  if( playbackDeviceInfo == NULL )
1713  return false;
1714 
1715  // regardless of source formats, we always mix to float
1716  playbackParameters.sampleFormat = paFloat32;
1717  playbackParameters.hostApiSpecificStreamInfo = NULL;
1718  playbackParameters.channelCount = mNumPlaybackChannels;
1719 
1721  playbackParameters.suggestedLatency =
1722  playbackDeviceInfo->defaultLowOutputLatency;
1723  else
1724  playbackParameters.suggestedLatency = latencyDuration/1000.0;
1725 
1727  }
1728 
1729  if( numCaptureChannels > 0)
1730  {
1731  useCapture = true;
1732  mCaptureFormat = captureFormat;
1733 
1734  const PaDeviceInfo *captureDeviceInfo;
1735  // retrieve the index of the device set in the prefs, or a sensible
1736  // default if it isn't set/valid
1737  captureParameters.device = getRecordDevIndex();
1738 
1739  captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
1740 
1741  if( captureDeviceInfo == NULL )
1742  return false;
1743 
1744  captureParameters.sampleFormat =
1746 
1747  captureParameters.hostApiSpecificStreamInfo = NULL;
1748  captureParameters.channelCount = mNumCaptureChannels;
1749 
1751  captureParameters.suggestedLatency =
1752  captureDeviceInfo->defaultHighInputLatency;
1753  else
1754  captureParameters.suggestedLatency = latencyDuration/1000.0;
1755 
1757  }
1758 
1759  SetMeters();
1760 
1761 #ifdef USE_PORTMIXER
1762 #ifdef __WXMSW__
1763  //mchinen nov 30 2010. For some reason Pa_OpenStream resets the input volume on windows.
1764  //so cache and restore after it.
1765  //The actual problem is likely in portaudio's pa_win_wmme.c OpenStream().
1766  float oldRecordVolume = Px_GetInputVolume(mPortMixer);
1767 #endif
1768 #endif
1769 
1770  // July 2016 (Carsten and Uwe)
1771  // BUG 193: Possibly tell portAudio to use 24 bit with DirectSound.
1772  int userData = 24;
1773  int* lpUserData = (captureFormat_saved == int24Sample) ? &userData : NULL;
1774 
1775  mLastPaError = Pa_OpenStream( &mPortStreamV19,
1776  useCapture ? &captureParameters : NULL,
1777  usePlayback ? &playbackParameters : NULL,
1778  mRate, paFramesPerBufferUnspecified,
1779  paNoFlag,
1780  audacityAudioCallback, lpUserData );
1781 
1782 
1783 #if USE_PORTMIXER
1784 #ifdef __WXMSW__
1785  Px_SetInputVolume(mPortMixer, oldRecordVolume);
1786 #endif
1787  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
1788 
1789  #ifdef __WXMAC__
1790  if (mPortMixer) {
1791  if (Px_SupportsPlaythrough(mPortMixer)) {
1792  bool playthrough = false;
1793 
1794  mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
1795 
1796  // Bug 388. Feature not supported.
1797  //gPrefs->Read(wxT("/AudioIO/Playthrough"), &playthrough, false);
1798  if (playthrough)
1799  Px_SetPlaythrough(mPortMixer, 1.0);
1800  else
1801  Px_SetPlaythrough(mPortMixer, 0.0);
1802  }
1803  }
1804  #endif
1805  }
1806 #endif
1807 
1808 #ifdef EXPERIMENTAL_MIDI_OUT
1809  // We use audio latency to estimate how far ahead of DACS we are writing
1810  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
1811  const PaStreamInfo* info = Pa_GetStreamInfo(mPortStreamV19);
1812  // this is an initial guess, but for PA/Linux/ALSA it's wrong and will be
1813  // updated with a better value:
1814  mAudioOutLatency = info->outputLatency;
1815  mSystemMinusAudioTimePlusLatency += mAudioOutLatency;
1816  }
1817 #endif
1818 
1819  return (mLastPaError == paNoError);
1820 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
void SetMeters()
Set the current VU meters - this should be done once after each call to StartStream currently...
Definition: AudioIO.cpp:2547
bool mSoftwarePlaythrough
Definition: AudioIO.h:704
MeterPanel * mOutputMeter
Definition: AudioIO.h:728
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3328
sampleFormat mCaptureFormat
Definition: AudioIO.h:710
MeterPanel * GetCaptureMeter()
Definition: Project.cpp:5104
PaStream * mPortStreamV19
Definition: AudioIO.h:703
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:3161
AudacityProject * mOwningProject
Definition: AudioIO.h:726
static PaSampleFormat AudacityToPortAudioSampleFormat(sampleFormat format)
Definition: AudioIO.cpp:1627
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:709
unsigned int mNumCaptureChannels
Definition: AudioIO.h:708
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:727
void SetCaptureMeter(AudacityProject *project, MeterPanel *meter)
Definition: AudioIO.cpp:2521
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
bool mUsingAlsa
Definition: AudioIO.h:771
MeterPanel * GetPlaybackMeter()
Definition: Project.cpp:5090
#define DEFAULT_LATENCY_DURATION
Definition: AudioIO.h:85
PaError mLastPaError
Definition: AudioIO.h:724
static int getRecordDevIndex(const wxString &devName=wxEmptyString)
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIO.cpp:3385
friend int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
int AudioIO::StartStream ( const TransportTracks tracks,
double  t0,
double  t1,
const AudioIOStartStreamOptions options 
)

Start recording or playing back audio.

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

Definition at line 1864 of file AudioIO.cpp.

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

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

1867 {
1868  mLostSamples = 0;
1869  mLostCaptureIntervals.clear();
1870  mDetectDropouts =
1871  gPrefs->Read( WarningDialogKey(wxT("DropoutDetected")), true ) != 0;
1872  auto cleanup = finally ( [this] { ClearRecordingException(); } );
1873 
1874  if( IsBusy() )
1875  return 0;
1876 
1877  const auto &sampleRate = options.rate;
1878 
1879  // We just want to set mStreamToken to -1 - this way avoids
1880  // an extremely rare but possible race condition, if two functions
1881  // somehow called StartStream at the same time...
1882  mStreamToken--;
1883  if (mStreamToken != -1)
1884  return 0;
1885 
1886  // TODO: we don't really need to close and reopen stream if the
1887  // format matches; however it's kind of tricky to keep it open...
1888  //
1889  // if (sampleRate == mRate &&
1890  // playbackChannels == mNumPlaybackChannels &&
1891  // captureChannels == mNumCaptureChannels &&
1892  // captureFormat == mCaptureFormat) {
1893 
1894  if (mPortStreamV19) {
1895  StopStream();
1896  while(mPortStreamV19)
1897  wxMilliSleep( 50 );
1898  }
1899 
1900 #ifdef __WXGTK__
1901  // Detect whether ALSA is the chosen host, and do the various involved MIDI
1902  // timing compensations only then.
1903  mUsingAlsa = (gPrefs->Read(wxT("/AudioIO/Host"), wxT("")) == "ALSA");
1904 #endif
1905 
1906  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
1907  gPrefs->Read(wxT("/AudioIO/SoundActivatedRecord"), &mPauseRec, false);
1908  int silenceLevelDB;
1909  gPrefs->Read(wxT("/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
1910  int dBRange;
1911  dBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
1912  if(silenceLevelDB < -dBRange)
1913  {
1914  silenceLevelDB = -dBRange + 3; // meter range was made smaller than SilenceLevel
1915  gPrefs->Write(ENV_DB_KEY, dBRange); // so set SilenceLevel reasonable
1916  gPrefs->Flush();
1917  }
1918  mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange; // meter goes -dBRange dB -> 0dB
1919 
1920  if ( !tracks.captureTracks.empty() ) {
1921  // It does not make sense to apply the time warp during overdub recording,
1922  // which defeats the purpose of making the recording synchronized with
1923  // the existing audio. (Unless we figured out the inverse warp of the
1924  // captured samples in real time.)
1925  // So just quietly ignore the time track.
1926  mTimeTrack = nullptr;
1927  }
1928  else {
1929  mTimeTrack = options.timeTrack;
1930  }
1931 
1932  // Clamp pre-roll so we don't play before time 0
1933  const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
1934  mT0 = t0 - preRoll;
1935  mT1 = t1;
1936  mRecordingSchedule = {};
1937  mRecordingSchedule.mPreRoll = preRoll;
1939  (gPrefs->ReadDouble(wxT("/AudioIO/LatencyCorrection"),
1941  / 1000.0;
1942  mRecordingSchedule.mDuration = t1 - t0;
1943  if (tracks.captureTracks.size() > 0)
1944  // adjust mT1 so that we don't give paComplete too soon to fill up the
1945  // desired length of recording
1947  if (options.pCrossfadeData)
1949 
1950  mListener = options.listener;
1951  mRate = sampleRate;
1952  mTime = mT0;
1953  mSeek = 0;
1955  mCaptureTracks = tracks.captureTracks;
1957 #ifdef EXPERIMENTAL_MIDI_OUT
1958  mMidiPlaybackTracks = tracks.midiTracks;
1959 #endif
1960 
1961  bool commit = false;
1962  auto cleanupTracks = finally([&]{
1963  if (!commit) {
1964  // Don't keep unnecessary shared pointers to tracks
1965  mPlaybackTracks.clear();
1966  mCaptureTracks.clear();
1967 #ifdef EXPERIMENTAL_MIDI_OUT
1968  mMidiPlaybackTracks.clear();
1969 #endif
1970  }
1971  });
1972 
1976 
1977  mPlaybackBuffers.reset();
1978  mPlaybackMixers.reset();
1979  mCaptureBuffers.reset();
1980  mResample.reset();
1981 
1982  double playbackTime = 4.0;
1983 
1984 #ifdef EXPERIMENTAL_MIDI_OUT
1985  streamStartTime = 0;
1986  streamStartTime = SystemTime(mUsingAlsa);
1987 #endif
1988 
1989 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1990  bool scrubbing = (options.pScrubbingOptions != nullptr);
1991 
1992  // Scrubbing is not compatible with looping or recording or a time track!
1993  if (scrubbing)
1994  {
1995  const auto &scrubOptions = *options.pScrubbingOptions;
1996 
1997  if (mCaptureTracks.size() > 0 ||
1998  mPlayMode == PLAY_LOOPED ||
1999  mTimeTrack != NULL ||
2000  scrubOptions.maxSpeed < ScrubbingOptions::MinAllowedScrubSpeed()) {
2001  wxASSERT(false);
2002  scrubbing = false;
2003  }
2004  else {
2005  playbackTime = lrint(scrubOptions.delay * sampleRate) / sampleRate;
2007  }
2008  }
2009 #endif
2010 
2011  // mWarpedTime and mWarpedLength are irrelevant when scrubbing,
2012  // else they are used in updating mTime,
2013  // and when not scrubbing or playing looped, mTime is also used
2014  // in the test for termination of playback.
2015 
2016  // with ComputeWarpedLength, it is now possible the calculate the warped length with 100% accuracy
2017  // (ignoring accumulated rounding errors during playback) which fixes the 'missing sound at the end' bug
2018  mWarpedTime = 0.0;
2019 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2020  if (scrubbing)
2021  mWarpedLength = 0.0;
2022  else
2023 #endif
2024  {
2025  if (mTimeTrack)
2026  // Following gives negative when mT0 > mT1
2028  else
2029  mWarpedLength = mT1 - mT0;
2030  // PRL allow backwards play
2031  mWarpedLength = fabs(mWarpedLength);
2032  }
2033 
2034  //
2035  // The RingBuffer sizes, and the max amount of the buffer to
2036  // fill at a time, both grow linearly with the number of
2037  // tracks. This allows us to scale up to many tracks without
2038  // killing performance.
2039  //
2040 
2041  // (warped) playback time to produce with each filling of the buffers
2042  // by the Audio thread (except at the end of playback):
2043  // usually, make fillings fewer and longer for less CPU usage.
2044  // But for useful scrubbing, we can't run too far ahead without checking
2045  // mouse input, so make fillings more and shorter.
2046  // What Audio thread produces for playback is then consumed by the PortAudio
2047  // thread, in many smaller pieces.
2048  wxASSERT( playbackTime >= 0 );
2049  mPlaybackSamplesToCopy = playbackTime * mRate;
2050 
2051  // Capacity of the playback buffer.
2052  mPlaybackRingBufferSecs = 10.0;
2053 
2054  mCaptureRingBufferSecs = 4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.size());
2055  mMinCaptureSecsToCopy = 0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.size());
2056 
2057  unsigned int playbackChannels = 0;
2058  unsigned int captureChannels = 0;
2059  sampleFormat captureFormat = floatSample;
2060 
2061  if (tracks.playbackTracks.size() > 0
2062 #ifdef EXPERIMENTAL_MIDI_OUT
2063  || tracks.midiTracks.size() > 0
2064 #endif
2065  )
2066  playbackChannels = 2;
2067 
2069  playbackChannels = 2;
2070 
2071  if (tracks.captureTracks.size() > 0)
2072  {
2073  // For capture, every input channel gets its own track
2074  captureChannels = mCaptureTracks.size();
2075  // I don't deal with the possibility of the capture tracks
2076  // having different sample formats, since it will never happen
2077  // with the current code. This code wouldn't *break* if this
2078  // assumption was false, but it would be sub-optimal. For example,
2079  // if the first track was 16-bit and the second track was 24-bit,
2080  // we would set the sound card to capture in 16 bits and the second
2081  // track wouldn't get the benefit of all 24 bits the card is capable
2082  // of.
2083  captureFormat = mCaptureTracks[0]->GetSampleFormat();
2084 
2085  // Tell project that we are about to start recording
2086  if (mListener)
2088  }
2089 
2090  bool successAudio;
2091 
2092  successAudio = StartPortAudioStream(sampleRate, playbackChannels,
2093  captureChannels, captureFormat);
2094 #ifdef EXPERIMENTAL_MIDI_OUT
2095 
2096  // TODO: it may be that midi out will not work unless audio in or out is
2097  // active -- this would be a bug and may require a change in the
2098  // logic here.
2099 
2100  bool successMidi = true;
2101 
2102  if(!mMidiPlaybackTracks.empty()){
2103  successMidi = StartPortMidiStream();
2104  }
2105 
2106  // On the other hand, if MIDI cannot be opened, we will not complain
2107 #endif
2108 
2109  if (!successAudio) {
2110  if (mListener && captureChannels > 0)
2112  mStreamToken = 0;
2113 
2114  // Don't cause a busy wait in the audio thread after stopping scrubbing
2116 
2117  return 0;
2118  }
2119 
2120  //
2121  // The (audio) stream has been opened successfully (assuming we tried
2122  // to open it). We now proceed to
2123  // allocate the memory structures the stream will need.
2124  //
2125 
2126  bool bDone;
2127  do
2128  {
2129  bDone = true; // assume success
2130  try
2131  {
2132  if( mNumPlaybackChannels > 0 ) {
2133  // Allocate output buffers. For every output track we allocate
2134  // a ring buffer of five seconds
2135  auto playbackBufferSize =
2136  (size_t)lrint(mRate * mPlaybackRingBufferSecs);
2137  auto playbackMixBufferSize =
2139 
2142 
2143  const Mixer::WarpOptions &warpOptions =
2144 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2145  scrubbing
2149  :
2150 #endif
2151  Mixer::WarpOptions(mTimeTrack);
2152 
2153  for (unsigned int i = 0; i < mPlaybackTracks.size(); i++)
2154  {
2155  mPlaybackBuffers[i] = std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
2156 
2157  // MB: use normal time for the end time, not warped time!
2158  WaveTrackConstArray mixTracks;
2159  mixTracks.push_back(mPlaybackTracks[i]);
2160 
2161  double endTime;
2162  if (make_iterator_range(tracks.prerollTracks).contains(mPlaybackTracks[i]))
2163  // Stop playing this track after pre-roll
2164  endTime = t0;
2165  else
2166  // Pass t1 -- not mT1 as may have been adjusted for latency
2167  // -- so that overdub recording stops playing back samples
2168  // at the right time, though transport may continue to record
2169  endTime = t1;
2170 
2171  mPlaybackMixers[i] = std::make_unique<Mixer>
2172  (mixTracks,
2173  // Don't throw for read errors, just play silence:
2174  false,
2175  warpOptions,
2176  mT0,
2177  endTime,
2178  1,
2179  playbackMixBufferSize, false,
2180  mRate, floatSample, false);
2181  mPlaybackMixers[i]->ApplyTrackGains(false);
2182  }
2183  }
2184 
2185  if( mNumCaptureChannels > 0 )
2186  {
2187  // Allocate input buffers. For every input track we allocate
2188  // a ring buffer of five seconds
2189  auto captureBufferSize = (size_t)(mRate * mCaptureRingBufferSecs + 0.5);
2190 
2191  // In the extraordinarily rare case that we can't even afford 100 samples, just give up.
2192  if(captureBufferSize < 100)
2193  {
2195  AudacityMessageBox(_("Out of memory!"));
2196  return 0;
2197  }
2198 
2201  mFactor = sampleRate / mRate;
2202 
2203  for( unsigned int i = 0; i < mCaptureTracks.size(); i++ )
2204  {
2205  mCaptureBuffers[i] = std::make_unique<RingBuffer>
2206  ( mCaptureTracks[i]->GetSampleFormat(),
2207  captureBufferSize );
2208  mResample[i] = std::make_unique<Resample>(true, mFactor, mFactor); // constant rate resampling
2209  }
2210  }
2211  }
2212  catch(std::bad_alloc&)
2213  {
2214  // Oops! Ran out of memory. This is pretty rare, so we'll just
2215  // try deleting everything, halving our buffer size, and try again.
2216  StartStreamCleanup(true);
2217  mPlaybackRingBufferSecs *= 0.5;
2219  mCaptureRingBufferSecs *= 0.5;
2220  mMinCaptureSecsToCopy *= 0.5;
2221  bDone = false;
2222 
2223  // In the extraordinarily rare case that we can't even afford 100 samples, just give up.
2224  auto playbackBufferSize = (size_t)lrint(mRate * mPlaybackRingBufferSecs);
2225  auto playbackMixBufferSize = mPlaybackSamplesToCopy;
2226  if(playbackBufferSize < 100 || playbackMixBufferSize < 100)
2227  {
2229  AudacityMessageBox(_("Out of memory!"));
2230  return 0;
2231  }
2232  }
2233  } while(!bDone);
2234 
2235  if (mNumPlaybackChannels > 0)
2236  {
2238  // Setup for realtime playback at the rate of the realtime
2239  // stream, not the rate of the track.
2240  em.RealtimeInitialize(mRate);
2241 
2242  // The following adds a NEW effect processor for each logical track and the
2243  // group determination should mimic what is done in audacityAudioCallback()
2244  // when calling RealtimeProcess().
2245  int group = 0;
2246  for (size_t i = 0, cnt = mPlaybackTracks.size(); i < cnt; i++)
2247  {
2248  const WaveTrack *vt = gAudioIO->mPlaybackTracks[i].get();
2249 
2250  unsigned chanCnt = 1;
2251  if (vt->GetLinked())
2252  {
2253  i++;
2254  chanCnt++;
2255  }
2256 
2257  // Setup for realtime playback at the rate of the realtime
2258  // stream, not the rate of the track.
2259  em.RealtimeAddProcessor(group++, chanCnt, mRate);
2260  }
2261  }
2262 
2263 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2264  AILASetStartTime();
2265 #endif
2266 
2267  if (options.pStartTime)
2268  {
2269  // Calculate the NEW time position
2270  mTime = std::max(mT0, std::min(mT1, *options.pStartTime));
2271  // Reset mixer positions for all playback tracks
2272  unsigned numMixers = mPlaybackTracks.size();
2273  for (unsigned ii = 0; ii < numMixers; ++ii)
2274  mPlaybackMixers[ii]->Reposition(mTime);
2275  if(mTimeTrack)
2277  else
2278  mWarpedTime = mTime - mT0;
2279  }
2280 
2281 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2282  if (scrubbing)
2283  {
2284  const auto &scrubOptions = *options.pScrubbingOptions;
2285  mScrubQueue =
2286  std::make_unique<ScrubQueue>(mT0, mT1, scrubOptions.startClockTimeMillis,
2287  sampleRate, 2 * scrubOptions.minStutter,
2288  scrubOptions);
2289  mScrubDuration = 0;
2290  mSilentScrub = false;
2291  }
2292  else
2293  mScrubQueue.reset();
2294 #endif
2295 
2296  // We signal the audio thread to call FillBuffers, to prime the RingBuffers
2297  // so that they will have data in them when the stream starts. Having the
2298  // audio thread call FillBuffers here makes the code more predictable, since
2299  // FillBuffers will ALWAYS get called from the Audio thread.
2301 
2302  while( mAudioThreadShouldCallFillBuffersOnce == true ) {
2303  if (mScrubQueue)
2304  mScrubQueue->Nudge();
2305  wxMilliSleep( 50 );
2306  }
2307 
2308  if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) {
2309 
2310 #ifdef REALTIME_ALSA_THREAD
2311  // PRL: Do this in hope of less thread scheduling jitter in calls to
2312  // audacityAudioCallback.
2313  // Not needed to make audio playback work smoothly.
2314  // But needed in case we also play MIDI, so that the variable "offset"
2315  // in AudioIO::MidiTime() is a better approximation of the duration
2316  // between the call of audacityAudioCallback and the actual output of
2317  // the first audio sample.
2318  // (Which we should be able to determine from fields of
2319  // PaStreamCallbackTimeInfo, but that seems not to work as documented with
2320  // ALSA.)
2321  if (mUsingAlsa)
2322  // Perhaps we should do this only if also playing MIDI ?
2323  PaAlsa_EnableRealtimeScheduling( mPortStreamV19, 1 );
2324 #endif
2325 
2326  //
2327  // Generate a unique value each time, to be returned to
2328  // clients accessing the AudioIO API, so they can query if they
2329  // are the ones who have reserved AudioIO or not.
2330  //
2331  // It is important to set this before setting the portaudio stream in
2332  // motion -- otherwise it may play an unspecified number of leading
2333  // zeroes.
2335 
2336  // This affects the AudioThread (not the portaudio callback).
2337  // Probably not needed so urgently before portaudio thread start for usual
2338  // playback, since our ring buffers have been primed already with 4 sec
2339  // of audio, but then we might be scrubbing, so do it.
2341 
2342  // Now start the PortAudio stream!
2343  PaError err;
2344  err = Pa_StartStream( mPortStreamV19 );
2345 
2346  if( err != paNoError )
2347  {
2348  mStreamToken = 0;
2350  if (mListener && mNumCaptureChannels > 0)
2353  AudacityMessageBox(LAT1CTOWX(Pa_GetErrorText(err)));
2354  return 0;
2355  }
2356  }
2357 
2358  // Update UI display only now, after all possibilities for error are past.
2359  if (mListener) {
2360  // advertise the chosen I/O sample rate to the UI
2361  mListener->OnAudioIORate((int)mRate);
2362  }
2363 
2364  if (mNumPlaybackChannels > 0)
2365  {
2366  wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
2367  e.SetEventObject(mOwningProject);
2368  e.SetInt(true);
2369  wxTheApp->ProcessEvent(e);
2370  }
2371 
2372  if (mNumCaptureChannels > 0)
2373  {
2374  wxCommandEvent e(EVT_AUDIOIO_CAPTURE);
2375  e.SetEventObject(mOwningProject);
2376  e.SetInt(true);
2377  wxTheApp->ProcessEvent(e);
2378  }
2379 
2380  // Enable warning popups for unfound aliased blockfiles.
2382 
2383  commit = true;
2384  return mStreamToken;
2385 }
virtual void OnAudioIOStartRecording()=0
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
void StopStream()
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:2562
double ComputeWarpedLength(double t0, double t1) const
Compute the duration (in seconds at playback) of the specified region of the track.
Definition: TimeTrack.cpp:160
double mMinCaptureSecsToCopy
Definition: AudioIO.h:700
TimeTrack * timeTrack
Definition: AudioIO.h:137
#define ENV_DB_KEY
Definition: GUISettings.h:15
static int mNextStreamToken
Definition: AudioIO.h:675
void SetMissingAliasedFileWarningShouldShow(bool b)
Changes the behavior of missing aliased blockfiles warnings.
WaveTrackConstArray prerollTracks
Definition: AudioIO.h:165
enum AudioIO::@3 mPlayMode
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:117
bool mDetectDropouts
Definition: AudioIO.h:831
sampleCount mScrubDuration
Definition: AudioIO.h:819
void RealtimeAddProcessor(int group, unsigned chans, float rate)
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Warning.cpp:115
double mTime
Current time position during playback, in seconds. Between mT0 and mT1.
Definition: AudioIO.h:684
bool mSoftwarePlaythrough
Definition: AudioIO.h:704
bool GetLinked() const
Definition: Track.h:279
const TimeTrack * mTimeTrack
Definition: AudioIO.h:769
struct AudioIO::RecordingSchedule mRecordingSchedule
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
void StartStreamCleanup(bool bOnlyBuffers=false)
Clean up after StartStream if it fails.
Definition: AudioIO.cpp:2387
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:670
virtual void OnAudioIOStopRecording()=0
bool IsBusy()
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2882
ScrubbingOptions * pScrubbingOptions
Definition: AudioIO.h:150
float mSilenceLevel
Definition: AudioIO.h:707
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:667
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:673
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
double mWarpedTime
Definition: AudioIO.h:689
#define DEFAULT_LATENCY_CORRECTION
Definition: AudioIO.h:86
#define ENV_DB_RANGE
Definition: GUISettings.h:16
PRCrossfadeData * pCrossfadeData
Definition: AudioIO.h:154
static double MaxAllowedScrubSpeed()
Definition: Scrubbing.h:64
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:668
volatile int mStreamToken
Definition: AudioIO.h:674
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:669
PaStream * mPortStreamV19
Definition: AudioIO.h:703
void ClearRecordingException()
Definition: AudioIO.h:827
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:67
double mCaptureRingBufferSecs
Definition: AudioIO.h:698
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:677
sampleFormat
Definition: Types.h:188
#define lrint(dbl)
Definition: float_cast.h:136
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
void RealtimeInitialize(double rate)
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
AudacityProject * mOwningProject
Definition: AudioIO.h:726
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:45
int min(int a, int b)
AudioIOListener * mListener
Definition: AudioIO.h:760
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:712
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:709
WaveTrackConstArray playbackTracks
Definition: AudioIO.h:158
#define LAT1CTOWX(X)
Definition: Internat.h:180
double mSeek
Definition: AudioIO.h:696
unsigned int mNumCaptureChannels
Definition: AudioIO.h:708
static EffectManager & Get()
unsigned long long mLostSamples
Definition: AudioIO.h:711
PRCrossfadeData mCrossfadeData
Definition: AudioIO.h:850
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
AudioIO * gAudioIO
Definition: AudioIO.cpp:482
volatile double mLastRecordingOffset
Definition: AudioIO.h:723
bool mUsingAlsa
Definition: AudioIO.h:771
double mWarpedLength
Definition: AudioIO.h:694
double mCutPreviewGapLen
Definition: AudioIO.h:756
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:680
double mCutPreviewGapStart
Definition: AudioIO.h:755
virtual void OnAudioIORate(int rate)=0
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:830
AudioIOListener * listener
Definition: AudioIO.h:138
AudacityApp & wxGetApp()
Functions for doing the mixdown of the tracks.
Definition: Mix.h:80
double mFactor
Definition: AudioIO.h:676
size_t mPlaybackSamplesToCopy
Definition: AudioIO.h:699
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. ...
Definition: AudioIO.cpp:1640
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:682
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:713
WaveTrackArray captureTracks
Definition: AudioIO.h:159
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:706
bool mSilentScrub
Definition: AudioIO.h:818
WaveTrackConstArray mPlaybackTracks
Definition: AudioIO.h:671
static double MinAllowedScrubSpeed()
Definition: Scrubbing.h:66
double mPlaybackRingBufferSecs
Definition: AudioIO.h:697
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 2387 of file AudioIO.cpp.

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

Referenced by StartStream().

2388 {
2389  if (mNumPlaybackChannels > 0)
2390  {
2392  }
2393 
2394  mPlaybackBuffers.reset();
2395  mPlaybackMixers.reset();
2396  mCaptureBuffers.reset();
2397  mResample.reset();
2398 
2399  if(!bOnlyBuffers)
2400  {
2401  Pa_AbortStream( mPortStreamV19 );
2402  Pa_CloseStream( mPortStreamV19 );
2403  mPortStreamV19 = NULL;
2404  mStreamToken = 0;
2405  }
2406 
2407 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2408  mScrubQueue.reset();
2409 #endif
2410 
2411 
2412  // Don't cause a busy wait in the audio thread after stopping scrubbing
2414 }
enum AudioIO::@3 mPlayMode
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:670
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:667
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:673
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:668
volatile int mStreamToken
Definition: AudioIO.h:674
PaStream * mPortStreamV19
Definition: AudioIO.h:703
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:709
static EffectManager & Get()
void RealtimeFinalize()
void AudioIO::StopStream ( )

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

Definition at line 2562 of file AudioIO.cpp.

References ClearRecordingException(), ControlToolBar::CommitRecording(), WaveTrack::Flush(), EffectManager::Get(), GetActiveProject(), AudacityProject::GetControlToolBar(), AudacityProject::GetMixerBoard(), GuardedCall(), mAudioThreadFillBuffersLoopRunning, mAudioThreadShouldCallFillBuffersOnce, mCaptureBuffers, mCaptureTracks, mInputMeter, mListener, mLostCaptureIntervals, mNumCaptureChannels, mNumPlaybackChannels, mOutputMeter, mOwningProject, mPlaybackBuffers, mPlaybackMixers, mPlaybackTracks, mPlayMode, mPortStreamV19, mRate, mRecordingSchedule, mResample, mScrubQueue, mStreamToken, mSuspendAudioThread, mUpdateMeters, mUpdatingMeters, AudioIOListener::OnAudioIORate(), AudioIOListener::OnAudioIOStopRecording(), PLAY_STRAIGHT, EffectManager::RealtimeFinalize(), MeterPanel::Reset(), MixerBoard::ResetMeters(), and wxGetApp().

Referenced by FillBuffers(), DeviceToolBar::OnChoice(), AudacityProject::OnCloseWindow(), PrefsDialog::OnOK(), Effect::Preview(), DeviceManager::Rescan(), MeterPanel::StartMonitoring(), StartStream(), MeterPanel::StopMonitoring(), and ControlToolBar::StopPlaying().

2563 {
2564  auto cleanup = finally ( [this] {
2566  mRecordingSchedule = {}; // free arrays
2567  } );
2568 
2569  if( mPortStreamV19 == NULL
2570 #ifdef EXPERIMENTAL_MIDI_OUT
2571  && mMidiStream == NULL
2572 #endif
2573  )
2574  return;
2575 
2576  if( Pa_IsStreamStopped( mPortStreamV19 )
2577 #ifdef EXPERIMENTAL_MIDI_OUT
2578  && !mMidiStreamActive
2579 #endif
2580  )
2581  return;
2582 
2583  wxMutexLocker locker(mSuspendAudioThread);
2584 
2585  // No longer need effects processing
2586  if (mNumPlaybackChannels > 0)
2587  {
2589  }
2590 
2591  //
2592  // We got here in one of two ways:
2593  //
2594  // 1. The user clicked the stop button and we therefore want to stop
2595  // as quickly as possible. So we use AbortStream(). If this is
2596  // the case the portaudio stream is still in the Running state
2597  // (see PortAudio state machine docs).
2598  //
2599  // 2. The callback told PortAudio to stop the stream since it had
2600  // reached the end of the selection. The UI thread discovered
2601  // this by noticing that AudioIO::IsActive() returned false.
2602  // IsActive() (which calls Pa_GetStreamActive()) will not return
2603  // false until all buffers have finished playing, so we can call
2604  // AbortStream without losing any samples. If this is the case
2605  // we are in the "callback finished state" (see PortAudio state
2606  // machine docs).
2607  //
2608  // The moral of the story: We can call AbortStream safely, without
2609  // losing samples.
2610  //
2611  // DMM: This doesn't seem to be true; it seems to be necessary to
2612  // call StopStream if the callback brought us here, and AbortStream
2613  // if the user brought us here.
2614  //
2615 
2617  if (mScrubQueue)
2618  mScrubQueue->Nudge();
2619 
2620  // Audacity can deadlock if it tries to update meters while
2621  // we're stopping PortAudio (because the meter updating code
2622  // tries to grab a UI mutex while PortAudio tries to join a
2623  // pthread). So we tell the callback to stop updating meters,
2624  // and wait until the callback has left this part of the code
2625  // if it was already there.
2626  mUpdateMeters = false;
2627  while(mUpdatingMeters) {
2628  ::wxSafeYield();
2629  wxMilliSleep( 50 );
2630  }
2631 
2632  // Turn off HW playthrough if PortMixer is being used
2633 
2634  #if defined(USE_PORTMIXER)
2635  if( mPortMixer ) {
2636  #if __WXMAC__
2637  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
2638  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
2639  mPreviousHWPlaythrough = -1.0;
2640  #endif
2641  }
2642  #endif
2643 
2644  if (mPortStreamV19) {
2645  Pa_AbortStream( mPortStreamV19 );
2646  Pa_CloseStream( mPortStreamV19 );
2647  mPortStreamV19 = NULL;
2648  }
2649 
2650  if (mNumPlaybackChannels > 0)
2651  {
2652  wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
2653  e.SetEventObject(mOwningProject);
2654  e.SetInt(false);
2655  wxTheApp->ProcessEvent(e);
2656  }
2657 
2658  if (mNumCaptureChannels > 0)
2659  {
2660  wxCommandEvent e(mStreamToken == 0 ? EVT_AUDIOIO_MONITOR : EVT_AUDIOIO_CAPTURE);
2661  e.SetEventObject(mOwningProject);
2662  e.SetInt(false);
2663  wxTheApp->ProcessEvent(e);
2664  }
2665 
2666 #ifdef EXPERIMENTAL_MIDI_OUT
2667  /* Stop Midi playback */
2668  if ( mMidiStream ) {
2669 
2670  mMidiStreamActive = false;
2671 
2672 #ifdef USE_MIDI_THREAD
2673  mMidiThreadFillBuffersLoopRunning = false; // stop output to stream
2674  // but output is in another thread. Wait for output to stop...
2675  while (mMidiThreadFillBuffersLoopActive) {
2676  wxMilliSleep(1);
2677  }
2678 #endif
2679 
2680  mMidiOutputComplete = true;
2681 
2682  // now we can assume "ownership" of the mMidiStream
2683  // if output in progress, send all off, etc.
2684  AllNotesOff();
2685  // AllNotesOff() should be sufficient to stop everything, but
2686  // in Linux, if you Pm_Close() immediately, it looks like
2687  // messages are dropped. ALSA then seems to send All Sound Off
2688  // and Reset All Controllers messages, but not all synthesizers
2689  // respond to these messages. This is probably a bug in PortMidi
2690  // if the All Off messages do not get out, but for security,
2691  // delay a bit so that messages can be delivered before closing
2692  // the stream. Add 2ms of "padding" to avoid any rounding errors.
2693  while (mMaxMidiTimestamp + 2 > MidiTime()) {
2694  wxMilliSleep(1); // deliver the all-off messages
2695  }
2696  Pm_Close(mMidiStream);
2697  mMidiStream = NULL;
2698  mIterator->end();
2699 
2700  // set in_use flags to false
2701  int nTracks = mMidiPlaybackTracks.size();
2702  for (int i = 0; i < nTracks; i++) {
2703  const auto t = mMidiPlaybackTracks[i].get();
2704  Alg_seq_ptr seq = &t->GetSeq();
2705  seq->set_in_use(false);
2706  }
2707 
2708  mIterator.reset(); // just in case someone tries to reference it
2709  }
2710 #endif
2711 
2712  // If there's no token, we were just monitoring, so we can
2713  // skip this next part...
2714  if (mStreamToken > 0) {
2715  // In either of the above cases, we want to make sure that any
2716  // capture data that made it into the PortAudio callback makes it
2717  // to the target WaveTrack. To do this, we ask the audio thread to
2718  // call FillBuffers one last time (it normally would not do so since
2719  // Pa_GetStreamActive() would now return false
2721 
2722  while( mAudioThreadShouldCallFillBuffersOnce == true )
2723  {
2724  // LLL: Experienced recursive yield here...once.
2725  wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error.
2726  if (mScrubQueue)
2727  mScrubQueue->Nudge();
2728  wxMilliSleep( 50 );
2729  }
2730 
2731  //
2732  // Everything is taken care of. Now, just free all the resources
2733  // we allocated in StartStream()
2734  //
2735 
2736  if (mPlaybackTracks.size() > 0)
2737  {
2738  mPlaybackBuffers.reset();
2739  mPlaybackMixers.reset();
2740  }
2741 
2742  //
2743  // Offset all recorded tracks to account for latency
2744  //
2745  if (mCaptureTracks.size() > 0)
2746  {
2747  mCaptureBuffers.reset();
2748  mResample.reset();
2749 
2750  //
2751  // We only apply latency correction when we actually played back
2752  // tracks during the recording. If we did not play back tracks,
2753  // there's nothing we could be out of sync with. This also covers the
2754  // case that we do not apply latency correction when recording the
2755  // first track in a project.
2756  //
2757 
2758  for (unsigned int i = 0; i < mCaptureTracks.size(); i++) {
2759  // The calls to Flush
2760  // may cause exceptions because of exhaustion of disk space.
2761  // Stop those exceptions here, or else they propagate through too
2762  // many parts of Audacity that are not effects or editing
2763  // operations. GuardedCall ensures that the user sees a warning.
2764 
2765  // Also be sure to Flush each track, at the top of the guarded call,
2766  // relying on the guarantee that the track will be left in a flushed
2767  // state, though the append buffer may be lost.
2768 
2769  GuardedCall( [&] {
2770  WaveTrack* track = mCaptureTracks[i].get();
2771 
2772  // use NOFAIL-GUARANTEE that track is flushed,
2773  // PARTIAL-GUARANTEE that some initial length of the recording
2774  // is saved.
2775  // See comments in FillBuffers().
2776  track->Flush();
2777  } );
2778  }
2779 
2780  for (auto &interval : mLostCaptureIntervals) {
2781  auto &start = interval.first;
2782  auto duration = interval.second;
2783  for (auto &track : mCaptureTracks) {
2784  GuardedCall([&] {
2785  track->SyncLockAdjust(start, start + duration);
2786  });
2787  }
2788  }
2789 
2791  ControlToolBar *bar = p->GetControlToolBar();
2792  bar->CommitRecording();
2793  }
2794  }
2795 
2796  if (mInputMeter)
2797  mInputMeter->Reset(mRate, false);
2798 
2799  if (mOutputMeter)
2800  mOutputMeter->Reset(mRate, false);
2801 
2802  MixerBoard* pMixerBoard = mOwningProject->GetMixerBoard();
2803  if (pMixerBoard)
2804  pMixerBoard->ResetMeters(false);
2805 
2806  mInputMeter.Release();
2807  mOutputMeter = NULL;
2808  mOwningProject = NULL;
2809 
2810  if (mListener && mNumCaptureChannels > 0)
2812 
2813  //
2814  // Only set token to 0 after we're totally finished with everything
2815  //
2816  mStreamToken = 0;
2817 
2818  mNumCaptureChannels = 0;
2820 
2821  mPlaybackTracks.clear();
2822  mCaptureTracks.clear();
2823 #ifdef HAVE_MIDI
2824  mMidiPlaybackTracks.clear();
2825 #endif
2826 
2827 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2828  mScrubQueue.reset();
2829 #endif
2830 
2831  if (mListener) {
2832  // Tell UI to hide sample rate
2834  }
2835 
2836  // Don't cause a busy wait in the audio thread after stopping scrubbing
2838 }
A ToolBar that has the main Transport buttons.
enum AudioIO::@3 mPlayMode
volatile bool mUpdatingMeters
Definition: AudioIO.h:730
struct AudioIO::RecordingSchedule mRecordingSchedule
void SyncLockAdjust(double oldT1, double newT1) override
Definition: WaveTrack.cpp:1147
MeterPanel * mOutputMeter
Definition: AudioIO.h:728
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:670
virtual void OnAudioIOStopRecording()=0
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:667
MixerBoard * GetMixerBoard()
Definition: Project.h:516
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:673
std::unique_ptr< ScrubQueue > mScrubQueue
Definition: AudioIO.h:815
wxMutex mSuspendAudioThread
Definition: AudioIO.h:812
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:668
volatile int mStreamToken
Definition: AudioIO.h:674
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:669
PaStream * mPortStreamV19
Definition: AudioIO.h:703
void ClearRecordingException()
Definition: AudioIO.h:827
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
AudacityProject * mOwningProject
Definition: AudioIO.h:726
AudioIOListener * mListener
Definition: AudioIO.h:760
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:712
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:709
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
unsigned int mNumCaptureChannels
Definition: AudioIO.h:708
static EffectManager & Get()
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:727
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:678
void Reset(double sampleRate, bool resetClipping)
This method is thread-safe! Feel free to call from a different thread (like from an audio I/O callbac...
Definition: Meter.cpp:826
bool mUpdateMeters
Definition: AudioIO.h:729
ControlToolBar * GetControlToolBar()
Definition: Project.cpp:5003
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
virtual void OnAudioIORate(int rate)=0
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:830
AudacityApp & wxGetApp()
void RealtimeFinalize()
void ResetMeters(const bool bResetClipping)
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:713
WaveTrackConstArray mPlaybackTracks
Definition: AudioIO.h:671
void Flush()
Flush must be called after last Append.
Definition: WaveTrack.cpp:1650
bool AudioIO::ValidateDeviceNames ( const wxString &  play,
const wxString &  rec 
)
static

Ensure selected device names are valid.

Definition at line 1168 of file AudioIO.cpp.

References getPlayDevIndex(), and getRecordDevIndex().

1169 {
1170  const PaDeviceInfo *pInfo = Pa_GetDeviceInfo(AudioIO::getPlayDevIndex(play));
1171  const PaDeviceInfo *rInfo = Pa_GetDeviceInfo(AudioIO::getRecordDevIndex(rec));
1172 
1173  if (!pInfo || !rInfo || pInfo->hostApi != rInfo->hostApi) {
1174  return false;
1175  }
1176 
1177  return true;
1178 }
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3328
static int getRecordDevIndex(const wxString &devName=wxEmptyString)
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIO.cpp:3385

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

Definition at line 762 of file AudioIO.h.

void InitAudioIO ( )
friend

Definition at line 1116 of file AudioIO.cpp.

1117 {
1118  ugAudioIO.reset(safenew AudioIO());
1119  gAudioIO = ugAudioIO.get();
1120  gAudioIO->mThread->Run();
1121 #ifdef EXPERIMENTAL_MIDI_OUT
1122 #ifdef USE_MIDI_THREAD
1123  gAudioIO->mMidiThread->Run();
1124 #endif
1125 #endif
1126 
1127  // Make sure device prefs are initialized
1128  if (gPrefs->Read(wxT("AudioIO/RecordingDevice"), wxT("")) == wxT("")) {
1129  int i = AudioIO::getRecordDevIndex();
1130  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
1131  if (info) {
1132  gPrefs->Write(wxT("/AudioIO/RecordingDevice"), DeviceName(info));
1133  gPrefs->Write(wxT("/AudioIO/Host"), HostName(info));
1134  }
1135  }
1136 
1137  if (gPrefs->Read(wxT("AudioIO/PlaybackDevice"), wxT("")) == wxT("")) {
1138  int i = AudioIO::getPlayDevIndex();
1139  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
1140  if (info) {
1141  gPrefs->Write(wxT("/AudioIO/PlaybackDevice"), DeviceName(info));
1142  gPrefs->Write(wxT("/AudioIO/Host"), HostName(info));
1143  }
1144  }
1145 
1146  gPrefs->Flush();
1147 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
std::unique_ptr< AudioIO > ugAudioIO
Definition: AudioIO.cpp:481
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1154
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3328
wxString HostName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:1161
#define safenew
Definition: Audacity.h:230
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:661
AudioIO * gAudioIO
Definition: AudioIO.cpp:482
static int getRecordDevIndex(const wxString &devName=wxEmptyString)
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
Definition: AudioIO.cpp:3385

Member Data Documentation

volatile bool AudioIO::mAudioThreadFillBuffersLoopActive
private

Definition at line 714 of file AudioIO.h.

Referenced by audacityAudioCallback(), AudioIO(), and AudioThread::Entry().

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

Definition at line 779 of file AudioIO.h.

Referenced by GetBestRate(), and HandleDeviceChange().

double AudioIO::mCachedBestRateOut
staticprivate

Definition at line 780 of file AudioIO.h.

Referenced by GetBestRate().

int AudioIO::mCachedCaptureIndex = -1
staticprivate
std::vector< long > AudioIO::mCachedCaptureRates
staticprivate

Definition at line 777 of file AudioIO.h.

Referenced by GetSupportedCaptureRates(), and HandleDeviceChange().

int AudioIO::mCachedPlaybackIndex = -1
staticprivate
std::vector< long > AudioIO::mCachedPlaybackRates
staticprivate

Definition at line 775 of file AudioIO.h.

Referenced by GetSupportedPlaybackRates(), and HandleDeviceChange().

std::vector< long > AudioIO::mCachedSampleRates
staticprivate

Definition at line 778 of file AudioIO.h.

Referenced by GetSupportedSampleRates(), and HandleDeviceChange().

ArrayOf<std::unique_ptr<RingBuffer> > AudioIO::mCaptureBuffers
private
sampleFormat AudioIO::mCaptureFormat
private

Definition at line 710 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StartPortAudioStream().

double AudioIO::mCaptureRingBufferSecs
private

Definition at line 698 of file AudioIO.h.

Referenced by StartStream().

WaveTrackArray AudioIO::mCaptureTracks
private

Definition at line 669 of file AudioIO.h.

Referenced by FillBuffers(), GetCommonlyAvailCapture(), StartStream(), and StopStream().

PRCrossfadeData AudioIO::mCrossfadeData {}
private

Definition at line 566 of file AudioIO.h.

double AudioIO::mCutPreviewGapLen
private

Definition at line 756 of file AudioIO.h.

Referenced by NormalizeStreamTime(), and StartStream().

double AudioIO::mCutPreviewGapStart
private

Definition at line 755 of file AudioIO.h.

Referenced by NormalizeStreamTime(), and StartStream().

bool AudioIO::mDetectDropouts { true }
private

Definition at line 831 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StartStream().

bool AudioIO::mDetectUpstreamDropouts { true }
bool AudioIO::mEmulateMixerOutputVol
private
double AudioIO::mFactor
private

Definition at line 676 of file AudioIO.h.

Referenced by FillBuffers(), and StartStream().

wxWeakRef<MeterPanel> AudioIO::mInputMeter {}
private
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

Definition at line 745 of file AudioIO.h.

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

PaError AudioIO::mLastPaError
private

Definition at line 724 of file AudioIO.h.

Referenced by AudioIO(), StartMonitoring(), and StartPortAudioStream().

wxLongLong AudioIO::mLastPlaybackTimeMillis
private

Definition at line 716 of file AudioIO.h.

Referenced by audacityAudioCallback(), and AudioIO().

volatile double AudioIO::mLastRecordingOffset
private

Definition at line 723 of file AudioIO.h.

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

AudioIOListener* AudioIO::mListener
private

Definition at line 760 of file AudioIO.h.

Referenced by AudioIO(), FillBuffers(), SetListener(), StartMonitoring(), StartStream(), and StopStream().

std::vector< std::pair<double, double> > AudioIO::mLostCaptureIntervals
private

Definition at line 830 of file AudioIO.h.

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

unsigned long long AudioIO::mLostSamples { 0 }
private

Definition at line 711 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StartStream().

double AudioIO::mMinCaptureSecsToCopy
private

Definition at line 700 of file AudioIO.h.

Referenced by FillBuffers(), and StartStream().

float AudioIO::mMixerOutputVol
private

Definition at line 746 of file AudioIO.h.

Referenced by audacityAudioCallback(), AudioIO(), GetMixer(), HandleDeviceChange(), and SetMixer().

int AudioIO::mNextStreamToken = 0
staticprivate

Definition at line 675 of file AudioIO.h.

Referenced by StartStream().

unsigned int AudioIO::mNumCaptureChannels
private
unsigned int AudioIO::mNumPlaybackChannels
private
MeterPanel* AudioIO::mOutputMeter
private
AudacityProject* AudioIO::mOwningProject
private
bool AudioIO::mPaused
private

True if audio playback is paused.

Definition at line 702 of file AudioIO.h.

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

bool AudioIO::mPauseRec
private

True if Sound Activated Recording is enabled.

Definition at line 706 of file AudioIO.h.

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

Definition at line 697 of file AudioIO.h.

Referenced by StartStream().

size_t AudioIO::mPlaybackSamplesToCopy
private

Definition at line 699 of file AudioIO.h.

Referenced by FillBuffers(), and StartStream().

WaveTrackConstArray AudioIO::mPlaybackTracks
private
enum { ... } AudioIO::mPlayMode
PaStream* AudioIO::mPortStreamV19
private
double AudioIO::mRate
private

Audio playback rate in samples per second.

Definition at line 678 of file AudioIO.h.

Referenced by audacityAudioCallback(), FillBuffers(), SetCaptureMeter(), SetMeters(), SetPlaybackMeter(), StartMonitoring(), StartPortAudioStream(), StartStream(), and StopStream().

wxAtomicInt AudioIO::mRecordingException {}
private

Definition at line 824 of file AudioIO.h.

Referenced by FillBuffers().

struct AudioIO::RecordingSchedule AudioIO::mRecordingSchedule
private
ArrayOf<std::unique_ptr<Resample> > AudioIO::mResample
private

Definition at line 667 of file AudioIO.h.

Referenced by FillBuffers(), StartStream(), StartStreamCleanup(), and StopStream().

sampleCount AudioIO::mScrubDuration
private

Definition at line 819 of file AudioIO.h.

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

std::unique_ptr<ScrubQueue> AudioIO::mScrubQueue
private
double AudioIO::mSeek
private

Definition at line 696 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StartStream().

float AudioIO::mSilenceLevel
private

Definition at line 707 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StartStream().

GrowableSampleBuffer AudioIO::mSilentBuf
private

Definition at line 758 of file AudioIO.h.

Referenced by FillBuffers().

bool AudioIO::mSilentScrub
private

Definition at line 818 of file AudioIO.h.

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

bool AudioIO::mSimulateRecordingErrors { false }
bool AudioIO::mSoftwarePlaythrough
private
volatile int AudioIO::mStreamToken
private
wxMutex AudioIO::mSuspendAudioThread
private

Definition at line 812 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StopStream().

double AudioIO::mT0
private

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

Definition at line 680 of file AudioIO.h.

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

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.

Definition at line 682 of file AudioIO.h.

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

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

Definition at line 661 of file AudioIO.h.

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

double AudioIO::mTime
private

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

Definition at line 684 of file AudioIO.h.

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

const TimeTrack* AudioIO::mTimeTrack
private

Definition at line 769 of file AudioIO.h.

Referenced by audacityAudioCallback(), and StartStream().

bool AudioIO::mUpdateMeters
private

Definition at line 729 of file AudioIO.h.

Referenced by audacityAudioCallback(), AudioIO(), SetMeters(), and StopStream().

volatile bool AudioIO::mUpdatingMeters
private

Definition at line 730 of file AudioIO.h.

Referenced by audacityAudioCallback(), AudioIO(), and StopStream().

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.

Definition at line 694 of file AudioIO.h.

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.

Definition at line 689 of file AudioIO.h.

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

const int AudioIO::NumRatesToTry
staticprivate
Initial value:

How many sample rates to try.

Definition at line 538 of file AudioIO.h.

Referenced by GetSupportedCaptureRates(), and GetSupportedPlaybackRates().

const int AudioIO::NumStandardRates
static
Initial value:

How many standard sample rates there are.

Definition at line 410 of file AudioIO.h.

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)

Definition at line 536 of file AudioIO.h.

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)

Definition at line 408 of file AudioIO.h.

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


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