Audacity  2.2.2
Classes | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | 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  PlaybackSchedule
 
struct  RecordingSchedule
 
struct  ScrubState
 
struct  TimeQueue
 

Public Member Functions

 AudioIO ()
 
 ~AudioIO ()
 
int AudioCallback (const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
 
PaStreamCallbackResult CallbackDoSeek ()
 
void CallbackCheckCompletion (int &callbackReturn, unsigned long len)
 
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 () const
 
void UpdateScrub (double endTimeOrSpeed, const ScrubbingOptions &options)
 Notify scrubbing engine of desired position or speed. 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. More...
 
void StopScrub ()
 
double GetLastScrubTime () const
 return the ending time of the last scrub interval. More...
 
bool IsBusy () const
 Returns true if audio i/o is busy starting, stopping, playing, or recording. More...
 
bool IsStreamActive () const
 Returns true if the audio i/o is running at all, but not during cleanup. More...
 
bool IsStreamActive (int token) const
 
wxLongLong GetLastPlaybackTime () const
 
AudacityProjectGetOwningProject () const
 
bool IsAudioTokenActive (int token) const
 Returns true if the stream is active, or even if audio I/O is busy cleaning up its data or writing to disk. More...
 
bool IsMonitoring () const
 Returns true if we're monitoring input (but not recording or playing actual audio) More...
 
void SetPaused (bool state)
 Pause and un-pause playback and recording. More...
 
bool IsPaused () const
 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 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) const
 Function to automatically set an acceptable volume. More...
 
void SetCaptureMeter (AudacityProject *project, MeterPanel *meter)
 
void SetPlaybackMeter (AudacityProject *project, MeterPanel *meter)
 
double GetBestRate (bool capturing, bool playing, double sampleRate)
 Return a valid sample rate that is supported by the current I/O device(s). More...
 
wxString LastPaErrorString ()
 
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 Member Functions

void SetMeters ()
 Set the current VU meters - this should be done once after each call to StartStream currently. 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 GetCommonlyFreePlayback ()
 Get the number of audio samples free in all of the playback buffers. More...
 
size_t GetCommonlyReadyPlayback ()
 Get the number of audio samples ready in all of the playback buffers. More...
 
size_t GetCommonlyAvailCapture ()
 Get the number of audio samples ready in all of the recording buffers. More...
 
bool AllocateBuffers (const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate, bool scrubbing)
 Allocate RingBuffer structures, and others, needed for playback and recording. More...
 
void StartStreamCleanup (bool bOnlyBuffers=false)
 Clean up after StartStream if it fails. More...
 
void SetRecordingException ()
 
void ClearRecordingException ()
 

Static Private Member Functions

static int getRecordDevIndex (const wxString &devName=wxEmptyString)
 get the index of the supplied (named) recording device, or the device selected in the preferences if none given. More...
 
static int getPlayDevIndex (const wxString &devName=wxEmptyString)
 get the index of the device selected in the preferences. More...
 

Private Attributes

std::unique_ptr< AudioThreadmThread
 
ArrayOf< std::unique_ptr
< Resample > > 
mResample
 
ArrayOf< std::unique_ptr
< RingBuffer > > 
mCaptureBuffers
 
WaveTrackArray mCaptureTracks
 
ArrayOf< std::unique_ptr
< RingBuffer > > 
mPlaybackBuffers
 
WaveTrackArray mPlaybackTracks
 
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
 
volatile int mStreamToken
 
double mFactor
 
double mRate
 Audio playback rate in samples per second. More...
 
double mSeek
 
double mPlaybackRingBufferSecs
 
double mCaptureRingBufferSecs
 
size_t mPlaybackSamplesToCopy
 Preferred batch size for replenishing the playback RingBuffer. More...
 
size_t mPlaybackQueueMinimum
 Occupancy of the queue we try to maintain, with bigger batches if needed. More...
 
double mMinCaptureSecsToCopy
 
bool 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
 
AudioIOListenermListener
 
bool mUsingAlsa { false }
 
wxMutex mSuspendAudioThread
 
std::unique_ptr< ScrubStatemScrubState
 
bool mSilentScrub
 
double mScrubSpeed
 
sampleCount mScrubDuration
 
wxAtomicInt mRecordingException {}
 
std::vector< std::pair< double,
double > > 
mLostCaptureIntervals
 
bool mDetectDropouts { true }
 
struct AudioIO::RecordingSchedule mRecordingSchedule
 
struct AudioIO::PlaybackSchedule mPlaybackSchedule
 
struct AudioIO::TimeQueue mTimeQueue
 

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

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

Constructor & Destructor Documentation

AudioIO::AudioIO ( )

Definition at line 987 of file AudioIO.cpp.

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

