Audacity  2.3.1
Public Member Functions | Static Public Member Functions | 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>

Inheritance diagram for AudioIO:
AudioIoCallback

Public Member Functions

 AudioIO ()
 
 ~AudioIO ()
 
AudioIOListenerGetListener ()
 
void SetListener (AudioIOListener *listener)
 
void StartMonitoring (double sampleRate)
 Start up Portaudio for capture and recording as needed for input monitoring and software playthrough only. More...
 
int StartStream (const TransportTracks &tracks, double t0, double t1, const AudioIOStartStreamOptions &options)
 Start recording or playing back audio. More...
 
void StopStream ()
 Stop recording, playback or input monitoring. More...
 
void SeekStream (double seconds)
 Move the playback / recording position of the current stream by the specified amount from where it is now. More...
 
bool IsScrubbing () 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
 
wxString LastPaErrorString ()
 
wxLongLong GetLastPlaybackTime () const
 
AudacityProjectGetOwningProject () const
 
PmTimestamp MidiTime ()
 Compute the current PortMidi timestamp time. More...
 
bool SetHasSolo (bool hasSolo)
 
bool GetHasSolo ()
 
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...
 
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...
 
wxString GetMidiDeviceInfo ()
 Get diagnostic information on all the available MIDI 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...
 
- Public Member Functions inherited from AudioIoCallback
 AudioIoCallback ()
 
 ~AudioIoCallback ()
 
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)
 
unsigned CountSoloingTracks ()
 
bool TrackShouldBeSilent (const WaveTrack &wt)
 
bool TrackHasBeenFadedOut (const WaveTrack &wt)
 
bool AllTracksAlreadySilent ()
 
void ComputeMidiTimings (const PaStreamCallbackTimeInfo *timeInfo, unsigned long framesPerBuffer)
 
void CheckSoundActivatedRecordingLevel (const void *inputBuffer)
 
void AddToOutputChannel (unsigned int chan, float *outputMeterFloats, float *outputFloats, float *tempFloats, float *tempBuf, bool drop, unsigned long len, WaveTrack *vt)
 
bool FillOutputBuffers (void *outputBuffer, unsigned long framesPerBuffer, float *tempFloats, float *outputMeterFloats)
 
void FillInputBuffers (const void *inputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackFlags statusFlags, float *tempFloats)
 
void UpdateTimePosition (unsigned long framesPerBuffer)
 