988 {
989  if (!std::atomic<double>{}.is_lock_free()) {
990  // If this check fails, then the atomic<double> members in AudioIO.h
991  // might be changed to atomic<float> to be more efficient with some
992  // loss of precision. That could be conditionally compiled depending
993  // on the platform.
994  wxASSERT(false);
995  }
996 
1000  mPortStreamV19 = NULL;
1001 
1002 #ifdef EXPERIMENTAL_MIDI_OUT
1003  mMidiStream = NULL;
1004  mMidiThreadFillBuffersLoopRunning = false;
1005  mMidiThreadFillBuffersLoopActive = false;
1006  mMidiStreamActive = false;
1007  mSendMidiState = false;
1008  mIterator = NULL;
1009 
1010  mNumFrames = 0;
1011  mNumPauseFrames = 0;
1012 #endif
1013 
1014 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1015  mAILAActive = false;
1016 #endif
1017  mStreamToken = 0;
1018 
1019  mLastPaError = paNoError;
1020 
1021  mLastRecordingOffset = 0.0;
1022  mNumCaptureChannels = 0;
1023  mPaused = false;
1024 
1025  mListener = NULL;
1026  mUpdateMeters = false;
1027  mUpdatingMeters = false;
1028 
1029  mOwningProject = NULL;
1030  mOutputMeter = NULL;
1031 
1032  PaError err = Pa_Initialize();
1033 
1034  if (err != paNoError) {
1035  wxString errStr = _("Could not find any audio devices.\n");
1036  errStr += _("You will not be able to play or record audio.\n\n");
1037  wxString paErrStr = LAT1CTOWX(Pa_GetErrorText(err));
1038  if (!paErrStr.IsEmpty())
1039  errStr += _("Error: ")+paErrStr;
1040  // XXX: we are in libaudacity, popping up dialogs not allowed! A
1041  // long-term solution will probably involve exceptions
1042  AudacityMessageBox(errStr, _("Error Initializing Audio"), wxICON_ERROR|wxOK);
1043 
1044  // Since PortAudio is not initialized, all calls to PortAudio
1045  // functions will fail. This will give reasonable behavior, since
1046  // the user will be able to do things not relating to audio i/o,
1047  // but any attempt to play or record will simply fail.
1048  }
1049 
1050 #ifdef EXPERIMENTAL_MIDI_OUT
1051  PmError pmErr = Pm_Initialize();
1052 
1053  if (pmErr != pmNoError) {
1054  wxString errStr =
1055  _("There was an error initializing the midi i/o layer.\n");
1056  errStr += _("You will not be able to play midi.\n\n");
1057  wxString pmErrStr = LAT1CTOWX(Pm_GetErrorText(pmErr));
1058  if (!pmErrStr.empty())
1059  errStr += _("Error: ") + pmErrStr;
1060  // XXX: we are in libaudacity, popping up dialogs not allowed! A
1061  // long-term solution will probably involve exceptions
1062  AudacityMessageBox(errStr, _("Error Initializing Midi"), wxICON_ERROR|wxOK);
1063 
1064  // Same logic for PortMidi as described above for PortAudio
1065  }
1066 
1067 #ifdef USE_MIDI_THREAD
1068  mMidiThread = std::make_unique<MidiThread>();
1069  mMidiThread->Create();
1070 #endif
1071 
1072 #endif
1073 
1074  // Start thread
1075  mThread = std::make_unique<AudioThread>();
1076  mThread->Create();
1077 
1078 #if defined(USE_PORTMIXER)
1079  mPortMixer = NULL;
1080  mPreviousHWPlaythrough = -1.0;
1082 #else
1083  mEmulateMixerOutputVol = true;
1084  mMixerOutputVol = 1.0;
1085  mInputMixerWorks = false;
1086 #endif
1087 
1089 
1090 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1091  mScrubState = NULL;
1092  mScrubDuration = 0;
1093  mSilentScrub = false;
1094 #endif
1095 }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
sampleCount mScrubDuration
Definition: AudioIO.h:911
volatile bool mUpdatingMeters
Definition: AudioIO.h:863
float mMixerOutputVol
Definition: AudioIO.h:879
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:878
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:861
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:831
volatile int mStreamToken
Definition: AudioIO.h:814
bool mEmulateMixerOutputVol
Definition: AudioIO.h:870
PaStream * mPortStreamV19
Definition: AudioIO.h:832
void HandleDeviceChange()
update state after changing what audio devices are selected
Definition: AudioIO.cpp:1240
AudacityProject * mOwningProject
Definition: AudioIO.h:859
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:845
AudioIOListener * mListener
Definition: AudioIO.h:881
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:841
#define LAT1CTOWX(X)
Definition: Internat.h:180
unsigned int mNumCaptureChannels
Definition: AudioIO.h:837
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:801
bool mUpdateMeters
Definition: AudioIO.h:862
_("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:852
volatile bool mAudioThreadFillBuffersLoopActive
Definition: AudioIO.h:843
PaError mLastPaError
Definition: AudioIO.h:853
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:842
bool mSilentScrub
Definition: AudioIO.h:909
AudioIO::~AudioIO ( )

Definition at line 1097 of file AudioIO.cpp.

References gAudioIO, and mThread.

1098 {
1099 #if defined(USE_PORTMIXER)
1100  if (mPortMixer) {
1101  #if __WXMAC__
1102  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1103  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1104  mPreviousHWPlaythrough = -1.0;
1105  #endif
1106  Px_CloseMixer(mPortMixer);
1107  mPortMixer = NULL;
1108  }
1109 #endif
1110 
1111  // FIXME: ? TRAP_ERR. Pa_Terminate probably OK if err without reporting.
1112  Pa_Terminate();
1113 
1114 #ifdef EXPERIMENTAL_MIDI_OUT
1115  Pm_Terminate();
1116 
1117  /* Delete is a "graceful" way to stop the thread.
1118  (Kill is the not-graceful way.) */
1119 
1120 #ifdef USE_MIDI_THREAD
1121  mMidiThread->Delete();
1122  mMidiThread.reset();
1123 #endif
1124 
1125 #endif
1126 
1127  /* Delete is a "graceful" way to stop the thread.
1128  (Kill is the not-graceful way.) */
1129 
1130  // This causes reentrancy issues during application shutdown
1131  // wxTheApp->Yield();
1132 
1133  mThread->Delete();
1134  mThread.reset();
1135 
1136  gAudioIO = nullptr;
1137 }
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:801
AudioIO * gAudioIO
Definition: AudioIO.cpp:483

Member Function Documentation

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

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

Returns true iff successful.

Definition at line 2051 of file AudioIO.cpp.

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

Referenced by StartStream().

2055 {
2056  bool success = false;
2057  auto cleanup = finally([&]{
2058  if (!success) StartStreamCleanup( false );
2059  });
2060 
2061  //
2062  // The (audio) stream has been opened successfully (assuming we tried
2063  // to open it). We now proceed to
2064  // allocate the memory structures the stream will need.
2065  //
2066 
2067  //
2068  // The RingBuffer sizes, and the max amount of the buffer to
2069  // fill at a time, both grow linearly with the number of
2070  // tracks. This allows us to scale up to many tracks without
2071  // killing performance.
2072  //
2073 
2074  // real playback time to produce with each filling of the buffers
2075  // by the Audio thread (except at the end of playback):
2076  // usually, make fillings fewer and longer for less CPU usage.
2077  // But for useful scrubbing, we can't run too far ahead without checking
2078  // mouse input, so make fillings more and shorter.
2079  // What Audio thread produces for playback is then consumed by the PortAudio
2080  // thread, in many smaller pieces.
2081  double playbackTime = 4.0;
2082  if (scrubbing)
2083  // Specify a very short minimum batch for non-seek scrubbing, to allow
2084  // more frequent polling of the mouse
2085  playbackTime =
2086  lrint(options.pScrubbingOptions->delay * mRate) / mRate;
2087 
2088  wxASSERT( playbackTime >= 0 );
2089  mPlaybackSamplesToCopy = playbackTime * mRate;
2090 
2091  // Capacity of the playback buffer.
2092  mPlaybackRingBufferSecs = 10.0;
2093 
2095  4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.size());
2097  0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.size());
2098 
2099  mTimeQueue.mHead = {};
2100  mTimeQueue.mTail = {};
2101  bool bDone;
2102  do
2103  {
2104  bDone = true; // assume success
2105  try
2106  {
2107  if( mNumPlaybackChannels > 0 ) {
2108  // Allocate output buffers. For every output track we allocate
2109  // a ring buffer of ten seconds
2110  auto playbackBufferSize =
2111  (size_t)lrint(mRate * mPlaybackRingBufferSecs);
2112 
2115 
2116  const Mixer::WarpOptions &warpOptions =
2117 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2118  scrubbing
2122  :
2123 #endif
2124  Mixer::WarpOptions(mPlaybackSchedule.mTimeTrack);
2125 
2127  if (scrubbing)
2128  // Specify enough playback RingBuffer latency so we can refill
2129  // once every seek stutter without falling behind the demand.
2130  // (Scrub might switch in and out of seeking with left mouse
2131  // presses in the ruler)
2133  2 * options.pScrubbingOptions->minStutterTime * mRate );
2135  std::min( mPlaybackQueueMinimum, playbackBufferSize );
2136 
2137  for (unsigned int i = 0; i < mPlaybackTracks.size(); i++)
2138  {
2139  // Bug 1763 - We must fade in from zero to avoid a click on starting.
2140  mPlaybackTracks[i]->SetOldChannelGain(0, 0.0);
2141  mPlaybackTracks[i]->SetOldChannelGain(1, 0.0);
2142 
2143  mPlaybackBuffers[i] =
2144  std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
2145  const auto timeQueueSize =
2146  (playbackBufferSize + TimeQueueGrainSize - 1)
2148  mTimeQueue.mData.reinit( timeQueueSize );
2149  mTimeQueue.mSize = timeQueueSize;
2150 
2151  // use track time for the end time, not real time!
2152  WaveTrackConstArray mixTracks;
2153  mixTracks.push_back(mPlaybackTracks[i]);
2154 
2155  double endTime;
2157  .contains(mPlaybackTracks[i]))
2158  // Stop playing this track after pre-roll
2159  endTime = t0;
2160  else
2161  // Pass t1 -- not mT1 as may have been adjusted for latency
2162  // -- so that overdub recording stops playing back samples
2163  // at the right time, though transport may continue to record
2164  endTime = t1;
2165 
2166  mPlaybackMixers[i] = std::make_unique<Mixer>
2167  (mixTracks,
2168  // Don't throw for read errors, just play silence:
2169  false,
2170  warpOptions,
2172  endTime,
2173  1,
2175  false,
2176  mRate, floatSample, false);
2177  mPlaybackMixers[i]->ApplyTrackGains(false);
2178  }
2179  }
2180 
2181  if( mNumCaptureChannels > 0 )
2182  {
2183  // Allocate input buffers. For every input track we allocate
2184  // a ring buffer of five seconds
2185  auto captureBufferSize =
2186  (size_t)(mRate * mCaptureRingBufferSecs + 0.5);
2187 
2188  // In the extraordinarily rare case that we can't even afford
2189  // 100 samples, just give up.
2190  if(captureBufferSize < 100)
2191  {
2192  AudacityMessageBox(_("Out of memory!"));
2193  return false;
2194  }
2195 
2198  mFactor = sampleRate / mRate;
2199 
2200  for( unsigned int i = 0; i < mCaptureTracks.size(); i++ )
2201  {
2202  mCaptureBuffers[i] = std::make_unique<RingBuffer>(
2203  mCaptureTracks[i]->GetSampleFormat(), captureBufferSize );
2204  mResample[i] =
2205  std::make_unique<Resample>(true, mFactor, mFactor);
2206  // constant rate resampling
2207  }
2208  }
2209  }
2210  catch(std::bad_alloc&)
2211  {
2212  // Oops! Ran out of memory. This is pretty rare, so we'll just
2213  // try deleting everything, halving our buffer size, and try again.
2214  StartStreamCleanup(true);
2215  mPlaybackRingBufferSecs *= 0.5;
2217  mCaptureRingBufferSecs *= 0.5;
2218  mMinCaptureSecsToCopy *= 0.5;
2219  bDone = false;
2220 
2221  // In the extraordinarily rare case that we can't even afford 100
2222  // samples, just give up.
2223  auto playbackBufferSize =
2224  (size_t)lrint(mRate * mPlaybackRingBufferSecs);
2225  if(playbackBufferSize < 100 || mPlaybackSamplesToCopy < 100)
2226  {
2227  AudacityMessageBox(_("Out of memory!"));
2228  return false;
2229  }
2230  }
2231  } while(!bDone);
2232 
2233  success = true;
2234  return true;
2235 }
double mMinCaptureSecsToCopy
Definition: AudioIO.h:829
struct AudioIO::TimeQueue mTimeQueue
WaveTrackConstArray prerollTracks
Definition: AudioIO.h:166
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:113
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:2237
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
ScrubbingOptions * pScrubbingOptions
Definition: AudioIO.h:151
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:807
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:813
size_t mPlaybackQueueMinimum
Occupancy of the queue we try to maintain, with bigger batches if needed.
Definition: AudioIO.h:827
static double MaxAllowedScrubSpeed()
Definition: Scrubbing.h:61
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
double minStutterTime
Definition: Scrubbing.h:59
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:809
std::vector< std::shared_ptr< const WaveTrack > > WaveTrackConstArray
Definition: AudioIO.h:68
double mCaptureRingBufferSecs
Definition: AudioIO.h:822
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:596
#define lrint(dbl)
Definition: float_cast.h:136
int min(int a, int b)
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
unsigned int mNumCaptureChannels
Definition: AudioIO.h:837
struct AudioIO::TimeQueue::Cursor mHead
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
_("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
struct AudioIO::TimeQueue::Cursor mTail
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:957
constexpr size_t TimeQueueGrainSize
Definition: AudioIO.cpp:506
Functions for doing the mixdown of the tracks.
Definition: Mix.h:80
double mFactor
Definition: AudioIO.h:816
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
Definition: AudioIO.h:825
struct AudioIO::PlaybackSchedule mPlaybackSchedule
static double MinAllowedScrubSpeed()
Definition: Scrubbing.h:63
double mPlaybackRingBufferSecs
Definition: AudioIO.h:821
int AudioIO::AudioCallback ( const void *  inputBuffer,
void *  outputBuffer,
unsigned long  framesPerBuffer,
const PaStreamCallbackTimeInfo *  timeInfo,
const PaStreamCallbackFlags  statusFlags,
void *  userData 
)

Definition at line 4697 of file AudioIO.cpp.

References CallbackCheckCompletion(), CallbackDoSeek(), ClearSamples(), AudioIO::TimeQueue::Consumer(), CopySamples(), DoSoftwarePlaythrough(), floatSample, EffectManager::Get(), WaveTrack::GetChannelGain(), WaveTrack::GetChannelIgnoringPan(), GetCommonlyReadyPlayback(), AudacityProject::GetControlToolBar(), Track::GetLinked(), PlayableTrack::GetMute(), WaveTrack::GetOldChannelGain(), Track::GetSelected(), PlayableTrack::GetSolo(), AudioIO::PlaybackSchedule::GetTrackTime(), int16Sample, int24Sample, AudioIO::PlaybackSchedule::Interactive(), MeterPanel::IsMeterDisabled(), IsPaused(), Track::LeftChannel, mAudioThreadFillBuffersLoopRunning, MAX, mCaptureBuffers, mCaptureFormat, mDetectDropouts, mDetectUpstreamDropouts, mEmulateMixerOutputVol, min(), mInputMeter, mLastPlaybackTimeMillis, mLastRecordingOffset, AudioIO::RecordingSchedule::mLatencyCorrection, mLostCaptureIntervals, mLostSamples, mMixerOutputVol, mNumCaptureChannels, mNumPlaybackChannels, Track::MonoChannel, mOutputMeter, mOwningProject, mPaused, mPauseRec, mPlaybackBuffers, mPlaybackSchedule, mPlaybackTracks, mPortStreamV19, mRate, mRecordingSchedule, mSeek, mSilenceLevel, mSimulateRecordingErrors, mSoftwarePlaythrough, mStreamToken, AudioIO::PlaybackSchedule::mT0, mTimeQueue, mUpdateMeters, mUpdatingMeters, mUsingAlsa, AudioIO::PlaybackSchedule::PassIsComplete(), ControlToolBar::Pause(), EffectManager::RealtimeProcess(), EffectManager::RealtimeProcessEnd(), EffectManager::RealtimeProcessStart(), Track::RightChannel, WaveTrack::SetOldChannelGain(), AudioIO::PlaybackSchedule::SetTrackTime(), AudioIO::PlaybackSchedule::TrackTimeUpdate(), and MeterPanel::UpdateDisplay().

Referenced by audacityAudioCallback().

4705 {
4706  const auto numPlaybackChannels = mNumPlaybackChannels;
4707  const auto numPlaybackTracks = mPlaybackTracks.size();
4708  const auto numCaptureChannels = mNumCaptureChannels;
4709  int callbackReturn = paContinue;
4710  void *tempBuffer = alloca(framesPerBuffer*sizeof(float)*
4711  MAX(numCaptureChannels,numPlaybackChannels));
4712  float *tempFloats = (float*)tempBuffer;
4713 
4714  // output meter may need samples untouched by volume emulation
4715  float *outputMeterFloats;
4716  outputMeterFloats =
4717  (outputBuffer && mEmulateMixerOutputVol &&
4718  mMixerOutputVol != 1.0) ?
4719  (float *)alloca(framesPerBuffer*numPlaybackChannels * sizeof(float)) :
4720  (float *)outputBuffer;
4721 
4722 #ifdef EXPERIMENTAL_MIDI_OUT
4723  if (mCallbackCount++ == 0) {
4724  // This is effectively mSystemMinusAudioTime when the buffer is empty:
4725  mStartTime = SystemTime(mUsingAlsa) - mPlaybackSchedule.mT0;
4726  // later, mStartTime - mSystemMinusAudioTime will tell us latency
4727  }
4728 
4729  /* GSW: Save timeInfo in case MidiPlayback needs it */
4730  mAudioCallbackClockTime = PaUtil_GetTime();
4731 
4732  /* for Linux, estimate a smooth audio time as a slowly-changing
4733  offset from system time */
4734  // rnow is system time as a double to simplify math
4735  double rnow = SystemTime(mUsingAlsa);
4736  // anow is next-sample-to-be-computed audio time as a double
4737  double anow = AudioTime();
4738 
4739  if (mUsingAlsa) {
4740  // timeInfo's fields are not all reliable.
4741 
4742  // enow is audio time estimated from our clock synchronization protocol,
4743  // which produces mSystemMinusAudioTime. But we want the estimate
4744  // to drift low, so we steadily increase mSystemMinusAudioTime to
4745  // simulate a fast system clock or a slow audio clock. If anow > enow,
4746  // we'll update mSystemMinusAudioTime to keep in sync. (You might think
4747  // we could just use anow as the "truth", but it has a lot of jitter,
4748  // so we are using enow to smooth out this jitter, in fact to < 1ms.)
4749  // Add worst-case clock drift using previous framesPerBuffer:
4750  const auto increase =
4751  mAudioFramesPerBuffer * 0.0002 / mRate;
4752  mSystemMinusAudioTime += increase;
4753  mSystemMinusAudioTimePlusLatency += increase;
4754  double enow = rnow - mSystemMinusAudioTime;
4755 
4756 
4757  // now, use anow instead if it is ahead of enow
4758  if (anow > enow) {
4759  mSystemMinusAudioTime = rnow - anow;
4760  // Update our mAudioOutLatency estimate during the first 20 callbacks.
4761  // During this period, the buffer should fill. Once we have a good
4762  // estimate of mSystemMinusAudioTime (expected in fewer than 20 callbacks)
4763  // we want to stop the updating in case there is clock drift, which would
4764  // cause the mAudioOutLatency estimation to drift as well. The clock drift
4765  // in the first 20 callbacks should be negligible, however.
4766  if (mCallbackCount < 20) {
4767  mAudioOutLatency = mStartTime -
4768  mSystemMinusAudioTime;
4769  }
4770  mSystemMinusAudioTimePlusLatency =
4771  mSystemMinusAudioTime + mAudioOutLatency;
4772  }
4773  }
4774  else {
4775  // If not using Alsa, rely on timeInfo to have meaningful values that are
4776  // more precise than the output latency value reported at stream start.
4777  mSystemMinusAudioTime = rnow - anow;
4778  mSystemMinusAudioTimePlusLatency =
4779  mSystemMinusAudioTime +
4780  (timeInfo->outputBufferDacTime - timeInfo->currentTime);
4781  }
4782 
4783  mAudioFramesPerBuffer = framesPerBuffer;
4784  if (IsPaused()
4785  // PRL: Why was this added? Was it only because of the mysterious
4786  // initial leading zeroes, now solved by setting mStreamToken early?
4787  // JKC: I think it's used for the MIDI time cursor. See comments
4788  // at head of file about AudioTime().
4789  || mStreamToken <= 0
4790  )
4791  mNumPauseFrames += framesPerBuffer;
4792 
4793  // PRL: Note that when there is a separate MIDI thread, it is effectively
4794  // blocked until the first visit to this line during a playback, and will
4795  // not read mSystemMinusAudioTimePlusLatency sooner:
4796  mNumFrames += framesPerBuffer;
4797 
4798 #ifndef USE_MIDI_THREAD
4799  if (mMidiStream)
4800  FillMidiBuffers();
4801 #endif
4802 
4803 #endif
4804  /* Send data to recording VU meter if applicable */
4805 
4806  if (mInputMeter &&
4807  !mInputMeter->IsMeterDisabled() &&
4808  inputBuffer) {
4809  // get here if meters are actually live , and being updated
4810  /* It's critical that we don't update the meters while StopStream is
4811  * trying to stop PortAudio, otherwise it can lead to a freeze. We use
4812  * two variables to synchronize:
4813  * mUpdatingMeters tells StopStream when the callback is about to enter
4814  * the code where it might update the meters, and
4815  * mUpdateMeters is how the rest of the code tells the callback when it
4816  * is allowed to actually do the updating.
4817  * Note that mUpdatingMeters must be set first to avoid a race condition.
4818  */
4819  mUpdatingMeters = true;
4820  if (mUpdateMeters) {
4821  if (mCaptureFormat == floatSample)
4822  mInputMeter->UpdateDisplay(numCaptureChannels,
4823  framesPerBuffer,
4824  (float *)inputBuffer);
4825  else {
4826  CopySamples((samplePtr)inputBuffer, mCaptureFormat,
4827  (samplePtr)tempFloats, floatSample,
4828  framesPerBuffer * numCaptureChannels);
4829  mInputMeter->UpdateDisplay(numCaptureChannels,
4830  framesPerBuffer,
4831  tempFloats);
4832  }
4833  }
4834  mUpdatingMeters = false;
4835  } // end recording VU meter update
4836 
4837  // Stop recording if 'silence' is detected
4838  //
4839  // LL: We'd gotten a little "dangerous" with the control toolbar calls
4840  // here because we are not running in the main GUI thread. Eventually
4841  // the toolbar attempts to update the active project's status bar.
4842  // But, since we're not in the main thread, we can get all manner of
4843  // really weird failures. Or none at all which is even worse, since
4844  // we don't know a problem exists.
4845  //
4846  // By using CallAfter(), we can schedule the call to the toolbar
4847  // to run in the main GUI thread after the next event loop iteration.
4848  if(mPauseRec && inputBuffer && mInputMeter) {
4849  if(mInputMeter->GetMaxPeak() < mSilenceLevel ) {
4850  if(!IsPaused()) {
4852  bar->CallAfter(&ControlToolBar::Pause);
4853  }
4854  }
4855  else {
4856  if(IsPaused()) {
4858  bar->CallAfter(&ControlToolBar::Pause);
4859  }
4860  }
4861  }
4862 
4863  // MOVE_TO: CountSoloedTracks() function
4864  unsigned numSolo = 0;
4865  for(unsigned t = 0; t < numPlaybackTracks; t++ )
4866  if( mPlaybackTracks[t]->GetSolo() )
4867  numSolo++;
4868 #ifdef EXPERIMENTAL_MIDI_OUT
4869  auto numMidiPlaybackTracks = mMidiPlaybackTracks.size();
4870  for( unsigned t = 0; t < numMidiPlaybackTracks; t++ )
4871  if( mMidiPlaybackTracks[t]->GetSolo() )
4872  numSolo++;
4873 #endif
4874 
4875 
4876  // MOVE_TO: CountDroppedTracks() function
4877  bool dropAllQuickly = true; //i.e. drop all channels, without any fade out.
4878  for (unsigned t = 0; t < numPlaybackTracks; t++)
4879  {
4880  WaveTrack *vt = mPlaybackTracks[t].get();
4881  bool drop = false;
4882  bool dropQuickly = false;
4883  bool linkFlag = false;
4884 
4885  if (linkFlag) {
4886  linkFlag = false;
4888  dropQuickly = dropQuickly && (vt->GetOldChannelGain(0) == 0.0);
4890  dropQuickly = dropQuickly && (vt->GetOldChannelGain(1) == 0.0);
4891  }
4892  else {
4893  drop = mPaused;
4894  dropQuickly = false;
4895 
4896  // Cut if somebody else is soloing
4897  if (numSolo>0 && !vt->GetSolo())
4898  drop = true;
4899 
4900  // Cut if we're muted (unless we're soloing)
4901  if (vt->GetMute() && !vt->GetSolo())
4902  drop = true;
4903 
4904  linkFlag = vt->GetLinked();
4905 
4906  dropQuickly = drop;
4909  dropQuickly = dropQuickly && (vt->GetOldChannelGain(0) == 0.0);
4912  dropQuickly = dropQuickly && (vt->GetOldChannelGain(1) == 0.0);
4913  }
4914  dropAllQuickly = dropAllQuickly && dropQuickly;
4915  }
4916 
4917 // This is a quick route, when paused and already at zero level on all channels.
4918 // However, we always fade-out into a pause, hence the 'dropAllQuickly' test
4919 // Net result is we may pause one frame later than requested, if we can't drop
4920 // all channels quickly (because some are not yet down to zero gain).
4921 // Note that if we are paused, the gain will be dropped to zero by the end of
4922 // this callback, and so the next time round 'dropAllQuickly' will be true.
4923 // All this logic will be easier when we shift over to working with gains that
4924 // go to zero, and not flags.
4925  if( mPaused && dropAllQuickly )
4926  {
4927  if (outputBuffer && numPlaybackChannels > 0)
4928  {
4929  ClearSamples((samplePtr)outputBuffer, floatSample,
4930  0, framesPerBuffer * numPlaybackChannels);
4931 
4932  if (inputBuffer && mSoftwarePlaythrough) {
4934  numCaptureChannels,
4935  (float *)outputBuffer, (int)framesPerBuffer);
4936  }
4937  }
4938  return paContinue;
4939  }
4940 
4941  if (mStreamToken > 0)
4942  {
4943  decltype(framesPerBuffer) maxLen = 0;
4944 
4945  //
4946  // Mix and copy to PortAudio's output buffer
4947  //
4948 
4949  if( outputBuffer && (numPlaybackChannels > 0) )
4950  {
4951  // The drop and dropQuickly booleans are for historical reasons.
4952  // JKC: The original code attempted to be faster by doing nothing on silenced audio.
4953  // This, IMHO, is 'premature optimisation'. Instead clearer and cleaner code would
4954  // simply use a gain of 0.0 for silent audio and go on through to the stage of
4955  // applying that 0.0 gain to the data mixed into the buffer.
4956  // Then (and only then) we would have if needed fast paths for:
4957  // - Applying a uniform gain of 0.0.
4958  // - Applying a uniform gain of 1.0.
4959  // - Applying some other uniform gain.
4960  // - Applying a linearly interpolated gain.
4961  // I would expect us not to need the fast paths, since linearly interpolated gain
4962  // is very cheap to process.
4963  bool drop = false;
4964  bool dropQuickly = false;
4965  bool linkFlag = false;
4966 
4967  float *outputFloats = (float *)outputBuffer;
4968  for( unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
4969  outputFloats[i] = 0.0;
4970 
4971  if (inputBuffer && mSoftwarePlaythrough) {
4973  numCaptureChannels,
4974  (float *)outputBuffer, (int)framesPerBuffer);
4975  }
4976 
4977  // Copy the results to outputMeterFloats if necessary
4978  if (outputMeterFloats != outputFloats) {
4979  for (unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
4980  outputMeterFloats[i] = outputFloats[i];
4981  }
4982  }
4983 
4984 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
4985  // While scrubbing, ignore seek requests
4987  mSeek = 0.0;
4988  else
4989 #endif
4990  if (mSeek)
4991  return CallbackDoSeek();
4992 
4993 
4994  WaveTrack **chans = (WaveTrack **) alloca(numPlaybackChannels * sizeof(WaveTrack *));
4995  float **tempBufs = (float **) alloca(numPlaybackChannels * sizeof(float *));
4996  for (unsigned int c = 0; c < numPlaybackChannels; c++)
4997  {
4998  tempBufs[c] = (float *) alloca(framesPerBuffer * sizeof(float));
4999  }
5000 
5002  em.RealtimeProcessStart();
5003 
5004  bool selected = false;
5005  int group = 0;
5006  int chanCnt = 0;
5007 
5008  // Choose a common size to take from all ring buffers
5009  const auto toGet =
5010  std::min<size_t>(framesPerBuffer, GetCommonlyReadyPlayback());
5011 
5012  for (unsigned t = 0; t < numPlaybackTracks; t++)
5013  {
5014  WaveTrack *vt = mPlaybackTracks[t].get();
5015 
5016  chans[chanCnt] = vt;
5017 
5018  if (linkFlag) {
5019  linkFlag = false;
5021  dropQuickly = dropQuickly && (vt->GetOldChannelGain(0) == 0.0);
5023  dropQuickly = dropQuickly && (vt->GetOldChannelGain(1) == 0.0);
5024  }
5025  else {
5026  drop = mPaused;
5027  dropQuickly = false;
5028 
5029  // Cut if somebody else is soloing
5030  if (numSolo>0 && !vt->GetSolo())
5031  drop = true;
5032 
5033  // Cut if we're muted (unless we're soloing)
5034  if (vt->GetMute() && !vt->GetSolo())
5035  drop = true;
5036 
5037  linkFlag = vt->GetLinked();
5038  selected = vt->GetSelected();
5039 
5040  // If we have a mono track, clear the right channel
5041  if (!linkFlag)
5042  {
5043  memset(tempBufs[1], 0, framesPerBuffer * sizeof(float));
5044  }
5045 
5046  dropQuickly = drop;
5049  dropQuickly = dropQuickly && (vt->GetOldChannelGain(0) == 0.0);
5052  dropQuickly = dropQuickly && (vt->GetOldChannelGain(1) == 0.0);
5053  }
5054 
5055 
5056 #define ORIGINAL_DO_NOT_PLAY_ALL_MUTED_TRACKS_TO_END
5057 #ifdef ORIGINAL_DO_NOT_PLAY_ALL_MUTED_TRACKS_TO_END
5058  decltype(framesPerBuffer) len = 0;
5059  // this is original code prior to r10680 -RBD
5060  if (dropQuickly)
5061  {
5062  len = mPlaybackBuffers[t]->Discard(framesPerBuffer);
5063  // keep going here.
5064  // we may still need to issue a paComplete.
5065  }
5066  else
5067  {
5068  len = mPlaybackBuffers[t]->Get((samplePtr)tempBufs[chanCnt],
5069  floatSample,
5070  toGet);
5071  // wxASSERT( len == toGet );
5072  if (len < framesPerBuffer)
5073  // This used to happen normally at the end of non-looping
5074  // plays, but it can also be an anomalous case where the
5075  // supply from FillBuffers fails to keep up with the
5076  // real-time demand in this thread (see bug 1932). We
5077  // must supply something to the sound card, so pad it with
5078  // zeroes and not random garbage.
5079  memset((void*)&tempBufs[chanCnt][len], 0,
5080  (framesPerBuffer - len) * sizeof(float));
5081 
5082  chanCnt++;
5083  }
5084 
5085  // PRL: Bug1104:
5086  // There can be a difference of len in different loop passes if one channel
5087  // of a stereo track ends before the other! Take a max!
5088 
5089  // PRL: More recent rewrites of FillBuffers should guarantee a
5090  // padding out of the ring buffers so that equal lengths are
5091  // available, so maxLen ought to increase from 0 only once
5092  maxLen = std::max(maxLen, len);
5093 
5094 
5095  if (linkFlag)
5096  {
5097  continue;
5098  }
5099 #else
5100  // This code was reorganized so that if all audio tracks
5101  // are muted, we still return paComplete when the end of
5102  // a selection is reached.
5103  // Vaughan, 2011-10-20: Further comments from Roger, by off-list email:
5104  // ...something to do with what it means to mute all audio tracks. E.g. if you
5105  // mute all and play, does the playback terminate immediately or play
5106  // silence? If it terminates immediately, does that terminate any MIDI
5107  // playback that might also be going on? ...Maybe muted audio tracks + MIDI,
5108  // the playback would NEVER terminate. ...I think the #else part is probably preferable...
5109  size_t len;
5110  if (dropQuickly)
5111  {
5112  len =
5113  mPlaybackBuffers[t]->Discard(framesPerBuffer);
5114  } else
5115  {
5116  len =
5117  mPlaybackBuffers[t]->Get((samplePtr)tempFloats,
5118  floatSample,
5119  framesPerBuffer);
5120  }
5121 #endif
5122 
5123  // Last channel of a track seen now
5124  len = maxLen;
5125 
5126  if( !dropQuickly && selected )
5127  {
5128  len = em.RealtimeProcess(group, chanCnt, tempBufs, len);
5129  }
5130  group++;
5131 
5132 
5133  CallbackCheckCompletion(callbackReturn, len);
5134 
5135  if (dropQuickly) // no samples to process, they've been discarded
5136  continue;
5137 
5138  if (len > 0) for (int c = 0; c < chanCnt; c++)
5139  {
5140  vt = chans[c];
5141 
5144  {
5145  float gain = vt->GetChannelGain(0);
5147  gain = 0.0;
5148 
5149  // Output volume emulation: possibly copy meter samples, then
5150  // apply volume, then copy to the output buffer
5151  if (outputMeterFloats != outputFloats)
5152  for (decltype(len) i = 0; i < len; ++i)
5153  outputMeterFloats[numPlaybackChannels*i] +=
5154  gain*tempFloats[i];
5155 
5157  gain *= mMixerOutputVol;
5158 
5159  float oldGain = vt->GetOldChannelGain(0);
5160  if( gain != oldGain )
5161  vt->SetOldChannelGain(0, gain);
5162  wxASSERT(len > 0);
5163  float deltaGain = (gain - oldGain) / len;
5164  for (decltype(len) i = 0; i < len; i++)
5165  outputFloats[numPlaybackChannels*i] += (oldGain + deltaGain * i) *tempBufs[c][i];
5166 
5167  }
5168 
5171  {
5172  float gain = vt->GetChannelGain(1);
5174  gain = 0.0;
5175 
5176  // Output volume emulation (as above)
5177  if (outputMeterFloats != outputFloats)
5178  for (decltype(len) i = 0; i < len; ++i)
5179  outputMeterFloats[numPlaybackChannels*i+1] +=
5180  gain*tempFloats[i];
5181 
5183  gain *= mMixerOutputVol;
5184 
5185  float oldGain = vt->GetOldChannelGain(1);
5186  if (gain != oldGain)
5187  vt->SetOldChannelGain(1,gain);
5188  wxASSERT(len > 0);
5189  float deltaGain = (gain - oldGain) / len;
5190  for(decltype(len) i = 0; i < len; i++)
5191  outputFloats[numPlaybackChannels*i+1] += (oldGain + deltaGain*i) *tempBufs[c][i];
5192  }
5193  }
5194 
5195  chanCnt = 0;
5196  }
5197 
5198  // Poke: If there are no playback tracks, then the earlier check
5199  // about the time indicator being past the end won't happen;
5200  // do it here instead (but not if looping or scrubbing)
5201  if (numPlaybackTracks == 0)
5202  CallbackCheckCompletion(callbackReturn, 0);
5203 
5204  // wxASSERT( maxLen == toGet );
5205 
5206  em.RealtimeProcessEnd();
5207 
5208  mLastPlaybackTimeMillis = ::wxGetLocalTimeMillis();
5209 
5210  //
5211  // Clip output to [-1.0,+1.0] range (msmeyer)
5212  //
5213  for(unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
5214  {
5215  float f = outputFloats[i];
5216  if (f > 1.0)
5217  outputFloats[i] = 1.0;
5218  else if (f < -1.0)
5219  outputFloats[i] = -1.0;
5220  }
5221 
5222  // Same for meter output
5223  if (outputMeterFloats != outputFloats)
5224  {
5225  for (unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i)
5226  {
5227  float f = outputMeterFloats[i];
5228  if (f > 1.0)
5229  outputMeterFloats[i] = 1.0;
5230  else if (f < -1.0)
5231  outputMeterFloats[i] = -1.0;
5232  }
5233  }
5234  }
5235 
5236  //
5237  // Copy from PortAudio to our input buffers.
5238  //
5239 
5240  if( inputBuffer && (numCaptureChannels > 0) )
5241  {
5242  // If there are no playback tracks, and we are recording, then the
5243  // earlier checks for being passed the end won't happen, so do it here.
5245  callbackReturn = paComplete;
5246  }
5247 
5248  // The error likely from a too-busy CPU falling behind real-time data
5249  // is paInputOverflow
5250  bool inputError =
5251  (statusFlags & (paInputOverflow))
5252  && !(statusFlags & paPrimingOutput);
5253 
5254  // But it seems it's easy to get false positives, at least on Mac
5255  // So we have not decided to enable this extra detection yet in
5256  // production
5257 
5258  size_t len = framesPerBuffer;
5259  for(unsigned t = 0; t < numCaptureChannels; t++)
5260  len = std::min( len,
5261  mCaptureBuffers[t]->AvailForPut());
5262 
5263  if (mSimulateRecordingErrors && 100LL * rand() < RAND_MAX)
5264  // Make spurious errors for purposes of testing the error
5265  // reporting
5266  len = 0;
5267 
5268  // A different symptom is that len < framesPerBuffer because
5269  // the other thread, executing FillBuffers, isn't consuming fast
5270  // enough from mCaptureBuffers; maybe it's CPU-bound, or maybe the
5271  // storage device it writes is too slow
5272  if (mDetectDropouts &&
5273  ((mDetectUpstreamDropouts && inputError) ||
5274  len < framesPerBuffer) ) {
5275  // Assume that any good partial buffer should be written leftmost
5276  // and zeroes will be padded after; label the zeroes.
5277  auto start = mPlaybackSchedule.GetTrackTime() +
5279  auto duration = (framesPerBuffer - len) / mRate;
5280  auto interval = std::make_pair( start, duration );
5281  mLostCaptureIntervals.push_back( interval );
5282  }
5283 
5284  if (len < framesPerBuffer)
5285  {
5286  mLostSamples += (framesPerBuffer - len);
5287  wxPrintf(wxT("lost %d samples\n"), (int)(framesPerBuffer - len));
5288  }
5289 
5290  if (len > 0) {
5291  for(unsigned t = 0; t < numCaptureChannels; t++) {
5292 
5293  // dmazzoni:
5294  // Un-interleave. Ugly special-case code required because the
5295  // capture channels could be in three different sample formats;
5296  // it'd be nice to be able to call CopySamples, but it can't
5297  // handle multiplying by the gain and then clipping. Bummer.
5298 
5299  switch(mCaptureFormat) {
5300  case floatSample: {
5301  float *inputFloats = (float *)inputBuffer;
5302  for(unsigned i = 0; i < len; i++)
5303  tempFloats[i] =
5304  inputFloats[numCaptureChannels*i+t];
5305  } break;
5306  case int24Sample:
5307  // We should never get here. Audacity's int24Sample format
5308  // is different from PortAudio's sample format and so we
5309  // make PortAudio return float samples when recording in
5310  // 24-bit samples.
5311  wxASSERT(false);
5312  break;
5313  case int16Sample: {
5314  short *inputShorts = (short *)inputBuffer;
5315  short *tempShorts = (short *)tempBuffer;
5316  for( unsigned i = 0; i < len; i++) {
5317  float tmp = inputShorts[numCaptureChannels*i+t];
5318  if (tmp > 32767)
5319  tmp = 32767;
5320  if (tmp < -32768)
5321  tmp = -32768;
5322  tempShorts[i] = (short)(tmp);
5323  }
5324  } break;
5325  } // switch
5326 
5327  const auto put =
5328  mCaptureBuffers[t]->Put(
5329  (samplePtr)tempBuffer, mCaptureFormat, len);
5330  // wxASSERT(put == len);
5331  // but we can't assert in this thread
5332  wxUnusedVar(put);
5333  }
5334  }
5335  }
5336 
5337  // Update the position seen by drawing code
5339  // To do: do this in all cases and remove TrackTimeUpdate
5341  else
5342  mPlaybackSchedule.TrackTimeUpdate( framesPerBuffer / mRate );
5343 
5344  // Record the reported latency from PortAudio.
5345  // TODO: Don't recalculate this with every callback?
5346 
5347  // 01/21/2009: Disabled until a better solution presents itself.
5348  #if 0
5349  // As of 06/17/2006, portaudio v19 returns inputBufferAdcTime set to
5350  // zero. It is being worked on, but for now we just can't do much
5351  // but follow the leader.
5352  //
5353  // 08/27/2006: too inconsistent for now...just leave it a zero.
5354  //
5355  // 04/16/2008: Looks like si->inputLatency comes back with something useful though.
5356  // This rearranged logic uses si->inputLatency, but if PortAudio fixes inputBufferAdcTime,
5357  // this code won't have to be modified to use it.
5358  // Also avoids setting mLastRecordingOffset except when simultaneously playing and recording.
5359  //
5360  if (numCaptureChannels > 0 && numPlaybackChannels > 0) // simultaneously playing and recording
5361  {
5362  if (timeInfo->inputBufferAdcTime > 0)
5363  mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
5364  else if (mLastRecordingOffset == 0.0)
5365  {
5366  const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
5367  mLastRecordingOffset = -si->inputLatency;
5368  }
5369  }
5370  #endif
5371  } // if mStreamToken > 0
5372  else
5373  {
5374  // No tracks to play, but we should clear the output, and
5375  // possibly do software playthrough...
5376 
5377  if( outputBuffer && (numPlaybackChannels > 0) ) {
5378  float *outputFloats = (float *)outputBuffer;
5379  for(unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
5380  outputFloats[i] = 0.0;
5381 
5382  if (inputBuffer && mSoftwarePlaythrough) {
5384  numCaptureChannels,
5385  (float *)outputBuffer, (int)framesPerBuffer);
5386  }
5387 
5388  // Copy the results to outputMeterFloats if necessary
5389  if (outputMeterFloats != outputFloats) {
5390  for (unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
5391  outputMeterFloats[i] = outputFloats[i];
5392  }
5393  }
5394  }
5395 
5396  }
5397  /* Send data to playback VU meter if applicable */
5398  if (mOutputMeter &&
5400  outputMeterFloats) {
5401  // Get here if playback meter is live
5402  /* It's critical that we don't update the meters while StopStream is
5403  * trying to stop PortAudio, otherwise it can lead to a freeze. We use
5404  * two variables to synchronize:
5405  * mUpdatingMeters tells StopStream when the callback is about to enter
5406  * the code where it might update the meters, and
5407  * mUpdateMeters is how the rest of the code tells the callback when it
5408  * is allowed to actually do the updating.
5409  * Note that mUpdatingMeters must be set first to avoid a race condition.
5410  */
5411  mUpdatingMeters = true;
5412  if (mUpdateMeters) {
5413  mOutputMeter->UpdateDisplay(numPlaybackChannels,
5414  framesPerBuffer,
5415  outputMeterFloats);
5416 
5417  //v Vaughan, 2011-02-25: Moved this update back to TrackPanel::OnTimer()
5418  // as it helps with playback issues reported by Bill and noted on Bug 258.
5419  // The problem there occurs if Software Playthrough is on.
5420  // Could conditionally do the update here if Software Playthrough is off,
5421  // and in TrackPanel::OnTimer() if Software Playthrough is on, but not now.
5422  // PRL 12 Jul 2015: and what was in TrackPanel::OnTimer is now handled by means of event
5423  // type EVT_TRACK_PANEL_TIMER
5424  //MixerBoard* pMixerBoard = mOwningProject->GetMixerBoard();
5425  //if (pMixerBoard)
5426  // pMixerBoard->UpdateMeters(GetStreamTime(),
5427  // (pProj->mLastPlayMode == loopedPlay));
5428  }
5429  mUpdatingMeters = false;
5430  } // end playback VU meter update
5431 
5432  return callbackReturn;
5433 }
bool IsPaused() const
Find out if playback / recording is currently paused.
Definition: AudioIO.cpp:2713
bool GetSolo() const
Definition: Track.h:392
A ToolBar that has the main Transport buttons.
size_t GetCommonlyReadyPlayback()
Get the number of audio samples ready in all of the playback buffers.
Definition: AudioIO.cpp:3247
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: AudioIO.h:1012
size_t RealtimeProcess(int group, unsigned chans, float **buffers, size_t numSamples)
bool Interactive() const
Definition: AudioIO.h:1047
bool GetSelected() const
Definition: Track.h:284
struct AudioIO::TimeQueue mTimeQueue
bool mDetectDropouts
Definition: AudioIO.h:923
void SetTrackTime(double time)
Set current track time value, unadjusted.
Definition: AudioIO.h:1017
void CopySamples(samplePtr src, sampleFormat srcFormat, samplePtr dst, sampleFormat dstFormat, unsigned int len, bool highQuality, unsigned int srcStride, unsigned int dstStride)
bool mDetectUpstreamDropouts
Definition: AudioIO.h:935
volatile bool mUpdatingMeters
Definition: AudioIO.h:863
float mMixerOutputVol
Definition: AudioIO.h:879
void TrackTimeUpdate(double realElapsed)
Definition: AudioIO.cpp:5579
bool mSoftwarePlaythrough
Definition: AudioIO.h:833
bool GetLinked() const
Definition: Track.h:287
struct AudioIO::RecordingSchedule mRecordingSchedule
MeterPanel * mOutputMeter
Definition: AudioIO.h:861
float GetChannelGain(int channel) const
Definition: WaveTrack.cpp:444
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
bool PassIsComplete() const
Definition: AudioIO.cpp:5508
float mSilenceLevel
Definition: AudioIO.h:836
sampleFormat mCaptureFormat
Definition: AudioIO.h:839
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:831
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
volatile int mStreamToken
Definition: AudioIO.h:814
bool mEmulateMixerOutputVol
Definition: AudioIO.h:870
PaStream * mPortStreamV19
Definition: AudioIO.h:832
bool IsMeterDisabled() const
Find out if the level meter is disabled or not.
Definition: Meter.cpp:1773
void UpdateDisplay(unsigned numChannels, int numFrames, float *sampleData)
Update the meters with a block of audio data.
Definition: Meter.cpp:886
char * samplePtr
Definition: Types.h:203
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
AudacityProject * mOwningProject
Definition: AudioIO.h:859
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:45
int min(int a, int b)
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:845
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
double Consumer(size_t nSamples, double rate)
Definition: AudioIO.cpp:5624
double mSeek
Definition: AudioIO.h:820
unsigned int mNumCaptureChannels
Definition: AudioIO.h:837
static EffectManager & Get()
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:860
unsigned long long mLostSamples
Definition: AudioIO.h:840
static void DoSoftwarePlaythrough(const void *inputBuffer, sampleFormat inputFormat, unsigned inputChannels, float *outputBuffer, int len)
Definition: AudioIO.cpp:4666
void CallbackCheckCompletion(int &callbackReturn, unsigned long len)
Definition: AudioIO.cpp:5486
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
bool mUpdateMeters
Definition: AudioIO.h:862
float GetOldChannelGain(int channel) const
Definition: WaveTrack.cpp:460
ControlToolBar * GetControlToolBar()
Definition: Project.cpp:5041
volatile double mLastRecordingOffset
Definition: AudioIO.h:852
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
bool mUsingAlsa
Definition: AudioIO.h:890
bool GetMute() const
Definition: Track.h:391
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:957
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:922
#define MAX(a, b)
Definition: AudioIO.cpp:4664
void RealtimeProcessEnd()
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:842
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:835
void SetOldChannelGain(int channel, float gain)
Definition: WaveTrack.cpp:465
struct AudioIO::PlaybackSchedule mPlaybackSchedule
virtual int GetChannelIgnoringPan() const
Definition: WaveTrack.cpp:236
void RealtimeProcessStart()
bool mSimulateRecordingErrors
Definition: AudioIO.h:931
PaStreamCallbackResult CallbackDoSeek()
Definition: AudioIO.cpp:5435
void AudioIO::CallbackCheckCompletion ( int &  callbackReturn,
unsigned long  len 
)