void DoPlaythrough (const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
 
void SendVuInputMeterData (float *tempFloats, const void *inputBuffer, unsigned long framesPerBuffer)
 
void SendVuOutputMeterData (float *outputMeterFloats, unsigned long framesPerBuffer)
 
double AudioTime ()
 
bool IsPaused () const
 Find out if playback / recording is currently paused. More...
 
size_t GetCommonlyReadyPlayback ()
 Get the number of audio samples ready in all of the playback buffers. More...
 
double MidiLoopOffset ()
 
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...
 

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...
 
- Static Public Attributes inherited from AudioIoCallback
static int mNextStreamToken = 0
 

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 ()
 
void PrepareMidiIterator (bool send=true, double offset=0)
 
bool StartPortMidiStream ()
 
double UncorrectedMidiEventTime ()
 
void OutputEvent ()
 
void FillMidiBuffers ()
 
void GetNextEvent ()
 
double PauseTime ()
 
void AllNotesOff (bool looping=false)
 
size_t GetCommonlyFreePlayback ()
 Get the number of audio samples free in all of the playback buffers. More...
 
size_t GetCommonlyAvailCapture ()
 Get the number of audio samples ready in all of the recording buffers. More...
 
bool AllocateBuffers (const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate, 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...
 

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

bool mHasSolo
 

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

Friends

class AudioThread
 
class MidiThread
 
void InitAudioIO ()
 

Additional Inherited Members

- Public Attributes inherited from AudioIoCallback
int mbHasSoloTracks
 
int mCallbackReturn
 
PmStream * mMidiStream
 
PmError mLastPmError
 
long mSynthLatency
 Latency of MIDI synthesizer. More...
 
volatile double mAudioCallbackClockTime
 PortAudio's clock time. More...
 
volatile long mNumFrames
 Number of frames output, including pauses. More...
 
volatile long mNumPauseFrames
 How many frames of zeros were output due to pauses? More...
 
volatile int mMidiLoopPasses
 total of backward jumps More...
 
volatile long mAudioFramesPerBuffer
 
volatile bool mMidiPaused
 
PmTimestamp mMaxMidiTimestamp
 
double mSystemMinusAudioTime
 
double mAudioOutLatency
 
double mStartTime
 
long mCallbackCount
 number of callbacks since stream start More...
 
volatile double mSystemMinusAudioTimePlusLatency
 
Alg_seq_ptr mSeq
 
std::unique_ptr< Alg_iterator > mIterator
 
Alg_event_ptr mNextEvent
 The next event to play (or null) More...
 
std::vector< std::pair< int,
int > > 
mPendingNotesOff
 
double mNextEventTime
 
NoteTrackmNextEventTrack
 Track of next event. More...
 
bool mMidiOutputComplete { true }
 True when output reaches mT1. More...
 
bool mNextIsNoteOn
 Is the next event a note-on? More...
 
bool mMidiStreamActive
 mMidiStreamActive tells when mMidiStream is open for output More...
 
bool mSendMidiState
 
NoteTrackConstArray mMidiPlaybackTracks
 
std::unique_ptr< AudioThreadmThread
 
std::unique_ptr< AudioThreadmMidiThread
 
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...
 
unsigned long mMaxFramesOutput
 
bool mbMicroFades
 
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 bool mMidiThreadFillBuffersLoopRunning
 
volatile bool mMidiThreadFillBuffersLoopActive
 
volatile double mLastRecordingOffset
 
PaError mLastPaError
 
std::unique_ptr< ScrubStatemScrubState
 
bool mSilentScrub
 
double mScrubSpeed
 
sampleCount mScrubDuration
 
bool mSimulateRecordingErrors { false }
 
bool mDetectUpstreamDropouts { true }
 
- Protected Member Functions inherited from AudioIoCallback
void SetRecordingException ()
 
void ClearRecordingException ()
 
- Protected Attributes inherited from AudioIoCallback
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
 
wxAtomicInt mRecordingException {}
 
std::vector< std::pair< double,
double > > 
mLostCaptureIntervals
 
bool mDetectDropouts { true }
 
struct
AudioIoCallback::RecordingSchedule 
mRecordingSchedule
 
struct
AudioIoCallback::PlaybackSchedule 
mPlaybackSchedule
 
struct AudioIoCallback::TimeQueue mTimeQueue
 
- Static Protected Attributes inherited from AudioIoCallback
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
 

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

Constructor & Destructor Documentation

AudioIO::AudioIO ( )

Definition at line 990 of file AudioIO.cpp.

References _(), AudacityMessageBox(), HandleDeviceChange(), LAT1CTOWX, AudioIoCallback::mAudioThreadFillBuffersLoopActive, AudioIoCallback::mAudioThreadFillBuffersLoopRunning, AudioIoCallback::mAudioThreadShouldCallFillBuffersOnce, AudioIoCallback::mEmulateMixerOutputVol, AudioIoCallback::mInputMixerWorks, AudioIoCallback::mIterator, AudioIoCallback::mLastPaError, AudioIoCallback::mLastPlaybackTimeMillis, AudioIoCallback::mLastRecordingOffset, AudioIoCallback::mListener, AudioIoCallback::mMidiStream, AudioIoCallback::mMidiStreamActive, AudioIoCallback::mMidiThread, AudioIoCallback::mMidiThreadFillBuffersLoopActive, AudioIoCallback::mMidiThreadFillBuffersLoopRunning, AudioIoCallback::mMixerOutputVol, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumFrames, AudioIoCallback::mNumPauseFrames, AudioIoCallback::mOutputMeter, AudioIoCallback::mOwningProject, AudioIoCallback::mPaused, AudioIoCallback::mPortStreamV19, AudioIoCallback::mScrubDuration, AudioIoCallback::mScrubState, AudioIoCallback::mSendMidiState, AudioIoCallback::mSilentScrub, AudioIoCallback::mStreamToken, AudioIoCallback::mThread, AudioIoCallback::mUpdateMeters, and AudioIoCallback::mUpdatingMeters.

991 {
992  if (!std::atomic<double>{}.is_lock_free()) {
993  // If this check fails, then the atomic<double> members in AudioIO.h
994  // might be changed to atomic<float> to be more efficient with some
995  // loss of precision. That could be conditionally compiled depending
996  // on the platform.
997  wxASSERT(false);
998  }
999 
1000  // This ASSERT because of casting in the callback
1001  // functions where we cast a tempFloats buffer to a (short*) buffer.
1002  // We have to ASSERT in the GUI thread, if we are to see it properly.
1003  wxASSERT( sizeof( short ) <= sizeof( float ));
1004 
1008  mPortStreamV19 = NULL;
1009 
1010 #ifdef EXPERIMENTAL_MIDI_OUT
1011  mMidiStream = NULL;
1014  mMidiStreamActive = false;
1015  mSendMidiState = false;
1016  mIterator = NULL;
1017 
1018  mNumFrames = 0;
1019  mNumPauseFrames = 0;
1020 #endif
1021 
1022 #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1023  mAILAActive = false;
1024 #endif
1025  mStreamToken = 0;
1026 
1027  mLastPaError = paNoError;
1028 
1029  mLastRecordingOffset = 0.0;
1030  mNumCaptureChannels = 0;
1031  mPaused = false;
1032 
1033  mListener = NULL;
1034  mUpdateMeters = false;
1035  mUpdatingMeters = false;
1036 
1037  mOwningProject = NULL;
1038  mOutputMeter = NULL;
1039 
1040  PaError err = Pa_Initialize();
1041 
1042  if (err != paNoError) {
1043  wxString errStr = _("Could not find any audio devices.\n");
1044  errStr += _("You will not be able to play or record audio.\n\n");
1045  wxString paErrStr = LAT1CTOWX(Pa_GetErrorText(err));
1046  if (!paErrStr.IsEmpty())
1047  errStr += _("Error: ")+paErrStr;
1048  // XXX: we are in libaudacity, popping up dialogs not allowed! A
1049  // long-term solution will probably involve exceptions
1050  AudacityMessageBox(errStr, _("Error Initializing Audio"), wxICON_ERROR|wxOK);
1051 
1052  // Since PortAudio is not initialized, all calls to PortAudio
1053  // functions will fail. This will give reasonable behavior, since
1054  // the user will be able to do things not relating to audio i/o,
1055  // but any attempt to play or record will simply fail.
1056  }
1057 
1058 #ifdef EXPERIMENTAL_MIDI_OUT
1059  PmError pmErr = Pm_Initialize();
1060 
1061  if (pmErr != pmNoError) {
1062  wxString errStr =
1063  _("There was an error initializing the midi i/o layer.\n");
1064  errStr += _("You will not be able to play midi.\n\n");
1065  wxString pmErrStr = LAT1CTOWX(Pm_GetErrorText(pmErr));
1066  if (!pmErrStr.empty())
1067  errStr += _("Error: ") + pmErrStr;
1068  // XXX: we are in libaudacity, popping up dialogs not allowed! A
1069  // long-term solution will probably involve exceptions
1070  AudacityMessageBox(errStr, _("Error Initializing Midi"), wxICON_ERROR|wxOK);
1071 
1072  // Same logic for PortMidi as described above for PortAudio
1073  }
1074 
1075 #ifdef USE_MIDI_THREAD
1076  mMidiThread = std::make_unique<MidiThread>();
1077  mMidiThread->Create();
1078 #endif
1079 
1080 #endif
1081 
1082  // Start thread
1083  mThread = std::make_unique<AudioThread>();
1084  mThread->Create();
1085 
1086 #if defined(USE_PORTMIXER)
1087  mPortMixer = NULL;
1088  mPreviousHWPlaythrough = -1.0;
1090 #else
1091  mEmulateMixerOutputVol = true;
1092  mMixerOutputVol = 1.0;
1093  mInputMixerWorks = false;
1094 #endif
1095 
1097 
1098 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
1099  mScrubState = NULL;
1100  mScrubDuration = 0;
1101  mSilentScrub = false;
1102 #endif
1103 }
float mMixerOutputVol
Definition: AudioIO.h:567
volatile bool mUpdatingMeters
Definition: AudioIO.h:551
AudacityProject * mOwningProject
Definition: AudioIO.h:547
volatile bool mMidiThreadFillBuffersLoopRunning
Definition: AudioIO.h:538
PaError mLastPaError
Definition: AudioIO.h:543
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
unsigned int mNumCaptureChannels
Definition: AudioIO.h:527
sampleCount mScrubDuration
Definition: AudioIO.h:600
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:535
volatile long mNumPauseFrames
How many frames of zeros were output due to pauses?
Definition: AudioIO.h:410
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:532
PaStream * mPortStreamV19
Definition: AudioIO.h:522
PmStream * mMidiStream
Definition: AudioIO.h:396
bool mMidiStreamActive
mMidiStreamActive tells when mMidiStream is open for output
Definition: AudioIO.h:465
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:489
void HandleDeviceChange()
update state after changing what audio devices are selected
Definition: AudioIO.cpp:1246
volatile bool mAudioThreadFillBuffersLoopActive
Definition: AudioIO.h:533
MeterPanel * mOutputMeter
Definition: AudioIO.h:549
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:521
#define LAT1CTOWX(X)
Definition: Internat.h:180
bool mSendMidiState
Definition: AudioIO.h:468
_("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:542
volatile int mStreamToken
Definition: AudioIO.h:502
bool mSilentScrub
Definition: AudioIO.h:598
std::unique_ptr< Alg_iterator > mIterator
Definition: AudioIO.h:447
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:595
bool mUpdateMeters
Definition: AudioIO.h:550
bool mEmulateMixerOutputVol
Definition: AudioIO.h:558
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:531
std::unique_ptr< AudioThread > mMidiThread
Definition: AudioIO.h:492
volatile long mNumFrames
Number of frames output, including pauses.
Definition: AudioIO.h:408
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:566
AudioIOListener * mListener
Definition: AudioIO.h:569
volatile bool mMidiThreadFillBuffersLoopActive
Definition: AudioIO.h:539
AudioIO::~AudioIO ( )

Definition at line 1105 of file AudioIO.cpp.

References gAudioIO, AudioIoCallback::mMidiThread, and AudioIoCallback::mThread.

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

Member Function Documentation

void AudioIO::AllNotesOff ( bool  looping = false)
private

Definition at line 4454 of file AudioIO.cpp.

References MidiTime(), AudioIoCallback::mMaxMidiTimestamp, AudioIoCallback::mMidiStream, and AudioIoCallback::mPendingNotesOff.

Referenced by StopStream().

4455 {
4456 #ifdef __WXGTK__
4457  bool doDelay = !looping;
4458 #else
4459  bool doDelay = false;
4460  static_cast<void>(looping);// compiler food.
4461 #endif
4462 
4463  // to keep track of when MIDI should all be delivered,
4464  // update mMaxMidiTimestamp to now:
4465  PmTimestamp now = MidiTime();
4466  if (mMaxMidiTimestamp < now) {
4467  mMaxMidiTimestamp = now;
4468  }
4469 #ifdef AUDIO_IO_GB_MIDI_WORKAROUND
4470  // PRL:
4471  // Send individual note-off messages for each note-on not yet paired.
4472 
4473  // RBD:
4474  // Even this did not work as planned. My guess is ALSA does not use
4475  // a "stable sort" for timed messages, so that when a note-off is
4476  // added later at the same time as a future note-on, the order is
4477  // not respected, and the note-off can go first, leaving a stuck note.
4478  // The workaround here is to use mMaxMidiTimestamp to ensure that
4479  // note-offs come at least 1ms later than any previous message
4480 
4481  // PRL:
4482  // I think we should do that only when stopping or pausing, not when looping
4483  // Note that on Linux, MIDI always uses ALSA, no matter whether portaudio
4484  // uses some other host api.
4485 
4486  mMaxMidiTimestamp += 1;
4487  for (const auto &pair : mPendingNotesOff) {
4488  Pm_WriteShort(mMidiStream,
4489  (doDelay ? mMaxMidiTimestamp : 0),
4490  Pm_Message(
4491  0x90 + pair.first, pair.second, 0));
4492  mMaxMidiTimestamp++; // allow 1ms per note-off
4493  }
4494  mPendingNotesOff.clear();
4495 
4496  // Proceed to do the usual messages too.
4497 #endif
4498 
4499  for (int chan = 0; chan < 16; chan++) {
4500  Pm_WriteShort(mMidiStream,
4501  (doDelay ? mMaxMidiTimestamp : 0),
4502  Pm_Message(0xB0 + chan, 0x7B, 0));
4503  mMaxMidiTimestamp++; // allow 1ms per all-notes-off
4504  }
4505 }
PmTimestamp MidiTime()
Compute the current PortMidi timestamp time.
Definition: AudioIO.cpp:4430
PmStream * mMidiStream
Definition: AudioIO.h:396
std::vector< std::pair< int, int > > mPendingNotesOff
Definition: AudioIO.h:452
PmTimestamp mMaxMidiTimestamp
Definition: AudioIO.h:423
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 2055 of file AudioIO.cpp.

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

Referenced by StartStream().

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

Definition at line 3746 of file AudioIO.cpp.

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

Referenced by AudioThread::Entry().

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

Definition at line 4341 of file AudioIO.cpp.

References AudioIoCallback::AudioTime(), AudioIoCallback::IsPaused(), AudioIoCallback::mAudioOutLatency, MIDI_MINIMAL_LATENCY_MS, MIDI_SLEEP, MidiTime(), AudioIoCallback::mMidiOutputComplete, AudioIoCallback::mMidiPaused, AudioIoCallback::mMidiPlaybackTracks, AudioIoCallback::mNextEvent, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIoCallback::mSynthLatency, AudioIoCallback::PlaybackSchedule::mT1, AudioIoCallback::PlaybackSchedule::PlayingStraight(), THREAD_LATENCY, and AudioIoCallback::PlaybackSchedule::TrackDuration().

Referenced by MidiThread::Entry().

4342 {
4343  // Keep track of time paused. If not paused, fill buffers.
4344  if (IsPaused()) {
4345  if (!mMidiPaused) {
4346  mMidiPaused = true;
4347  AllNotesOff(); // to avoid hanging notes during pause
4348  }
4349  return;
4350  }
4351 
4352  if (mMidiPaused) {
4353  mMidiPaused = false;
4354  }
4355 
4356  //---- Duplicated code -----
4357  // TODO this code is duplicated. Look for mbHasSoloTracks.
4358  bool hasSolo = false;
4359  auto numPlaybackTracks = mPlaybackTracks.size();
4360  for(unsigned t = 0; t < numPlaybackTracks; t++ )
4361  if( mPlaybackTracks[t]->GetSolo() ) {
4362  hasSolo = true;
4363  break;
4364  }
4365  auto numMidiPlaybackTracks = mMidiPlaybackTracks.size();
4366  for(unsigned t = 0; t < numMidiPlaybackTracks; t++ )
4367  if( mMidiPlaybackTracks[t]->GetSolo() ) {
4368  hasSolo = true;
4369  break;
4370  }
4371  SetHasSolo(hasSolo);
4372  //---- End duplicated code -----
4373 
4374 
4375  // If we compute until mNextEventTime > current audio time,
4376  // we would have a built-in compute-ahead of mAudioOutLatency, and
4377  // it's probably good to compute MIDI when we compute audio (so when
4378  // we stop, both stop about the same time).
4379  double time = AudioTime(); // compute to here
4380  // But if mAudioOutLatency is very low, we might need some extra
4381  // compute-ahead to deal with mSynthLatency or even this thread.
4382  double actual_latency = (MIDI_SLEEP + THREAD_LATENCY +
4384  if (actual_latency > mAudioOutLatency) {
4385  time += actual_latency - mAudioOutLatency;
4386  }
4387  while (mNextEvent &&
4388  UncorrectedMidiEventTime() < time) {
4389  OutputEvent();
4390  GetNextEvent();
4391  }
4392 
4393  // test for end
4394  double realTime = MidiTime() * 0.001 -
4395  PauseTime();
4396  realTime -= 1; // MidiTime() runs ahead 1s
4397 
4398  // XXX Is this still true now? It seems to break looping --Poke
4399  //
4400  // The TrackPanel::OnTimer() method updates the time position
4401  // indicator every 200ms, so it tends to not advance the
4402  // indicator to the end of the selection (mT1) but instead stop
4403  // up to 200ms before the end. At this point, output is shut
4404  // down and the indicator is removed, but for a brief time, the
4405  // indicator is clearly stopped before reaching mT1. To avoid
4406  // this, we do not set mMidiOutputComplete until we are actually
4407  // 0.22s beyond mT1 (even though we stop playing at mT1). This
4408  // gives OnTimer() time to wake up and draw the final time
4409  // position at mT1 before shutting down the stream.
4410  const double loopDelay = 0.220;
4411 
4412  auto timeAtSpeed = mPlaybackSchedule.TrackDuration(realTime);
4413 
4415  (mPlaybackSchedule.PlayingStraight() && // PRL: what if scrubbing?
4416  timeAtSpeed >= mPlaybackSchedule.mT1 + loopDelay);
4417  // !mNextEvent);
4418 }
#define MIDI_SLEEP
Definition: AudioIO.cpp:466
#define THREAD_LATENCY
Definition: AudioIO.cpp:471
double TrackDuration(double realElapsed) const
Definition: AudioIO.cpp:5733
Alg_event_ptr mNextEvent
The next event to play (or null)
Definition: AudioIO.h:449
long mSynthLatency
Latency of MIDI synthesizer.
Definition: AudioIO.h:400
void AllNotesOff(bool looping=false)
Definition: AudioIO.cpp:4454
void GetNextEvent()
Definition: AudioIO.cpp:4305
PmTimestamp MidiTime()
Compute the current PortMidi timestamp time.
Definition: AudioIO.cpp:4430
double mAudioOutLatency
Definition: AudioIO.h:431
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:499
double AudioTime()
Definition: AudioIO.h:379
void OutputEvent()
Definition: AudioIO.cpp:4158
bool SetHasSolo(bool hasSolo)
Definition: AudioIO.cpp:4334
bool IsPaused() const
Find out if playback / recording is currently paused.
Definition: AudioIO.cpp:2709
double PauseTime()
Definition: AudioIO.cpp:4420
NoteTrackConstArray mMidiPlaybackTracks
Definition: AudioIO.h:469
bool mMidiOutputComplete
True when output reaches mT1.
Definition: AudioIO.h:461
double UncorrectedMidiEventTime()
Definition: AudioIO.cpp:4144
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
double mT1
Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 duri...
Definition: AudioIO.h:649
volatile bool mMidiPaused
Definition: AudioIO.h:420
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 3105 of file AudioIO.cpp.

References make_iterator_range(), AudioIoCallback::mCachedBestRateIn, and AudioIoCallback::mCachedBestRateOut.

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

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

Definition at line 1026 of file AudioIO.h.

1026 { return mCaptureFormat; }
sampleFormat mCaptureFormat
Definition: AudioIO.h:529
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 3262 of file AudioIO.cpp.

References AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, and min().

3263 {
3264  auto commonlyAvail = mCaptureBuffers[0]->AvailForGet();
3265  for (unsigned i = 1; i < mCaptureTracks.size(); ++i)
3266  commonlyAvail = std::min(commonlyAvail,
3267  mCaptureBuffers[i]->AvailForGet());
3268  return commonlyAvail;
3269 }
int min(int a, int b)
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:497
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:496
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 3239 of file AudioIO.cpp.

References min(), AudioIoCallback::mPlaybackBuffers, and AudioIoCallback::mPlaybackTracks.

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

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

Definition at line 3401 of file AudioIO.cpp.

References audacityAudioCallback(), DEFAULT_LATENCY_CORRECTION, DeviceName(), gPrefs, HostName(), and name.

Referenced by HelpActions::Handler::OnAudioDeviceInfo().

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

Definition at line 900 of file AudioIO.h.

900 { return mHasSolo; }
bool mHasSolo
Definition: AudioIO.h:897
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 1218 of file AudioIO.cpp.

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

Definition at line 877 of file AudioIO.h.

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

return the ending time of the last scrub interval.

Referenced by Scrubber::ContinueScrubbingPoll().

AudioIOListener* AudioIO::GetListener ( )
inline

Definition at line 809 of file AudioIO.h.

References AudioIoCallback::mListener.

Referenced by AudacityProject::OnCloseWindow().

809 { return mListener; }
AudioIOListener * mListener
Definition: AudioIO.h:569
wxString AudioIO::GetMidiDeviceInfo ( )

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

Definition at line 3641 of file AudioIO.cpp.

References gPrefs, and name.

Referenced by HelpActions::Handler::OnMidiDeviceInfo().

3642 {
3643  wxStringOutputStream o;
3644  wxTextOutputStream s(o, wxEOL_UNIX);
3645  wxString e(wxT("\n"));
3646 
3647  if (IsStreamActive()) {
3648  return wxT("Stream is active ... unable to gather information.");
3649  }
3650 
3651 
3652  // XXX: May need to trap errors as with the normal device info
3653  int recDeviceNum = Pm_GetDefaultInputDeviceID();
3654  int playDeviceNum = Pm_GetDefaultOutputDeviceID();
3655  int cnt = Pm_CountDevices();
3656 
3657  wxLogDebug(wxT("PortMidi reports %d MIDI devices"), cnt);
3658 
3659  s << wxT("==============================") << e;
3660  s << wxT("Default recording device number: ") << recDeviceNum << e;
3661  s << wxT("Default playback device number: ") << playDeviceNum << e;
3662 
3663  wxString recDevice = gPrefs->Read(wxT("/MidiIO/RecordingDevice"), wxT(""));
3664  wxString playDevice = gPrefs->Read(wxT("/MidiIO/PlaybackDevice"), wxT(""));
3665 
3666  // This gets info on all available audio devices (input and output)
3667  if (cnt <= 0) {
3668  s << wxT("No devices found\n");
3669  return o.GetString();
3670  }
3671 
3672  for (int i = 0; i < cnt; i++) {
3673  s << wxT("==============================") << e;
3674 
3675  const PmDeviceInfo* info = Pm_GetDeviceInfo(i);
3676  if (!info) {
3677  s << wxT("Device info unavailable for: ") << i << e;
3678  continue;
3679  }
3680 
3681  wxString name = wxSafeConvertMB2WX(info->name);
3682  wxString hostName = wxSafeConvertMB2WX(info->interf);
3683 
3684  s << wxT("Device ID: ") << i << e;
3685  s << wxT("Device name: ") << name << e;
3686  s << wxT("Host name: ") << hostName << e;
3687  s << wxT("Supports output: ") << info->output << e;
3688  s << wxT("Supports input: ") << info->input << e;
3689  s << wxT("Opened: ") << info->opened << e;
3690 
3691  if (name == playDevice && info->output)
3692  playDeviceNum = i;
3693 
3694  if (name == recDevice && info->input)
3695  recDeviceNum = i;
3696 
3697  // XXX: This is only done because the same was applied with PortAudio
3698  // If PortMidi returns -1 for the default device, use the first one
3699  if (recDeviceNum < 0 && info->input){
3700  recDeviceNum = i;
3701  }
3702  if (playDeviceNum < 0 && info->output){
3703  playDeviceNum = i;
3704  }
3705  }
3706 
3707  bool haveRecDevice = (recDeviceNum >= 0);
3708  bool havePlayDevice = (playDeviceNum >= 0);
3709 
3710  s << wxT("==============================") << e;
3711  if (haveRecDevice) {
3712  s << wxT("Selected MIDI recording device: ") << recDeviceNum << wxT(" - ") << recDevice << e;
3713  } else {
3714  s << wxT("No MIDI recording device found for '") << recDevice << wxT("'.") << e;
3715  }
3716  if (havePlayDevice) {
3717  s << wxT("Selected MIDI playback device: ") << playDeviceNum << wxT(" - ") << playDevice << e;
3718  } else {
3719  s << wxT("No MIDI playback device found for '") << playDevice << wxT("'.") << e;
3720  }
3721 
3722  // Mention our conditional compilation flags for Alpha only
3723 #ifdef IS_ALPHA
3724 
3725  s << wxT("==============================") << e;
3726 #ifdef EXPERIMENTAL_MIDI_OUT
3727  s << wxT("EXPERIMENTAL_MIDI_OUT is enabled") << e;
3728 #else
3729  s << wxT("EXPERIMENTAL_MIDI_OUT is NOT enabled") << e;
3730 #endif
3731 #ifdef EXPERIMENTAL_MIDI_IN
3732  s << wxT("EXPERIMENTAL_MIDI_IN is enabled") << e;
3733 #else
3734  s << wxT("EXPERIMENTAL_MIDI_IN is NOT enabled") << e;
3735 #endif
3736 
3737 #endif
3738 
3739  return o.GetString();
3740 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2749
const wxChar * name
Definition: Distortion.cpp:94
void AudioIO::GetMixer ( int *  inputSource,
float *  inputVolume,
float *  playbackVolume 
)

Definition at line 1177 of file AudioIO.cpp.

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

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

1179 {
1180 #if defined(USE_PORTMIXER)
1181 
1182  PxMixer *mixer = mPortMixer;
1183 
1184  if( mixer )
1185  {
1186  *recordDevice = Px_GetCurrentInputSource(mixer);
1187 
1188  if (mInputMixerWorks)
1189  *recordVolume = Px_GetInputVolume(mixer);
1190  else
1191  *recordVolume = 1.0f;
1192 
1194  *playbackVolume = mMixerOutputVol;
1195  else
1196  *playbackVolume = Px_GetPCMOutputVolume(mixer);
1197 
1198  return;
1199  }
1200 
1201 #endif
1202 
1203  *recordDevice = 0;
1204  *recordVolume = 1.0f;
1205  *playbackVolume = mMixerOutputVol;
1206 }
float mMixerOutputVol
Definition: AudioIO.h:567
bool mEmulateMixerOutputVol
Definition: AudioIO.h:558
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:566
void AudioIO::GetNextEvent ( )
private

Definition at line 4305 of file AudioIO.cpp.

References gAllNotesOff, AudioIoCallback::MidiLoopOffset(), AudioIoCallback::mIterator, AudioIoCallback::mNextEvent, AudioIoCallback::mNextEventTime, AudioIoCallback::mNextEventTrack, AudioIoCallback::mNextIsNoteOn, AudioIoCallback::mPlaybackSchedule, and AudioIoCallback::PlaybackSchedule::mT1.

Referenced by PrepareMidiIterator().

4306 {
4307  mNextEventTrack = NULL; // clear it just to be safe
4308  // now get the next event and the track from which it came
4309  double nextOffset;
4310  if (!mIterator) {
4311  mNextEvent = NULL;
4312  return;
4313  }
4314  auto midiLoopOffset = MidiLoopOffset();
4316  (void **) &mNextEventTrack,
4317  &nextOffset, mPlaybackSchedule.mT1 + midiLoopOffset);
4318 
4319  mNextEventTime = mPlaybackSchedule.mT1 + midiLoopOffset + 1;
4320  if (mNextEvent) {
4322  mNextEvent->get_end_time()) + nextOffset;;
4323  }
4324  if (mNextEventTime > (mPlaybackSchedule.mT1 + midiLoopOffset)){ // terminate playback at mT1
4326  mNextEventTime = mPlaybackSchedule.mT1 + midiLoopOffset - ALG_EPS;
4327  mNextIsNoteOn = true; // do not look at duration
4328  mIterator->end();
4329  mIterator.reset(); // debugging aid
4330  }
4331 }
Alg_event_ptr mNextEvent
The next event to play (or null)
Definition: AudioIO.h:449
bool mNextIsNoteOn
Is the next event a note-on?
Definition: AudioIO.h:463
double mNextEventTime
Definition: AudioIO.h:457
static Alg_update gAllNotesOff
Definition: AudioIO.cpp:4141
NoteTrack * mNextEventTrack
Track of next event.
Definition: AudioIO.h:459
std::unique_ptr< Alg_iterator > mIterator
Definition: AudioIO.h:447
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
double mT1
Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 duri...
Definition: AudioIO.h:649
double MidiLoopOffset()
Definition: AudioIO.h:413
unsigned AudioIO::GetNumCaptureChannels ( ) const
inline
unsigned AudioIO::GetNumPlaybackChannels ( ) const
inline

Definition at line 1027 of file AudioIO.h.

Referenced by ControlToolBar::StartScrolling().

1027 { return mNumPlaybackChannels; }
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:528
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 3085 of file AudioIO.cpp.

References make_iterator_range().

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

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

Definition at line 878 of file AudioIO.h.

References AudioIoCallback::mLastPlaybackTimeMillis.

Referenced by ControlToolBar::CanStopAudioStream().

878 { return mOwningProject; }
AudacityProject * mOwningProject
Definition: AudioIO.h:547
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 3285 of file AudioIO.cpp.

References DeviceName(), and gPrefs.

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

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

References DeviceName(), and gPrefs.

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

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

References BAD_STREAM_TIME, AudioIoCallback::mPlaybackSchedule, and AudioIoCallback::PlaybackSchedule::NormalizeTrackTime().

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

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

References DEFAULT_LATENCY_DURATION, gPrefs, make_iterator_range(), AudioIoCallback::mCachedCaptureIndex, and AudioIoCallback::mCachedCaptureRates.

Referenced by HandleDeviceChange().

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

References make_iterator_range(), AudioIoCallback::mCachedPlaybackIndex, and AudioIoCallback::mCachedPlaybackRates.

Referenced by HandleDeviceChange().

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

References make_iterator_range(), AudioIoCallback::mCachedCaptureIndex, AudioIoCallback::mCachedPlaybackIndex, and AudioIoCallback::mCachedSampleRates.

Referenced by HandleDeviceChange().

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

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

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

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

References AudioIoCallback::mInputMixerWorks.

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

1209 {
1210  return mInputMixerWorks;
1211 }
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIO.h:566
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 2768 of file AudioIO.cpp.

References AudioIoCallback::mStreamToken.

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

2769 {
2770  return ( token > 0 && token == mStreamToken );
2771 }
volatile int mStreamToken
Definition: AudioIO.h:502
bool AudioIO::IsAvailable ( AudacityProject projecT) const

Function to automatically set an acceptable volume.

Definition at line 2367 of file AudioIO.cpp.

References AudioIoCallback::mOwningProject.

Referenced by EffectUIHost::Initialize().

2368 {
2369  return mOwningProject == NULL || mOwningProject == project;
2370 }
AudacityProject * mOwningProject
Definition: AudioIO.h:547
bool AudioIO::IsBusy ( ) const
bool AudioIO::IsCapturing ( ) const

Definition at line 5789 of file AudioIO.cpp.

References AudioIoCallback::PlaybackSchedule::GetTrackTime(), AudioIoCallback::mPlaybackSchedule, AudioIoCallback::RecordingSchedule::mPreRoll, AudioIoCallback::mRecordingSchedule, and AudioIoCallback::PlaybackSchedule::mT0.

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

5790 {
5791  // Includes a test of mTime, used in the main thread
5792  return IsStreamActive() &&
5793  GetNumCaptureChannels() > 0 &&
5796 }
unsigned GetNumCaptureChannels() const
Definition: AudioIO.h:1028
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2749
double GetTrackTime() const
Get current track time value, unadjusted.
Definition: AudioIO.h:702
struct AudioIoCallback::RecordingSchedule mRecordingSchedule
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:647
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
bool AudioIO::IsMonitoring ( ) const

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

Definition at line 2773 of file AudioIO.cpp.

References AudioIoCallback::mPortStreamV19, and AudioIoCallback::mStreamToken.

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

2774 {
2775  return ( mPortStreamV19 && mStreamToken==0 );
2776 }
PaStream * mPortStreamV19
Definition: AudioIO.h:522
volatile int mStreamToken
Definition: AudioIO.h:502
bool AudioIO::IsScrubbing ( ) const
inline

Definition at line 843 of file AudioIO.h.

Referenced by ControlToolBar::OnPause().

843 { return IsBusy() && mScrubState != 0; }
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
Definition: AudioIO.cpp:2741
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:595
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 2749 of file AudioIO.cpp.

References AudioIoCallback::mMidiOutputComplete, AudioIoCallback::mMidiStreamActive, and AudioIoCallback::mPortStreamV19.

Referenced by ControlToolBar::CanStopAudioStream(), LabelTrack::DoCaptureKey(), TransportActions::DoPlayStopSelect(), DeviceToolBar::EnableDisableButtons(), HandleDeviceChange(), EffectUIHost::Initialize(), AudacityProject::IsAudioActive(), IsStreamActive(), LabelEditActions::Handler::OnAddLabelPlaying(), AudacityProject::OnCloseWindow(), ControlToolBar::OnKeyEvent(), SelectActions::Handler::OnSetLeftSelection(), SelectActions::Handler::OnSetRightSelection(), TrackPanel::OnTimer(), Effect::Preview(), LyricsPanel::UpdateLyrics(), and AudacityProject::ZoomInByFactor().

2750 {
2751  bool isActive = false;
2752  // JKC: Not reporting any Pa error, but that looks OK.
2753  if( mPortStreamV19 )
2754  isActive = (Pa_IsStreamActive( mPortStreamV19 ) > 0);
2755 
2756 #ifdef EXPERIMENTAL_MIDI_OUT
2758  isActive = true;
2759 #endif
2760  return isActive;
2761 }
PaStream * mPortStreamV19
Definition: AudioIO.h:522
bool mMidiStreamActive
mMidiStreamActive tells when mMidiStream is open for output
Definition: AudioIO.h:465
bool mMidiOutputComplete
True when output reaches mT1.
Definition: AudioIO.h:461
bool AudioIO::IsStreamActive ( int  token) const

Definition at line 2763 of file AudioIO.cpp.

References IsAudioTokenActive(), and IsStreamActive().

2764 {
2765  return (this->IsStreamActive() && this->IsAudioTokenActive(token));
2766 }
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
Definition: AudioIO.cpp:2749
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:2768
wxString AudioIO::LastPaErrorString ( )

Definition at line 1666 of file AudioIO.cpp.

References AudioIoCallback::mLastPaError.

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

1667 {
1668  return wxString::Format(wxT("%d %s."), (int) mLastPaError, Pa_GetErrorText(mLastPaError));
1669 }
PaError mLastPaError
Definition: AudioIO.h:543
PmTimestamp AudioIO::MidiTime ( )

Compute the current PortMidi timestamp time.

This is used by PortMidi to synchronize midi time to audio samples

Definition at line 4430 of file AudioIO.cpp.

References MIDI_MINIMAL_LATENCY_MS, AudioIoCallback::mSystemMinusAudioTimePlusLatency, AudioIoCallback::mUsingAlsa, and SystemTime().

Referenced by MidiTime(), StartPortMidiStream(), and StopStream().

4431 {
4432  // note: the extra 0.0005 is for rounding. Round down by casting to
4433  // unsigned long, then convert to PmTimeStamp (currently signed)
4434 
4435  // PRL: the time correction is really Midi latency achieved by different
4436  // means than specifying it to Pm_OpenStream. The use of the accumulated
4437  // sample count generated by the audio callback (in AudioTime()) might also
4438  // have the virtue of keeping the Midi output synched with audio.
4439 
4440  PmTimestamp ts;
4441  // subtract latency here because mSystemMinusAudioTime gets us
4442  // to the current *write* time, but we're writing ahead by audio output
4443  // latency (mAudioOutLatency).
4444  double now = SystemTime(mUsingAlsa);
4445  ts = (PmTimestamp) ((unsigned long)
4446  (1000 * (now + 1.0005 -
4448  // wxPrintf("AudioIO::MidiTime() %d time %g sys-aud %g\n",
4449  // ts, now, mSystemMinusAudioTime);
4450  return ts + MIDI_MINIMAL_LATENCY_MS;
4451 }
bool mUsingAlsa
Definition: AudioIO.h:578
volatile double mSystemMinusAudioTimePlusLatency
Definition: AudioIO.h:444
static double SystemTime(bool usingAlsa)
Definition: AudioIO.cpp:796
void AudioIO::OutputEvent ( )
private

Definition at line 4158 of file AudioIO.cpp.

References PlayableTrack::GetMute(), PlayableTrack::GetSolo(), NoteTrack::GetVelocity(), NoteTrack::IsVisibleChan(), AudioIoCallback::PlaybackSchedule::Looping(), AudioIoCallback::MidiLoopOffset(), AudioIoCallback::mIterator, AudioIoCallback::mMaxMidiTimestamp, AudioIoCallback::mMidiLoopPasses, AudioIoCallback::mMidiStream, AudioIoCallback::mNextEvent, AudioIoCallback::mNextEventTrack, AudioIoCallback::mNextIsNoteOn, AudioIoCallback::mPendingNotesOff, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mSendMidiState, AudioIoCallback::mSynthLatency, name, and ROUND.

Referenced by PrepareMidiIterator().

4159 {
4160  int channel = (mNextEvent->chan) & 0xF; // must be in [0..15]
4161  int command = -1;
4162  int data1 = -1;
4163  int data2 = -1;
4164 
4165  double eventTime = UncorrectedMidiEventTime();
4166 
4167  // 0.0005 is for rounding
4168  double time = eventTime + 0.0005 -
4169  (mSynthLatency * 0.001);
4170 
4171  time += 1; // MidiTime() has a 1s offset
4172  // state changes have to go out without delay because the
4173  // midi stream time gets reset when playback starts, and
4174  // we don't want to leave any control changes scheduled for later
4175  if (time < 0 || mSendMidiState) time = 0;
4176  PmTimestamp timestamp = (PmTimestamp) (time * 1000); /* s to ms */
4177 
4178  // The special event gAllNotesOff means "end of playback, send
4179  // all notes off on all channels"
4180  if (mNextEvent == &gAllNotesOff) {
4181  bool looping = mPlaybackSchedule.Looping();
4182  AllNotesOff(looping);
4183  if (looping) {
4184  // jump back to beginning of loop
4185  ++mMidiLoopPasses;
4187  } else {
4188  mNextEvent = NULL;
4189  }
4190  return;
4191  }
4192 
4193  // if mNextEvent's channel is visible, play it, visibility can
4194  // be updated while playing. Be careful: if we have a note-off,
4195  // then we must not pay attention to the channel selection
4196  // or mute/solo buttons because we must turn the note off
4197  // even if the user changed something after the note began
4198  // Note that because multiple tracks can output to the same
4199  // MIDI channels, it is not a good idea to send "All Notes Off"
4200  // when the user presses the mute button. We have no easy way
4201  // to know what notes are sounding on any given muted track, so
4202  // we'll just wait for the note-off events to happen.
4203  // Also note that note-offs are only sent when we call
4204  // mIterator->request_note_off(), so notes that are not played
4205  // will note generate random note-offs. There is the interesting
4206  // case that if the playback is paused, all-notes-off WILL be sent
4207  // and if playback resumes, the pending note-off events WILL also
4208  // be sent (but if that is a problem, there would also be a problem
4209  // in the non-pause case.
4210  if (((mNextEventTrack->IsVisibleChan(channel)) &&
4211  // only play if note is not muted:
4212  !((mHasSolo || mNextEventTrack->GetMute()) &&
4213  !mNextEventTrack->GetSolo())) ||
4214  (mNextEvent->is_note() && !mNextIsNoteOn)) {
4215  // Note event
4216  if (mNextEvent->is_note() && !mSendMidiState) {
4217  // Pitch and velocity
4218  data1 = mNextEvent->get_pitch();
4219  if (mNextIsNoteOn) {
4220  data2 = mNextEvent->get_loud(); // get velocity
4221  int offset = mNextEventTrack->GetVelocity();
4222  data2 += offset; // offset comes from per-track slider
4223  // clip velocity to insure a legal note-on value
4224  data2 = (data2 < 1 ? 1 : (data2 > 127 ? 127 : data2));
4225  // since we are going to play this note, we need to get a note_off
4226  mIterator->request_note_off();
4227 
4228 #ifdef AUDIO_IO_GB_MIDI_WORKAROUND
4229  mPendingNotesOff.push_back(std::make_pair(channel, data1));
4230 #endif
4231  }
4232  else {
4233  data2 = 0; // 0 velocity means "note off"
4234 #ifdef AUDIO_IO_GB_MIDI_WORKAROUND
4235  auto end = mPendingNotesOff.end();
4236  auto iter = std::find(
4237  mPendingNotesOff.begin(), end, std::make_pair(channel, data1) );
4238  if (iter != end)
4239  mPendingNotesOff.erase(iter);
4240 #endif
4241  }
4242  command = 0x90; // MIDI NOTE ON (or OFF when velocity == 0)
4243  // Update event
4244  } else if (mNextEvent->is_update()) {
4245  // this code is based on allegrosmfwr.cpp -- it could be improved
4246  // by comparing attribute pointers instead of string compares
4247  Alg_update_ptr update = (Alg_update_ptr) mNextEvent;
4248  const char *name = update->get_attribute();
4249 
4250  if (!strcmp(name, "programi")) {
4251  // Instrument change
4252  data1 = update->parameter.i;
4253  data2 = 0;
4254  command = 0xC0; // MIDI PROGRAM CHANGE
4255  } else if (!strncmp(name, "control", 7)) {
4256  // Controller change
4257 
4258  // The number of the controller being changed is embedded
4259  // in the parameter name.
4260  data1 = atoi(name + 7);
4261  // Allegro normalizes controller values
4262  data2 = ROUND(update->parameter.r * 127);
4263  command = 0xB0;
4264  } else if (!strcmp(name, "bendr")) {
4265  // Bend change
4266 
4267  // Reverse Allegro's post-processing of bend values
4268  int temp = ROUND(0x2000 * (update->parameter.r + 1));
4269  if (temp > 0x3fff) temp = 0x3fff; // 14 bits maximum
4270  if (temp < 0) temp = 0;
4271  data1 = temp & 0x7f; // low 7 bits
4272  data2 = temp >> 7; // high 7 bits
4273  command = 0xE0; // MIDI PITCH BEND
4274  } else if (!strcmp(name, "pressurer")) {
4275  // Pressure change
4276  data1 = (int) (update->parameter.r * 127);
4277  if (update->get_identifier() < 0) {
4278  // Channel pressure
4279  data2 = 0;
4280  command = 0xD0; // MIDI CHANNEL PRESSURE
4281  } else {
4282  // Key pressure
4283  data2 = data1;
4284  data1 = update->get_identifier();
4285  command = 0xA0; // MIDI POLY PRESSURE
4286  }
4287  }
4288  }
4289  if (command != -1) {
4290  // keep track of greatest timestamp used
4291  if (timestamp > mMaxMidiTimestamp) {
4292  mMaxMidiTimestamp = timestamp;
4293  }
4294  Pm_WriteShort(mMidiStream, timestamp,
4295  Pm_Message((int) (command + channel),
4296  (long) data1, (long) data2));
4297  /* wxPrintf("Pm_WriteShort %lx (%p) @ %d, advance %d\n",
4298  Pm_Message((int) (command + channel),
4299  (long) data1, (long) data2),
4300  mNextEvent, timestamp, timestamp - Pt_Time()); */
4301  }
4302  }
4303 }
volatile int mMidiLoopPasses
total of backward jumps
Definition: AudioIO.h:412
bool GetSolo() const
Definition: Track.h:777
Alg_event_ptr mNextEvent
The next event to play (or null)
Definition: AudioIO.h:449
long mSynthLatency
Latency of MIDI synthesizer.
Definition: AudioIO.h:400
bool IsVisibleChan(int c) const
Definition: NoteTrack.h:223
void AllNotesOff(bool looping=false)
Definition: AudioIO.cpp:4454
PmStream * mMidiStream
Definition: AudioIO.h:396
bool mNextIsNoteOn
Is the next event a note-on?
Definition: AudioIO.h:463
std::vector< std::pair< int, int > > mPendingNotesOff
Definition: AudioIO.h:452
PmTimestamp mMaxMidiTimestamp
Definition: AudioIO.h:423
bool mSendMidiState
Definition: AudioIO.h:468
const wxChar * name
Definition: Distortion.cpp:94
static Alg_update gAllNotesOff
Definition: AudioIO.cpp:4141
float GetVelocity() const
Definition: NoteTrack.h:116
#define ROUND(x)
Definition: AudioIO.cpp:475
NoteTrack * mNextEventTrack
Track of next event.
Definition: AudioIO.h:459
std::unique_ptr< Alg_iterator > mIterator
Definition: AudioIO.h:447
void PrepareMidiIterator(bool send=true, double offset=0)
Definition: AudioIO.cpp:2278
bool GetMute() const
Definition: Track.h:776
bool mHasSolo
Definition: AudioIO.h:897
double UncorrectedMidiEventTime()
Definition: AudioIO.cpp:4144
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
double MidiLoopOffset()
Definition: AudioIO.h:413
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 1213 of file AudioIO.cpp.

References AudioIoCallback::mEmulateMixerOutputVol.

Referenced by MixerToolBar::SetToolTips().

1214 {
1215  return mEmulateMixerOutputVol;
1216 }
bool mEmulateMixerOutputVol
Definition: AudioIO.h:558
double AudioIO::PauseTime ( )
private

Definition at line 4420 of file AudioIO.cpp.

References AudioIoCallback::mNumPauseFrames, and AudioIoCallback::mRate.

4421 {
4422  return mNumPauseFrames / mRate;
4423 }
volatile long mNumPauseFrames
How many frames of zeros were output due to pauses?
Definition: AudioIO.h:410
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:506
void AudioIO::PrepareMidiIterator ( bool  send = true,
double  offset = 0 
)
private

Definition at line 2278 of file AudioIO.cpp.

References GetNextEvent(), AudioIoCallback::mIterator, AudioIoCallback::mMidiPlaybackTracks, AudioIoCallback::mNextEvent, AudioIoCallback::mNextEventTime, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mSendMidiState, AudioIoCallback::PlaybackSchedule::mT0, and OutputEvent().

Referenced by StartPortMidiStream().

2279 {
2280  int i;
2281  int nTracks = mMidiPlaybackTracks.size();
2282  // instead of initializing with an Alg_seq, we use begin_seq()
2283  // below to add ALL Alg_seq's.
2284  mIterator = std::make_unique<Alg_iterator>(nullptr, false);
2285  // Iterator not yet intialized, must add each track...
2286  for (i = 0; i < nTracks; i++) {
2287  const auto t = mMidiPlaybackTracks[i].get();
2288  Alg_seq_ptr seq = &t->GetSeq();
2289  // mark sequence tracks as "in use" since we're handing this
2290  // off to another thread and want to make sure nothing happens
2291  // to the data until playback finishes. This is just a sanity check.
2292  seq->set_in_use(true);
2293  mIterator->begin_seq(seq,
2294  // casting away const, but allegro just uses the pointer as an opaque "cookie"
2295  (void*)t, t->GetOffset() + offset);
2296  }
2297  GetNextEvent(); // prime the pump for FillMidiBuffers
2298 
2299  // Start MIDI from current cursor position
2300  mSendMidiState = true;
2301  while (mNextEvent &&
2302  mNextEventTime < mPlaybackSchedule.mT0 + offset) {
2303  if (send) OutputEvent();
2304  GetNextEvent();
2305  }
2306  mSendMidiState = false;
2307 }
Alg_event_ptr mNextEvent
The next event to play (or null)
Definition: AudioIO.h:449
void GetNextEvent()
Definition: AudioIO.cpp:4305
void OutputEvent()
Definition: AudioIO.cpp:4158
double mNextEventTime
Definition: AudioIO.h:457
bool mSendMidiState
Definition: AudioIO.h:468
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:647
std::unique_ptr< Alg_iterator > mIterator
Definition: AudioIO.h:447
NoteTrackConstArray mMidiPlaybackTracks
Definition: AudioIO.h:469
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
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 840 of file AudioIO.h.

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

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

Definition at line 2372 of file AudioIO.cpp.

References AudioIoCallback::mInputMeter, AudioIoCallback::mOwningProject, and AudioIoCallback::mRate.

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

2373 {
2374  if (( mOwningProject ) && ( mOwningProject != project))
2375  return;
2376 
2377  if (meter)
2378  {
2379  mInputMeter = meter;
2380  mInputMeter->Reset(mRate, true);
2381  }
2382  else
2383  mInputMeter.Release();
2384 }
AudacityProject * mOwningProject
Definition: AudioIO.h:547
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:548
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:506
bool AudioIO::SetHasSolo ( bool  hasSolo)

Definition at line 4334 of file AudioIO.cpp.

4335 {
4336  mHasSolo = hasSolo;
4337  return mHasSolo;
4338 }
bool mHasSolo
Definition: AudioIO.h:897
void AudioIO::SetListener ( AudioIOListener listener)

Definition at line 4131 of file AudioIO.cpp.

References AudioIoCallback::mListener.

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

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

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

Definition at line 2398 of file AudioIO.cpp.

References AudioIoCallback::mInputMeter, AudioIoCallback::mOutputMeter, AudioIoCallback::mRate, AudioIoCallback::mUpdateMeters, and MeterPanel::Reset().

Referenced by StartPortAudioStream().

2399 {
2400  if (mInputMeter)
2401  mInputMeter->Reset(mRate, true);
2402  if (mOutputMeter)
2403  mOutputMeter->Reset(mRate, true);
2404 
2405  mUpdateMeters = true;
2406 }
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:548
MeterPanel * mOutputMeter
Definition: AudioIO.h:549
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:506
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:550
void AudioIO::SetMixer ( int  inputSource)

Definition at line 1147 of file AudioIO.cpp.

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

1148 {
1149 #if defined(USE_PORTMIXER)
1150  int oldRecordSource = Px_GetCurrentInputSource(mPortMixer);
1151  if ( inputSource != oldRecordSource )
1152  Px_SetCurrentInputSource(mPortMixer, inputSource);
1153 #endif
1154 }
void AudioIO::SetMixer ( int  inputSource,
float  inputVolume,
float  playbackVolume 
)

Definition at line 1156 of file AudioIO.cpp.

References AudioIoCallback::mMixerOutputVol, and SetMixer().

1158 {
1159  mMixerOutputVol = playbackVolume;
1160 #if defined(USE_PORTMIXER)
1161  PxMixer *mixer = mPortMixer;
1162  if( !mixer )
1163  return;
1164 
1165  float oldRecordVolume = Px_GetInputVolume(mixer);
1166  float oldPlaybackVolume = Px_GetPCMOutputVolume(mixer);
1167 
1168  SetMixer(inputSource);
1169  if( oldRecordVolume != recordVolume )
1170  Px_SetInputVolume(mixer, recordVolume);
1171  if( oldPlaybackVolume != playbackVolume )
1172  Px_SetPCMOutputVolume(mixer, playbackVolume);
1173 
1174 #endif
1175 }
float mMixerOutputVol
Definition: AudioIO.h:567
void SetMixer(int inputSource)
Definition: AudioIO.cpp:1147
void AudioIO::SetPaused ( bool  state)

Pause and un-pause playback and recording.

Definition at line 2692 of file AudioIO.cpp.

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

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

2693 {
2694  if (state != mPaused)
2695  {
2696  if (state)
2697  {
2699  }
2700  else
2701  {
2703  }
2704  }
2705 
2706  mPaused = state;
2707 }
bool mPaused
True if audio playback is paused.
Definition: AudioIO.h:521
static EffectManager & Get()
void RealtimeSuspend()
void AudioIO::SetPlaybackMeter ( AudacityProject project,
MeterPanel meter 
)

Definition at line 2386 of file AudioIO.cpp.

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

Referenced by AudacityProject::SetPlaybackMeter().

2387 {
2388  if (( mOwningProject ) && ( mOwningProject != project))
2389  return;
2390 
2391  mOutputMeter = meter;
2392  if (mOutputMeter)
2393  {
2394  mOutputMeter->Reset(mRate, true);
2395  }
2396 }
AudacityProject * mOwningProject
Definition: AudioIO.h:547
MeterPanel * mOutputMeter
Definition: AudioIO.h:549
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:506
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::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 1671 of file AudioIO.cpp.

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

Referenced by MeterPanel::StartMonitoring().

1672 {
1673  if ( mPortStreamV19 || mStreamToken )
1674  return;
1675 
1676  bool success;
1677  long captureChannels;
1678  auto captureFormat = QualityPrefs::SampleFormatChoice();
1679  gPrefs->Read(wxT("/AudioIO/RecordChannels"), &captureChannels, 2L);
1680  gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
1681  int playbackChannels = 0;
1682 
1684  playbackChannels = 2;
1685 
1686  // FIXME: TRAP_ERR StartPortAudioStream (a PaError may be present)
1687  // but StartPortAudioStream function only returns true or false.
1688  mUsingAlsa = false;
1689  success = StartPortAudioStream(sampleRate, (unsigned int)playbackChannels,
1690  (unsigned int)captureChannels,
1691  captureFormat);
1692 
1693  if (!success) {
1694  wxString msg = wxString::Format(_("Error opening recording device.\nError code: %s"), gAudioIO->LastPaErrorString());
1695  ShowErrorDialog(mOwningProject, _("Error"), msg, wxT("Error_opening_sound_device"));
1696  return;
1697  }
1698 
1699  wxCommandEvent e(EVT_AUDIOIO_MONITOR);
1700  e.SetEventObject(mOwningProject);
1701  e.SetInt(true);
1702  wxTheApp->ProcessEvent(e);
1703 
1704  // FIXME: TRAP_ERR PaErrorCode 'noted' but not reported in StartMonitoring.
1705  // Now start the PortAudio stream!
1706  // TODO: ? Factor out and reuse error reporting code from end of
1707  // AudioIO::StartStream?
1708  mLastPaError = Pa_StartStream( mPortStreamV19 );
1709 
1710  // Update UI display only now, after all possibilities for error are past.
1711  if ((mLastPaError == paNoError) && mListener) {
1712  // advertise the chosen I/O sample rate to the UI
1713  mListener->OnAudioIORate((int)mRate);
1714  }
1715 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
AudacityProject * mOwningProject
Definition: AudioIO.h:547
PaError mLastPaError
Definition: AudioIO.h:543
bool mUsingAlsa
Definition: AudioIO.h:578
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:1666
PaStream * mPortStreamV19
Definition: AudioIO.h:522
bool mSoftwarePlaythrough
Definition: AudioIO.h:523
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:506
_("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:491
volatile int mStreamToken
Definition: AudioIO.h:502
virtual void OnAudioIORate(int rate)=0
static sampleFormat SampleFormatChoice()
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:1460
AudioIOListener * mListener
Definition: AudioIO.h:569
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 1460 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, AudioIoCallback::mAudioFramesPerBuffer, AudioIoCallback::mAudioOutLatency, AudioIoCallback::mCallbackCount, AudioIoCallback::mCaptureFormat, AudioIoCallback::mInputMeter, AudioIoCallback::mLastPaError, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumFrames, AudioIoCallback::mNumPauseFrames, AudioIoCallback::mNumPlaybackChannels, AudioIoCallback::mOutputMeter, AudioIoCallback::mOwningProject, AudioIoCallback::mPortStreamV19, AudioIoCallback::mRate, AudioIoCallback::mSoftwarePlaythrough, AudioIoCallback::mSystemMinusAudioTime, AudioIoCallback::mSystemMinusAudioTimePlusLatency, AudioIoCallback::mUsingAlsa, SetCaptureMeter(), SetMeters(), and SystemTime().

Referenced by StartMonitoring(), and StartStream().

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

Definition at line 2309 of file AudioIO.cpp.

References DEFAULT_SYNTH_LATENCY, gPrefs, MIDI_MINIMAL_LATENCY_MS, MidiTime(), AudioIoCallback::mLastPmError, AudioIoCallback::mMaxMidiTimestamp, AudioIoCallback::mMidiLoopPasses, AudioIoCallback::mMidiOutputComplete, AudioIoCallback::mMidiPaused, AudioIoCallback::mMidiPlaybackTracks, AudioIoCallback::mMidiStream, AudioIoCallback::mMidiStreamActive, AudioIoCallback::mMidiThreadFillBuffersLoopRunning, AudioIoCallback::mSynthLatency, name, and PrepareMidiIterator().

Referenced by StartStream().

2310 {
2311  int i;
2312  int nTracks = mMidiPlaybackTracks.size();
2313  // Only start MIDI stream if there is an open track
2314  if (nTracks == 0)
2315  return false;
2316 
2317  //wxPrintf("StartPortMidiStream: mT0 %g mTime %g\n",
2318  // mT0, mTime);
2319 
2320  /* get midi playback device */
2321  PmDeviceID playbackDevice = Pm_GetDefaultOutputDeviceID();
2322  wxString playbackDeviceName = gPrefs->Read(wxT("/MidiIO/PlaybackDevice"),
2323  wxT(""));
2324  mSynthLatency = gPrefs->Read(wxT("/MidiIO/SynthLatency"),
2326  if (wxStrcmp(playbackDeviceName, wxT("")) != 0) {
2327  for (i = 0; i < Pm_CountDevices(); i++) {
2328  const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
2329  if (!info) continue;
2330  if (!info->output) continue;
2331  wxString interf = wxSafeConvertMB2WX(info->interf);
2332  wxString name = wxSafeConvertMB2WX(info->name);
2333  interf.Append(wxT(": ")).Append(name);
2334  if (wxStrcmp(interf, playbackDeviceName) == 0) {
2335  playbackDevice = i;
2336  }
2337  }
2338  } // (else playback device has Pm_GetDefaultOuputDeviceID())
2339 
2340  /* open output device */
2341  mLastPmError = Pm_OpenOutput(&mMidiStream,
2342  playbackDevice,
2343  NULL,
2344  0,
2345  &::MidiTime,
2346  NULL,
2348  if (mLastPmError == pmNoError) {
2349  mMidiStreamActive = true;
2350  mMidiPaused = false;
2351  mMidiLoopPasses = 0;
2352  mMidiOutputComplete = false;
2353  mMaxMidiTimestamp = 0;
2355 
2356  // It is ok to call this now, but do not send timestamped midi
2357  // until after the first audio callback, which provides necessary
2358  // data for MidiTime().
2359  Pm_Synchronize(mMidiStream); // start using timestamps
2360  // start midi output flowing (pending first audio callback)
2362  }
2363  return (mLastPmError == pmNoError);
2364 }
volatile int mMidiLoopPasses
total of backward jumps
Definition: AudioIO.h:412
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
long mSynthLatency
Latency of MIDI synthesizer.
Definition: AudioIO.h:400
volatile bool mMidiThreadFillBuffersLoopRunning
Definition: AudioIO.h:538
PmTimestamp MidiTime()
Compute the current PortMidi timestamp time.
Definition: AudioIO.cpp:4430
#define DEFAULT_SYNTH_LATENCY
Definition: AudioIO.h:84
PmStream * mMidiStream
Definition: AudioIO.h:396
PmError mLastPmError
Definition: AudioIO.h:397
bool mMidiStreamActive
mMidiStreamActive tells when mMidiStream is open for output
Definition: AudioIO.h:465
PmTimestamp mMaxMidiTimestamp
Definition: AudioIO.h:423
const wxChar * name
Definition: Distortion.cpp:94
void PrepareMidiIterator(bool send=true, double offset=0)
Definition: AudioIO.cpp:2278
NoteTrackConstArray mMidiPlaybackTracks
Definition: AudioIO.h:469
bool mMidiOutputComplete
True when output reaches mT1.
Definition: AudioIO.h:461
volatile bool mMidiPaused
Definition: AudioIO.h:420
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 1717 of file AudioIO.cpp.

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

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

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

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

Referenced by AllocateBuffers(), and StartStream().

2242 {
2243  if (mNumPlaybackChannels > 0)
2244  {
2246  }
2247 
2248  mPlaybackBuffers.reset();
2249  mPlaybackMixers.reset();
2250  mCaptureBuffers.reset();
2251  mResample.reset();
2252  mTimeQueue.mData.reset();
2253 
2254  if(!bOnlyBuffers)
2255  {
2256  Pa_AbortStream( mPortStreamV19 );
2257  Pa_CloseStream( mPortStreamV19 );
2258  mPortStreamV19 = NULL;
2259  mStreamToken = 0;
2260  }
2261 
2262 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2263  mScrubState.reset();
2264 #endif
2265 }
struct AudioIoCallback::TimeQueue mTimeQueue
PaStream * mPortStreamV19
Definition: AudioIO.h:522
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:528
static EffectManager & Get()
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:498
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:495
volatile int mStreamToken
Definition: AudioIO.h:502
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:595
void RealtimeFinalize()
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:501
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:496
void AudioIO::StopScrub ( )

Definition at line 2722 of file AudioIO.cpp.

References AudioIoCallback::mScrubState.

Referenced by Scrubber::StopScrubbing().

2723 {
2724  if (mScrubState)
2725  mScrubState->Stop();
2726 }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:595
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 AllNotesOff(), AudioIoCallback::ClearRecordingException(), ControlToolBar::CommitRecording(), DEFAULT_LATENCY_DURATION, EXPERIMENTAL_MIDI_OUT, WaveTrack::Flush(), EffectManager::Get(), AudacityProject::GetControlToolBar(), gPrefs, GuardedCall(), AudioIoCallback::mAudioThreadFillBuffersLoopRunning, AudioIoCallback::mAudioThreadShouldCallFillBuffersOnce, AudioIoCallback::mbMicroFades, AudioIoCallback::mCaptureBuffers, AudioIoCallback::mCaptureTracks, AudioIoCallback::RecordingSchedule::mCrossfadeData, AudioIoCallback::TimeQueue::mData, MidiTime(), AudioIoCallback::mInputMeter, AudioIoCallback::mIterator, AudioIoCallback::mListener, AudioIoCallback::mLostCaptureIntervals, AudioIoCallback::mMaxMidiTimestamp, AudioIoCallback::mMidiOutputComplete, AudioIoCallback::mMidiPlaybackTracks, AudioIoCallback::mMidiStream, AudioIoCallback::mMidiStreamActive, AudioIoCallback::mMidiThreadFillBuffersLoopActive, AudioIoCallback::mMidiThreadFillBuffersLoopRunning, AudioIoCallback::mNumCaptureChannels, AudioIoCallback::mNumPlaybackChannels, AudioIoCallback::mOutputMeter, AudioIoCallback::mOwningProject, AudioIoCallback::mPlaybackBuffers, AudioIoCallback::mPlaybackMixers, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::mPlaybackTracks, AudioIoCallback::mPortStreamV19, AudioIoCallback::mRate, AudioIoCallback::mRecordingSchedule, AudioIoCallback::mResample, AudioIoCallback::mScrubState, AudioIoCallback::mStreamToken, AudioIoCallback::mSuspendAudioThread, AudioIoCallback::mTimeQueue, AudioIoCallback::mUpdateMeters, AudioIoCallback::mUpdatingMeters, AudioIOListener::OnAudioIORate(), AudioIOListener::OnAudioIOStopRecording(), EffectManager::RealtimeFinalize(), MeterPanel::Reset(), AudioIoCallback::PlaybackSchedule::ResetMode(), and wxGetApp().

Referenced by 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.mCrossfadeData.clear(); // 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( mbMicroFades && (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...
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  mInputMeter.Release();
2659  mOutputMeter = NULL;
2660  mOwningProject = NULL;
2661 
2662  if (mListener && mNumCaptureChannels > 0)
2664 
2665  //
2666  // Only set token to 0 after we're totally finished with everything
2667  //
2668  mStreamToken = 0;
2669 
2670  mNumCaptureChannels = 0;
2672 
2673  mPlaybackTracks.clear();
2674  mCaptureTracks.clear();
2675 #ifdef HAVE_MIDI
2676  mMidiPlaybackTracks.clear();
2677 #endif
2678 
2679 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
2680  mScrubState.reset();
2681 #endif
2682 
2683  if (mListener) {
2684  // Tell UI to hide sample rate
2686  }
2687 
2688  // Don't cause a busy wait in the audio thread after stopping scrubbing
2690 }
A ToolBar that has the main Transport buttons.
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
volatile bool mUpdatingMeters
Definition: AudioIO.h:551
wxMutex mSuspendAudioThread
Definition: AudioIO.h:591
struct AudioIoCallback::TimeQueue mTimeQueue
AudacityProject * mOwningProject
Definition: AudioIO.h:547
volatile bool mMidiThreadFillBuffersLoopRunning
Definition: AudioIO.h:538
void SyncLockAdjust(double oldT1, double newT1) override
Definition: WaveTrack.cpp:1169
unsigned int mNumCaptureChannels
Definition: AudioIO.h:527
virtual void OnAudioIOStopRecording()=0
void AllNotesOff(bool looping=false)
Definition: AudioIO.cpp:4454
void ClearRecordingException()
Definition: AudioIO.h:609
PmTimestamp MidiTime()
Compute the current PortMidi timestamp time.
Definition: AudioIO.cpp:4430
struct AudioIoCallback::RecordingSchedule mRecordingSchedule
volatile bool mAudioThreadFillBuffersLoopRunning
Definition: AudioIO.h:532
PaStream * mPortStreamV19
Definition: AudioIO.h:522
wxWeakRef< MeterPanel > mInputMeter
Definition: AudioIO.h:548
PmStream * mMidiStream
Definition: AudioIO.h:396
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
bool mMidiStreamActive
mMidiStreamActive tells when mMidiStream is open for output
Definition: AudioIO.h:465
bool mbMicroFades
Definition: AudioIO.h:508
MeterPanel * mOutputMeter
Definition: AudioIO.h:549
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:499
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:528
static EffectManager & Get()
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:498
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:612
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:495
double mRate
Audio playback rate in samples per second.
Definition: AudioIO.h:506
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
PmTimestamp mMaxMidiTimestamp
Definition: AudioIO.h:423
ControlToolBar * GetControlToolBar()
Definition: Project.cpp:4810
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:497
#define EXPERIMENTAL_MIDI_OUT
Definition: Experimental.h:145
volatile int mStreamToken
Definition: AudioIO.h:502
std::unique_ptr< Alg_iterator > mIterator
Definition: AudioIO.h:447
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:595
bool mUpdateMeters
Definition: AudioIO.h:550
virtual void OnAudioIORate(int rate)=0
AudacityApp & wxGetApp()
#define DEFAULT_LATENCY_DURATION
Definition: AudioIO.h:86
volatile bool mAudioThreadShouldCallFillBuffersOnce
Definition: AudioIO.h:531
NoteTrackConstArray mMidiPlaybackTracks
Definition: AudioIO.h:469
void RealtimeFinalize()
PRCrossfadeData mCrossfadeData
Definition: AudioIO.h:632
bool mMidiOutputComplete
True when output reaches mT1.
Definition: AudioIO.h:461
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
AudioIOListener * mListener
Definition: AudioIO.h:569
ArrayOf< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:501
void Flush()
Flush must be called after last Append.
Definition: WaveTrack.cpp:1671
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:496
volatile bool mMidiThreadFillBuffersLoopActive
Definition: AudioIO.h:539
double AudioIO::UncorrectedMidiEventTime ( )
private

Definition at line 4144 of file AudioIO.cpp.

References AudioIoCallback::MidiLoopOffset(), AudioIoCallback::mMidiLoopPasses, AudioIoCallback::mNextEventTime, AudioIoCallback::mPlaybackSchedule, AudioIoCallback::PlaybackSchedule::mT0, AudioIoCallback::PlaybackSchedule::mTimeTrack, AudioIoCallback::PlaybackSchedule::mWarpedLength, and AudioIoCallback::PlaybackSchedule::RealDuration().

4145 {
4146  double time;
4148  time =
4152  else
4153  time = mNextEventTime;
4154 
4155  return time + PauseTime();
4156 }
volatile int mMidiLoopPasses
total of backward jumps
Definition: AudioIO.h:412
double RealDuration(double trackTime1) const
Definition: AudioIO.cpp:5741
double mNextEventTime
Definition: AudioIO.h:457
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Definition: AudioIO.h:647
const TimeTrack * mTimeTrack
Definition: AudioIO.h:674
double PauseTime()
Definition: AudioIO.cpp:4420
struct AudioIoCallback::PlaybackSchedule mPlaybackSchedule
double MidiLoopOffset()
Definition: AudioIO.h:413
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 2716 of file AudioIO.cpp.

Referenced by Scrubber::ContinueScrubbingPoll().

2717 {
2718  if (mScrubState)
2719  mScrubState->Update(endTimeOrSpeed, options);
2720 }
std::unique_ptr< ScrubState > mScrubState
Definition: AudioIO.h:595
bool AudioIO::ValidateDeviceNames ( const wxString &  play,
const wxString &  rec 
)
static

Ensure selected device names are valid.

Definition at line 981 of file AudioIO.cpp.

References getPlayDevIndex(), and getRecordDevIndex().

982 {
983  const PaDeviceInfo *pInfo = Pa_GetDeviceInfo(AudioIO::getPlayDevIndex(play));
984  const PaDeviceInfo *rInfo = Pa_GetDeviceInfo(AudioIO::getRecordDevIndex(rec));
985 
986  // Valid iff both defined and the same api.
987  return pInfo != nullptr && rInfo != nullptr && pInfo->hostApi == rInfo->hostApi;
988 }
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3285
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:3342

Friends And Related Function Documentation

friend class AudioThread
friend

Definition at line 1084 of file AudioIO.h.

void InitAudioIO ( )
friend

Definition at line 929 of file AudioIO.cpp.

930 {
931  ugAudioIO.reset(safenew AudioIO());
932  gAudioIO = ugAudioIO.get();
933  gAudioIO->mThread->Run();
934 #ifdef EXPERIMENTAL_MIDI_OUT
935 #ifdef USE_MIDI_THREAD
936  gAudioIO->mMidiThread->Run();
937 #endif
938 #endif
939 
940  // Make sure device prefs are initialized
941  if (gPrefs->Read(wxT("AudioIO/RecordingDevice"), wxT("")) == wxT("")) {
942  int i = AudioIO::getRecordDevIndex();
943  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
944  if (info) {
945  gPrefs->Write(wxT("/AudioIO/RecordingDevice"), DeviceName(info));
946  gPrefs->Write(wxT("/AudioIO/Host"), HostName(info));
947  }
948  }
949 
950  if (gPrefs->Read(wxT("AudioIO/PlaybackDevice"), wxT("")) == wxT("")) {
951  int i = AudioIO::getPlayDevIndex();
952  const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
953  if (info) {
954  gPrefs->Write(wxT("/AudioIO/PlaybackDevice"), DeviceName(info));
955  gPrefs->Write(wxT("/AudioIO/Host"), HostName(info));
956  }
957  }
958 
959  gPrefs->Flush();
960 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
std::unique_ptr< AudioIO > ugAudioIO
Definition: AudioIO.cpp:490
AudioIO()
Definition: AudioIO.cpp:990
wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:967
static int getPlayDevIndex(const wxString &devName=wxEmptyString)
get the index of the device selected in the preferences.
Definition: AudioIO.cpp:3285
wxString HostName(const PaDeviceInfo *info)
Definition: AudioIO.cpp:974
#define safenew
Definition: Audacity.h:230
std::unique_ptr< AudioThread > mThread
Definition: AudioIO.h:489
AudioIO * gAudioIO
Definition: AudioIO.cpp:491
std::unique_ptr< AudioThread > mMidiThread
Definition: AudioIO.h:492
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:3342
friend class MidiThread
friend

Definitio