Definition at line 5486 of file AudioIO.cpp.

References mPaused, mPlaybackSchedule, AudioIO::PlaybackSchedule::PassIsComplete(), AudioIO::PlaybackSchedule::PlayingAtSpeed(), and AudioIO::PlaybackSchedule::PlayingStraight().

Referenced by AudioCallback().

5488 {
5489  if (mPaused)
5490  return;
5491  bool done = mPlaybackSchedule.PassIsComplete();
5492  if (done)
5493  done = (
5495  // some leftover length allowed in this case
5496  || (mPlaybackSchedule.PlayingStraight() && len == 0)
5497  );
5498  if(done) {
5499  // PRL: singalling MIDI output complete is necessary if
5500  // not USE_MIDI_THREAD, otherwise it's harmlessly redundant
5501 #ifdef EXPERIMENTAL_MIDI_OUT
5502  mMidiOutputComplete = true,
5503 #endif
5504  callbackReturn = paComplete;
5505  }
5506 }
bool PassIsComplete() const
Definition: AudioIO.cpp:5508
bool PlayingAtSpeed() const
Definition: AudioIO.h:1046
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:831
bool PlayingStraight() const
Definition: AudioIO.h:1043
struct AudioIO::PlaybackSchedule mPlaybackSchedule
PaStreamCallbackResult AudioIO::CallbackDoSeek ( )

Definition at line 5435 of file AudioIO.cpp.

References AudioIO::PlaybackSchedule::ClampTrackTime(), AudioIO::PlaybackSchedule::GetTrackTime(), mAudioThreadFillBuffersLoopActive, mAudioThreadFillBuffersLoopRunning, mAudioThreadShouldCallFillBuffersOnce, mPlaybackBuffers, mPlaybackMixers, mPlaybackSchedule, mPlaybackTracks, mSeek, mStreamToken, mSuspendAudioThread, AudioIO::PlaybackSchedule::RealTimeInit(), and AudioIO::PlaybackSchedule::SetTrackTime().

Referenced by AudioCallback().

5436 {
5437  const int token = mStreamToken;
5438  wxMutexLocker locker(mSuspendAudioThread);
5439  if (token != mStreamToken)
5440  // This stream got destroyed while we waited for it
5441  return paAbort;
5442 
5443  const auto numPlaybackTracks = mPlaybackTracks.size();
5444 
5445  // Pause audio thread and wait for it to finish
5448  {
5449  wxMilliSleep( 50 );
5450  }
5451 
5452  // Calculate the NEW time position, in the PortAudio callback
5453  const auto time = mPlaybackSchedule.ClampTrackTime(
5456  mSeek = 0.0;
5457 
5459 
5460  // Reset mixer positions and flush buffers for all tracks
5461  for (size_t i = 0; i < numPlaybackTracks; i++)
5462  {
5463  mPlaybackMixers[i]->Reposition( time );
5464  const auto toDiscard =
5465  mPlaybackBuffers[i]->AvailForGet();
5466  const auto discarded =
5467  mPlaybackBuffers[i]->Discard( toDiscard );
5468  // wxASSERT( discarded == toDiscard );
5469  // but we can't assert in this thread
5470  wxUnusedVar(discarded);
5471  }
5472 
5473  // Reload the ring buffers
5476  {
5477  wxMilliSleep( 50 );
5478  }
5479 
5480  // Reenable the audio thread
5482 
5483  return paContinue;
5484 }
double ClampTrackTime(double trackTime) const
Clamps argument to be between mT0 and mT1.
Definition: AudioIO.cpp:2853
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: AudioIO.h:1012
void SetTrackTime(double time)
Set current track time value, unadjusted.
Definition: AudioIO.h:1017
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:813
void RealTimeInit(double trackTime)
Definition: AudioIO.cpp:5676
wxMutex mSuspendAudioThread
Definition: AudioIO.h:903
volatile int mStreamToken
Definition: AudioIO.h:814
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:841
double mSeek
Definition: AudioIO.h:820
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
volatile bool mAudioThreadFillBuffersLoopActive
Definition: AudioIO.h:843
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:842
struct AudioIO::PlaybackSchedule mPlaybackSchedule
void AudioIO::ClearRecordingException ( )
inlineprivate

Definition at line 919 of file AudioIO.h.

Referenced by StartStream(), and StopStream().

920  { if (mRecordingException) wxAtomicDec( mRecordingException ); }
wxAtomicInt mRecordingException
Definition: AudioIO.h:916
void AudioIO::FillBuffers ( )
private

Definition at line 3743 of file AudioIO.cpp.

References SampleBuffer::Allocate(), sampleCount::as_double(), ClearSamples(), AudioIO::RecordingSchedule::Consumed(), AutoSaveFile::EndTag(), floatSample, format, GetCommonlyAvailCapture(), GetCommonlyFreePlayback(), GetCommonlyReadyPlayback(), GuardedCall(), AudioIO::PlaybackSchedule::Interactive(), AutoSaveFile::IsEmpty(), IsStreamActive(), limitSampleBufferSize(), AudioIO::PlaybackSchedule::Looping(), lrint, mAudioThreadShouldCallFillBuffersOnce, mCaptureBuffers, mCaptureTracks, AudioIO::RecordingSchedule::mCrossfadeData, mFactor, min(), AudioIO::TimeQueue::mLastTime, AudioIO::RecordingSchedule::mLatencyCorrected, mListener, mMinCaptureSecsToCopy, mPlaybackBuffers, mPlaybackMixers, mPlaybackQueueMinimum, mPlaybackSamplesToCopy, mPlaybackSchedule, mPlaybackTracks, AudioIO::RecordingSchedule::mPosition, mRate, mRecordingException, mRecordingSchedule, mResample, mScrubDuration, mScrubSpeed, mScrubState, mSilentScrub, mTimeQueue, AudioIO::PlaybackSchedule::mWarpedTime, AudioIOListener::OnAudioIONewBlockFiles(), AudioIO::PlaybackSchedule::PLAY_AT_SPEED, AudioIO::PlaybackSchedule::PLAY_LOOPED, AudioIO::PlaybackSchedule::PLAY_SCRUB, AudioIO::PlaybackSchedule::PlayingStraight(), AudioIO::TimeQueue::Producer(), SampleBuffer::ptr(), AudioIO::PlaybackSchedule::RealTimeAdvance(), AudioIO::PlaybackSchedule::RealTimeRemaining(), AudioIO::PlaybackSchedule::RealTimeRestart(), SetRecordingException(), AutoSaveFile::StartTag(), StopStream(), AudioIO::RecordingSchedule::ToConsume(), AudioIO::RecordingSchedule::ToDiscard(), AudioIO::RecordingSchedule::TotalCorrection(), AutoSaveFile::WriteAttr(), and AutoSaveFile::WriteSubTree().

Referenced by AudioThread::Entry().

3744 {
3745  unsigned int i;
3746 
3747  auto delayedHandler = [this] ( AudacityException * pException ) {
3748  // In the main thread, stop recording
3749  // This is one place where the application handles disk
3750  // exhaustion exceptions from wave track operations, without rolling
3751  // back to the last pushed undo state. Instead, partial recording
3752  // results are pushed as a NEW undo state. For this reason, as
3753  // commented elsewhere, we want an exception safety guarantee for
3754  // the output wave tracks, after the failed append operation, that
3755  // the tracks remain as they were after the previous successful
3756  // (block-level) appends.
3757 
3758  // Note that the Flush in StopStream() may throw another exception,
3759  // but StopStream() contains that exception, and the logic in
3760  // AudacityException::DelayedHandlerAction prevents redundant message
3761  // boxes.
3762  StopStream();
3763  DefaultDelayedHandlerAction{}( pException );
3764  };
3765 
3766  if (mPlaybackTracks.size() > 0)
3767  {
3768  // Though extremely unlikely, it is possible that some buffers
3769  // will have more samples available than others. This could happen
3770  // if we hit this code during the PortAudio callback. To keep
3771  // things simple, we only write as much data as is vacant in
3772  // ALL buffers, and advance the global time by that much.
3773  auto nAvailable = GetCommonlyFreePlayback();
3774 
3775  //
3776  // Don't fill the buffers at all unless we can do the
3777  // full mMaxPlaybackSecsToCopy. This improves performance
3778  // by not always trying to process tiny chunks, eating the
3779  // CPU unnecessarily.
3780  //
3781  // The exception is if we're at the end of the selected
3782  // region - then we should just fill the buffer.
3783  //
3784  // May produce a larger amount when initially priming the buffer, or
3785  // perhaps again later in play to avoid underfilling the queue and falling
3786  // behind the real-time demand on the consumer side in the callback.
3787  auto nReady = GetCommonlyReadyPlayback();
3788  auto nNeeded =
3790 
3791  // wxASSERT( nNeeded <= nAvailable );
3792 
3793  auto realTimeRemaining = mPlaybackSchedule.RealTimeRemaining();
3794  if (nAvailable >= mPlaybackSamplesToCopy ||
3796  nAvailable / mRate >= realTimeRemaining))
3797  {
3798  // Limit maximum buffer size (increases performance)
3799  auto available = std::min( nAvailable,
3800  std::max( nNeeded, mPlaybackSamplesToCopy ) );
3801 
3802  // msmeyer: When playing a very short selection in looped
3803  // mode, the selection must be copied to the buffer multiple
3804  // times, to ensure, that the buffer has a reasonable size
3805  // This is the purpose of this loop.
3806  // PRL: or, when scrubbing, we may get work repeatedly from the
3807  // user interface.
3808  bool done = false;
3809  do {
3810  // How many samples to produce for each channel.
3811  auto frames = available;
3812  bool progress = true;
3813  auto toProcess = frames;
3814 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
3816  // scrubbing and play-at-speed are not limited by the real time
3817  // and length accumulators
3818  toProcess =
3819  frames = limitSampleBufferSize(frames, mScrubDuration);
3820  else
3821 #endif
3822  {
3823  double deltat = frames / mRate;
3824  if (deltat > realTimeRemaining)
3825  {
3826  frames = realTimeRemaining * mRate;
3827  toProcess = frames;
3828  // Don't fall into an infinite loop, if loop-playing a selection
3829  // that is so short, it has no samples: detect that case
3830  progress =
3831  !(mPlaybackSchedule.Looping() &&
3832  mPlaybackSchedule.mWarpedTime == 0.0 && frames == 0);
3833  mPlaybackSchedule.RealTimeAdvance( realTimeRemaining );
3834  }
3835  else
3837  realTimeRemaining = mPlaybackSchedule.RealTimeRemaining();
3838  }
3839 
3840  if (!progress)
3841  frames = available, toProcess = 0;
3842 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
3844  toProcess = 0;
3845 #endif
3846 
3847  // Update the time queue. This must be done before writing to the
3848  // ring buffers of samples, for proper synchronization with the
3849  // consumer side in the PortAudio thread, which reads the time
3850  // queue after reading the sample queues. The sample queues use
3851  // atomic variables, the time queue doesn't.
3854  frames);
3855 
3856  for (i = 0; i < mPlaybackTracks.size(); i++)
3857  {
3858  // The mixer here isn't actually mixing: it's just doing
3859  // resampling, format conversion, and possibly time track
3860  // warping
3861  samplePtr warpedSamples;
3862 
3863  if (frames > 0)
3864  {
3865  size_t processed = 0;
3866  if ( toProcess )
3867  processed = mPlaybackMixers[i]->Process( toProcess );
3868  //wxASSERT(processed <= toProcess);
3869  warpedSamples = mPlaybackMixers[i]->GetBuffer();
3870  const auto put = mPlaybackBuffers[i]->Put(
3871  warpedSamples, floatSample, processed, frames - processed);
3872  // wxASSERT(put == frames);
3873  // but we can't assert in this thread
3874  wxUnusedVar(put);
3875  }
3876  }
3877 
3878  available -= frames;
3879  wxASSERT(available >= 0);
3880 
3881  switch (mPlaybackSchedule.mPlayMode)
3882  {
3883 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
3886  {
3887  mScrubDuration -= frames;
3888  wxASSERT(mScrubDuration >= 0);
3889  done = (available == 0);
3890  if (!done && mScrubDuration <= 0)
3891  {
3892  sampleCount startSample, endSample;
3893  mScrubState->Get(
3894  startSample, endSample, available, mScrubDuration);
3895  if (mScrubDuration < 0)
3896  {
3897  // Can't play anything
3898  // Stop even if we don't fill up available
3899  mScrubDuration = 0;
3900  done = true;
3901  }
3902  else
3903  {
3904  mSilentScrub = (endSample == startSample);
3905  double startTime, endTime;
3906  startTime = startSample.as_double() / mRate;
3907  endTime = endSample.as_double() / mRate;
3908  auto diff = (endSample - startSample).as_long_long();
3909  if (mScrubDuration == 0)
3910  mScrubSpeed = 0;
3911  else
3912  mScrubSpeed =
3913  double(diff) / mScrubDuration.as_double();
3914  if (!mSilentScrub)
3915  {
3916  for (i = 0; i < mPlaybackTracks.size(); i++)
3917  mPlaybackMixers[i]->SetTimesAndSpeed(
3918  startTime, endTime, fabs( mScrubSpeed ));
3919  }
3920  mTimeQueue.mLastTime = startTime;
3921  }
3922  }
3923  }
3924  break;
3925 #endif
3927  {
3928  done = !progress || (available == 0);
3929  // msmeyer: If playing looped, check if we are at the end of the buffer
3930  // and if yes, restart from the beginning.
3931  if (realTimeRemaining <= 0)
3932  {
3933  for (i = 0; i < mPlaybackTracks.size(); i++)
3934  mPlaybackMixers[i]->Restart();
3936  realTimeRemaining = mPlaybackSchedule.RealTimeRemaining();
3937  }
3938  }
3939  break;
3940  default:
3941  done = true;
3942  break;
3943  }
3944  } while (!done);
3945  }
3946  } // end of playback buffering
3947 
3948  if (!mRecordingException &&
3949  mCaptureTracks.size() > 0)
3950  GuardedCall( [&] {
3951  // start record buffering
3952  const auto avail = GetCommonlyAvailCapture(); // samples
3953  const auto remainingTime =
3954  std::max(0.0, mRecordingSchedule.ToConsume());
3955  // This may be a very big double number:
3956  const auto remainingSamples = remainingTime * mRate;
3957  bool latencyCorrected = true;
3958 
3959  double deltat = avail / mRate;
3960 
3962  deltat >= mMinCaptureSecsToCopy)
3963  {
3964  // Append captured samples to the end of the WaveTracks.
3965  // The WaveTracks have their own buffering for efficiency.
3966  AutoSaveFile blockFileLog;
3967  auto numChannels = mCaptureTracks.size();
3968 
3969  for( i = 0; i < numChannels; i++ )
3970  {
3971  sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
3972 
3973  AutoSaveFile appendLog;
3974  size_t discarded = 0;
3975 
3977  const auto correction = mRecordingSchedule.TotalCorrection();
3978  if (correction >= 0) {
3979  // Rightward shift
3980  // Once only (per track per recording), insert some initial
3981  // silence.
3982  size_t size = floor( correction * mRate * mFactor);
3983  SampleBuffer temp(size, trackFormat);
3984  ClearSamples(temp.ptr(), trackFormat, 0, size);
3985  mCaptureTracks[i]->Append(temp.ptr(), trackFormat,
3986  size, 1, &appendLog);
3987  }
3988  else {
3989  // Leftward shift
3990  // discard some samples from the ring buffers.
3991  size_t size = floor(
3993 
3994  // The ring buffer might have grown concurrently -- don't discard more
3995  // than the "avail" value noted above.
3996  discarded = mCaptureBuffers[i]->Discard(std::min(avail, size));
3997 
3998  if (discarded < size)
3999  // We need to visit this again to complete the
4000  // discarding.
4001  latencyCorrected = false;
4002  }
4003  }
4004 
4005  const float *pCrossfadeSrc = nullptr;
4006  size_t crossfadeStart = 0, totalCrossfadeLength = 0;
4007  if (i < mRecordingSchedule.mCrossfadeData.size())
4008  {
4009  // Do crossfading
4010  // The supplied crossfade samples are at the same rate as the track
4011  const auto &data = mRecordingSchedule.mCrossfadeData[i];
4012  totalCrossfadeLength = data.size();
4013  if (totalCrossfadeLength) {
4014  crossfadeStart =
4015  floor(mRecordingSchedule.Consumed() * mCaptureTracks[i]->GetRate());
4016  if (crossfadeStart < totalCrossfadeLength)
4017  pCrossfadeSrc = data.data() + crossfadeStart;
4018  }
4019  }
4020 
4021  wxASSERT(discarded <= avail);
4022  size_t toGet = avail - discarded;
4023  SampleBuffer temp;
4024  size_t size;
4026  if( mFactor == 1.0 )
4027  {
4028  // Take captured samples directly
4029  size = toGet;
4030  if (pCrossfadeSrc)
4031  // Change to float for crossfade calculation
4032  format = floatSample;
4033  else
4034  format = trackFormat;
4035  temp.Allocate(size, format);
4036  const auto got =
4037  mCaptureBuffers[i]->Get(temp.ptr(), format, toGet);
4038  // wxASSERT(got == toGet);
4039  // but we can't assert in this thread
4040  wxUnusedVar(got);
4041  if (double(size) > remainingSamples)
4042  size = floor(remainingSamples);
4043  }
4044  else
4045  {
4046  size = lrint(toGet * mFactor);
4047  format = floatSample;
4048  SampleBuffer temp1(toGet, floatSample);
4049  temp.Allocate(size, format);
4050  const auto got =
4051  mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, toGet);
4052  // wxASSERT(got == toGet);
4053  // but we can't assert in this thread
4054  wxUnusedVar(got);
4055  /* we are re-sampling on the fly. The last resampling call
4056  * must flush any samples left in the rate conversion buffer
4057  * so that they get recorded
4058  */
4059  if (toGet > 0 ) {
4060  if (double(toGet) > remainingSamples)
4061  toGet = floor(remainingSamples);
4062  const auto results =
4063  mResample[i]->Process(mFactor, (float *)temp1.ptr(), toGet,
4064  !IsStreamActive(), (float *)temp.ptr(), size);
4065  size = results.second;
4066  }
4067  }
4068 
4069  if (pCrossfadeSrc) {
4070  wxASSERT(format == floatSample);
4071  size_t crossfadeLength = std::min(size, totalCrossfadeLength - crossfadeStart);
4072  if (crossfadeLength) {
4073  auto ratio = double(crossfadeStart) / totalCrossfadeLength;
4074  auto ratioStep = 1.0 / totalCrossfadeLength;
4075  auto pCrossfadeDst = (float*)temp.ptr();
4076 
4077  // Crossfade loop here
4078  for (size_t ii = 0; ii < crossfadeLength; ++ii) {
4079  *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
4080  ++pCrossfadeSrc, ++pCrossfadeDst;
4081  ratio += ratioStep;
4082  }
4083  }
4084  }
4085 
4086  // Now append
4087  // see comment in second handler about guarantee
4088  mCaptureTracks[i]->Append(temp.ptr(), format,
4089  size, 1,
4090  &appendLog);
4091 
4092  if (!appendLog.IsEmpty())
4093  {
4094  blockFileLog.StartTag(wxT("recordingrecovery"));
4095  blockFileLog.WriteAttr(wxT("id"), mCaptureTracks[i]->GetAutoSaveIdent());
4096  blockFileLog.WriteAttr(wxT("channel"), (int)i);
4097  blockFileLog.WriteAttr(wxT("numchannels"), numChannels);
4098  blockFileLog.WriteSubTree(appendLog);
4099  blockFileLog.EndTag(wxT("recordingrecovery"));
4100  }
4101  } // end loop over capture channels
4102 
4103  // Now update the recording shedule position
4104  mRecordingSchedule.mPosition += avail / mRate;
4105  mRecordingSchedule.mLatencyCorrected = latencyCorrected;
4106 
4107  if (mListener && !blockFileLog.IsEmpty())
4108  mListener->OnAudioIONewBlockFiles(blockFileLog);
4109  }
4110  // end of record buffering
4111  },
4112  // handler
4113  [this] ( AudacityException *pException ) {
4114  if ( pException ) {
4115  // So that we don't attempt to fill the recording buffer again
4116  // before the main thread stops recording
4118  return ;
4119  }
4120  else
4121  // Don't want to intercept other exceptions (?)
4122  throw;
4123  },
4124  delayedHandler
4125  );
4126 }
size_t GetCommonlyAvailCapture()
Get the number of audio samples ready in all of the recording buffers.
Definition: AudioIO.cpp:3259
void StartTag(const wxString &name) override
void StopStream()
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:2408
size_t GetCommonlyReadyPlayback()
Get the number of audio samples ready in all of the playback buffers.
Definition: AudioIO.cpp:3247
double mMinCaptureSecsToCopy
Definition: AudioIO.h:829
bool Interactive() const
Definition: AudioIO.h:1047
double RealTimeRemaining() const
Definition: AudioIO.cpp:5666
root of a hierarchy of classes that are thrown and caught by Audacity.
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
void WriteAttr(const wxString &name, const wxString &value) override
bool IsEmpty() const
double TotalCorrection() const
Definition: AudioIO.h:949
struct AudioIO::TimeQueue mTimeQueue
double mScrubSpeed
Definition: AudioIO.h:910
sampleCount mScrubDuration
Definition: AudioIO.h:911
SampleBuffer & Allocate(size_t count, sampleFormat format)
Definition: SampleFormat.h:67
double as_double() const
Definition: Types.h:88
struct AudioIO::RecordingSchedule mRecordingSchedule
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2753
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
void Producer(const PlaybackSchedule &schedule, double rate, double scrubSpeed, size_t nSamples)
Definition: AudioIO.cpp:5591
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:807
void WriteSubTree(const AutoSaveFile &value)
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:813
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:178
wxAtomicInt mRecordingException
Definition: AudioIO.h:916
size_t GetCommonlyFreePlayback()
Get the number of audio samples free in all of the playback buffers.
Definition: AudioIO.cpp:3236
size_t mPlaybackQueueMinimum
Occupancy of the queue we try to maintain, with bigger batches if needed.
Definition: AudioIO.h:827
void EndTag(const wxString &name) override
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
int format
Definition: ExportPCM.cpp:56
double Consumed() const
Definition: AudioIO.cpp:5694
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:809
double ToDiscard() const
Definition: AudioIO.cpp:5699
sampleFormat
Definition: Types.h:188
double ToConsume() const
Definition: AudioIO.cpp:5689
#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:881
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:841
samplePtr ptr() const
Definition: SampleFormat.h:81
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
bool PlayingStraight() const
Definition: AudioIO.h:1043
PRCrossfadeData mCrossfadeData
Definition: AudioIO.h:942
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
virtual void OnAudioIONewBlockFiles(const AutoSaveFile &blockFileLog)=0
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
double mFactor
Definition: AudioIO.h:816
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
Definition: AudioIO.h:825
bool Looping() const
Definition: AudioIO.h:1044
void RealTimeAdvance(double increment)
Definition: AudioIO.cpp:5671
struct AudioIO::PlaybackSchedule mPlaybackSchedule
void SetRecordingException()
Definition: AudioIO.h:917
bool mSilentScrub
Definition: AudioIO.h:909
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 
)

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

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

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

3103 {
3104  // Check if we can use the cached value
3105  if (mCachedBestRateIn != 0.0 && mCachedBestRateIn == sampleRate) {
3106  return mCachedBestRateOut;
3107  }
3108 
3109  // In order to cache the value, all early returns should instead set retval
3110  // and jump to finished
3111  double retval;
3112 
3113  std::vector<long> rates;
3114  if (capturing) wxLogDebug(wxT("AudioIO::GetBestRate() for capture"));
3115  if (playing) wxLogDebug(wxT("AudioIO::GetBestRate() for playback"));
3116  wxLogDebug(wxT("GetBestRate() suggested rate %.0lf Hz"), sampleRate);
3117 
3118  if (capturing && !playing) {
3119  rates = GetSupportedCaptureRates(-1, sampleRate);
3120  }
3121  else if (playing && !capturing) {
3122  rates = GetSupportedPlaybackRates(-1, sampleRate);
3123  }
3124  else { // we assume capturing and playing - the alternative would be a
3125  // bit odd
3126  rates = GetSupportedSampleRates(-1, -1, sampleRate);
3127  }
3128  /* rem rates is the array of hardware-supported sample rates (in the current
3129  * configuration), sampleRate is the Project Rate (desired sample rate) */
3130  long rate = (long)sampleRate;
3131 
3132  if (make_iterator_range(rates).contains(rate)) {
3133  wxLogDebug(wxT("GetBestRate() Returning %.0ld Hz"), rate);
3134  retval = rate;
3135  goto finished;
3136  /* the easy case - the suggested rate (project rate) is in the list, and
3137  * we can just accept that and send back to the caller. This should be
3138  * the case for most users most of the time (all of the time on
3139  * Win MME as the OS does resampling) */
3140  }
3141 
3142  /* if we get here, there is a problem - the project rate isn't supported
3143  * on our hardware, so we can't us it. Need to come up with an alternative
3144  * rate to use. The process goes like this:
3145  * * If there are no rates to pick from, we're stuck and return 0 (error)
3146  * * If there are some rates, we pick the next one higher than the requested
3147  * rate to use.
3148  * * If there aren't any higher, we use the highest available rate */
3149 
3150  if (rates.empty()) {
3151  /* we're stuck - there are no supported rates with this hardware. Error */
3152  wxLogDebug(wxT("GetBestRate() Error - no supported sample rates"));
3153  retval = 0.0;
3154  goto finished;
3155  }
3156  int i;
3157  for (i = 0; i < (int)rates.size(); i++) // for each supported rate
3158  {
3159  if (rates[i] > rate) {
3160  // supported rate is greater than requested rate
3161  wxLogDebug(wxT("GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
3162  retval = rates[i];
3163  goto finished;
3164  }
3165  }
3166 
3167  wxLogDebug(wxT("GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
3168  retval = rates.back(); // the highest available rate
3169  goto finished;
3170 
3171 finished:
3172  mCachedBestRateIn = sampleRate;
3173  mCachedBestRateOut = retval;
3174  return retval;
3175 }
static double mCachedBestRateIn
Definition: AudioIO.h:898
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:3038
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:596
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:2972
static double mCachedBestRateOut
Definition: AudioIO.h:899
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:2910
sampleFormat AudioIO::GetCaptureFormat ( )
inline

Definition at line 540 of file AudioIO.h.

540 { return mCaptureFormat; }
sampleFormat mCaptureFormat
Definition: AudioIO.h:839
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 3259 of file AudioIO.cpp.

References mCaptureBuffers, mCaptureTracks, and min().

Referenced by FillBuffers().

3260 {
3261  auto commonlyAvail = mCaptureBuffers[0]->AvailForGet();
3262  for (unsigned i = 1; i < mCaptureTracks.size(); ++i)
3263  commonlyAvail = std::min(commonlyAvail,
3264  mCaptureBuffers[i]->AvailForGet());
3265  return commonlyAvail;
3266 }
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:809
int min(int a, int b)
size_t AudioIO::GetCommonlyFreePlayback ( )
private

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

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

Definition at line 3236 of file AudioIO.cpp.

References min(), mPlaybackBuffers, and mPlaybackTracks.

Referenced by FillBuffers().

3237 {
3238  auto commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
3239  for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
3240  commonlyAvail = std::min(commonlyAvail,
3241  mPlaybackBuffers[i]->AvailForPut());
3242  // MB: subtract a few samples because the code in FillBuffers has rounding
3243  // errors
3244  return commonlyAvail - std::min(size_t(10), commonlyAvail);
3245 }
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
int min(int a, int b)
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
size_t AudioIO::GetCommonlyReadyPlayback ( )
private

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

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

Definition at line 3247 of file AudioIO.cpp.

References min(), mPlaybackBuffers, and mPlaybackTracks.

Referenced by AudioCallback(), and FillBuffers().

3248 {
3249  if (mPlaybackTracks.empty())
3250  return 0;
3251 
3252  auto commonlyAvail = mPlaybackBuffers[0]->AvailForGet();
3253  for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
3254  commonlyAvail = std::min(commonlyAvail,
3255  mPlaybackBuffers[i]->AvailForGet());
3256  return commonlyAvail;
3257 }
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
int min(int a, int b)
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
wxString AudioIO::GetDeviceInfo ( )

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

Definition at line 3398 of file AudioIO.cpp.

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

Referenced by AudacityProject::OnAudioDeviceInfo().

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

1213 {
1214 #if defined(USE_PORTMIXER)
1215 
1216  wxArrayString deviceNames;
1217 
1218  if( mPortMixer )
1219  {
1220  int numSources = Px_GetNumInputSources(mPortMixer);
1221  for( int source = 0; source < numSources; source++ )
1222  deviceNames.Add(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
1223  }
1224  else
1225  {
1226  wxLogDebug(wxT("AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
1227  }
1228 
1229  return deviceNames;
1230 
1231 #else
1232 
1233  wxArrayString blank;
1234 
1235  return blank;
1236 
1237 #endif
1238 }
wxLongLong AudioIO::GetLastPlaybackTime ( ) const
inline

Definition at line 389 of file AudioIO.h.

Referenced by AudacityProject::SeekWhenAudioActive().

389 { return mLastPlaybackTimeMillis; }
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:845
double AudioIO::GetLastScrubTime ( ) const

return the ending time of the last scrub interval.

Referenced by Scrubber::ContinueScrubbingPoll().

AudioIOListener* AudioIO::GetListener ( )
inline

Definition at line 324 of file AudioIO.h.

Referenced by AudacityProject::OnCloseWindow().

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

Definition at line 1171 of file AudioIO.cpp.

References mEmulateMixerOutputVol, mInputMixerWorks, and mMixerOutputVol.

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

1173 {
1174 #if defined(USE_PORTMIXER)
1175 
1176  PxMixer *mixer = mPortMixer;
1177 
1178  if( mixer )
1179  {
1180  *recordDevice = Px_GetCurrentInputSource(mixer);
1181 
1182  if (mInputMixerWorks)
1183  *recordVolume = Px_GetInputVolume(mixer);
1184  else
1185  *recordVolume = 1.0f;
1186 
1188  *playbackVolume = mMixerOutputVol;
1189  else
1190  *playbackVolume = Px_GetPCMOutputVolume(mixer);
1191 
1192  return;
1193  }
1194 
1195 #endif
1196 
1197  *recordDevice = 0;
1198  *recordVolume = 1.0f;
1199  *playbackVolume = mMixerOutputVol;
1200 }
float mMixerOutputVol
Definition: AudioIO.h:879
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:878
bool mEmulateMixerOutputVol
Definition: AudioIO.h:870
unsigned AudioIO::GetNumCaptureChannels ( ) const
inline
unsigned AudioIO::GetNumPlaybackChannels ( ) const
inline

Definition at line 541 of file AudioIO.h.

Referenced by ControlToolBar::StartScrolling().

541 { return mNumPlaybackChannels; }
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
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 3082 of file AudioIO.cpp.

References GetSupportedSampleRates(), and make_iterator_range().

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

3083 {
3084  auto rates = GetSupportedSampleRates();
3085 
3086  if (make_iterator_range(rates).contains(44100))
3087  return 44100;
3088 
3089  if (make_iterator_range(rates).contains(48000))
3090  return 48000;
3091 
3092  // if there are no supported rates, the next bit crashes. So check first,
3093  // and give them a "sensible" value if there are no valid values. They
3094  // will still get an error later, but with any luck may have changed
3095  // something by then. It's no worse than having an invalid default rate
3096  // stored in the preferences, which we don't check for
3097  if (rates.empty()) return 44100;
3098 
3099  return rates.back();
3100 }
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:3038
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:596
AudacityProject* AudioIO::GetOwningProject ( ) const
inline

Definition at line 390 of file AudioIO.h.

Referenced by ControlToolBar::CanStopAudioStream().

390 { return mOwningProject; }
AudacityProject * mOwningProject
Definition: AudioIO.h:859
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 3282 of file AudioIO.cpp.

References DeviceName(), and gPrefs.

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

3283 {
3284  wxString devName(devNameArg);
3285  // if we don't get given a device, look up the preferences
3286  if (devName.IsEmpty())
3287  {
3288  devName = gPrefs->Read(wxT("/AudioIO/PlaybackDevice"), wxT(""));
3289  }
3290 
3291  wxString hostName = gPrefs->Read(wxT("/AudioIO/Host"), wxT(""));
3292  PaHostApiIndex hostCnt = Pa_GetHostApiCount();
3293  PaHostApiIndex hostNum;
3294  for (hostNum = 0; hostNum < hostCnt; hostNum++)
3295  {
3296  const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
3297  if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
3298  {
3299  for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
3300  {
3301  PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
3302 
3303  const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
3304  if (dinfo && DeviceName(dinfo) == devName && dinfo->maxOutputChannels > 0 )
3305  {
3306  // this device name matches the stored one, and works.
3307  // So we say this is the answer and return it
3308  return deviceNum;
3309  }
3310  }
3311 
3312  // The device wasn't found so use the default for this host.
3313  // LL: At this point, preferences and active no longer match.
3314  return hinfo->defaultOutputDevice;
3315  }
3316  }
3317 
3318  // The host wasn't found, so use the default output device.
3319  // FIXME: TRAP_ERR PaErrorCode not handled well (this code is similar to input code
3320  // and the input side has more comments.)
3321 
3322  PaDeviceIndex deviceNum = Pa_GetDefaultOutputDevice();
3323 
3324  // Sometimes PortAudio returns -1 if it cannot find a suitable default
3325  // device, so we just use the first one available
3326  //
3327  // LL: At this point, preferences and active no longer match
3328  //
3329  // And I can't imagine how far we'll get specifying an "invalid" index later
3330  // on...are we certain "0" even exists?
3331  if (deviceNum < 0) {
3332  wxASSERT(false);
3333  deviceNum = 0;
3334  }
3335 
3336  return deviceNum;
3337 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:961
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 3339 of file AudioIO.cpp.

References DeviceName(), and gPrefs.

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

3340 {
3341  wxString devName(devNameArg);
3342  // if we don't get given a device, look up the preferences
3343  if (devName.IsEmpty())
3344  {
3345  devName = gPrefs->Read(wxT("/AudioIO/RecordingDevice"), wxT(""));
3346  }
3347 
3348  wxString hostName = gPrefs->Read(wxT("/AudioIO/Host"), wxT(""));
3349  PaHostApiIndex hostCnt = Pa_GetHostApiCount();
3350  PaHostApiIndex hostNum;
3351  for (hostNum = 0; hostNum < hostCnt; hostNum++)
3352  {
3353  const PaHostApiInfo *hinfo = Pa_GetHostApiInfo(hostNum);
3354  if (hinfo && wxString(wxSafeConvertMB2WX(hinfo->name)) == hostName)
3355  {
3356  for (PaDeviceIndex hostDevice = 0; hostDevice < hinfo->deviceCount; hostDevice++)
3357  {
3358  PaDeviceIndex deviceNum = Pa_HostApiDeviceIndexToDeviceIndex(hostNum, hostDevice);
3359 
3360  const PaDeviceInfo *dinfo = Pa_GetDeviceInfo(deviceNum);
3361  if (dinfo && DeviceName(dinfo) == devName && dinfo->maxInputChannels > 0 )
3362  {
3363  // this device name matches the stored one, and works.
3364  // So we say this is the answer and return it
3365  return deviceNum;
3366  }
3367  }
3368 
3369  // The device wasn't found so use the default for this host.
3370  // LL: At this point, preferences and active no longer match.
3371  return hinfo->defaultInputDevice;
3372  }
3373  }
3374 
3375  // The host wasn't found, so use the default input device.
3376  // FIXME: TRAP_ERR PaErrorCode not handled well in getRecordDevIndex()
3377  PaDeviceIndex deviceNum = Pa_GetDefaultInputDevice();
3378 
3379  // Sometimes PortAudio returns -1 if it cannot find a suitable default
3380  // device, so we just use the first one available
3381  // PortAudio has an error reporting function. We should log/report the error?
3382  //
3383  // LL: At this point, preferences and active no longer match
3384  //
3385  // And I can't imagine how far we'll get specifying an "invalid" index later
3386  // on...are we certain "0" even exists?
3387  if (deviceNum < 0) {
3388  // JKC: This ASSERT will happen if you run with no config file
3389  // This happens once. Config file will exist on the next run.
3390  // TODO: Look into this a bit more. Could be relevant to blank Device Toolbar.
3391  wxASSERT(false);
3392  deviceNum = 0;
3393  }
3394 
3395  return deviceNum;
3396 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:961
double AudioIO::GetStreamTime ( )

During playback, the track time most recently played.

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

Definition at line 2899 of file AudioIO.cpp.

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

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

2900 {
2901  // Track time readout for the main thread
2902 
2903  if( !IsStreamActive() )
2904  return BAD_STREAM_TIME;
2905 
2907 }
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2753
#define BAD_STREAM_TIME
Definition: AudioIO.h:81
struct AudioIO::PlaybackSchedule mPlaybackSchedule
double NormalizeTrackTime() const
Normalizes mTime, clamping it and handling gaps from cut preview.
Definition: AudioIO.cpp:2861
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 2972 of file AudioIO.cpp.

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

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

2973 {
2974  if (devIndex == -1)
2975  { // not given a device, look up in prefs / default
2976  devIndex = getRecordDevIndex();
2977  }
2978 
2979  // Check if we can use the cached rates
2980  if (mCachedCaptureIndex != -1 && devIndex == mCachedCaptureIndex
2981  && (rate == 0.0 || make_iterator_range(mCachedCaptureRates).contains(rate)))
2982  {
2983  return mCachedCaptureRates;
2984  }
2985 
2986  std::vector<long> supported;
2987  int irate = (int)rate;
2988  const PaDeviceInfo* devInfo = NULL;
2989  int i;
2990 
2991  devInfo = Pa_GetDeviceInfo(devIndex);
2992 
2993  if (!devInfo)
2994  {
2995  wxLogDebug(wxT("GetSupportedCaptureRates() Could not get device info!"));
2996  return supported;
2997  }
2998 
2999  double latencyDuration = DEFAULT_LATENCY_DURATION;
3000  long recordChannels = 1;
3001  gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration);
3002  gPrefs->Read(wxT("/AudioIO/RecordChannels"), &recordChannels);
3003 
3004  // LLL: Remove when a proper method of determining actual supported
3005  // DirectSound rate is devised.
3006  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
3007  bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
3008 
3009  PaStreamParameters pars;
3010 
3011  pars.device = devIndex;
3012  pars.channelCount = recordChannels;
3013  pars.sampleFormat = paFloat32;
3014  pars.suggestedLatency = latencyDuration / 1000.0;
3015  pars.hostApiSpecificStreamInfo = NULL;
3016 
3017  for (i = 0; i < NumRatesToTry; i++)
3018  {
3019  // LLL: Remove when a proper method of determining actual supported
3020  // DirectSound rate is devised.
3021  if (!(isDirectSound && RatesToTry[i] > 200000))
3022  if (Pa_IsFormatSupported(&pars, NULL, RatesToTry[i]) == 0)
3023  supported.push_back(RatesToTry[i]);
3024  }
3025 
3026  if (irate != 0 && !make_iterator_range(supported).contains(irate))
3027  {
3028  // LLL: Remove when a proper method of determining actual supported
3029  // DirectSound rate is devised.
3030  if (!(isDirectSound && RatesToTry[i] > 200000))
3031  if (Pa_IsFormatSupported(&pars, NULL, irate) == 0)
3032  supported.push_back(irate);
3033  }
3034 
3035  return supported;
3036 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
static std::vector< long > mCachedCaptureRates
Definition: AudioIO.h:896
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:596
static int mCachedCaptureIndex
Definition: AudioIO.h:895
static const int NumRatesToTry
How many sample rates to try.
Definition: AudioIO.h:689
#define DEFAULT_LATENCY_DURATION
Definition: AudioIO.h:86
static const int RatesToTry[]
Array of audio sample rates to try to use.
Definition: AudioIO.h:687
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:3339
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 2910 of file AudioIO.cpp.

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

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

2911 {
2912  if (devIndex == -1)
2913  { // weren't given a device index, get the prefs / default one
2914  devIndex = getPlayDevIndex();
2915  }
2916 
2917  // Check if we can use the cached rates
2918  if (mCachedPlaybackIndex != -1 && devIndex == mCachedPlaybackIndex
2919  && (rate == 0.0 || make_iterator_range(mCachedPlaybackRates).contains(rate)))
2920  {
2921  return mCachedPlaybackRates;
2922  }
2923 
2924  std::vector<long> supported;
2925  int irate = (int)rate;
2926  const PaDeviceInfo* devInfo = NULL;
2927  int i;
2928 
2929  devInfo = Pa_GetDeviceInfo(devIndex);
2930 
2931  if (!devInfo)
2932  {
2933  wxLogDebug(wxT("GetSupportedPlaybackRates() Could not get device info!"));
2934  return supported;
2935  }
2936 
2937  // LLL: Remove when a proper method of determining actual supported
2938  // DirectSound rate is devised.
2939  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(devInfo->hostApi);
2940  bool isDirectSound = (hostInfo && hostInfo->type == paDirectSound);
2941 
2942  PaStreamParameters pars;
2943 
2944  pars.device = devIndex;
2945  pars.channelCount = 1;
2946  pars.sampleFormat = paFloat32;
2947  pars.suggestedLatency = devInfo->defaultHighOutputLatency;
2948  pars.hostApiSpecificStreamInfo = NULL;
2949 
2950  // JKC: PortAudio Errors handled OK here. No need to report them
2951  for (i = 0; i < NumRatesToTry; i++)
2952  {
2953  // LLL: Remove when a proper method of determining actual supported
2954  // DirectSound rate is devised.
2955  if (!(isDirectSound && RatesToTry[i] > 200000))
2956  if (Pa_IsFormatSupported(NULL, &pars, RatesToTry[i]) == 0)
2957  supported.push_back(RatesToTry[i]);
2958  }
2959 
2960  if (irate != 0 && !make_iterator_range(supported).contains(irate))
2961  {
2962  // LLL: Remove when a proper method of determining actual supported
2963  // DirectSound rate is devised.
2964  if (!(isDirectSound && RatesToTry[i] > 200000))
2965  if (Pa_IsFormatSupported(NULL, &pars, irate) == 0)
2966  supported.push_back(irate);
2967  }
2968 
2969  return supported;
2970 }
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3282
static int mCachedPlaybackIndex
Definition: AudioIO.h:893
static std::vector< long > mCachedPlaybackRates
Definition: AudioIO.h:894
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:596
static const int NumRatesToTry
How many sample rates to try.
Definition: AudioIO.h:689
static const int RatesToTry[]
Array of audio sample rates to try to use.
Definition: AudioIO.h:687
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 3038 of file AudioIO.cpp.

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

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

3039 {
3040  // Not given device indices, look up prefs
3041  if (playDevice == -1) {
3042  playDevice = getPlayDevIndex();
3043  }
3044  if (recDevice == -1) {
3045  recDevice = getRecordDevIndex();
3046  }
3047 
3048  // Check if we can use the cached rates
3049  if (mCachedPlaybackIndex != -1 && mCachedCaptureIndex != -1 &&
3050  playDevice == mCachedPlaybackIndex &&
3051  recDevice == mCachedCaptureIndex &&
3052  (rate == 0.0 || make_iterator_range(mCachedSampleRates).contains(rate)))
3053  {
3054  return mCachedSampleRates;
3055  }
3056 
3057  auto playback = GetSupportedPlaybackRates(playDevice, rate);
3058  auto capture = GetSupportedCaptureRates(recDevice, rate);
3059  int i;
3060 
3061  // Return only sample rates which are in both arrays
3062  std::vector<long> result;
3063 
3064  for (i = 0; i < (int)playback.size(); i++)
3065  if (make_iterator_range(capture).contains(playback[i]))
3066  result.push_back(playback[i]);
3067 
3068  // If this yields no results, use the default sample rates nevertheless
3069 /* if (result.IsEmpty())
3070  {
3071  for (i = 0; i < NumStandardRates; i++)
3072  result.Add(StandardRates[i]);
3073  }*/
3074 
3075  return result;
3076 }
static std::vector< long > mCachedSampleRates
Definition: AudioIO.h:897
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3282
static int mCachedPlaybackIndex
Definition: AudioIO.h:893
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:596
static int mCachedCaptureIndex
Definition: AudioIO.h:895
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:2972
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:2910
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:3339
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 1240 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().

1241 {
1242  // This should not happen, but it would screw things up if it did.
1243  // Vaughan, 2010-10-08: But it *did* happen, due to a bug, and nobody
1244  // caught it because this method just returned. Added wxASSERT().
1245  wxASSERT(!IsStreamActive());
1246  if (IsStreamActive())
1247  return;
1248 
1249  // get the selected record and playback devices
1250  const int playDeviceNum = getPlayDevIndex();
1251  const int recDeviceNum = getRecordDevIndex();
1252 
1253  // If no change needed, return
1254  if (mCachedPlaybackIndex == playDeviceNum &&
1255  mCachedCaptureIndex == recDeviceNum)
1256  return;
1257 
1258  // cache playback/capture rates
1261  mCachedSampleRates = GetSupportedSampleRates(playDeviceNum, recDeviceNum);
1262  mCachedPlaybackIndex = playDeviceNum;
1263  mCachedCaptureIndex = recDeviceNum;
1264  mCachedBestRateIn = 0.0;
1265 
1266 #if defined(USE_PORTMIXER)
1267 
1268  // if we have a PortMixer object, close it down
1269  if (mPortMixer) {
1270  #if __WXMAC__
1271  // on the Mac we must make sure that we restore the hardware playthrough
1272  // state of the sound device to what it was before, because there isn't
1273  // a UI for this (!)
1274  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1275  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1276  mPreviousHWPlaythrough = -1.0;
1277  #endif
1278  Px_CloseMixer(mPortMixer);
1279  mPortMixer = NULL;
1280  }
1281 
1282  // that might have given us no rates whatsoever, so we have to guess an
1283  // answer to do the next bit
1284  int numrates = mCachedSampleRates.size();
1285  int highestSampleRate;
1286  if (numrates > 0)
1287  {
1288  highestSampleRate = mCachedSampleRates[numrates - 1];
1289  }
1290  else
1291  { // we don't actually have any rates that work for Rec and Play. Guess one
1292  // to use for messing with the mixer, which doesn't actually do either
1293  highestSampleRate = 44100;
1294  // mCachedSampleRates is still empty, but it's not used again, so
1295  // can ignore
1296  }
1297  mInputMixerWorks = false;
1298  mEmulateMixerOutputVol = true;
1299  mMixerOutputVol = 1.0;
1300 
1301  int error;
1302  // This tries to open the device with the samplerate worked out above, which
1303  // will be the highest available for play and record on the device, or
1304  // 44.1kHz if the info cannot be fetched.
1305 
1306  PaStream *stream;
1307 
1308  PaStreamParameters playbackParameters;
1309 
1310  playbackParameters.device = playDeviceNum;
1311  playbackParameters.sampleFormat = paFloat32;
1312  playbackParameters.hostApiSpecificStreamInfo = NULL;
1313  playbackParameters.channelCount = 1;
1314  if (Pa_GetDeviceInfo(playDeviceNum))
1315  playbackParameters.suggestedLatency =
1316  Pa_GetDeviceInfo(playDeviceNum)->defaultLowOutputLatency;
1317  else
1318  playbackParameters.suggestedLatency = DEFAULT_LATENCY_CORRECTION/1000.0;
1319 
1320  PaStreamParameters captureParameters;
1321 
1322  captureParameters.device = recDeviceNum;
1323  captureParameters.sampleFormat = paFloat32;;
1324  captureParameters.hostApiSpecificStreamInfo = NULL;
1325  captureParameters.channelCount = 1;
1326  if (Pa_GetDeviceInfo(recDeviceNum))
1327  captureParameters.suggestedLatency =
1328  Pa_GetDeviceInfo(recDeviceNum)->defaultLowInputLatency;
1329  else
1330  captureParameters.suggestedLatency = DEFAULT_LATENCY_CORRECTION/1000.0;
1331 
1332  // try opening for record and playback
1333  error = Pa_OpenStream(&stream,
1334  &captureParameters, &playbackParameters,
1335  highestSampleRate, paFramesPerBufferUnspecified,
1336  paClipOff | paDitherOff,
1337  audacityAudioCallback, NULL);
1338 
1339  if (!error) {
1340  // Try portmixer for this stream
1341  mPortMixer = Px_OpenMixer(stream, 0);
1342  if (!mPortMixer) {
1343  Pa_CloseStream(stream);
1344  error = true;
1345  }
1346  }
1347 
1348  // if that failed, try just for record
1349  if( error ) {
1350  error = Pa_OpenStream(&stream,
1351  &captureParameters, NULL,
1352  highestSampleRate, paFramesPerBufferUnspecified,
1353  paClipOff | paDitherOff,
1354  audacityAudioCallback, NULL);
1355 
1356  if (!error) {
1357  mPortMixer = Px_OpenMixer(stream, 0);
1358  if (!mPortMixer) {
1359  Pa_CloseStream(stream);
1360  error = true;
1361  }
1362  }
1363  }
1364 
1365  // finally, try just for playback
1366  if ( error ) {
1367  error = Pa_OpenStream(&stream,
1368  NULL, &playbackParameters,
1369  highestSampleRate, paFramesPerBufferUnspecified,
1370  paClipOff | paDitherOff,
1371  audacityAudioCallback, NULL);
1372 
1373  if (!error) {
1374  mPortMixer = Px_OpenMixer(stream, 0);
1375  if (!mPortMixer) {
1376  Pa_CloseStream(stream);
1377  error = true;
1378  }
1379  }
1380  }
1381 
1382  // FIXME: TRAP_ERR errors in HandleDeviceChange not reported.
1383  // if it's still not working, give up
1384  if( error )
1385  return;
1386 
1387  // Set input source
1388 #if USE_PORTMIXER
1389  int sourceIndex;
1390  if (gPrefs->Read(wxT("/AudioIO/RecordingSourceIndex"), &sourceIndex)) {
1391  if (sourceIndex >= 0) {
1392  //the current index of our source may be different because the stream
1393  //is a combination of two devices, so update it.
1394  sourceIndex = getRecordSourceIndex(mPortMixer);
1395  if (sourceIndex >= 0)
1396  SetMixer(sourceIndex);
1397  }
1398  }
1399 #endif
1400 
1401  // Determine mixer capabilities - if it doesn't support control of output
1402  // signal level, we emulate it (by multiplying this value by all outgoing
1403  // samples)
1404 
1405  mMixerOutputVol = Px_GetPCMOutputVolume(mPortMixer);
1406  mEmulateMixerOutputVol = false;
1407  Px_SetPCMOutputVolume(mPortMixer, 0.0);
1408  if (Px_GetPCMOutputVolume(mPortMixer) > 0.1)
1409  mEmulateMixerOutputVol = true;
1410  Px_SetPCMOutputVolume(mPortMixer, 0.2f);
1411  if (Px_GetPCMOutputVolume(mPortMixer) < 0.1 ||
1412  Px_GetPCMOutputVolume(mPortMixer) > 0.3)
1413  mEmulateMixerOutputVol = true;
1414  Px_SetPCMOutputVolume(mPortMixer, mMixerOutputVol);
1415 
1416  float inputVol = Px_GetInputVolume(mPortMixer);
1417  mInputMixerWorks = true; // assume it works unless proved wrong
1418  Px_SetInputVolume(mPortMixer, 0.0);
1419  if (Px_GetInputVolume(mPortMixer) > 0.1)
1420  mInputMixerWorks = false; // can't set to zero
1421  Px_SetInputVolume(mPortMixer, 0.2f);
1422  if (Px_GetInputVolume(mPortMixer) < 0.1 ||
1423  Px_GetInputVolume(mPortMixer) > 0.3)
1424  mInputMixerWorks = false; // can't set level accurately
1425  Px_SetInputVolume(mPortMixer, inputVol);
1426 
1427  Pa_CloseStream(stream);
1428 
1429 
1430  #if 0
1431  wxPrintf("PortMixer: Playback: %s Recording: %s\n",
1432  mEmulateMixerOutputVol? "emulated": "native",
1433  mInputMixerWorks? "hardware": "no control");
1434  #endif
1435 
1436  mMixerOutputVol = 1.0;
1437 
1438 #endif // USE_PORTMIXER
1439 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
static std::vector< long > mCachedSampleRates
Definition: AudioIO.h:897
static double mCachedBestRateIn
Definition: AudioIO.h:898
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:3038
float mMixerOutputVol
Definition: AudioIO.h:879
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:878
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2753
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3282
static int mCachedPlaybackIndex
Definition: AudioIO.h:893
#define DEFAULT_LATENCY_CORRECTION
Definition: AudioIO.h:87
static std::vector< long > mCachedPlaybackRates
Definition: AudioIO.h:894
bool mEmulateMixerOutputVol
Definition: AudioIO.h:870
static std::vector< long > mCachedCaptureRates
Definition: AudioIO.h:896
int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
Definition: AudioIO.cpp:4687
void SetMixer(int inputSource)
Definition: AudioIO.cpp:1139
static int mCachedCaptureIndex
Definition: AudioIO.h:895
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:2972
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:2910
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:3339
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 1202 of file AudioIO.cpp.

References mInputMixerWorks.

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

1203 {
1204  return mInputMixerWorks;
1205 }
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:878
bool AudioIO::IsAudioTokenActive ( int  token) const

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

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

References mStreamToken.

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

2773 {
2774  return ( token > 0 && token == mStreamToken );
2775 }
volatile int mStreamToken
Definition: AudioIO.h:814
bool AudioIO::IsAvailable ( AudacityProject projecT) const

Function to automatically set an acceptable volume.

Definition at line 2363 of file AudioIO.cpp.

References mOwningProject.

Referenced by EffectUIHost::Initialize().

2364 {
2365  return mOwningProject == NULL || mOwningProject == project;
2366 }
AudacityProject * mOwningProject
Definition: AudioIO.h:859
bool AudioIO::IsBusy ( ) const
bool AudioIO::IsCapturing ( ) const

Definition at line 5704 of file AudioIO.cpp.

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

Referenced by PlayIndicatorOverlayBase::Draw(), PlayIndicatorOverlay::OnTimer(), and AdornedRulerPanel::UpdateButtonStates().

5705 {
5706  // Includes a test of mTime, used in the main thread
5707  return IsStreamActive() &&
5708  GetNumCaptureChannels() > 0 &&
5711 }
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: AudioIO.h:1012
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:542
struct AudioIO::RecordingSchedule mRecordingSchedule
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2753
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:957
struct AudioIO::PlaybackSchedule mPlaybackSchedule
bool AudioIO::IsMonitoring ( ) const

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

Definition at line 2777 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().

2778 {
2779  return ( mPortStreamV19 && mStreamToken==0 );
2780 }
volatile int mStreamToken
Definition: AudioIO.h:814
PaStream * mPortStreamV19
Definition: AudioIO.h:832
bool AudioIO::IsPaused ( ) const

Find out if playback / recording is currently paused.

Definition at line 2713 of file AudioIO.cpp.

References mPaused.

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

2714 {
2715  return mPaused;
2716 }
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:831
bool AudioIO::IsScrubbing ( ) const
inline

Definition at line 358 of file AudioIO.h.

Referenced by ControlToolBar::OnPause().

358 { return IsBusy() && mScrubState != 0; }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2745
bool AudioIO::IsStreamActive ( ) const

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

References mPortStreamV19.

Referenced by ControlToolBar::CanStopAudioStream(), LabelTrack::DoCaptureKey(), AudacityProject::DoPlayStopSelect(), DeviceToolBar::EnableDisableButtons(), FillBuffers(), GetDeviceInfo(), GetStreamTime(), HandleDeviceChange(), EffectUIHost::Initialize(), AudacityProject::IsAudioActive(), IsCapturing(), 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().

2754 {
2755  bool isActive = false;
2756  // JKC: Not reporting any Pa error, but that looks OK.
2757  if( mPortStreamV19 )
2758  isActive = (Pa_IsStreamActive( mPortStreamV19 ) > 0);
2759 
2760 #ifdef EXPERIMENTAL_MIDI_OUT
2761  if( mMidiStreamActive && !mMidiOutputComplete )
2762  isActive = true;
2763 #endif
2764  return isActive;
2765 }
PaStream * mPortStreamV19
Definition: AudioIO.h:832
bool AudioIO::IsStreamActive ( int  token) const

Definition at line 2767 of file AudioIO.cpp.

References IsAudioTokenActive(), and IsStreamActive().

2768 {
2769  return (this->IsStreamActive() && this->IsAudioTokenActive(token));
2770 }
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2753
bool IsAudioTokenActive(int token) const
Returns true if the stream is active, or even if audio I/O is busy cleaning up its data or writing to...
Definition: AudioIO.cpp:2772
wxString AudioIO::LastPaErrorString ( )

Definition at line 1660 of file AudioIO.cpp.

References mLastPaError.

Referenced by ControlToolBar::DoRecord(), and StartMonitoring().

1661 {
1662  return wxString::Format(wxT("%d %s."), (int) mLastPaError, Pa_GetErrorText(mLastPaError));
1663 }
PaError mLastPaError
Definition: AudioIO.h:853
const std::vector< std::pair<double, double> >& AudioIO::LostCaptureIntervals ( )
inline

Definition at line 927 of file AudioIO.h.

Referenced by AudacityProject::OnAudioIOStopRecording().

928  { return mLostCaptureIntervals; }
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:922
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 1207 of file AudioIO.cpp.

References mEmulateMixerOutputVol.

Referenced by MixerToolBar::SetToolTips().

1208 {
1209  return mEmulateMixerOutputVol;
1210 }
bool mEmulateMixerOutputVol
Definition: AudioIO.h:870
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 355 of file AudioIO.h.

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

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

Definition at line 2368 of file AudioIO.cpp.

References mInputMeter, mOwningProject, and mRate.

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

2369 {
2370  if (!mOwningProject || mOwningProject == project)
2371  {
2372  if (meter)
2373  {
2374  mInputMeter = meter;
2375  mInputMeter->Reset(mRate, true);
2376  }
2377  else
2378  mInputMeter.Release();
2379  }
2380 }
AudacityProject * mOwningProject
Definition: AudioIO.h:859
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:860
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
void AudioIO::SetListener ( AudioIOListener listener)

Definition at line 4128 of file AudioIO.cpp.

References IsBusy(), and mListener.

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

4129 {
4130  if (IsBusy())
4131  return;
4132 
4133  mListener = listener;
4134 }
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2745
AudioIOListener * mListener
Definition: AudioIO.h:881
void AudioIO::SetMeters ( )
private

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

Definition at line 2394 of file AudioIO.cpp.

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

Referenced by StartPortAudioStream().

2395 {
2396  if (mInputMeter)
2397  mInputMeter->Reset(mRate, true);
2398  if (mOutputMeter)
2399  mOutputMeter->Reset(mRate, true);
2400 
2401  MixerBoard* pMixerBoard = mOwningProject->GetMixerBoard();
2402  if (pMixerBoard)
2403  pMixerBoard->ResetMeters(true);
2404 
2405  mUpdateMeters = true;
2406 }
MeterPanel * mOutputMeter
Definition: AudioIO.h:861
MixerBoard * GetMixerBoard()
Definition: Project.h:518
AudacityProject * mOwningProject
Definition: AudioIO.h:859
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:860
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
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:862
void ResetMeters(const bool bResetClipping)
void AudioIO::SetMixer ( int  inputSource)

Definition at line 1139 of file AudioIO.cpp.

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

1140 {
1141 #if defined(USE_PORTMIXER)
1142  int oldRecordSource = Px_GetCurrentInputSource(mPortMixer);
1143  if ( inputSource != oldRecordSource )
1144  Px_SetCurrentInputSource(mPortMixer, inputSource);
1145 #endif
1146 }
void AudioIO::SetMixer ( int  inputSource,
float  inputVolume,
float  playbackVolume 
)

Definition at line 1147 of file AudioIO.cpp.

References mMixerOutputVol, and SetMixer().

1149 {
1150  mMixerOutputVol = playbackVolume;
1151 
1152 #if defined(USE_PORTMIXER)
1153  PxMixer *mixer = mPortMixer;
1154 
1155  if( mixer )
1156  {
1157  float oldRecordVolume = Px_GetInputVolume(mixer);
1158  float oldPlaybackVolume = Px_GetPCMOutputVolume(mixer);
1159 
1160  SetMixer(inputSource);
1161  if( oldRecordVolume != recordVolume )
1162  Px_SetInputVolume(mixer, recordVolume);
1163  if( oldPlaybackVolume != playbackVolume )
1164  Px_SetPCMOutputVolume(mixer, playbackVolume);
1165 
1166  return;
1167  }
1168 #endif
1169 }
float mMixerOutputVol
Definition: AudioIO.h:879
void SetMixer(int inputSource)
Definition: AudioIO.cpp:1139
void AudioIO::SetPaused ( bool  state)

Pause and un-pause playback and recording.

Definition at line 2696 of file AudioIO.cpp.

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

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

2697 {
2698  if (state != mPaused)
2699  {
2700  if (state)
2701  {
2703  }
2704  else
2705  {
2707  }
2708  }
2709 
2710  mPaused = state;
2711 }
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:831
static EffectManager & Get()
void RealtimeSuspend()
void AudioIO::SetPlaybackMeter ( AudacityProject project,
MeterPanel meter 
)

Definition at line 2382 of file AudioIO.cpp.

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

Referenced by AudacityProject::SetPlaybackMeter().

2383 {
2384  if (!mOwningProject || mOwningProject == project)
2385  {
2386  mOutputMeter = meter;
2387  if (mOutputMeter)
2388  {
2389  mOutputMeter->Reset(mRate, true);
2390  }
2391  }
2392 }
MeterPanel * mOutputMeter
Definition: AudioIO.h:861
AudacityProject * mOwningProject
Definition: AudioIO.h:859
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
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 917 of file AudioIO.h.

Referenced by FillBuffers().

918  { wxAtomicInc( mRecordingException ); }
wxAtomicInt mRecordingException
Definition: AudioIO.h:916
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 1665 of file AudioIO.cpp.

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

Referenced by MeterPanel::StartMonitoring().

1666 {
1667  if ( mPortStreamV19 || mStreamToken )
1668  return;
1669 
1670  bool success;
1671  long captureChannels;
1672  auto captureFormat = QualityPrefs::SampleFormatChoice();
1673  gPrefs->Read(wxT("/AudioIO/RecordChannels"), &captureChannels, 2L);
1674  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
1675  int playbackChannels = 0;
1676 
1678  playbackChannels = 2;
1679 
1680  // FIXME: TRAP_ERR StartPortAudioStream (a PaError may be present)
1681  // but StartPortAudioStream function only returns true or false.
1682  mUsingAlsa = false;
1683  success = StartPortAudioStream(sampleRate, (unsigned int)playbackChannels,
1684  (unsigned int)captureChannels,
1685  captureFormat);
1686 
1687  if (!success) {
1688  wxString msg = wxString::Format(_("Error opening recording device.\nError code: %s"), gAudioIO->LastPaErrorString());
1689  ShowErrorDialog(mOwningProject, _("Error"), msg, wxT("Error_opening_sound_device"));
1690  return;
1691  }
1692 
1693  wxCommandEvent e(EVT_AUDIOIO_MONITOR);
1694  e.SetEventObject(mOwningProject);
1695  e.SetInt(true);
1696  wxTheApp->ProcessEvent(e);
1697 
1698  // FIXME: TRAP_ERR PaErrorCode 'noted' but not reported in StartMonitoring.
1699  // Now start the PortAudio stream!
1700  // TODO: ? Factor out and reuse error reporting code from end of
1701  // AudioIO::StartStream?
1702  mLastPaError = Pa_StartStream( mPortStreamV19 );
1703 
1704  // Update UI display only now, after all possibilities for error are past.
1705  if ((mLastPaError == paNoError) && mListener) {
1706  // advertise the chosen I/O sample rate to the UI
1707  mListener->OnAudioIORate((int)mRate);
1708  }
1709 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
bool mSoftwarePlaythrough
Definition: AudioIO.h:833
void ShowErrorDialog(wxWindow *parent, const wxString &dlogTitle, const wxString &message, const wxString &helpPage, const bool Close)
Displays an error dialog with a button that offers help.
wxString LastPaErrorString()
Definition: AudioIO.cpp:1660
volatile int mStreamToken
Definition: AudioIO.h:814
PaStream * mPortStreamV19
Definition: AudioIO.h:832
AudacityProject * mOwningProject
Definition: AudioIO.h:859
AudioIOListener * mListener
Definition: AudioIO.h:881
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
_("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:483
bool mUsingAlsa
Definition: AudioIO.h:890
virtual void OnAudioIORate(int rate)=0
static sampleFormat SampleFormatChoice()
PaError mLastPaError
Definition: AudioIO.h:853
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:1454
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 1454 of file AudioIO.cpp.

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

Referenced by StartMonitoring(), and StartStream().

1458 {
1459 #ifdef EXPERIMENTAL_MIDI_OUT
1460  mNumFrames = 0;
1461  mNumPauseFrames = 0;
1462  // we want this initial value to be way high. It should be
1463  // sufficient to assume AudioTime is zero and therefore
1464  // mSystemMinusAudioTime is SystemTime(), but we'll add 1000s
1465  // for good measure. On the first callback, this should be
1466  // reduced to SystemTime() - mT0, and note that mT0 is always
1467  // positive.
1468  mSystemMinusAudioTimePlusLatency =
1469  mSystemMinusAudioTime = SystemTime(mUsingAlsa) + 1000;
1470  mAudioOutLatency = 0.0; // set when stream is opened
1471  mCallbackCount = 0;
1472  mAudioFramesPerBuffer = 0;
1473 #endif
1475 
1476  // PRL: Protection from crash reported by David Bailes, involving starting
1477  // and stopping with frequent changes of active window, hard to reproduce
1478  if (!mOwningProject)
1479  return false;
1480 
1481  mInputMeter.Release();
1482  mOutputMeter = NULL;
1483 
1484  mLastPaError = paNoError;
1485  // pick a rate to do the audio I/O at, from those available. The project
1486  // rate is suggested, but we may get something else if it isn't supported
1487  mRate = GetBestRate(numCaptureChannels > 0, numPlaybackChannels > 0, sampleRate);
1488 
1489  // July 2016 (Carsten and Uwe)
1490  // BUG 193: Tell PortAudio sound card will handle 24 bit (under DirectSound) using
1491  // userData.
1492  int captureFormat_saved = captureFormat;
1493  // Special case: Our 24-bit sample format is different from PortAudio's
1494  // 3-byte packed format. So just make PortAudio return float samples,
1495  // since we need float values anyway to apply the gain.
1496  // ANSWER-ME: So we *never* actually handle 24-bit?! This causes mCapture to
1497  // be set to floatSample below.
1498  // JKC: YES that's right. Internally Audacity uses float, and float has space for
1499  // 24 bits as well as exponent. Actual 24 bit would require packing and
1500  // unpacking unaligned bytes and would be inefficient.
1501  // ANSWER ME: is floatSample 64 bit on 64 bit machines?
1502  if (captureFormat == int24Sample)
1503  captureFormat = floatSample;
1504 
1505  mNumPlaybackChannels = numPlaybackChannels;
1506  mNumCaptureChannels = numCaptureChannels;
1507 
1508  bool usePlayback = false, useCapture = false;
1509  PaStreamParameters playbackParameters{};
1510  PaStreamParameters captureParameters{};
1511 
1512  double latencyDuration = DEFAULT_LATENCY_DURATION;
1513  gPrefs->Read(wxT("/AudioIO/LatencyDuration"), &latencyDuration);
1514 
1515  if( numPlaybackChannels > 0)
1516  {
1517  usePlayback = true;
1518 
1519  // this sets the device index to whatever is "right" based on preferences,
1520  // then defaults
1521  playbackParameters.device = getPlayDevIndex();
1522 
1523  const PaDeviceInfo *playbackDeviceInfo;
1524  playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
1525 
1526  if( playbackDeviceInfo == NULL )
1527  return false;
1528 
1529  // regardless of source formats, we always mix to float
1530  playbackParameters.sampleFormat = paFloat32;
1531  playbackParameters.hostApiSpecificStreamInfo = NULL;
1532  playbackParameters.channelCount = mNumPlaybackChannels;
1533 
1535  playbackParameters.suggestedLatency =
1536  playbackDeviceInfo->defaultLowOutputLatency;
1537  else {
1538  // When using WASAPI, the suggested latency does not affect
1539  // the latency of the playback, but the position of playback is given as if
1540  // there was the suggested latency. This results in the last "suggested latency"
1541  // of a selection not being played. So for WASAPI use 0.0 for the suggested
1542  // latency regardless of user setting. See bug 1949.
1543  const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
1544  bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
1545  playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
1546  }
1547 
1549  }
1550 
1551  if( numCaptureChannels > 0)
1552  {
1553  useCapture = true;
1554  mCaptureFormat = captureFormat;
1555 
1556  const PaDeviceInfo *captureDeviceInfo;
1557  // retrieve the index of the device set in the prefs, or a sensible
1558  // default if it isn't set/valid
1559  captureParameters.device = getRecordDevIndex();
1560 
1561  captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
1562 
1563  if( captureDeviceInfo == NULL )
1564  return false;
1565 
1566  captureParameters.sampleFormat =
1568 
1569  captureParameters.hostApiSpecificStreamInfo = NULL;
1570  captureParameters.channelCount = mNumCaptureChannels;
1571 
1573  captureParameters.suggestedLatency =
1574  captureDeviceInfo->defaultHighInputLatency;
1575  else
1576  captureParameters.suggestedLatency = latencyDuration/1000.0;
1577 
1579  }
1580 
1581  SetMeters();
1582 
1583 #ifdef USE_PORTMIXER
1584 #ifdef __WXMSW__
1585  //mchinen nov 30 2010. For some reason Pa_OpenStream resets the input volume on windows.
1586  //so cache and restore after it.
1587  //The actual problem is likely in portaudio's pa_win_wmme.c OpenStream().
1588  float oldRecordVolume = Px_GetInputVolume(mPortMixer);
1589 #endif
1590 #endif
1591 
1592  // July 2016 (Carsten and Uwe)
1593  // BUG 193: Possibly tell portAudio to use 24 bit with DirectSound.
1594  int userData = 24;
1595  int* lpUserData = (captureFormat_saved == int24Sample) ? &userData : NULL;
1596 
1597  // (Linux, bug 1885) After scanning devices it takes a little time for the
1598  // ALSA device to be available, so allow retries.
1599  // On my test machine, no more than 3 attempts are required.
1600  unsigned int maxTries = 1;
1601 #ifdef __WXGTK__
1603  maxTries = 5;
1604 #endif
1605 
1606  for (unsigned int tries = 0; tries < maxTries; tries++) {
1607  mLastPaError = Pa_OpenStream( &mPortStreamV19,
1608  useCapture ? &captureParameters : NULL,
1609  usePlayback ? &playbackParameters : NULL,
1610  mRate, paFramesPerBufferUnspecified,
1611  paNoFlag,
1612  audacityAudioCallback, lpUserData );
1613  if (mLastPaError == paNoError) {
1614  break;
1615  }
1616  wxLogDebug("Attempt %u to open capture stream failed with: %d", 1 + tries, mLastPaError);
1617  wxMilliSleep(1000);
1618  }
1619 
1620 
1621 #if USE_PORTMIXER
1622 #ifdef __WXMSW__
1623  Px_SetInputVolume(mPortMixer, oldRecordVolume);
1624 #endif
1625  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
1626 
1627  #ifdef __WXMAC__
1628  if (mPortMixer) {
1629  if (Px_SupportsPlaythrough(mPortMixer)) {
1630  bool playthrough = false;
1631 
1632  mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
1633 
1634  // Bug 388. Feature not supported.
1635  //gPrefs->Read(wxT("/AudioIO/Playthrough"), &playthrough, false);
1636  if (playthrough)
1637  Px_SetPlaythrough(mPortMixer, 1.0);
1638  else
1639  Px_SetPlaythrough(mPortMixer, 0.0);
1640  }
1641  }
1642  #endif
1643  }
1644 #endif
1645 
1646 #ifdef EXPERIMENTAL_MIDI_OUT
1647  // We use audio latency to estimate how far ahead of DACS we are writing
1648  if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
1649  const PaStreamInfo* info = Pa_GetStreamInfo(mPortStreamV19);
1650  // this is an initial guess, but for PA/Linux/ALSA it's wrong and will be
1651  // updated with a better value:
1652  mAudioOutLatency = info->outputLatency;
1653  mSystemMinusAudioTimePlusLatency += mAudioOutLatency;
1654  }
1655 #endif
1656 
1657  return (mLastPaError == paNoError);
1658 }
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:2394
bool mSoftwarePlaythrough
Definition: AudioIO.h:833
MeterPanel * mOutputMeter
Definition: AudioIO.h:861
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3282
sampleFormat mCaptureFormat
Definition: AudioIO.h:839
MeterPanel * GetCaptureMeter()
Definition: Project.cpp:5142
PaStream * mPortStreamV19
Definition: AudioIO.h:832
int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
Definition: AudioIO.cpp:4687
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:3102
AudacityProject * mOwningProject
Definition: AudioIO.h:859
static PaSampleFormat AudacityToPortAudioSampleFormat(sampleFormat format)
Definition: AudioIO.cpp:1441
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
unsigned int mNumCaptureChannels
Definition: AudioIO.h:837
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:860
void SetCaptureMeter(AudacityProject *project, MeterPanel *meter)
Definition: AudioIO.cpp:2368
static DeviceManager * Instance()
Gets the singleton instance.
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
float GetTimeSinceRescan()
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:309
bool mUsingAlsa
Definition: AudioIO.h:890
MeterPanel * GetPlaybackMeter()
Definition: Project.cpp:5128
#define DEFAULT_LATENCY_DURATION
Definition: AudioIO.h:86
PaError mLastPaError
Definition: AudioIO.h:853
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:3339
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 1711 of file AudioIO.cpp.

References AllocateBuffers(), AudacityMessageBox(), TransportTracks::captureTracks, AudioIO::PlaybackSchedule::ClampTrackTime(), ClearRecordingException(), Scrubber::ContinueScrubbingPoll(), DEFAULT_LATENCY_CORRECTION, ENV_DB_KEY, ENV_DB_RANGE, floatSample, EffectManager::Get(), Track::GetLinked(), AudacityProject::GetScrubber(), AudioIO::PlaybackSchedule::GetTrackTime(), gPrefs, AudioIO::PlaybackSchedule::Init(), AudioIO::PlaybackSchedule::Interactive(), IsBusy(), LAT1CTOWX, AudioIOStartStreamOptions::listener, mAudioThreadFillBuffersLoopRunning, mAudioThreadShouldCallFillBuffersOnce, mCaptureBuffers, mCaptureTracks, AudioIO::RecordingSchedule::mCrossfadeData, AudioIO::TimeQueue::mData, mDetectDropouts, AudioIO::RecordingSchedule::mDuration, min(), mLastRecordingOffset, AudioIO::TimeQueue::mLastTime, AudioIO::RecordingSchedule::mLatencyCorrection, mListener, mLostCaptureIntervals, mLostSamples, mNextStreamToken, mNumCaptureChannels, mNumPlaybackChannels, mOwningProject, mPauseRec, mPlaybackBuffers, mPlaybackMixers, mPlaybackSchedule, mPlaybackTracks, mPortStreamV19, AudioIO::RecordingSchedule::mPreRoll, mRate, mRecordingSchedule, mResample, mScrubDuration, mScrubState, mSeek, mSilenceLevel, mSilentScrub, mSoftwarePlaythrough, mStreamToken, AudioIO::PlaybackSchedule::mT0, mTimeQueue, mUsingAlsa, AudioIOListener::OnAudioIORate(), AudioIOListener::OnAudioIOStartRecording(), AudioIOListener::OnAudioIOStopRecording(), AudioIOStartStreamOptions::pCrossfadeData, TransportTracks::playbackTracks, AudioIOStartStreamOptions::preRoll, AudioIOStartStreamOptions::pScrubbingOptions, AudioIOStartStreamOptions::pStartTime, AudioIOStartStreamOptions::rate, EffectManager::RealtimeAddProcessor(), AudioIO::PlaybackSchedule::RealTimeInit(), EffectManager::RealtimeInitialize(), AudioIO::PlaybackSchedule::ResetMode(), Scrubber::ScrubPollInterval_ms, AudacityApp::SetMissingAliasedFileWarningShouldShow(), AudioIO::PlaybackSchedule::SetTrackTime(), StartPortAudioStream(), StartStreamCleanup(), StopStream(), WarningDialogKey(), and wxGetApp().

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

1714 {
1715  mLostSamples = 0;
1716  mLostCaptureIntervals.clear();
1717  mDetectDropouts =
1718  gPrefs->Read( WarningDialogKey(wxT("DropoutDetected")), true ) != 0;
1719  auto cleanup = finally ( [this] { ClearRecordingException(); } );
1720 
1721  if( IsBusy() )
1722  return 0;
1723 
1724  const auto &sampleRate = options.rate;
1725 
1726  // We just want to set mStreamToken to -1 - this way avoids
1727  // an extremely rare but possible race condition, if two functions
1728  // somehow called StartStream at the same time...
1729  mStreamToken--;
1730  if (mStreamToken != -1)
1731  return 0;
1732 
1733  // TODO: we don't really need to close and reopen stream if the
1734  // format matches; however it's kind of tricky to keep it open...
1735  //
1736  // if (sampleRate == mRate &&
1737  // playbackChannels == mNumPlaybackChannels &&
1738  // captureChannels == mNumCaptureChannels &&
1739  // captureFormat == mCaptureFormat) {
1740 
1741  if (mPortStreamV19) {
1742  StopStream();
1743  while(mPortStreamV19)
1744  wxMilliSleep( 50 );
1745  }
1746 
1747 #ifdef __WXGTK__
1748  // Detect whether ALSA is the chosen host, and do the various involved MIDI
1749  // timing compensations only then.
1750  mUsingAlsa = (gPrefs->Read(wxT("/AudioIO/Host"), wxT("")) == "ALSA");
1751 #endif
1752 
1753  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
1754  gPrefs->Read(wxT("/AudioIO/SoundActivatedRecord"), &mPauseRec, false);
1755  int silenceLevelDB;
1756  gPrefs->Read(wxT("/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
1757  int dBRange;
1758  dBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
1759  if(silenceLevelDB < -dBRange)
1760  {
1761  silenceLevelDB = -dBRange + 3; // meter range was made smaller than SilenceLevel
1762  gPrefs->Write(ENV_DB_KEY, dBRange); // so set SilenceLevel reasonable
1763  gPrefs->Flush();
1764  }
1765  mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange; // meter goes -dBRange dB -> 0dB
1766 
1767  // Clamp pre-roll so we don't play before time 0
1768  const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
1769  mRecordingSchedule = {};
1770  mRecordingSchedule.mPreRoll = preRoll;
1772  (gPrefs->ReadDouble(wxT("/AudioIO/LatencyCorrection"),
1774  / 1000.0;
1775  mRecordingSchedule.mDuration = t1 - t0;
1776  if (options.pCrossfadeData)
1778 
1779  mListener = options.listener;
1780  mRate = sampleRate;
1781 
1782  mSeek = 0;
1784  mCaptureTracks = tracks.captureTracks;
1786 #ifdef EXPERIMENTAL_MIDI_OUT
1787  mMidiPlaybackTracks = tracks.midiTracks;
1788 #endif
1789 
1790  bool commit = false;
1791  auto cleanupTracks = finally([&]{
1792  if (!commit) {
1793  // Don't keep unnecessary shared pointers to tracks
1794  mPlaybackTracks.clear();
1795  mCaptureTracks.clear();
1796 #ifdef EXPERIMENTAL_MIDI_OUT
1797  mMidiPlaybackTracks.clear();
1798 #endif
1799 
1800  // Don't cause a busy wait in the audio thread after stopping scrubbing
1802  }
1803  });
1804 
1805  mPlaybackBuffers.reset();
1806  mPlaybackMixers.reset();
1807  mCaptureBuffers.reset();
1808  mResample.reset();
1809  mTimeQueue.mData.reset();
1810 
1811 #ifdef EXPERIMENTAL_MIDI_OUT
1812  streamStartTime = 0;
1813  streamStartTime = SystemTime(mUsingAlsa);
1814 #endif
1815 
1817  t0, t1, options, mCaptureTracks.empty() ? nullptr : &mRecordingSchedule );
1818  const bool scrubbing = mPlaybackSchedule.Interactive();
1819 
1820  unsigned int playbackChannels = 0;
1821  unsigned int captureChannels = 0;
1822  sampleFormat captureFormat = floatSample;
1823 
1824  if (tracks.playbackTracks.size() > 0
1825 #ifdef EXPERIMENTAL_MIDI_OUT
1826  || tracks.midiTracks.size() > 0
1827 #endif
1828  )
1829  playbackChannels = 2;
1830 
1832  playbackChannels = 2;
1833 
1834  if (tracks.captureTracks.size() > 0)
1835  {
1836  // For capture, every input channel gets its own track
1837  captureChannels = mCaptureTracks.size();
1838  // I don't deal with the possibility of the capture tracks
1839  // having different sample formats, since it will never happen
1840  // with the current code. This code wouldn't *break* if this
1841  // assumption was false, but it would be sub-optimal. For example,
1842  // if the first track was 16-bit and the second track was 24-bit,
1843  // we would set the sound card to capture in 16 bits and the second
1844  // track wouldn't get the benefit of all 24 bits the card is capable
1845  // of.
1846  captureFormat = mCaptureTracks[0]->GetSampleFormat();
1847 
1848  // Tell project that we are about to start recording
1849  if (mListener)
1851  }
1852 
1853  bool successAudio;
1854 
1855  successAudio = StartPortAudioStream(sampleRate, playbackChannels,
1856  captureChannels, captureFormat);
1857 #ifdef EXPERIMENTAL_MIDI_OUT
1858 
1859  // TODO: it may be that midi out will not work unless audio in or out is
1860  // active -- this would be a bug and may require a change in the
1861  // logic here.
1862 
1863  bool successMidi = true;
1864 
1865  if(!mMidiPlaybackTracks.empty()){
1866  successMidi = StartPortMidiStream();
1867  }
1868 
1869  // On the other hand, if MIDI cannot be opened, we will not complain
1870 #endif
1871 
1872  if (!successAudio) {
1873  if (mListener && captureChannels > 0)
1875  mStreamToken = 0;
1876 
1877  return 0;
1878  }
1879 
1880  if ( ! AllocateBuffers( options, tracks, t0, t1, sampleRate, scrubbing ) )
1881  return 0;
1882 
1883  if (mNumPlaybackChannels > 0)
1884  {
1886  // Setup for realtime playback at the rate of the realtime
1887  // stream, not the rate of the track.
1889 
1890  // The following adds a NEW effect processor for each logical track and the
1891  // group determination should mimic what is done in audacityAudioCallback()
1892  // when calling RealtimeProcess().
1893  int group = 0;
1894  for (size_t i = 0, cnt = mPlaybackTracks.size(); i < cnt; i++)
1895  {
1896  const WaveTrack *vt = mPlaybackTracks[i].get();
1897 
1898  unsigned chanCnt = 1;
1899  if (vt->GetLinked())
1900  {
1901  i++;
1902  chanCnt++;
1903  }
1904 
1905  // Setup for realtime playback at the rate of the realtime
1906  // stream, not the rate of the track.
1907  em.RealtimeAddProcessor(group++, chanCnt, mRate);
1908  }
1909  }
1910 
1911 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1912  AILASetStartTime();
1913 #endif
1914 
1915  if (options.pStartTime)
1916  {
1917  // Calculate the NEW time position
1918  const auto time = mPlaybackSchedule.ClampTrackTime( *options.pStartTime );
1919 
1920  // Main thread's initialization of mTime
1922 
1923  // Reset mixer positions for all playback tracks
1924  unsigned numMixers = mPlaybackTracks.size();
1925  for (unsigned ii = 0; ii < numMixers; ++ii)
1926  mPlaybackMixers[ii]->Reposition( time );
1928  }
1929 
1930  // Now that we are done with SetTrackTime():
1932  if (mTimeQueue.mData)
1934  // else recording only without overdub
1935 
1936 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1937  if (scrubbing)
1938  {
1939  const auto &scrubOptions = *options.pScrubbingOptions;
1940  mScrubState =
1941  std::make_unique<ScrubState>(
1943  mRate,
1944  scrubOptions);
1945  mScrubDuration = 0;
1946  mSilentScrub = false;
1947  }
1948  else
1949  mScrubState.reset();
1950 #endif
1951 
1952  // We signal the audio thread to call FillBuffers, to prime the RingBuffers
1953  // so that they will have data in them when the stream starts. Having the
1954  // audio thread call FillBuffers here makes the code more predictable, since
1955  // FillBuffers will ALWAYS get called from the Audio thread.
1957 
1959 #ifndef USE_SCRUB_THREAD
1960  // Yuck, we either have to poll "by hand" when scrub polling doesn't
1961  // work with a thread, or else yield to timer messages, but that would
1962  // execute too much else
1963  if (mScrubState) {
1965  wxMilliSleep( Scrubber::ScrubPollInterval_ms * 0.9 );
1966  }
1967  else
1968 #endif
1969  wxMilliSleep( 50 );
1970  }
1971 
1972  if(mNumPlaybackChannels > 0 || mNumCaptureChannels > 0) {
1973 
1974 #ifdef REALTIME_ALSA_THREAD
1975  // PRL: Do this in hope of less thread scheduling jitter in calls to
1976  // audacityAudioCallback.
1977  // Not needed to make audio playback work smoothly.
1978  // But needed in case we also play MIDI, so that the variable "offset"
1979  // in AudioIO::MidiTime() is a better approximation of the duration
1980  // between the call of audacityAudioCallback and the actual output of
1981  // the first audio sample.
1982  // (Which we should be able to determine from fields of
1983  // PaStreamCallbackTimeInfo, but that seems not to work as documented with
1984  // ALSA.)
1985  if (mUsingAlsa)
1986  // Perhaps we should do this only if also playing MIDI ?
1987  PaAlsa_EnableRealtimeScheduling( mPortStreamV19, 1 );
1988 #endif
1989 
1990  //
1991  // Generate a unique value each time, to be returned to
1992  // clients accessing the AudioIO API, so they can query if they
1993  // are the ones who have reserved AudioIO or not.
1994  //
1995  // It is important to set this before setting the portaudio stream in
1996  // motion -- otherwise it may play an unspecified number of leading
1997  // zeroes.
1999 
2000  // This affects the AudioThread (not the portaudio callback).
2001  // Probably not needed so urgently before portaudio thread start for usual
2002  // playback, since our ring buffers have been primed already with 4 sec
2003  // of audio, but then we might be scrubbing, so do it.
2005 
2006  // Now start the PortAudio stream!
2007  PaError err;
2008  err = Pa_StartStream( mPortStreamV19 );
2009 
2010  if( err != paNoError )
2011  {
2012  mStreamToken = 0;
2014  if (mListener && mNumCaptureChannels > 0)
2017  AudacityMessageBox(LAT1CTOWX(Pa_GetErrorText(err)));
2018  return 0;
2019  }
2020  }
2021 
2022  // Update UI display only now, after all possibilities for error are past.
2023  if (mListener) {
2024  // advertise the chosen I/O sample rate to the UI
2025  mListener->OnAudioIORate((int)mRate);
2026  }
2027 
2028  if (mNumPlaybackChannels > 0)
2029  {
2030  wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
2031  e.SetEventObject(mOwningProject);
2032  e.SetInt(true);
2033  wxTheApp->ProcessEvent(e);
2034  }
2035 
2036  if (mNumCaptureChannels > 0)
2037  {
2038  wxCommandEvent e(EVT_AUDIOIO_CAPTURE);
2039  e.SetEventObject(mOwningProject);
2040  e.SetInt(true);
2041  wxTheApp->ProcessEvent(e);
2042  }
2043 
2044  // Enable warning popups for unfound aliased blockfiles.
2046 
2047  commit = true;
2048  return mStreamToken;
2049 }
virtual void OnAudioIOStartRecording()=0
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
void StopStream()
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:2408
double ClampTrackTime(double trackTime) const
Clamps argument to be between mT0 and mT1.
Definition: AudioIO.cpp:2853
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: AudioIO.h:1012
bool Interactive() const
Definition: AudioIO.h:1047
Scrubber & GetScrubber()
Definition: Project.h:805
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
#define ENV_DB_KEY
Definition: GUISettings.h:15
static int mNextStreamToken
Definition: AudioIO.h:815
struct AudioIO::TimeQueue mTimeQueue
void SetMissingAliasedFileWarningShouldShow(bool b)
Changes the behavior of missing aliased blockfiles warnings.
bool mDetectDropouts
Definition: AudioIO.h:923
void SetTrackTime(double time)
Set current track time value, unadjusted.
Definition: AudioIO.h:1017
sampleCount mScrubDuration
Definition: AudioIO.h:911
void RealtimeAddProcessor(int group, unsigned chans, float rate)
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Warning.cpp:115
WaveTrackArray playbackTracks
Definition: AudioIO.h:159
bool mSoftwarePlaythrough
Definition: AudioIO.h:833
bool GetLinked() const
Definition: Track.h:287
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:2237
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
virtual void OnAudioIOStopRecording()=0
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2745
ScrubbingOptions * pScrubbingOptions
Definition: AudioIO.h:151
static constexpr unsigned ScrubPollInterval_ms
Definition: Scrubbing.h:71
float mSilenceLevel
Definition: AudioIO.h:836
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:807
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:813
void RealTimeInit(double trackTime)
Definition: AudioIO.cpp:5676
#define DEFAULT_LATENCY_CORRECTION
Definition: AudioIO.h:87
#define ENV_DB_RANGE
Definition: GUISettings.h:16
PRCrossfadeData * pCrossfadeData
Definition: AudioIO.h:155
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
volatile int mStreamToken
Definition: AudioIO.h:814
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:809
void ContinueScrubbingPoll()
Definition: Scrubbing.cpp:521
PaStream * mPortStreamV19
Definition: AudioIO.h:832
void ClearRecordingException()
Definition: AudioIO.h:919
sampleFormat
Definition: Types.h:188
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
void RealtimeInitialize(double rate)
AudacityProject * mOwningProject
Definition: AudioIO.h:859
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:881
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:841
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
#define LAT1CTOWX(X)
Definition: Internat.h:180
double mSeek
Definition: AudioIO.h:820
unsigned int mNumCaptureChannels
Definition: AudioIO.h:837
static EffectManager & Get()
unsigned long long mLostSamples
Definition: AudioIO.h:840
PRCrossfadeData mCrossfadeData
Definition: AudioIO.h:942
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
bool AllocateBuffers(const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate, bool scrubbing)
Allocate RingBuffer structures, and others, needed for playback and recording.
Definition: AudioIO.cpp:2051
volatile double mLastRecordingOffset
Definition: AudioIO.h:852
bool mUsingAlsa
Definition: AudioIO.h:890
virtual void OnAudioIORate(int rate)=0
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:957
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:922
AudioIOListener * listener
Definition: AudioIO.h:139
void Init(double t0, double t1, const AudioIOStartStreamOptions &options, const RecordingSchedule *pRecordingSchedule)
Definition: AudioIO.cpp:2782
AudacityApp & wxGetApp()
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:1454
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:842
WaveTrackArray captureTracks
Definition: AudioIO.h:160
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:835
struct AudioIO::PlaybackSchedule mPlaybackSchedule
bool mSilentScrub
Definition: AudioIO.h:909
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 2237 of file AudioIO.cpp.

References EffectManager::Get(), mCaptureBuffers, AudioIO::TimeQueue::mData, mNumPlaybackChannels, mPlaybackBuffers, mPlaybackMixers, mPortStreamV19, mResample, mScrubState, mStreamToken, mTimeQueue, and EffectManager::RealtimeFinalize().

Referenced by AllocateBuffers(), and StartStream().

2238 {
2239  if (mNumPlaybackChannels > 0)
2240  {
2242  }
2243 
2244  mPlaybackBuffers.reset();
2245  mPlaybackMixers.reset();
2246  mCaptureBuffers.reset();
2247  mResample.reset();
2248  mTimeQueue.mData.reset();
2249 
2250  if(!bOnlyBuffers)
2251  {
2252  Pa_AbortStream( mPortStreamV19 );
2253  Pa_CloseStream( mPortStreamV19 );
2254  mPortStreamV19 = NULL;
2255  mStreamToken = 0;
2256  }
2257 
2258 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2259  mScrubState.reset();
2260 #endif
2261 }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
struct AudioIO::TimeQueue mTimeQueue
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:807
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:813
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
volatile int mStreamToken
Definition: AudioIO.h:814
PaStream * mPortStreamV19
Definition: AudioIO.h:832
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
static EffectManager & Get()
void RealtimeFinalize()
void AudioIO::StopScrub ( )

Definition at line 2726 of file AudioIO.cpp.

References mScrubState.

Referenced by Scrubber::StopScrubbing().

2727 {
2728  if (mScrubState)
2729  mScrubState->Stop();
2730 }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
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 2408 of file AudioIO.cpp.

References ClearRecordingException(), ControlToolBar::CommitRecording(), DEFAULT_LATENCY_DURATION, WaveTrack::Flush(), EffectManager::Get(), AudacityProject::GetControlToolBar(), AudacityProject::GetMixerBoard(), gPrefs, GuardedCall(), mAudioThreadFillBuffersLoopRunning, mAudioThreadShouldCallFillBuffersOnce, mCaptureBuffers, mCaptureTracks, AudioIO::TimeQueue::mData, mInputMeter, mListener, mLostCaptureIntervals, mNumCaptureChannels, mNumPlaybackChannels, mOutputMeter, mOwningProject, mPlaybackBuffers, mPlaybackMixers, mPlaybackSchedule, mPlaybackTracks, mPortStreamV19, mRate, mRecordingSchedule, mResample, mScrubState, mStreamToken, mSuspendAudioThread, mTimeQueue, mUpdateMeters, mUpdatingMeters, AudioIOListener::OnAudioIORate(), AudioIOListener::OnAudioIOStopRecording(), EffectManager::RealtimeFinalize(), MeterPanel::Reset(), MixerBoard::ResetMeters(), AudioIO::PlaybackSchedule::ResetMode(), and wxGetApp().

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

2409 {
2410  auto cleanup = finally ( [this] {
2412  mRecordingSchedule = {}; // free arrays
2413  } );
2414 
2415  if( mPortStreamV19 == NULL
2416 #ifdef EXPERIMENTAL_MIDI_OUT
2417  && mMidiStream == NULL
2418 #endif
2419  )
2420  return;
2421 
2422  if( Pa_IsStreamStopped( mPortStreamV19 )
2423 #ifdef EXPERIMENTAL_MIDI_OUT
2424  && !mMidiStreamActive
2425 #endif
2426  )
2427  return;
2428 
2430  {
2431  // PortAudio callback can use the information that we are stopping to fade
2432  // out the audio. Give PortAudio callback a chance to do so.
2434  long latency;
2435  gPrefs->Read( wxT("/AudioIO/LatencyDuration"), &latency, DEFAULT_LATENCY_DURATION );
2436  // If we can gracefully fade out in 200ms, with the faded-out play buffers making it through
2437  // the sound card, then do so. If we can't, don't wait around. Just stop quickly and accept
2438  // there will be a click.
2439  if( latency < 150 )
2440  wxMilliSleep( latency + 50);
2441  }
2442 
2443  wxMutexLocker locker(mSuspendAudioThread);
2444 
2445  // No longer need effects processing
2446  if (mNumPlaybackChannels > 0)
2447  {
2449  }
2450 
2451  //
2452  // We got here in one of two ways:
2453  //
2454  // 1. The user clicked the stop button and we therefore want to stop
2455  // as quickly as possible. So we use AbortStream(). If this is
2456  // the case the portaudio stream is still in the Running state
2457  // (see PortAudio state machine docs).
2458  //
2459  // 2. The callback told PortAudio to stop the stream since it had
2460  // reached the end of the selection. The UI thread discovered
2461  // this by noticing that AudioIO::IsActive() returned false.
2462  // IsActive() (which calls Pa_GetStreamActive()) will not return
2463  // false until all buffers have finished playing, so we can call
2464  // AbortStream without losing any samples. If this is the case
2465  // we are in the "callback finished state" (see PortAudio state
2466  // machine docs).
2467  //
2468  // The moral of the story: We can call AbortStream safely, without
2469  // losing samples.
2470  //
2471  // DMM: This doesn't seem to be true; it seems to be necessary to
2472  // call StopStream if the callback brought us here, and AbortStream
2473  // if the user brought us here.
2474  //
2475 
2477 
2478  // Audacity can deadlock if it tries to update meters while
2479  // we're stopping PortAudio (because the meter updating code
2480  // tries to grab a UI mutex while PortAudio tries to join a
2481  // pthread). So we tell the callback to stop updating meters,
2482  // and wait until the callback has left this part of the code
2483  // if it was already there.
2484  mUpdateMeters = false;
2485  while(mUpdatingMeters) {
2486  ::wxSafeYield();
2487  wxMilliSleep( 50 );
2488  }
2489 
2490  // Turn off HW playthrough if PortMixer is being used
2491 
2492  #if defined(USE_PORTMIXER)
2493  if( mPortMixer ) {
2494  #if __WXMAC__
2495  if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
2496  Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
2497  mPreviousHWPlaythrough = -1.0;
2498  #endif
2499  }
2500  #endif
2501 
2502  if (mPortStreamV19) {
2503  Pa_AbortStream( mPortStreamV19 );
2504  Pa_CloseStream( mPortStreamV19 );
2505  mPortStreamV19 = NULL;
2506  }
2507 
2508  if (mNumPlaybackChannels > 0)
2509  {
2510  wxCommandEvent e(EVT_AUDIOIO_PLAYBACK);
2511  e.SetEventObject(mOwningProject);
2512  e.SetInt(false);
2513  wxTheApp->ProcessEvent(e);
2514  }
2515 
2516  if (mNumCaptureChannels > 0)
2517  {
2518  wxCommandEvent e(mStreamToken == 0 ? EVT_AUDIOIO_MONITOR : EVT_AUDIOIO_CAPTURE);
2519  e.SetEventObject(mOwningProject);
2520  e.SetInt(false);
2521  wxTheApp->ProcessEvent(e);
2522  }
2523 
2524 #ifdef EXPERIMENTAL_MIDI_OUT
2525  /* Stop Midi playback */
2526  if ( mMidiStream ) {
2527 
2528  mMidiStreamActive = false;
2529 
2530 #ifdef USE_MIDI_THREAD
2531  mMidiThreadFillBuffersLoopRunning = false; // stop output to stream
2532  // but output is in another thread. Wait for output to stop...
2533  while (mMidiThreadFillBuffersLoopActive) {
2534  wxMilliSleep(1);
2535  }
2536 #endif
2537 
2538  mMidiOutputComplete = true;
2539 
2540  // now we can assume "ownership" of the mMidiStream
2541  // if output in progress, send all off, etc.
2542  AllNotesOff();
2543  // AllNotesOff() should be sufficient to stop everything, but
2544  // in Linux, if you Pm_Close() immediately, it looks like
2545  // messages are dropped. ALSA then seems to send All Sound Off
2546  // and Reset All Controllers messages, but not all synthesizers
2547  // respond to these messages. This is probably a bug in PortMidi
2548  // if the All Off messages do not get out, but for security,
2549  // delay a bit so that messages can be delivered before closing
2550  // the stream. Add 2ms of "padding" to avoid any rounding errors.
2551  while (mMaxMidiTimestamp + 2 > MidiTime()) {
2552  wxMilliSleep(1); // deliver the all-off messages
2553  }
2554  Pm_Close(mMidiStream);
2555  mMidiStream = NULL;
2556  mIterator->end();
2557 
2558  // set in_use flags to false
2559  int nTracks = mMidiPlaybackTracks.size();
2560  for (int i = 0; i < nTracks; i++) {
2561  const auto t = mMidiPlaybackTracks[i].get();
2562  Alg_seq_ptr seq = &t->GetSeq();
2563  seq->set_in_use(false);
2564  }
2565 
2566  mIterator.reset(); // just in case someone tries to reference it
2567  }
2568 #endif
2569 
2570  // If there's no token, we were just monitoring, so we can
2571  // skip this next part...
2572  if (mStreamToken > 0) {
2573  // In either of the above cases, we want to make sure that any
2574  // capture data that made it into the PortAudio callback makes it
2575  // to the target WaveTrack. To do this, we ask the audio thread to
2576  // call FillBuffers one last time (it normally would not do so since
2577  // Pa_GetStreamActive() would now return false
2579 
2581  {
2582  // LLL: Experienced recursive yield here...once.
2583  wxGetApp().Yield(true); // Pass true for onlyIfNeeded to avoid recursive call error.
2584  wxMilliSleep( 50 );
2585  }
2586 
2587  //
2588  // Everything is taken care of. Now, just free all the resources
2589  // we allocated in StartStream()
2590  //
2591 
2592  if (mPlaybackTracks.size() > 0)
2593  {
2594  mPlaybackBuffers.reset();
2595  mPlaybackMixers.reset();
2596  mTimeQueue.mData.reset();
2597  }
2598 
2599  //
2600  // Offset all recorded tracks to account for latency
2601  //
2602  if (mCaptureTracks.size() > 0)
2603  {
2604  mCaptureBuffers.reset();
2605  mResample.reset();
2606 
2607  //
2608  // We only apply latency correction when we actually played back
2609  // tracks during the recording. If we did not play back tracks,
2610  // there's nothing we could be out of sync with. This also covers the
2611  // case that we do not apply latency correction when recording the
2612  // first track in a project.
2613  //
2614 
2615  for (unsigned int i = 0; i < mCaptureTracks.size(); i++) {
2616  // The calls to Flush
2617  // may cause exceptions because of exhaustion of disk space.
2618  // Stop those exceptions here, or else they propagate through too
2619  // many parts of Audacity that are not effects or editing
2620  // operations. GuardedCall ensures that the user sees a warning.
2621 
2622  // Also be sure to Flush each track, at the top of the guarded call,
2623  // relying on the guarantee that the track will be left in a flushed
2624  // state, though the append buffer may be lost.
2625 
2626  GuardedCall( [&] {
2627  WaveTrack* track = mCaptureTracks[i].get();
2628 
2629  // use NOFAIL-GUARANTEE that track is flushed,
2630  // PARTIAL-GUARANTEE that some initial length of the recording
2631  // is saved.
2632  // See comments in FillBuffers().
2633  track->Flush();
2634  } );
2635  }
2636 
2637  for (auto &interval : mLostCaptureIntervals) {
2638  auto &start = interval.first;
2639  auto duration = interval.second;
2640  for (auto &track : mCaptureTracks) {
2641  GuardedCall([&] {
2642  track->SyncLockAdjust(start, start + duration);
2643  });
2644  }
2645  }
2646 
2648  bar->CommitRecording();
2649  }
2650  }
2651 
2652  if (mInputMeter)
2653  mInputMeter->Reset(mRate, false);
2654 
2655  if (mOutputMeter)
2656  mOutputMeter->Reset(mRate, false);
2657 
2658  MixerBoard* pMixerBoard = mOwningProject->GetMixerBoard();
2659  if (pMixerBoard)
2660  pMixerBoard->ResetMeters(false);
2661 
2662  mInputMeter.Release();
2663  mOutputMeter = NULL;
2664  mOwningProject = NULL;
2665 
2666  if (mListener && mNumCaptureChannels > 0)
2668 
2669  //
2670  // Only set token to 0 after we're totally finished with everything
2671  //
2672  mStreamToken = 0;
2673 
2674  mNumCaptureChannels = 0;
2676 
2677  mPlaybackTracks.clear();
2678  mCaptureTracks.clear();
2679 #ifdef HAVE_MIDI
2680  mMidiPlaybackTracks.clear();
2681 #endif
2682 
2683 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2684  mScrubState.reset();
2685 #endif
2686 
2687  if (mListener) {
2688  // Tell UI to hide sample rate
2690  }
2691 
2692  // Don't cause a busy wait in the audio thread after stopping scrubbing
2694 }
A ToolBar that has the main Transport buttons.
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
struct AudioIO::TimeQueue mTimeQueue
volatile bool mUpdatingMeters
Definition: AudioIO.h:863
struct AudioIO::RecordingSchedule mRecordingSchedule
void SyncLockAdjust(double oldT1, double newT1) override
Definition: WaveTrack.cpp:1163
MeterPanel * mOutputMeter
Definition: AudioIO.h:861
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:810
virtual void OnAudioIOStopRecording()=0
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:807
MixerBoard * GetMixerBoard()
Definition: Project.h:518
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:813
wxMutex mSuspendAudioThread
Definition: AudioIO.h:903
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:808
volatile int mStreamToken
Definition: AudioIO.h:814
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:809
PaStream * mPortStreamV19
Definition: AudioIO.h:832
void ClearRecordingException()
Definition: AudioIO.h:919
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
AudacityProject * mOwningProject
Definition: AudioIO.h:859
AudioIOListener * mListener
Definition: AudioIO.h:881
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:841
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:838
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
unsigned int mNumCaptureChannels
Definition: AudioIO.h:837
static EffectManager & Get()
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:860
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:811
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:818
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:862
ControlToolBar * GetControlToolBar()
Definition: Project.cpp:5041
virtual void OnAudioIORate(int rate)=0
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:922
AudacityApp & wxGetApp()
#define DEFAULT_LATENCY_DURATION
Definition: AudioIO.h:86
void RealtimeFinalize()
void ResetMeters(const bool bResetClipping)
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:842
struct AudioIO::PlaybackSchedule mPlaybackSchedule
void Flush()
Flush must be called after last Append.
Definition: WaveTrack.cpp:1666
void AudioIO::UpdateScrub ( double  endTimeOrSpeed,
const ScrubbingOptions options 
)

Notify scrubbing engine of desired position or speed. 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.

Definition at line 2720 of file AudioIO.cpp.

Referenced by Scrubber::ContinueScrubbingPoll().

2721 {
2722  if (mScrubState)
2723  mScrubState->Update(endTimeOrSpeed, options);
2724 }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:906
bool AudioIO::ValidateDeviceNames ( const wxString &  play,
const wxString &  rec 
)
static

Ensure selected device names are valid.

Definition at line 975 of file AudioIO.cpp.

References getPlayDevIndex(), and getRecordDevIndex().

976 {
977  const PaDeviceInfo *pInfo = Pa_GetDeviceInfo(AudioIO::getPlayDevIndex(play));
978  const PaDeviceInfo *rInfo = Pa_GetDeviceInfo(AudioIO::getRecordDevIndex(rec));
979 
980  if (!pInfo || !rInfo || pInfo->hostApi != rInfo->hostApi) {
981  return false;
982  }
983 
984  return true;
985 }
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3282
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:3339

Friends And Related Function Documentation

friend class AudioThread
friend

Definition at line 883 of file AudioIO.h.

void InitAudioIO ( )
friend

Definition at line 923 of file AudioIO.cpp.

924 {
925  ugAudioIO.reset(safenew AudioIO());
926  gAudioIO = ugAudioIO.get();
927  gAudioIO->mThread->Run();
928 #ifdef EXPERIMENTAL_MIDI_OUT
929 #ifdef USE_MIDI_THREAD
930  gAudioIO->mMidiThread->Run();
931 #endif
932 #endif
933 
934  // Make sure device prefs are initialized
935  if (gPrefs->Read(wxT("AudioIO/RecordingDevice"), wxT("")) == wxT("")) {
936  int i = AudioIO::getRecordDevIndex();
937  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
938  if (info) {
939  gPrefs->Write(wxT("/AudioIO/RecordingDevice"), DeviceName(info));
940  gPrefs->Write(wxT("/AudioIO/Host"), HostName(info));
941  }
942  }
943 
944  if (gPrefs->Read(wxT("AudioIO/PlaybackDevice"), wxT("")) == wxT("")) {
945  int i = AudioIO::getPlayDevIndex();
946  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
947  if (info) {
948  gPrefs->Write(wxT("/AudioIO/PlaybackDevice"), DeviceName(info));
949  gPrefs->Write(wxT("/AudioIO/Host"), HostName(info));
950  }
951  }
952 
953  gPrefs->Flush();
954 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
std::unique_ptr< AudioIO > ugAudioIO
Definition: AudioIO.cpp:482
AudioIO()
Definition: AudioIO.cpp:987
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:961
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3282
wxString HostName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:968
#define safenew
Definition: Audacity.h:230
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:801
AudioIO * gAudioIO
Definition: AudioIO.cpp:483
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:3339

Member Data Documentation

volatile bool AudioIO::mAudioThreadFillBuffersLoopActive
private

Definition at line 843 of file AudioIO.h.

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

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

Definition at line 898 of file AudioIO.h.

Referenced by GetBestRate(), and HandleDeviceChange().

double AudioIO::mCachedBestRateOut
staticprivate

Definition at line 899 of file AudioIO.h.

Referenced by GetBestRate().

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

Definition at line 896 of file AudioIO.h.

Referenced by GetSupportedCaptureRates(), and HandleDeviceChange().

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

Definition at line 894 of file AudioIO.h.

Referenced by GetSupportedPlaybackRates(), and HandleDeviceChange().

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

Definition at line 897 of file AudioIO.h.

Referenced by GetSupportedSampleRates(), and HandleDeviceChange().

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

Definition at line 839 of file AudioIO.h.

Referenced by AudioCallback(), and StartPortAudioStream().

double AudioIO::mCaptureRingBufferSecs
private

Definition at line 822 of file AudioIO.h.

Referenced by AllocateBuffers().

WaveTrackArray AudioIO::mCaptureTracks
private
bool AudioIO::mDetectDropouts { true }
private

Definition at line 923 of file AudioIO.h.

Referenced by AudioCallback(), and StartStream().

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

Definition at line 870 of file AudioIO.h.

Referenced by AudioCallback(), AudioIO(), GetMixer(), HandleDeviceChange(), and OutputMixerEmulated().

double AudioIO::mFactor
private

Definition at line 816 of file AudioIO.h.

Referenced by AllocateBuffers(), and FillBuffers().

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

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

PaError AudioIO::mLastPaError
private

Definition at line 853 of file AudioIO.h.

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

wxLongLong AudioIO::mLastPlaybackTimeMillis
private

Definition at line 845 of file AudioIO.h.

Referenced by AudioCallback(), and AudioIO().

volatile double AudioIO::mLastRecordingOffset
private

Definition at line 852 of file AudioIO.h.

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

AudioIOListener* AudioIO::mListener
private

Definition at line 881 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 922 of file AudioIO.h.

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

unsigned long long AudioIO::mLostSamples { 0 }
private

Definition at line 840 of file AudioIO.h.

Referenced by AudioCallback(), and StartStream().

double AudioIO::mMinCaptureSecsToCopy
private

Definition at line 829 of file AudioIO.h.

Referenced by AllocateBuffers(), and FillBuffers().

float AudioIO::mMixerOutputVol
private

Definition at line 879 of file AudioIO.h.

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

int AudioIO::mNextStreamToken = 0
staticprivate

Definition at line 815 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 831 of file AudioIO.h.

Referenced by AudioCallback(), AudioIO(), CallbackCheckCompletion(), IsPaused(), and SetPaused().

bool AudioIO::mPauseRec
private

True if Sound Activated Recording is enabled.

Definition at line 835 of file AudioIO.h.

Referenced by AudioCallback(), and StartStream().

ArrayOf<std::unique_ptr<RingBuffer> > AudioIO::mPlaybackBuffers
private

Definition at line