Audacity 3.2.0
AudioIO.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 AudioIO.cpp
6
7 Copyright 2000-2004:
8 Dominic Mazzoni
9 Joshua Haberman
10 Markus Meyer
11 Matt Brubeck
12
13 This program is free software; you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at your option)
16 any later version.
17
18********************************************************************//*****************************************************************//****************************************************************//****************************************************************//*******************************************************************/
61
62
63#include "AudioIO.h"
64
65
66
67#include "AudioIOExt.h"
68#include "AudioIOListener.h"
69
70#include "float_cast.h"
71#include "DeviceManager.h"
72
73#include <cfloat>
74#include <math.h>
75#include <stdlib.h>
76#include <algorithm>
77#include <numeric>
78#include <optional>
79
80#ifdef __WXMSW__
81#include <malloc.h>
82#endif
83
84#ifdef HAVE_ALLOCA_H
85#include <alloca.h>
86#endif
87
88#include "portaudio.h"
89
90#if USE_PORTMIXER
91#include "portmixer.h"
92#endif
93
94#include <wx/app.h>
95#include <wx/frame.h>
96#include <wx/wxcrtvararg.h>
97#include <wx/log.h>
98#include <wx/textctrl.h>
99#include <wx/timer.h>
100#include <wx/intl.h>
101#include <wx/debug.h>
102
103#if defined(__WXMAC__) || defined(__WXMSW__)
104#include <wx/power.h>
105#endif
106
107#include "Meter.h"
108#include "Mix.h"
109#include "Resample.h"
110#include "RingBuffer.h"
111#include "Decibels.h"
112#include "Prefs.h"
113#include "Project.h"
114#include "ProjectWindows.h"
115#include "WaveTrack.h"
116#include "TransactionScope.h"
117
119#include "QualitySettings.h"
121#include "BasicUI.h"
122
123#include "Gain.h"
124
125#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
126 #define LOWER_BOUND 0.0
127 #define UPPER_BOUND 1.0
128#endif
129
130using std::max;
131using std::min;
132
134{
135 return static_cast< AudioIO* >( AudioIOBase::Get() );
136}
137
139 TransportState(std::weak_ptr<AudacityProject> wOwningProject,
140 const WaveTrackArray &playbackTracks,
141 unsigned numPlaybackChannels, double sampleRate)
142 {
143 if (auto pOwningProject = wOwningProject.lock();
144 pOwningProject && numPlaybackChannels > 0) {
145 // Setup for realtime playback at the rate of the realtime
146 // stream, not the rate of the track.
148 move(wOwningProject), sampleRate, numPlaybackChannels);
149 // The following adds a new effect processor for each logical track.
150 for (size_t i = 0, cnt = playbackTracks.size(); i < cnt;) {
151 // An array of non-nulls only should be given to us
152 auto vt = playbackTracks[i].get();
153 if (!vt) {
154 wxASSERT(false);
155 continue;
156 }
157 unsigned chanCnt = TrackList::Channels(vt).size();
158 i += chanCnt; // Visit leaders only
160 ->AddTrack(*vt, numPlaybackChannels, sampleRate);
161 }
162 }
163 }
164
165 std::optional<RealtimeEffects::InitializationScope> mpRealtimeInitialization;
166};
167
168// static
173
174#ifdef __WXGTK__
175 // Might #define this for a useful thing on Linux
176 #undef REALTIME_ALSA_THREAD
177#else
178 // never on the other operating systems
179 #undef REALTIME_ALSA_THREAD
180#endif
181
182#ifdef REALTIME_ALSA_THREAD
183#include "pa_linux_alsa.h"
184#endif
185
186int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
187 unsigned long framesPerBuffer,
188 const PaStreamCallbackTimeInfo *timeInfo,
189 PaStreamCallbackFlags statusFlags, void *userData );
190
191
193//
194// UI Thread Context
195//
197
199{
200 auto pAudioIO = safenew AudioIO();
201 ugAudioIO.reset(pAudioIO);
202 pAudioIO->StartThread();
203
204 // Make sure device prefs are initialized
205 if (gPrefs->Read(wxT("AudioIO/RecordingDevice"), wxT("")).empty()) {
206 int i = getRecordDevIndex();
207 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
208 if (info) {
211 }
212 }
213
214 if (gPrefs->Read(wxT("AudioIO/PlaybackDevice"), wxT("")).empty()) {
215 int i = getPlayDevIndex();
216 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
217 if (info) {
220 }
221 }
222
223 gPrefs->Flush();
224}
225
227{
228 ugAudioIO.reset();
229}
230
231bool AudioIO::ValidateDeviceNames(const wxString &play, const wxString &rec)
232{
233 const PaDeviceInfo *pInfo = Pa_GetDeviceInfo(getPlayDevIndex(play));
234 const PaDeviceInfo *rInfo = Pa_GetDeviceInfo(getRecordDevIndex(rec));
235
236 // Valid iff both defined and the same api.
237 return pInfo != nullptr && rInfo != nullptr && pInfo->hostApi == rInfo->hostApi;
238}
239
241{
242 if (!std::atomic<double>{}.is_lock_free()) {
243 // If this check fails, then the atomic<double> members in AudioIO.h
244 // might be changed to atomic<float> to be more efficient with some
245 // loss of precision. That could be conditionally compiled depending
246 // on the platform.
247 wxASSERT(false);
248 }
249
250 // This ASSERT because of casting in the callback
251 // functions where we cast a tempFloats buffer to a (short*) buffer.
252 // We have to ASSERT in the GUI thread, if we are to see it properly.
253 wxASSERT( sizeof( short ) <= sizeof( float ));
254
256 .store(false, std::memory_order_relaxed);
258 .store(false, std::memory_order_relaxed);
260 .store(false, std::memory_order_relaxed);
261
262 mAudioThreadAcknowledge.store(Acknowledge::eNone, std::memory_order_relaxed);
263
264 mPortStreamV19 = NULL;
265
266 mNumPauseFrames = 0;
267
268#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
269 mAILAActive = false;
270#endif
271
272 mLastPaError = paNoError;
273
276 mSilenceLevel = 0.0;
277
278 mOutputMeter.reset();
279
280 PaError err = Pa_Initialize();
281
282 if (err != paNoError) {
283 auto errStr = XO("Could not find any audio devices.\n");
284 errStr += XO("You will not be able to play or record audio.\n\n");
285 wxString paErrStr = LAT1CTOWX(Pa_GetErrorText(err));
286 if (!paErrStr.empty())
287 errStr += XO("Error: %s").Format( paErrStr );
288 // XXX: we are in libaudacity, popping up dialogs not allowed! A
289 // long-term solution will probably involve exceptions
291 errStr,
292 XO("Error Initializing Audio"),
293 wxICON_ERROR|wxOK);
294
295 // Since PortAudio is not initialized, all calls to PortAudio
296 // functions will fail. This will give reasonable behavior, since
297 // the user will be able to do things not relating to audio i/o,
298 // but any attempt to play or record will simply fail.
299 }
300
301#if defined(USE_PORTMIXER)
302 mPortMixer = NULL;
303 mPreviousHWPlaythrough = -1.0;
305#else
306 mInputMixerWorks = false;
307#endif
308
310
312}
313
315{
316 mAudioThread = std::thread(AudioThread, ref(mFinishAudioThread));
317}
318
320{
321 if ( !mOwningProject.expired() )
322 // Unlikely that this will be destroyed earlier than any projects, but
323 // be prepared anyway
325
326#if defined(USE_PORTMIXER)
327 if (mPortMixer) {
328 #if __WXMAC__
329 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
330 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
331 mPreviousHWPlaythrough = -1.0;
332 #endif
333 Px_CloseMixer(mPortMixer);
334 mPortMixer = NULL;
335 }
336#endif
337
338 // FIXME: ? TRAP_ERR. Pa_Terminate probably OK if err without reporting.
339 Pa_Terminate();
340
341 /* Delete is a "graceful" way to stop the thread.
342 (Kill is the not-graceful way.) */
343
344 // This causes reentrancy issues during application shutdown
345 // wxTheApp->Yield();
346
347 mFinishAudioThread.store(true, std::memory_order_release);
348 mAudioThread.join();
349}
350
351std::shared_ptr<RealtimeEffectState>
352AudioIO::AddState(AudacityProject &project, Track *pTrack, const PluginID & id)
353{
355 if (mpTransportState && mpTransportState->mpRealtimeInitialization)
356 if (auto pProject = GetOwningProject(); pProject.get() == &project)
357 pInit = &*mpTransportState->mpRealtimeInitialization;
358 return RealtimeEffectManager::Get(project).AddState(pInit, pTrack, id);
359}
360
361std::shared_ptr<RealtimeEffectState>
363 Track *pTrack, size_t index, const PluginID & id)
364{
366 if (mpTransportState && mpTransportState->mpRealtimeInitialization)
367 if (auto pProject = GetOwningProject(); pProject.get() == &project)
368 pInit = &*mpTransportState->mpRealtimeInitialization;
369 return RealtimeEffectManager::Get(project)
370 .ReplaceState(pInit, pTrack, index, id);
371}
372
374 Track *pTrack, const std::shared_ptr<RealtimeEffectState> pState)
375{
377 if (mpTransportState && mpTransportState->mpRealtimeInitialization)
378 if (auto pProject = GetOwningProject(); pProject.get() == &project)
379 pInit = &*mpTransportState->mpRealtimeInitialization;
380 RealtimeEffectManager::Get(project).RemoveState(pInit, pTrack, pState);
381}
382
383void AudioIO::SetMixer(int inputSource, float recordVolume,
384 float playbackVolume)
385{
386 SetMixerOutputVol(playbackVolume);
387 AudioIOPlaybackVolume.Write(playbackVolume);
388
389#if defined(USE_PORTMIXER)
390 PxMixer *mixer = mPortMixer;
391 if( !mixer )
392 return;
393
394 float oldRecordVolume = Px_GetInputVolume(mixer);
395
396 AudioIoCallback::SetMixer(inputSource);
397 if( oldRecordVolume != recordVolume )
398 Px_SetInputVolume(mixer, recordVolume);
399
400#endif
401}
402
403void AudioIO::GetMixer(int *recordDevice, float *recordVolume,
404 float *playbackVolume)
405{
406 *playbackVolume = GetMixerOutputVol();
407
408#if defined(USE_PORTMIXER)
409
410 PxMixer *mixer = mPortMixer;
411
412 if( mixer )
413 {
414 *recordDevice = Px_GetCurrentInputSource(mixer);
415
417 *recordVolume = Px_GetInputVolume(mixer);
418 else
419 *recordVolume = 1.0f;
420
421 return;
422 }
423
424#endif
425
426 *recordDevice = 0;
427 *recordVolume = 1.0f;
428}
429
431{
432 return mInputMixerWorks;
433}
434
436{
437#if defined(USE_PORTMIXER)
438
439 wxArrayString deviceNames;
440
441 if( mPortMixer )
442 {
443 int numSources = Px_GetNumInputSources(mPortMixer);
444 for( int source = 0; source < numSources; source++ )
445 deviceNames.push_back(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
446 }
447 else
448 {
449 wxLogDebug(wxT("AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
450 }
451
452 return deviceNames;
453
454#else
455
456 wxArrayString blank;
457
458 return blank;
459
460#endif
461}
462
464{
465 switch(format) {
466 case int16Sample:
467 return paInt16;
468 case int24Sample:
469 return paInt24;
470 case floatSample:
471 default:
472 return paFloat32;
473 }
474}
475
477 unsigned int numPlaybackChannels,
478 unsigned int numCaptureChannels,
479 sampleFormat captureFormat)
480{
481 auto sampleRate = options.rate;
482 mNumPauseFrames = 0;
483 SetOwningProject( options.pProject );
484 bool success = false;
485 auto cleanup = finally([&]{
486 if (!success)
488 });
489
490 // PRL: Protection from crash reported by David Bailes, involving starting
491 // and stopping with frequent changes of active window, hard to reproduce
492 if (mOwningProject.expired())
493 return false;
494
495 mInputMeter.reset();
496 mOutputMeter.reset();
497
498 mLastPaError = paNoError;
499 // pick a rate to do the audio I/O at, from those available. The project
500 // rate is suggested, but we may get something else if it isn't supported
501 mRate = GetBestRate(numCaptureChannels > 0, numPlaybackChannels > 0, sampleRate);
502
503 // July 2016 (Carsten and Uwe)
504 // BUG 193: Tell PortAudio sound card will handle 24 bit (under DirectSound) using
505 // userData.
506 int captureFormat_saved = captureFormat;
507 // Special case: Our 24-bit sample format is different from PortAudio's
508 // 3-byte packed format. So just make PortAudio return float samples,
509 // since we need float values anyway to apply the gain.
510 // ANSWER-ME: So we *never* actually handle 24-bit?! This causes mCapture to
511 // be set to floatSample below.
512 // JKC: YES that's right. Internally Audacity uses float, and float has space for
513 // 24 bits as well as exponent. Actual 24 bit would require packing and
514 // unpacking unaligned bytes and would be inefficient.
515 // ANSWER ME: is floatSample 64 bit on 64 bit machines?
516 if (captureFormat == int24Sample)
517 captureFormat = floatSample;
518
519 mNumPlaybackChannels = numPlaybackChannels;
520 mNumCaptureChannels = numCaptureChannels;
521
522 bool usePlayback = false, useCapture = false;
523 PaStreamParameters playbackParameters{};
524 PaStreamParameters captureParameters{};
525
526 auto latencyDuration = AudioIOLatencyDuration.Read();
527
528 if( numPlaybackChannels > 0)
529 {
530 usePlayback = true;
531
532 // this sets the device index to whatever is "right" based on preferences,
533 // then defaults
534 playbackParameters.device = getPlayDevIndex();
535
536 const PaDeviceInfo *playbackDeviceInfo;
537 playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
538
539 if( playbackDeviceInfo == NULL )
540 return false;
541
542 // regardless of source formats, we always mix to float
543 playbackParameters.sampleFormat = paFloat32;
544 playbackParameters.hostApiSpecificStreamInfo = NULL;
545 playbackParameters.channelCount = mNumPlaybackChannels;
546
548 playbackParameters.suggestedLatency =
549 playbackDeviceInfo->defaultLowOutputLatency;
550 else {
551 // When using WASAPI, the suggested latency does not affect
552 // the latency of the playback, but the position of playback is given as if
553 // there was the suggested latency. This results in the last "suggested latency"
554 // of a selection not being played. So for WASAPI use 0.0 for the suggested
555 // latency regardless of user setting. See bug 1949.
556 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
557 bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
558 playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
559 }
560
561 mOutputMeter = options.playbackMeter;
562 }
563
564 if( numCaptureChannels > 0)
565 {
566 useCapture = true;
567 mCaptureFormat = captureFormat;
568
569 const PaDeviceInfo *captureDeviceInfo;
570 // retrieve the index of the device set in the prefs, or a sensible
571 // default if it isn't set/valid
572 captureParameters.device = getRecordDevIndex();
573
574 captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
575
576 if( captureDeviceInfo == NULL )
577 return false;
578
579 captureParameters.sampleFormat =
581
582 captureParameters.hostApiSpecificStreamInfo = NULL;
583 captureParameters.channelCount = mNumCaptureChannels;
584
586 captureParameters.suggestedLatency =
587 captureDeviceInfo->defaultHighInputLatency;
588 else
589 captureParameters.suggestedLatency = latencyDuration/1000.0;
590
592 }
593
594 SetMeters();
595
596#ifdef USE_PORTMIXER
597#ifdef __WXMSW__
598 //mchinen nov 30 2010. For some reason Pa_OpenStream resets the input volume on windows.
599 //so cache and restore after it.
600 //The actual problem is likely in portaudio's pa_win_wmme.c OpenStream().
601 float oldRecordVolume = Px_GetInputVolume(mPortMixer);
602#endif
603#endif
604
605 // July 2016 (Carsten and Uwe)
606 // BUG 193: Possibly tell portAudio to use 24 bit with DirectSound.
607 int userData = 24;
608 int* lpUserData = (captureFormat_saved == int24Sample) ? &userData : NULL;
609
610 // (Linux, bug 1885) After scanning devices it takes a little time for the
611 // ALSA device to be available, so allow retries.
612 // On my test machine, no more than 3 attempts are required.
613 unsigned int maxTries = 1;
614#ifdef __WXGTK__
615 {
616 using namespace std::chrono;
618 maxTries = 5;
619 }
620#endif
621
622 for (unsigned int tries = 0; tries < maxTries; tries++) {
623 mLastPaError = Pa_OpenStream( &mPortStreamV19,
624 useCapture ? &captureParameters : NULL,
625 usePlayback ? &playbackParameters : NULL,
626 mRate, paFramesPerBufferUnspecified,
627 paNoFlag,
628 audacityAudioCallback, lpUserData );
629 if (mLastPaError == paNoError) {
630 break;
631 }
632 wxLogDebug("Attempt %u to open capture stream failed with: %d", 1 + tries, mLastPaError);
633 using namespace std::chrono;
634 std::this_thread::sleep_for(1s);
635 }
636
637
638#if USE_PORTMIXER
639#ifdef __WXMSW__
640 Px_SetInputVolume(mPortMixer, oldRecordVolume);
641#endif
642 if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
643
644 #ifdef __WXMAC__
645 if (mPortMixer) {
646 if (Px_SupportsPlaythrough(mPortMixer)) {
647 bool playthrough = false;
648
649 mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
650
651 // Bug 388. Feature not supported.
652 //gPrefs->Read(wxT("/AudioIO/Playthrough"), &playthrough, false);
653 if (playthrough)
654 Px_SetPlaythrough(mPortMixer, 1.0);
655 else
656 Px_SetPlaythrough(mPortMixer, 0.0);
657 }
658 }
659 #endif
660 }
661#endif
662
663#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
664 // Don't want the system to sleep while audio I/O is active
665 if (mPortStreamV19 != NULL && mLastPaError == paNoError) {
666 wxPowerResource::Acquire(wxPOWER_RESOURCE_SCREEN, _("Audacity Audio"));
667 }
668#endif
669
670 return (success = (mLastPaError == paNoError));
671}
672
674{
675 return wxString::Format(wxT("%d %s."), (int) mLastPaError, Pa_GetErrorText(mLastPaError));
676}
677
679 const std::shared_ptr<AudacityProject> &pProject )
680{
681 if ( !mOwningProject.expired() ) {
682 wxASSERT(false);
684 }
685
686 mOwningProject = pProject;
687}
688
690{
691 mOwningProject.reset();
692}
693
695{
697 return;
698
699 bool success;
700 auto captureFormat = QualitySettings::SampleFormatChoice();
701 auto captureChannels = AudioIORecordChannels.Read();
702 gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
703 int playbackChannels = 0;
704
706 playbackChannels = 2;
707
708 // FIXME: TRAP_ERR StartPortAudioStream (a PaError may be present)
709 // but StartPortAudioStream function only returns true or false.
710 mUsingAlsa = false;
711 success = StartPortAudioStream(options, (unsigned int)playbackChannels,
712 (unsigned int)captureChannels,
713 captureFormat);
714
715 auto pOwningProject = mOwningProject.lock();
716 if (!success) {
717 using namespace BasicUI;
718 auto msg = XO("Error opening recording device.\nError code: %s")
719 .Format( Get()->LastPaErrorString() );
720 ShowErrorDialog( *ProjectFramePlacement( pOwningProject.get() ),
721 XO("Error"), msg, wxT("Error_opening_sound_device"),
722 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
723 return;
724 }
725
726 Publish({ pOwningProject.get(), AudioIOEvent::MONITOR, true });
727
728 // FIXME: TRAP_ERR PaErrorCode 'noted' but not reported in StartMonitoring.
729 // Now start the PortAudio stream!
730 // TODO: ? Factor out and reuse error reporting code from end of
731 // AudioIO::StartStream?
732 mLastPaError = Pa_StartStream( mPortStreamV19 );
733
734 // Update UI display only now, after all possibilities for error are past.
735 auto pListener = GetListener();
736 if ((mLastPaError == paNoError) && pListener) {
737 // advertise the chosen I/O sample rate to the UI
738 pListener->OnAudioIORate((int)mRate);
739 }
740}
741
743 double t0, double t1, double mixerLimit,
744 const AudioIOStartStreamOptions &options)
745{
746 const auto &pStartTime = options.pStartTime;
747 t1 = std::min(t1, mixerLimit);
748
749 mLostSamples = 0;
750 mLostCaptureIntervals.clear();
752 gPrefs->Read( WarningDialogKey(wxT("DropoutDetected")), true ) != 0;
753 auto cleanup = finally ( [this] { ClearRecordingException(); } );
754
755 if( IsBusy() )
756 return 0;
757
758 // We just want to set mStreamToken to -1 - this way avoids
759 // an extremely rare but possible race condition, if two functions
760 // somehow called StartStream at the same time...
761 mStreamToken--;
762 if (mStreamToken != -1)
763 return 0;
764
765 // TODO: we don't really need to close and reopen stream if the
766 // format matches; however it's kind of tricky to keep it open...
767 //
768 // if (sampleRate == mRate &&
769 // playbackChannels == mNumPlaybackChannels &&
770 // captureChannels == mNumCaptureChannels &&
771 // captureFormat == mCaptureFormat) {
772
773 if (mPortStreamV19) {
774 StopStream();
775 while(mPortStreamV19) {
776 using namespace std::chrono;
777 std::this_thread::sleep_for(50ms);
778 }
779 }
780
781#ifdef __WXGTK__
782 // Detect whether ALSA is the chosen host, and do the various involved MIDI
783 // timing compensations only then.
784 mUsingAlsa = (AudioIOHost.Read() == L"ALSA");
785#endif
786
787 gPrefs->Read(wxT("/AudioIO/SWPlaythrough"), &mSoftwarePlaythrough, false);
788 gPrefs->Read(wxT("/AudioIO/SoundActivatedRecord"), &mPauseRec, false);
789 gPrefs->Read(wxT("/AudioIO/Microfades"), &mbMicroFades, false);
790 int silenceLevelDB;
791 gPrefs->Read(wxT("/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
792 int dBRange = DecibelScaleCutoff.Read();
793 if(silenceLevelDB < -dBRange)
794 {
795 silenceLevelDB = -dBRange + 3;
796 // meter range was made smaller than SilenceLevel
797 // so set SilenceLevel reasonable
798
799 // PRL: update prefs, or correct it only in-session?
800 // The behavior (as of 2.3.1) was the latter, the code suggested that
801 // the intent was the former; I preserve the behavior, but uncomment
802 // this if you disagree.
803 // gPrefs->Write(wxT("/AudioIO/SilenceLevel"), silenceLevelDB);
804 // gPrefs->Flush();
805 }
806 mSilenceLevel = DB_TO_LINEAR(silenceLevelDB); // meter goes -dBRange dB -> 0dB
807
808 // Clamp pre-roll so we don't play before time 0
809 const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
815 if (options.pCrossfadeData)
817
818 mListener = options.listener;
819 mRate = options.rate;
820
821 mSeek = 0;
825
826 bool commit = false;
827 auto cleanupTracks = finally([&]{
828 if (!commit) {
829 // Don't keep unnecessary shared pointers to tracks
830 mPlaybackTracks.clear();
831 mCaptureTracks.clear();
832 for(auto &ext : Extensions())
833 ext.AbortOtherStream();
834
835 // Don't cause a busy wait in the audio thread after stopping scrubbing
837 }
838 });
839
840 mPlaybackBuffers.reset();
841 mScratchBuffers.clear();
842 mScratchPointers.clear();
843 mPlaybackMixers.clear();
844 mCaptureBuffers.reset();
845 mResample.reset();
847
849 t0, t1, options, mCaptureTracks.empty() ? nullptr : &mRecordingSchedule );
850
851 unsigned int playbackChannels = 0;
852 unsigned int captureChannels = 0;
853 sampleFormat captureFormat = floatSample;
854
855 auto pListener = GetListener();
856
857 if (tracks.playbackTracks.size() > 0
858 || tracks.otherPlayableTracks.size() > 0)
859 playbackChannels = 2;
860
862 playbackChannels = 2;
863
864 if (tracks.captureTracks.size() > 0)
865 {
866 // For capture, every input channel gets its own track
867 captureChannels = mCaptureTracks.size();
868 // I don't deal with the possibility of the capture tracks
869 // having different sample formats, since it will never happen
870 // with the current code. This code wouldn't *break* if this
871 // assumption was false, but it would be sub-optimal. For example,
872 // if the first track was 16-bit and the second track was 24-bit,
873 // we would set the sound card to capture in 16 bits and the second
874 // track wouldn't get the benefit of all 24 bits the card is capable
875 // of.
876 captureFormat = mCaptureTracks[0]->GetSampleFormat();
877
878 // Tell project that we are about to start recording
879 if (pListener)
880 pListener->OnAudioIOStartRecording();
881 }
882
883 bool successAudio;
884
885 successAudio = StartPortAudioStream(options, playbackChannels,
886 captureChannels, captureFormat);
887
888 // Call this only after reassignment of mRate that might happen in the
889 // previous call.
891
892#ifdef EXPERIMENTAL_MIDI_OUT
893 auto range = Extensions();
894 successAudio = successAudio &&
895 std::all_of(range.begin(), range.end(),
896 [this, &tracks, t0](auto &ext){
897 return ext.StartOtherStream( tracks,
898 (mPortStreamV19 != NULL && mLastPaError == paNoError)
899 ? Pa_GetStreamInfo(mPortStreamV19) : nullptr,
900 t0, mRate ); });
901#endif
902
903 if (!successAudio) {
904 if (pListener && captureChannels > 0)
905 pListener->OnAudioIOStopRecording();
906 mStreamToken = 0;
907
908 return 0;
909 }
910
911 {
912 double mixerStart = t0;
913 if (pStartTime)
914 mixerStart = std::min( mixerStart, *pStartTime );
915 if ( ! AllocateBuffers( options, tracks,
916 mixerStart, mixerLimit, options.rate ) )
917 return 0;
918 }
919
920 mpTransportState = std::make_unique<TransportState>( mOwningProject,
922
923#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
924 AILASetStartTime();
925#endif
926
927 if (pStartTime)
928 {
929 // Calculate the NEW time position
930 const auto time = *pStartTime;
931
932 // Main thread's initialization of mTime
935
936 // Reset mixer positions for all playback tracks
937 for (auto &mixer : mPlaybackMixers)
938 mixer->Reposition( time );
939 }
940
941 // Now that we are done with AllocateBuffers() and SetTrackTime():
943 // else recording only without overdub
944
945 // We signal the audio thread to call TrackBufferExchange, to prime the RingBuffers
946 // so that they will have data in them when the stream starts. Having the
947 // audio thread call TrackBufferExchange here makes the code more predictable, since
948 // TrackBufferExchange will ALWAYS get called from the Audio thread.
950 .store(true, std::memory_order_release);
951
953 .load(std::memory_order_acquire)) {
954 using namespace std::chrono;
955 auto interval = 50ms;
956 if (options.playbackStreamPrimer) {
957 interval = options.playbackStreamPrimer();
958 }
959 std::this_thread::sleep_for(interval);
960 }
961
963
964#ifdef REALTIME_ALSA_THREAD
965 // PRL: Do this in hope of less thread scheduling jitter in calls to
966 // audacityAudioCallback.
967 // Not needed to make audio playback work smoothly.
968 // But needed in case we also play MIDI, so that the variable "offset"
969 // in AudioIO::MidiTime() is a better approximation of the duration
970 // between the call of audacityAudioCallback and the actual output of
971 // the first audio sample.
972 // (Which we should be able to determine from fields of
973 // PaStreamCallbackTimeInfo, but that seems not to work as documented with
974 // ALSA.)
975 if (mUsingAlsa)
976 // Perhaps we should do this only if also playing MIDI ?
977 PaAlsa_EnableRealtimeScheduling( mPortStreamV19, 1 );
978#endif
979
980 //
981 // Generate a unique value each time, to be returned to
982 // clients accessing the AudioIO API, so they can query if they
983 // are the ones who have reserved AudioIO or not.
984 //
985 // It is important to set this before setting the portaudio stream in
986 // motion -- otherwise it may play an unspecified number of leading
987 // zeroes.
989
990 // This affects AudioThread (not the portaudio callback).
991 // Probably not needed so urgently before portaudio thread start for usual
992 // playback, since our ring buffers have been primed already with 4 sec
993 // of audio, but then we might be scrubbing, so do it.
995
996 mForceFadeOut.store(false, std::memory_order_relaxed);
997
998 // Now start the PortAudio stream!
999 PaError err;
1000 err = Pa_StartStream( mPortStreamV19 );
1001
1002 if( err != paNoError )
1003 {
1004 mStreamToken = 0;
1005
1007
1008 if (pListener && mNumCaptureChannels > 0)
1009 pListener->OnAudioIOStopRecording();
1011 // PRL: PortAudio error messages are sadly not internationalized
1013 Verbatim( LAT1CTOWX(Pa_GetErrorText(err)) ) );
1014 return 0;
1015 }
1016 }
1017
1018 // Update UI display only now, after all possibilities for error are past.
1019 if (pListener) {
1020 // advertise the chosen I/O sample rate to the UI
1021 pListener->OnAudioIORate((int)mRate);
1022 }
1023
1024 auto pOwningProject = mOwningProject.lock();
1025 if (mNumPlaybackChannels > 0)
1026 Publish({ pOwningProject.get(), AudioIOEvent::PLAYBACK, true });
1027 if (mNumCaptureChannels > 0)
1028 Publish({ pOwningProject.get(), AudioIOEvent::CAPTURE, true });
1029
1030 commit = true;
1031
1033
1034 return mStreamToken;
1035}
1036
1037void AudioIO::DelayActions(bool recording)
1038{
1039 mDelayingActions = recording;
1040}
1041
1043{
1045}
1046
1048{
1049 if (!action)
1050 return;
1051
1052 {
1053 std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
1055 // Enqueue it, even if perhaps not still recording,
1056 // but it wasn't cleared yet
1058 prevAction = std::move(mPostRecordingAction),
1059 nextAction = std::move(action)
1060 ]{ prevAction(); nextAction(); };
1061 return;
1062 }
1063 else if (DelayingActions()) {
1064 mPostRecordingAction = std::move(action);
1065 return;
1066 }
1067 }
1068
1069 // Don't delay it except until idle time.
1070 // (Recording might start between now and then, but won't go far before
1071 // the action is done. So the system isn't bulletproof yet.)
1072 wxTheApp->CallAfter(std::move(action));
1073}
1074
1076 const AudioIOStartStreamOptions &options,
1077 const TransportTracks &tracks, double t0, double t1, double sampleRate )
1078{
1079 bool success = false;
1080 auto cleanup = finally([&]{
1081 if (!success) StartStreamCleanup( false );
1082 });
1083
1084 auto &policy = mPlaybackSchedule.GetPolicy();
1085 auto times = policy.SuggestedBufferTimes(mPlaybackSchedule);
1086
1087 //
1088 // The (audio) stream has been opened successfully (assuming we tried
1089 // to open it). We now proceed to
1090 // allocate the memory structures the stream will need.
1091 //
1092
1093 //
1094 // The RingBuffer sizes, and the max amount of the buffer to
1095 // fill at a time, both grow linearly with the number of
1096 // tracks. This allows us to scale up to many tracks without
1097 // killing performance.
1098 //
1099
1100 // real playback time to produce with each filling of the buffers
1101 // by the Audio thread (except at the end of playback):
1102 // usually, make fillings fewer and longer for less CPU usage.
1103 // What Audio thread produces for playback is then consumed by the PortAudio
1104 // thread, in many smaller pieces.
1105 double playbackTime = lrint(times.batchSize.count() * mRate) / mRate;
1106
1107 wxASSERT( playbackTime >= 0 );
1108 mPlaybackSamplesToCopy = playbackTime * mRate;
1109
1110 // Capacity of the playback buffer.
1111 mPlaybackRingBufferSecs = times.ringBufferDelay;
1112
1114 4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.size());
1116 0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.size());
1117
1118 bool bDone;
1119 do
1120 {
1121 bDone = true; // assume success
1122 try
1123 {
1124 if( mNumPlaybackChannels > 0 ) {
1125 // Allocate output buffers. For every output track we allocate
1126 // a ring buffer of ten seconds
1127 auto playbackBufferSize =
1128 (size_t)lrint(mRate * mPlaybackRingBufferSecs.count());
1129
1130 // Always make at least one playback buffer
1132 std::max<size_t>(1, mPlaybackTracks.size()));
1133 // Number of scratch buffers depends on device playback channels
1134 if (mNumPlaybackChannels > 0) {
1135 mScratchBuffers.resize(mNumPlaybackChannels * 2 + 1);
1136 mScratchPointers.clear();
1137 for (auto &buffer : mScratchBuffers) {
1138 buffer.Allocate(playbackBufferSize, floatSample);
1139 mScratchPointers.push_back(
1140 reinterpret_cast<float*>(buffer.ptr()));
1141 }
1142 }
1143 mPlaybackMixers.clear();
1144
1145 const auto &warpOptions =
1146 policy.MixerWarpOptions(mPlaybackSchedule);
1147
1148 mPlaybackQueueMinimum = lrint( mRate * times.latency.count() );
1150 std::min( mPlaybackQueueMinimum, playbackBufferSize );
1151
1152 if (mPlaybackTracks.empty())
1153 // Make at least one playback buffer
1154 mPlaybackBuffers[0] =
1155 std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
1156
1157 for (unsigned int i = 0; i < mPlaybackTracks.size(); i++) {
1158 const auto &pTrack = mPlaybackTracks[i];
1159 // Bug 1763 - We must fade in from zero to avoid a click on starting.
1160 pTrack->SetOldChannelGain(0, 0.0);
1161 pTrack->SetOldChannelGain(1, 0.0);
1162
1163 mPlaybackBuffers[i] =
1164 std::make_unique<RingBuffer>(floatSample, playbackBufferSize);
1165
1166 if (pTrack->IsLeader()) {
1167 // use track time for the end time, not real time!
1168 double startTime, endTime;
1169 if (!tracks.prerollTracks.empty())
1170 startTime = mPlaybackSchedule.mT0;
1171 else
1172 startTime = t0;
1173
1175 .contains(pTrack))
1176 // Stop playing this track after pre-roll
1177 endTime = t0;
1178 else
1179 // Pass t1 -- not mT1 as may have been adjusted for latency
1180 // -- so that overdub recording stops playing back samples
1181 // at the right time, though transport may continue to
1182 // record
1183 endTime = t1;
1184
1185 Mixer::Inputs mixTracks;
1186 const auto range =
1187 TrackList::Channels<const SampleTrack>(pTrack.get());
1188 for (auto channel : range)
1189 mixTracks.push_back(
1190 channel->SharedPointer<const SampleTrack>());
1191 mPlaybackMixers.emplace_back(std::make_unique<Mixer>(
1192 move(mixTracks),
1193 // Don't throw for read errors, just play silence:
1194 false,
1195 warpOptions, startTime, endTime, range.size(),
1197 false, // not interleaved
1199 false, // low quality dithering and resampling
1200 nullptr, // no custom mix-down
1201 false // don't apply track gains
1202 ));
1203 }
1204 }
1205
1206 const auto timeQueueSize = 1 +
1207 (playbackBufferSize + TimeQueueGrainSize - 1)
1209 mPlaybackSchedule.mTimeQueue.Resize( timeQueueSize );
1210 }
1211
1212 if( mNumCaptureChannels > 0 )
1213 {
1214 // Allocate input buffers. For every input track we allocate
1215 // a ring buffer of five seconds
1216 auto captureBufferSize =
1217 (size_t)(mRate * mCaptureRingBufferSecs + 0.5);
1218
1219 // In the extraordinarily rare case that we can't even afford
1220 // 100 samples, just give up.
1221 if(captureBufferSize < 100)
1222 {
1223 AudacityMessageBox( XO("Out of memory!") );
1224 return false;
1225 }
1226
1229 mFactor = sampleRate / mRate;
1230
1231 for( unsigned int i = 0; i < mCaptureTracks.size(); i++ )
1232 {
1233 mCaptureBuffers[i] = std::make_unique<RingBuffer>(
1234 mCaptureTracks[i]->GetSampleFormat(), captureBufferSize );
1235 mResample[i] =
1236 std::make_unique<Resample>(true, mFactor, mFactor);
1237 // constant rate resampling
1238 }
1239 }
1240 }
1241 catch(std::bad_alloc&)
1242 {
1243 // Oops! Ran out of memory. This is pretty rare, so we'll just
1244 // try deleting everything, halving our buffer size, and try again.
1245 StartStreamCleanup(true);
1249 mMinCaptureSecsToCopy *= 0.5;
1250 bDone = false;
1251
1252 // In the extraordinarily rare case that we can't even afford 100
1253 // samples, just give up.
1254 auto playbackBufferSize =
1255 (size_t)lrint(mRate * mPlaybackRingBufferSecs.count());
1256 if(playbackBufferSize < 100 || mPlaybackSamplesToCopy < 100)
1257 {
1258 AudacityMessageBox( XO("Out of memory!") );
1259 return false;
1260 }
1261 }
1262 } while(!bDone);
1263
1264 success = true;
1265 return true;
1266}
1267
1268void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
1269{
1270 mpTransportState.reset();
1271
1272 mPlaybackBuffers.reset();
1273 mScratchBuffers.clear();
1274 mScratchPointers.clear();
1275 mPlaybackMixers.clear();
1276 mCaptureBuffers.reset();
1277 mResample.reset();
1279
1280 if(!bOnlyBuffers)
1281 {
1282 Pa_AbortStream( mPortStreamV19 );
1283 Pa_CloseStream( mPortStreamV19 );
1284 mPortStreamV19 = NULL;
1285 mStreamToken = 0;
1286 }
1287
1289}
1290
1292{
1293 auto pOwningProject = mOwningProject.lock();
1294 return !pOwningProject || pOwningProject.get() == &project;
1295}
1296
1298{
1299 if (auto pInputMeter = mInputMeter.lock())
1300 pInputMeter->Reset(mRate, true);
1301 if (auto pOutputMeter = mOutputMeter.lock())
1302 pOutputMeter->Reset(mRate, true);
1303}
1304
1306{
1307 auto cleanup = finally ( [this] {
1309 mRecordingSchedule.mCrossfadeData.clear(); // free arrays
1310 } );
1311
1312 if( mPortStreamV19 == NULL )
1313 return;
1314
1315 // DV: This code seems to be unnecessary.
1316 // We do not leave mPortStreamV19 open in stopped
1317 // state. (Do we?)
1318 // This breaks WASAPI backend, as it sets the `running`
1319 // flag to `false` asynchronously.
1320 // Previously we have patched PortAudio and the patch
1321 // was breaking IsStreamStopped() == !IsStreamActive()
1322 // invariant.
1323 /*
1324 if ( Pa_IsStreamStopped(mPortStreamV19) )
1325 return;
1326 */
1327
1328#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1329 // Re-enable system sleep
1330 wxPowerResource::Release(wxPOWER_RESOURCE_SCREEN);
1331#endif
1332
1334 .load(std::memory_order_relaxed) )
1335 {
1336 // PortAudio callback can use the information that we are stopping to fade
1337 // out the audio. Give PortAudio callback a chance to do so.
1338 mForceFadeOut.store(true, std::memory_order_relaxed);
1339 auto latency = static_cast<long>(AudioIOLatencyDuration.Read());
1340 // If we can gracefully fade out in 200ms, with the faded-out play buffers making it through
1341 // the sound card, then do so. If we can't, don't wait around. Just stop quickly and accept
1342 // there will be a click.
1343 if( mbMicroFades && (latency < 150 )) {
1344 using namespace std::chrono;
1345 std::this_thread::sleep_for(milliseconds{latency + 50});
1346 }
1347 }
1348
1349 wxMutexLocker locker(mSuspendAudioThread);
1350
1351 //
1352 // We got here in one of two ways:
1353 //
1354 // 1. The user clicked the stop button and we therefore want to stop
1355 // as quickly as possible. So we use AbortStream(). If this is
1356 // the case the portaudio stream is still in the Running state
1357 // (see PortAudio state machine docs).
1358 //
1359 // 2. The callback told PortAudio to stop the stream since it had
1360 // reached the end of the selection. The UI thread discovered
1361 // this by noticing that AudioIO::IsActive() returned false.
1362 // IsActive() (which calls Pa_GetStreamActive()) will not return
1363 // false until all buffers have finished playing, so we can call
1364 // AbortStream without losing any samples. If this is the case
1365 // we are in the "callback finished state" (see PortAudio state
1366 // machine docs).
1367 //
1368 // The moral of the story: We can call AbortStream safely, without
1369 // losing samples.
1370 //
1371 // DMM: This doesn't seem to be true; it seems to be necessary to
1372 // call StopStream if the callback brought us here, and AbortStream
1373 // if the user brought us here.
1374 //
1375 // DV: Seems that Pa_CloseStream calls Pa_AbortStream internally,
1376 // at least for PortAudio 19.7.0+
1377
1379
1380 // Turn off HW playthrough if PortMixer is being used
1381
1382 #if defined(USE_PORTMIXER)
1383 if( mPortMixer ) {
1384 #if __WXMAC__
1385 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1386 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1387 mPreviousHWPlaythrough = -1.0;
1388 #endif
1389 }
1390 #endif
1391
1392 if (mPortStreamV19) {
1393 // DV: Pa_CloseStream will close Pa_AbortStream internally,
1394 // but it doesn't hurt to do it ourselves.
1395 // PA_AbortStream will silently fail if stream is stopped.
1396 if (!Pa_IsStreamStopped( mPortStreamV19 ))
1397 Pa_AbortStream( mPortStreamV19 );
1398
1399 Pa_CloseStream( mPortStreamV19 );
1400
1401 mPortStreamV19 = NULL;
1402 }
1403
1404
1405
1406 // We previously told AudioThread to stop processing, now let's
1407 // be sure it has really stopped before resetting mpTransportState
1409
1410
1411 for( auto &ext : Extensions() )
1412 ext.StopOtherStream();
1413
1414 auto pListener = GetListener();
1415
1416 // If there's no token, we were just monitoring, so we can
1417 // skip this next part...
1418 if (mStreamToken > 0) {
1419 // In either of the above cases, we want to make sure that any
1420 // capture data that made it into the PortAudio callback makes it
1421 // to the target WaveTrack. To do this, we ask the audio thread to
1422 // call TrackBufferExchange one last time (it normally would not do so since
1423 // Pa_GetStreamActive() would now return false
1425 }
1426
1427 // No longer need effects processing. This must be done after the stream is stopped
1428 // to prevent the callback from being invoked after the effects are finalized.
1429 mpTransportState.reset();
1430
1431 //
1432 // Everything is taken care of. Now, just free all the resources
1433 // we allocated in StartStream()
1434 //
1435 if (mPlaybackTracks.size() > 0)
1436 {
1437 mPlaybackBuffers.reset();
1438 mScratchBuffers.clear();
1439 mScratchPointers.clear();
1440 mPlaybackMixers.clear();
1442 }
1443
1444 if (mStreamToken > 0)
1445 {
1446 //
1447 // Offset all recorded tracks to account for latency
1448 //
1449 if (mCaptureTracks.size() > 0)
1450 {
1451 mCaptureBuffers.reset();
1452 mResample.reset();
1453
1454 //
1455 // We only apply latency correction when we actually played back
1456 // tracks during the recording. If we did not play back tracks,
1457 // there's nothing we could be out of sync with. This also covers the
1458 // case that we do not apply latency correction when recording the
1459 // first track in a project.
1460 //
1461
1462 for (unsigned int i = 0; i < mCaptureTracks.size(); i++) {
1463 // The calls to Flush
1464 // may cause exceptions because of exhaustion of disk space.
1465 // Stop those exceptions here, or else they propagate through too
1466 // many parts of Audacity that are not effects or editing
1467 // operations. GuardedCall ensures that the user sees a warning.
1468
1469 // Also be sure to Flush each track, at the top of the guarded call,
1470 // relying on the guarantee that the track will be left in a flushed
1471 // state, though the append buffer may be lost.
1472
1473 GuardedCall( [&] {
1474 WaveTrack* track = mCaptureTracks[i].get();
1475
1476 // use No-fail-guarantee that track is flushed,
1477 // Partial-guarantee that some initial length of the recording
1478 // is saved.
1479 // See comments in TrackBufferExchange().
1480 track->Flush();
1481 } );
1482 }
1483
1484
1485 if (!mLostCaptureIntervals.empty())
1486 {
1487 // This scope may combine many splittings of wave tracks
1488 // into one transaction, lessening the number of checkpoints
1489 std::optional<TransactionScope> pScope;
1490 if (auto pOwningProject = mOwningProject.lock())
1491 pScope.emplace(*pOwningProject, "Dropouts");
1492 for (auto &interval : mLostCaptureIntervals) {
1493 auto &start = interval.first;
1494 auto duration = interval.second;
1495 for (auto &track : mCaptureTracks) {
1496 GuardedCall([&] {
1497 track->SyncLockAdjust(start, start + duration);
1498 });
1499 }
1500 }
1501 if (pScope)
1502 pScope->Commit();
1503 }
1504
1505 if (pListener)
1506 pListener->OnCommitRecording();
1507 }
1508 }
1509
1510
1511
1512 if (auto pInputMeter = mInputMeter.lock())
1513 pInputMeter->Reset(mRate, false);
1514
1515 if (auto pOutputMeter = mOutputMeter.lock())
1516 pOutputMeter->Reset(mRate, false);
1517
1518 mInputMeter.reset();
1519 mOutputMeter.reset();
1521
1522 if (pListener && mNumCaptureChannels > 0)
1523 pListener->OnAudioIOStopRecording();
1524
1525 wxTheApp->CallAfter([this]{
1527 // Recording was restarted between StopStream and idle time
1528 // So the actions can keep waiting
1529 return;
1530 // In case some other thread was waiting on the mutex too:
1531 std::this_thread::yield();
1532 std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
1536 }
1537 DelayActions(false);
1538 });
1539
1540 //
1541 // Only set token to 0 after we're totally finished with everything
1542 //
1543 bool wasMonitoring = mStreamToken == 0;
1544 mStreamToken = 0;
1545
1546 {
1547 auto pOwningProject = mOwningProject.lock();
1548 if (mNumPlaybackChannels > 0)
1549 Publish({ pOwningProject.get(), AudioIOEvent::PLAYBACK, false });
1550 if (mNumCaptureChannels > 0)
1551 Publish({ pOwningProject.get(),
1552 wasMonitoring
1555 false });
1556 }
1557
1560
1561 mPlaybackTracks.clear();
1562 mCaptureTracks.clear();
1563
1565
1566 if (pListener) {
1567 // Tell UI to hide sample rate
1568 pListener->OnAudioIORate(0);
1569 }
1570
1571 // Don't cause a busy wait in the audio thread after stopping scrubbing
1573}
1574
1575void AudioIO::SetPaused(bool state)
1576{
1577 if (state != IsPaused())
1578 {
1579 if (auto pOwningProject = mOwningProject.lock()) {
1580 // The realtime effects manager may remain "active" but becomes
1581 // "suspended" or "resumed".
1582 auto &em = RealtimeEffectManager::Get(*pOwningProject);
1583 em.SetSuspended(state);
1584 }
1585 }
1586
1587 mPaused.store(state, std::memory_order_relaxed);
1588}
1589
1590double AudioIO::GetBestRate(bool capturing, bool playing, double sampleRate)
1591{
1592 // Check if we can use the cached value
1593 if (mCachedBestRateIn != 0.0 && mCachedBestRateIn == sampleRate
1594 && mCachedBestRatePlaying == playing && mCachedBestRateCapturing == capturing) {
1595 return mCachedBestRateOut;
1596 }
1597
1598 // In order to cache the value, all early returns should instead set retval
1599 // and jump to finished
1600 double retval;
1601
1602 std::vector<long> rates;
1603 if (capturing) wxLogDebug(wxT("AudioIO::GetBestRate() for capture"));
1604 if (playing) wxLogDebug(wxT("AudioIO::GetBestRate() for playback"));
1605 wxLogDebug(wxT("GetBestRate() suggested rate %.0lf Hz"), sampleRate);
1606
1607 if (capturing && !playing) {
1608 rates = GetSupportedCaptureRates(-1, sampleRate);
1609 }
1610 else if (playing && !capturing) {
1611 rates = GetSupportedPlaybackRates(-1, sampleRate);
1612 }
1613 else { // we assume capturing and playing - the alternative would be a
1614 // bit odd
1615 rates = GetSupportedSampleRates(-1, -1, sampleRate);
1616 }
1617 /* rem rates is the array of hardware-supported sample rates (in the current
1618 * configuration), sampleRate is the Project Rate (desired sample rate) */
1619 long rate = (long)sampleRate;
1620
1621 if (make_iterator_range(rates).contains(rate)) {
1622 wxLogDebug(wxT("GetBestRate() Returning %.0ld Hz"), rate);
1623 retval = rate;
1624 goto finished;
1625 /* the easy case - the suggested rate (project rate) is in the list, and
1626 * we can just accept that and send back to the caller. This should be
1627 * the case for most users most of the time (all of the time on
1628 * Win MME as the OS does resampling) */
1629 }
1630
1631 /* if we get here, there is a problem - the project rate isn't supported
1632 * on our hardware, so we can't us it. Need to come up with an alternative
1633 * rate to use. The process goes like this:
1634 * * If there are no rates to pick from, we're stuck and return 0 (error)
1635 * * If there are some rates, we pick the next one higher than the requested
1636 * rate to use.
1637 * * If there aren't any higher, we use the highest available rate */
1638
1639 if (rates.empty()) {
1640 /* we're stuck - there are no supported rates with this hardware. Error */
1641 wxLogDebug(wxT("GetBestRate() Error - no supported sample rates"));
1642 retval = 0.0;
1643 goto finished;
1644 }
1645 int i;
1646 for (i = 0; i < (int)rates.size(); i++) // for each supported rate
1647 {
1648 if (rates[i] > rate) {
1649 // supported rate is greater than requested rate
1650 wxLogDebug(wxT("GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1651 retval = rates[i];
1652 goto finished;
1653 }
1654 }
1655
1656 wxLogDebug(wxT("GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1657 retval = rates.back(); // the highest available rate
1658 goto finished;
1659
1660finished:
1661 mCachedBestRateIn = sampleRate;
1662 mCachedBestRateOut = retval;
1663 mCachedBestRatePlaying = playing;
1664 mCachedBestRateCapturing = capturing;
1665 return retval;
1666}
1667
1669{
1670 // Track time readout for the main thread
1671
1672 if( !IsStreamActive() )
1673 return BAD_STREAM_TIME;
1674
1676}
1677
1678
1680//
1681// Audio Thread Context
1682//
1684
1686void AudioIO::AudioThread(std::atomic<bool> &finish)
1687{
1688 enum class State { eUndefined, eOnce, eLoopRunning, eDoNothing, eMonitoring } lastState = State::eUndefined;
1689 AudioIO *const gAudioIO = AudioIO::Get();
1690 while (!finish.load(std::memory_order_acquire)) {
1691 using Clock = std::chrono::steady_clock;
1692 auto loopPassStart = Clock::now();
1693 auto &schedule = gAudioIO->mPlaybackSchedule;
1694 const auto interval = schedule.GetPolicy().SleepInterval(schedule);
1695
1696 // Set LoopActive outside the tests to avoid race condition
1698 .store(true, std::memory_order_relaxed);
1700 .load(std::memory_order_acquire) )
1701 {
1702 gAudioIO->TrackBufferExchange();
1704 .store(false, std::memory_order_release);
1705
1706 lastState = State::eOnce;
1707 }
1709 .load(std::memory_order_relaxed))
1710 {
1711 if (lastState != State::eLoopRunning)
1712 {
1713 // Main thread has told us to start - acknowledge that we do
1715 std::memory_order::memory_order_release);
1716 }
1717 lastState = State::eLoopRunning;
1718
1719 // We call the processing after raising the acknowledge flag, because the main thread
1720 // only needs to know that the message was seen.
1721 //
1722 // This is unlike the case with mAudioThreadShouldCallTrackBufferExchangeOnce where the
1723 // store really means that the one-time exchange was done.
1724
1725 gAudioIO->TrackBufferExchange();
1726 }
1727 else
1728 {
1729 if ( (lastState == State::eLoopRunning)
1730 || (lastState == State::eMonitoring ) )
1731 {
1732 // Main thread has told us to stop; (actually: to neither process "once" nor "loop running")
1733 // acknowledge that we received the order and that no more processing will be done.
1735 std::memory_order::memory_order_release);
1736 }
1737 lastState = State::eDoNothing;
1738
1739 if (gAudioIO->IsMonitoring())
1740 {
1741 lastState = State::eMonitoring;
1742 }
1743 }
1744
1746 .store(false, std::memory_order_relaxed);
1747
1748 std::this_thread::sleep_until( loopPassStart + interval );
1749 }
1750}
1751
1752
1754{
1755 auto commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
1756 for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
1757 commonlyAvail = std::min(commonlyAvail,
1758 mPlaybackBuffers[i]->AvailForPut());
1759 // MB: subtract a few samples because the code in TrackBufferExchange has rounding
1760 // errors
1761 return commonlyAvail - std::min(size_t(10), commonlyAvail);
1762}
1763
1765{
1766 auto commonlyAvail = mPlaybackBuffers[0]->AvailForGet();
1767 for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
1768 commonlyAvail = std::min(commonlyAvail,
1769 mPlaybackBuffers[i]->AvailForGet());
1770 return commonlyAvail;
1771}
1772
1774{
1775 auto commonlyAvail = mPlaybackBuffers[0]->WrittenForGet();
1776 for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
1777 commonlyAvail = std::min(commonlyAvail,
1778 mPlaybackBuffers[i]->WrittenForGet());
1779 return commonlyAvail;
1780}
1781
1783{
1784 auto commonlyAvail = mCaptureBuffers[0]->AvailForGet();
1785 for (unsigned i = 1; i < mCaptureTracks.size(); ++i)
1786 commonlyAvail = std::min(commonlyAvail,
1787 mCaptureBuffers[i]->AvailForGet());
1788 return commonlyAvail;
1789}
1790
1791// This method is the data gateway between the audio thread (which
1792// communicates with the disk) and the PortAudio callback thread
1793// (which communicates with the audio device).
1795{
1798}
1799
1801{
1802 std::optional<RealtimeEffects::ProcessingScope> pScope;
1803 if (mpTransportState && mpTransportState->mpRealtimeInitialization)
1804 pScope.emplace(
1805 *mpTransportState->mpRealtimeInitialization, mOwningProject);
1806
1807 if (mNumPlaybackChannels == 0)
1808 return;
1809
1810 // It is possible that some buffers will have more samples available than
1811 // others. This could happen if we hit this code during the PortAudio
1812 // callback. Also, if in a previous pass, unequal numbers of samples were
1813 // discarded from ring buffers for differing latencies.
1814
1815 // To keep things simple, we write no more data than is vacant in
1816 // ALL buffers, and advance the global time by that much.
1817 auto nAvailable = GetCommonlyFreePlayback();
1818
1819 // Don't fill the buffers at all unless we can do
1820 // at least mPlaybackSamplesToCopy. This improves performance
1821 // by not always trying to process tiny chunks, eating the
1822 // CPU unnecessarily.
1823 if (nAvailable < mPlaybackSamplesToCopy)
1824 return;
1825
1826 // More than mPlaybackSamplesToCopy might be copied:
1827 // May produce a larger amount when initially priming the buffer, or
1828 // perhaps again later in play to avoid underfilling the queue and
1829 // falling behind the real-time demand on the consumer side in the
1830 // callback.
1831 auto GetNeeded = [&]() -> size_t {
1832 // Note that reader might concurrently consume between loop passes below
1833 // So this might not be nondecreasing
1834 auto nReady = GetCommonlyWrittenForPlayback();
1836 };
1837 auto nNeeded = GetNeeded();
1838
1839 // wxASSERT( nNeeded <= nAvailable );
1840
1841 auto Flush = [&]{
1842 /* The flushing of all the Puts to the RingBuffers is lifted out of the
1843 do-loop in ProcessPlaybackSlices, and also after transformation of the
1844 stream for realtime effects.
1845
1846 It's only here that a release is done on the atomic variable that
1847 indicates the readiness of sample data to the consumer. That atomic
1848 also synchronizes the use of the TimeQueue.
1849 */
1850 for (size_t i = 0; i < std::max(size_t{1}, mPlaybackTracks.size()); ++i)
1851 mPlaybackBuffers[i]->Flush();
1852 };
1853
1854 while (true) {
1855 // Limit maximum buffer size (increases performance)
1856 auto available = std::min( nAvailable,
1857 std::max( nNeeded, mPlaybackSamplesToCopy ) );
1858
1859 // After each loop pass or after break
1860 Finally Do{ Flush };
1861
1862 if (!ProcessPlaybackSlices(pScope, available))
1863 // We are not making progress. May fail to satisfy the minimum but
1864 // won't loop forever
1865 break;
1866
1867 // Loop again to satisfy the minimum queue requirement in case there
1868 // was discarding of processed data for effect latencies
1869 nNeeded = GetNeeded();
1870 if (nNeeded == 0)
1871 break;
1872
1873 // Might increase because the reader consumed some
1874 nAvailable = GetCommonlyFreePlayback();
1875 }
1876}
1877
1879 std::optional<RealtimeEffects::ProcessingScope> &pScope, size_t available)
1880{
1881 auto &policy = mPlaybackSchedule.GetPolicy();
1882
1883 // msmeyer: When playing a very short selection in looped
1884 // mode, the selection must be copied to the buffer multiple
1885 // times, to ensure, that the buffer has a reasonable size
1886 // This is the purpose of this loop.
1887 // PRL: or, when scrubbing, we may get work repeatedly from the
1888 // user interface.
1889 bool done = false;
1890 bool progress = false;
1891 do {
1892 const auto slice =
1893 policy.GetPlaybackSlice(mPlaybackSchedule, available);
1894 const auto &[frames, toProduce] = slice;
1895 progress = progress || toProduce > 0;
1896
1897 // Update the time queue. This must be done before writing to the
1898 // ring buffers of samples, for proper synchronization with the
1899 // consumer side in the PortAudio thread, which reads the time
1900 // queue after reading the sample queues. The sample queues use
1901 // atomic variables, the time queue doesn't.
1903
1904 size_t i = 0;
1905 for (auto &mixer : mPlaybackMixers) {
1906 // The mixer here isn't actually mixing: it's just doing
1907 // resampling, format conversion, and possibly time track
1908 // warping
1909 if (frames > 0) {
1910 size_t produced = 0;
1911 if ( toProduce )
1912 produced = mixer->Process( toProduce );
1913 //wxASSERT(produced <= toProduce);
1914 for(size_t j = 0, nChannels =
1916 j < nChannels; ++i, ++j
1917 ) {
1918 auto warpedSamples = mixer->GetBuffer(j);
1919 const auto put = mPlaybackBuffers[i]->Put(
1920 warpedSamples, floatSample, produced, frames - produced);
1921 // wxASSERT(put == frames);
1922 // but we can't assert in this thread
1923 wxUnusedVar(put);
1924 }
1925 }
1926 }
1927
1928 if (mPlaybackTracks.empty())
1929 // Produce silence in the single ring buffer
1930 mPlaybackBuffers[0]->Put(nullptr, floatSample, 0, frames);
1931
1932 available -= frames;
1933 // wxASSERT(available >= 0); // don't assert on this thread
1934
1935 done = policy.RepositionPlayback( mPlaybackSchedule, mPlaybackMixers,
1936 frames, available );
1937 } while (available && !done);
1938
1939 // Do any realtime effect processing, more efficiently in at most
1940 // two buffers per track, after all the little slices have been written.
1941 TransformPlayBuffers(pScope);
1942 return progress;
1943}
1944
1945
1947 std::optional<RealtimeEffects::ProcessingScope> &pScope)
1948{
1949 // Transform written but un-flushed samples in the RingBuffers in-place.
1950
1951 // Avoiding std::vector
1952 auto pointers =
1953 static_cast<float**>(alloca(mNumPlaybackChannels * sizeof(float*)));
1954
1955 const auto numPlaybackTracks = mPlaybackTracks.size();
1956 for (unsigned t = 0; t < numPlaybackTracks; ++t) {
1957 const auto vt = mPlaybackTracks[t].get();
1958 if (!(vt && vt->IsLeader()))
1959 continue;
1960 // vt is mono, or is the first of its group of channels
1961 const auto nChannels = std::min<size_t>(
1963
1964 // Loop over the blocks of unflushed data, at most two
1965 for (unsigned iBlock : {0, 1}) {
1966 size_t len = 0;
1967 size_t iChannel = 0;
1968 for (; iChannel < nChannels; ++iChannel) {
1969 auto &ringBuffer = *mPlaybackBuffers[t + iChannel];
1970 const auto pair =
1971 ringBuffer.GetUnflushed(iBlock);
1972 // Playback RingBuffers have float format: see AllocateBuffers
1973 pointers[iChannel] = reinterpret_cast<float*>(pair.first);
1974 // The lengths of corresponding unflushed blocks should be
1975 // the same for all channels
1976 if (len == 0)
1977 len = pair.second;
1978 else
1979 assert(len == pair.second);
1980 }
1981
1982 // Are there more output device channels than channels of vt?
1983 // Such as when a mono track is processed for stereo play?
1984 // Then supply some non-null fake input buffers, because the
1985 // various ProcessBlock overrides of effects may crash without it.
1986 // But it would be good to find the fixes to make this unnecessary.
1987 float **scratch = &mScratchPointers[mNumPlaybackChannels + 1];
1988 while (iChannel < mNumPlaybackChannels)
1989 memset((pointers[iChannel++] = *scratch++), 0, len * sizeof(float));
1990
1991 if (len && pScope) {
1992 auto discardable = pScope->Process( *vt, &pointers[0],
1993 mScratchPointers.data(),
1994 // The single dummy output buffer:
1997 iChannel = 0;
1998 for (; iChannel < nChannels; ++iChannel) {
1999 auto &ringBuffer = *mPlaybackBuffers[t + iChannel];
2000 auto discarded = ringBuffer.Unput(discardable);
2001 // assert(discarded == discardable);
2002 }
2003 }
2004 }
2005 }
2006}
2007
2009{
2010 if (mRecordingException || mCaptureTracks.empty())
2011 return;
2012
2013 auto delayedHandler = [this] ( AudacityException * pException ) {
2014 // In the main thread, stop recording
2015 // This is one place where the application handles disk
2016 // exhaustion exceptions from wave track operations, without rolling
2017 // back to the last pushed undo state. Instead, partial recording
2018 // results are pushed as a NEW undo state. For this reason, as
2019 // commented elsewhere, we want an exception safety guarantee for
2020 // the output wave tracks, after the failed append operation, that
2021 // the tracks remain as they were after the previous successful
2022 // (block-level) appends.
2023
2024 // Note that the Flush in StopStream() may throw another exception,
2025 // but StopStream() contains that exception, and the logic in
2026 // AudacityException::DelayedHandlerAction prevents redundant message
2027 // boxes.
2028 StopStream();
2029 DefaultDelayedHandlerAction( pException );
2030 };
2031
2032 GuardedCall( [&] {
2033 // start record buffering
2034 const auto avail = GetCommonlyAvailCapture(); // samples
2035 const auto remainingTime =
2036 std::max(0.0, mRecordingSchedule.ToConsume());
2037 // This may be a very big double number:
2038 const auto remainingSamples = remainingTime * mRate;
2039 bool latencyCorrected = true;
2040
2041 double deltat = avail / mRate;
2042
2044 .load(std::memory_order_relaxed) ||
2045 deltat >= mMinCaptureSecsToCopy)
2046 {
2047 bool newBlocks = false;
2048
2049 // Append captured samples to the end of the WaveTracks.
2050 // The WaveTracks have their own buffering for efficiency.
2051 auto numChannels = mCaptureTracks.size();
2052
2053 for( size_t i = 0; i < numChannels; i++ )
2054 {
2055 sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
2056
2057 size_t discarded = 0;
2058
2060 const auto correction = mRecordingSchedule.TotalCorrection();
2061 if (correction >= 0) {
2062 // Rightward shift
2063 // Once only (per track per recording), insert some initial
2064 // silence.
2065 size_t size = floor( correction * mRate * mFactor);
2066 SampleBuffer temp(size, trackFormat);
2067 ClearSamples(temp.ptr(), trackFormat, 0, size);
2068 mCaptureTracks[i]->Append(temp.ptr(), trackFormat, size, 1);
2069 }
2070 else {
2071 // Leftward shift
2072 // discard some samples from the ring buffers.
2073 size_t size = floor(
2075
2076 // The ring buffer might have grown concurrently -- don't discard more
2077 // than the "avail" value noted above.
2078 discarded = mCaptureBuffers[i]->Discard(std::min(avail, size));
2079
2080 if (discarded < size)
2081 // We need to visit this again to complete the
2082 // discarding.
2083 latencyCorrected = false;
2084 }
2085 }
2086
2087 const float *pCrossfadeSrc = nullptr;
2088 size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2089 if (i < mRecordingSchedule.mCrossfadeData.size())
2090 {
2091 // Do crossfading
2092 // The supplied crossfade samples are at the same rate as the track
2093 const auto &data = mRecordingSchedule.mCrossfadeData[i];
2094 totalCrossfadeLength = data.size();
2095 if (totalCrossfadeLength) {
2096 crossfadeStart =
2097 floor(mRecordingSchedule.Consumed() * mCaptureTracks[i]->GetRate());
2098 if (crossfadeStart < totalCrossfadeLength)
2099 pCrossfadeSrc = data.data() + crossfadeStart;
2100 }
2101 }
2102
2103 wxASSERT(discarded <= avail);
2104 size_t toGet = avail - discarded;
2105 SampleBuffer temp;
2106 size_t size;
2108 if( mFactor == 1.0 )
2109 {
2110 // Take captured samples directly
2111 size = toGet;
2112 if (pCrossfadeSrc)
2113 // Change to float for crossfade calculation
2115 else
2116 format = trackFormat;
2117 temp.Allocate(size, format);
2118 const auto got =
2119 mCaptureBuffers[i]->Get(temp.ptr(), format, toGet);
2120 // wxASSERT(got == toGet);
2121 // but we can't assert in this thread
2122 wxUnusedVar(got);
2123 if (double(size) > remainingSamples)
2124 size = floor(remainingSamples);
2125 }
2126 else
2127 {
2128 size = lrint(toGet * mFactor);
2130 SampleBuffer temp1(toGet, floatSample);
2131 temp.Allocate(size, format);
2132 const auto got =
2133 mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, toGet);
2134 // wxASSERT(got == toGet);
2135 // but we can't assert in this thread
2136 wxUnusedVar(got);
2137 /* we are re-sampling on the fly. The last resampling call
2138 * must flush any samples left in the rate conversion buffer
2139 * so that they get recorded
2140 */
2141 if (toGet > 0 ) {
2142 if (double(toGet) > remainingSamples)
2143 toGet = floor(remainingSamples);
2144 const auto results =
2145 mResample[i]->Process(mFactor, (float *)temp1.ptr(), toGet,
2146 !IsStreamActive(), (float *)temp.ptr(), size);
2147 size = results.second;
2148 }
2149 }
2150
2151 if (pCrossfadeSrc) {
2152 wxASSERT(format == floatSample);
2153 size_t crossfadeLength = std::min(size, totalCrossfadeLength - crossfadeStart);
2154 if (crossfadeLength) {
2155 auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2156 auto ratioStep = 1.0 / totalCrossfadeLength;
2157 auto pCrossfadeDst = (float*)temp.ptr();
2158
2159 // Crossfade loop here
2160 for (size_t ii = 0; ii < crossfadeLength; ++ii) {
2161 *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2162 ++pCrossfadeSrc, ++pCrossfadeDst;
2163 ratio += ratioStep;
2164 }
2165 }
2166 }
2167
2168 // Now append
2169 // see comment in second handler about guarantee
2170 newBlocks = mCaptureTracks[i]->Append(temp.ptr(), format, size, 1)
2171 || newBlocks;
2172 } // end loop over capture channels
2173
2174 // Now update the recording schedule position
2176 mRecordingSchedule.mLatencyCorrected = latencyCorrected;
2177
2178 auto pListener = GetListener();
2179 if (pListener && newBlocks)
2180 pListener->OnAudioIONewBlocks(&mCaptureTracks);
2181
2182 }
2183 // end of record buffering
2184 },
2185 // handler
2186 [this] ( AudacityException *pException ) {
2187 if ( pException ) {
2188 // So that we don't attempt to fill the recording buffer again
2189 // before the main thread stops recording
2191 return ;
2192 }
2193 else
2194 // Don't want to intercept other exceptions (?)
2195 throw;
2196 },
2197 delayedHandler );
2198}
2199
2201 const std::shared_ptr< AudioIOListener > &listener)
2202{
2203 if (IsBusy())
2204 return;
2205
2206 mListener = listener;
2207}
2208
2209// Automated Input Level Adjustment - Automatically tries to find an acceptable input volume
2210#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2211
2212#include "ProjectStatus.h"
2213
2214void AudioIO::AILAInitialize() {
2215 gPrefs->Read(wxT("/AudioIO/AutomatedInputLevelAdjustment"), &mAILAActive, false);
2216 gPrefs->Read(wxT("/AudioIO/TargetPeak"), &mAILAGoalPoint, AILA_DEF_TARGET_PEAK);
2217 gPrefs->Read(wxT("/AudioIO/DeltaPeakVolume"), &mAILAGoalDelta, AILA_DEF_DELTA_PEAK);
2218 gPrefs->Read(wxT("/AudioIO/AnalysisTime"), &mAILAAnalysisTime, AILA_DEF_ANALYSIS_TIME);
2219 gPrefs->Read(wxT("/AudioIO/NumberAnalysis"), &mAILATotalAnalysis, AILA_DEF_NUMBER_ANALYSIS);
2220 mAILAGoalDelta /= 100.0;
2221 mAILAGoalPoint /= 100.0;
2222 mAILAAnalysisTime /= 1000.0;
2223 mAILAMax = 0.0;
2224 mAILALastStartTime = max(0.0, mPlaybackSchedule.mT0);
2225 mAILAClipped = false;
2226 mAILAAnalysisCounter = 0;
2227 mAILAChangeFactor = 1.0;
2228 mAILALastChangeType = 0;
2229 mAILATopLevel = 1.0;
2230 mAILAAnalysisEndTime = -1.0;
2231}
2232
2233void AudioIO::AILADisable() {
2234 mAILAActive = false;
2235}
2236
2237bool AudioIO::AILAIsActive() {
2238 return mAILAActive;
2239}
2240
2241void AudioIO::AILASetStartTime() {
2242 mAILAAbsolutStartTime = Pa_GetStreamTime(mPortStreamV19);
2243 wxPrintf("START TIME %f\n\n", mAILAAbsolutStartTime);
2244}
2245
2246double AudioIO::AILAGetLastDecisionTime() {
2247 return mAILAAnalysisEndTime;
2248}
2249
2250void AudioIO::AILAProcess(double maxPeak) {
2251 const auto proj = mOwningProject.lock();
2252 if (proj && mAILAActive) {
2253 if (mInputMeter && mInputMeter->IsClipping()) {
2254 mAILAClipped = true;
2255 wxPrintf("clipped");
2256 }
2257
2258 mAILAMax = max(mAILAMax, maxPeak);
2259
2260 if ((mAILATotalAnalysis == 0 || mAILAAnalysisCounter < mAILATotalAnalysis) && mPlaybackSchedule.GetTrackTime() - mAILALastStartTime >= mAILAAnalysisTime) {
2261 auto ToLinearIfDB = [](double value, int dbRange) {
2262 if (dbRange >= 0)
2263 value = pow(10.0, (-(1.0-value) * dbRange)/20.0);
2264 return value;
2265 };
2266
2267 putchar('\n');
2268 mAILAMax = mInputMeter ? ToLinearIfDB(mAILAMax, mInputMeter->GetDBRange()) : 0.0;
2269 double iv = (double) Px_GetInputVolume(mPortMixer);
2270 unsigned short changetype = 0; //0 - no change, 1 - increase change, 2 - decrease change
2271 wxPrintf("mAILAAnalysisCounter:%d\n", mAILAAnalysisCounter);
2272 wxPrintf("\tmAILAClipped:%d\n", mAILAClipped);
2273 wxPrintf("\tmAILAMax (linear):%f\n", mAILAMax);
2274 wxPrintf("\tmAILAGoalPoint:%f\n", mAILAGoalPoint);
2275 wxPrintf("\tmAILAGoalDelta:%f\n", mAILAGoalDelta);
2276 wxPrintf("\tiv:%f\n", iv);
2277 wxPrintf("\tmAILAChangeFactor:%f\n", mAILAChangeFactor);
2278 if (mAILAClipped || mAILAMax > mAILAGoalPoint + mAILAGoalDelta) {
2279 wxPrintf("too high:\n");
2280 mAILATopLevel = min(mAILATopLevel, iv);
2281 wxPrintf("\tmAILATopLevel:%f\n", mAILATopLevel);
2282 //if clipped or too high
2283 if (iv <= LOWER_BOUND) {
2284 //we can't improve it more now
2285 if (mAILATotalAnalysis != 0) {
2286 mAILAActive = false;
2287 ProjectStatus::Get( *proj ).Set(
2288 XO(
2289"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too high.") );
2290 }
2291 wxPrintf("\talready min vol:%f\n", iv);
2292 }
2293 else {
2294 float vol = (float) max(LOWER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2295 Px_SetInputVolume(mPortMixer, vol);
2296 auto msg = XO(
2297"Automated Recording Level Adjustment decreased the volume to %f.").Format( vol );
2298 ProjectStatus::Get( *proj ).Set(msg);
2299 changetype = 1;
2300 wxPrintf("\tnew vol:%f\n", vol);
2301 float check = Px_GetInputVolume(mPortMixer);
2302 wxPrintf("\tverified %f\n", check);
2303 }
2304 }
2305 else if ( mAILAMax < mAILAGoalPoint - mAILAGoalDelta ) {
2306 //if too low
2307 wxPrintf("too low:\n");
2308 if (iv >= UPPER_BOUND || iv + 0.005 > mAILATopLevel) { //condition for too low volumes and/or variable volumes that cause mAILATopLevel to decrease too much
2309 //we can't improve it more
2310 if (mAILATotalAnalysis != 0) {
2311 mAILAActive = false;
2312 ProjectStatus::Get( *proj ).Set(
2313 XO(
2314"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too low.") );
2315 }
2316 wxPrintf("\talready max vol:%f\n", iv);
2317 }
2318 else {
2319 float vol = (float) min(UPPER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2320 if (vol > mAILATopLevel) {
2321 vol = (iv + mAILATopLevel)/2.0;
2322 wxPrintf("\tTruncated vol:%f\n", vol);
2323 }
2324 Px_SetInputVolume(mPortMixer, vol);
2325 auto msg = XO(
2326"Automated Recording Level Adjustment increased the volume to %.2f.")
2327 .Format( vol );
2328 ProjectStatus::Get( *proj ).Set(msg);
2329 changetype = 2;
2330 wxPrintf("\tnew vol:%f\n", vol);
2331 float check = Px_GetInputVolume(mPortMixer);
2332 wxPrintf("\tverified %f\n", check);
2333 }
2334 }
2335
2336 mAILAAnalysisCounter++;
2337 //const PaStreamInfo* info = Pa_GetStreamInfo(mPortStreamV19);
2338 //double latency = 0.0;
2339 //if (info)
2340 // latency = info->inputLatency;
2341 //mAILAAnalysisEndTime = mTime+latency;
2342 mAILAAnalysisEndTime = Pa_GetStreamTime(mPortStreamV19) - mAILAAbsolutStartTime;
2343 mAILAMax = 0;
2344 wxPrintf("\tA decision was made @ %f\n", mAILAAnalysisEndTime);
2345 mAILAClipped = false;
2346 mAILALastStartTime = mPlaybackSchedule.GetTrackTime();
2347
2348 if (changetype == 0)
2349 mAILAChangeFactor *= 0.8; //time factor
2350 else if (mAILALastChangeType == changetype)
2351 mAILAChangeFactor *= 1.1; //concordance factor
2352 else
2353 mAILAChangeFactor *= 0.7; //discordance factor
2354 mAILALastChangeType = changetype;
2355 putchar('\n');
2356 }
2357
2358 if (mAILAActive && mAILATotalAnalysis != 0 && mAILAAnalysisCounter >= mAILATotalAnalysis) {
2359 mAILAActive = false;
2360 if (mAILAMax > mAILAGoalPoint + mAILAGoalDelta)
2361 ProjectStatus::Get( *proj ).Set(
2362 XO(
2363"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too high.") );
2364 else if (mAILAMax < mAILAGoalPoint - mAILAGoalDelta)
2365 ProjectStatus::Get( *proj ).Set(
2366 XO(
2367"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too low.") );
2368 else {
2369 auto msg = XO(
2370"Automated Recording Level Adjustment stopped. %.2f seems an acceptable volume.")
2371 .Format( Px_GetInputVolume(mPortMixer) );
2372 ProjectStatus::Get( *proj ).Set(msg);
2373 }
2374 }
2375 }
2376}
2377#endif
2378
2379#define MAX(a,b) ((a) > (b) ? (a) : (b))
2380
2382 sampleFormat inputFormat,
2383 unsigned inputChannels,
2384 float *outputBuffer,
2385 unsigned long len)
2386{
2387 for (unsigned int i=0; i < inputChannels; i++) {
2388 auto inputPtr = inputBuffer + (i * SAMPLE_SIZE(inputFormat));
2389
2390 SamplesToFloats(inputPtr, inputFormat,
2391 outputBuffer + i, len, inputChannels, 2);
2392 }
2393
2394 // One mono input channel goes to both output channels...
2395 if (inputChannels == 1)
2396 for (int i=0; i < len; i++)
2397 outputBuffer[2*i + 1] = outputBuffer[2*i];
2398}
2399
2400int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
2401 unsigned long framesPerBuffer,
2402 const PaStreamCallbackTimeInfo *timeInfo,
2403 const PaStreamCallbackFlags statusFlags, void *userData )
2404{
2405 auto gAudioIO = AudioIO::Get();
2406 return gAudioIO->AudioCallback(
2407 static_cast<constSamplePtr>(inputBuffer),
2408 static_cast<float*>(outputBuffer), framesPerBuffer,
2409 timeInfo, statusFlags, userData);
2410}
2411
2412// Stop recording if 'silence' is detected
2413// Start recording if sound detected.
2414//
2415// By using CallAfter(), we can schedule the call to the toolbar
2416// to run in the main GUI thread after the next event loop iteration.
2417// That's important, because Pause() updates GUI, such as status bar,
2418// and that should NOT happen in this audio non-gui thread.
2420 float *inputSamples,
2421 unsigned long framesPerBuffer
2422 )
2423{
2424 // Quick returns if next to nothing to do.
2425 if( !mPauseRec )
2426 return;
2427
2428 float maxPeak = 0.;
2429 for( unsigned long i = 0, cnt = framesPerBuffer * mNumCaptureChannels; i < cnt; ++i ) {
2430 float sample = fabs(*(inputSamples++));
2431 if (sample > maxPeak) {
2432 maxPeak = sample;
2433 }
2434 }
2435
2436 bool bShouldBePaused = maxPeak < mSilenceLevel;
2437 if( bShouldBePaused != IsPaused() )
2438 {
2439 auto pListener = GetListener();
2440 if ( pListener )
2441 pListener->OnSoundActivationThreshold();
2442 }
2443}
2444
2445// A function to apply the requested gain, fading up or down from the
2446// most recently applied gain.
2448 float * outputMeterFloats,
2449 float * outputFloats,
2450 const float * tempBuf,
2451 bool drop,
2452 unsigned long len,
2453 WaveTrack *vt
2454 )
2455{
2456 const auto numPlaybackChannels = mNumPlaybackChannels;
2457
2458 float gain = vt->GetChannelGain(chan);
2459 if (drop || mForceFadeOut.load(std::memory_order_relaxed) || IsPaused())
2460 gain = 0.0;
2461
2462 // Output volume emulation: possibly copy meter samples, then
2463 // apply volume, then copy to the output buffer
2464 if (outputMeterFloats != outputFloats)
2465 for ( unsigned i = 0; i < len; ++i)
2466 outputMeterFloats[numPlaybackChannels*i+chan] +=
2467 gain*tempBuf[i];
2468
2469 // DV: We use gain to emulate panning.
2470 // Let's keep the old behavior for panning.
2471 gain *= ExpGain(GetMixerOutputVol());
2472
2473 float oldGain = vt->GetOldChannelGain(chan);
2474 if( gain != oldGain )
2475 vt->SetOldChannelGain(chan, gain);
2476 // if no microfades, jump in volume.
2477 if( !mbMicroFades )
2478 oldGain =gain;
2479 wxASSERT(len > 0);
2480
2481 // Linear interpolate.
2482 float deltaGain = (gain - oldGain) / len;
2483 for (unsigned i = 0; i < len; i++)
2484 outputFloats[numPlaybackChannels*i+chan] += (oldGain + deltaGain * i) *tempBuf[i];
2485};
2486
2487// Limit values to -1.0..+1.0
2488void ClampBuffer(float * pBuffer, unsigned long len){
2489 for(unsigned i = 0; i < len; i++)
2490 pBuffer[i] = wxClip( pBuffer[i], -1.0f, 1.0f);
2491};
2492
2493
2494// return true, IFF we have fully handled the callback.
2495//
2496// Mix and copy to PortAudio's output buffer
2497// from our intermediate playback buffers
2498//
2500 float *outputBuffer,
2501 unsigned long framesPerBuffer,
2502 float *outputMeterFloats
2503)
2504{
2505 const auto numPlaybackTracks = mPlaybackTracks.size();
2506 const auto numPlaybackChannels = mNumPlaybackChannels;
2507 const auto numCaptureChannels = mNumCaptureChannels;
2508
2509 mMaxFramesOutput = 0;
2510
2511 // Quick returns if next to nothing to do.
2512 if (mStreamToken <= 0 ||
2513 !outputBuffer ||
2514 numPlaybackChannels <= 0) {
2515 // So that UpdateTimePosition() will be correct, in case of MIDI play with
2516 // no audio output channels
2517 mMaxFramesOutput = framesPerBuffer;
2518 return false;
2519 }
2520
2521 float *outputFloats = outputBuffer;
2522
2524 mSeek = 0.0;
2525
2526 if (mSeek){
2528 return true;
2529 }
2530
2531 // ------ MEMORY ALLOCATION ----------------------
2532 // These are small structures.
2533 WaveTrack **chans = (WaveTrack **) alloca(numPlaybackChannels * sizeof(WaveTrack *));
2534 float **tempBufs = (float **) alloca(numPlaybackChannels * sizeof(float *));
2535
2536 // And these are larger structures....
2537 for (unsigned int c = 0; c < numPlaybackChannels; c++)
2538 tempBufs[c] = (float *) alloca(framesPerBuffer * sizeof(float));
2539 // ------ End of MEMORY ALLOCATION ---------------
2540
2541 int chanCnt = 0;
2542
2543 // Choose a common size to take from all ring buffers
2544 const auto toGet =
2545 std::min<size_t>(framesPerBuffer, GetCommonlyReadyPlayback());
2546
2547 // The drop and dropQuickly booleans are so named for historical reasons.
2548 // JKC: The original code attempted to be faster by doing nothing on silenced audio.
2549 // This, IMHO, is 'premature optimisation'. Instead clearer and cleaner code would
2550 // simply use a gain of 0.0 for silent audio and go on through to the stage of
2551 // applying that 0.0 gain to the data mixed into the buffer.
2552 // Then (and only then) we would have if needed fast paths for:
2553 // - Applying a uniform gain of 0.0.
2554 // - Applying a uniform gain of 1.0.
2555 // - Applying some other uniform gain.
2556 // - Applying a linearly interpolated gain.
2557 // I would expect us not to need the fast paths, since linearly interpolated gain
2558 // is very cheap to process.
2559
2560 bool drop = false; // Track should become silent.
2561 bool dropQuickly = false; // Track has already been faded to silence.
2562 for (unsigned t = 0; t < numPlaybackTracks; t++)
2563 {
2564 WaveTrack *vt = mPlaybackTracks[t].get();
2565 chans[chanCnt] = vt;
2566
2567 // TODO: more-than-two-channels
2568 auto nextTrack =
2569 t + 1 < numPlaybackTracks
2570 ? mPlaybackTracks[t + 1].get()
2571 : nullptr;
2572
2573 // First and last channel in this group (for example left and right
2574 // channels of stereo).
2575 bool firstChannel = vt->IsLeader();
2576 bool lastChannel = !nextTrack || nextTrack->IsLeader();
2577
2578 if ( firstChannel )
2579 {
2580 // IF mono THEN clear 'the other' channel.
2581 if ( lastChannel && (numPlaybackChannels>1)) {
2582 // TODO: more-than-two-channels
2583 memset(tempBufs[1], 0, framesPerBuffer * sizeof(float));
2584 }
2585 drop = TrackShouldBeSilent( *vt );
2586 dropQuickly = drop;
2587 }
2588
2589 if( mbMicroFades )
2590 dropQuickly = dropQuickly && TrackHasBeenFadedOut( *vt );
2591
2592 decltype(framesPerBuffer) len = 0;
2593
2594 if (dropQuickly)
2595 {
2596 len = mPlaybackBuffers[t]->Discard(toGet);
2597 // keep going here.
2598 // we may still need to issue a paComplete.
2599 }
2600 else
2601 {
2602 len = mPlaybackBuffers[t]->Get((samplePtr)tempBufs[chanCnt],
2604 toGet);
2605 // wxASSERT( len == toGet );
2606 if (len < framesPerBuffer)
2607 // This used to happen normally at the end of non-looping
2608 // plays, but it can also be an anomalous case where the
2609 // supply from TrackBufferExchange fails to keep up with the
2610 // real-time demand in this thread (see bug 1932). We
2611 // must supply something to the sound card, so pad it with
2612 // zeroes and not random garbage.
2613 memset((void*)&tempBufs[chanCnt][len], 0,
2614 (framesPerBuffer - len) * sizeof(float));
2615 chanCnt++;
2616 }
2617
2618 // PRL: Bug1104:
2619 // There can be a difference of len in different loop passes if one channel
2620 // of a stereo track ends before the other! Take a max!
2621
2622 // PRL: More recent rewrites of TrackBufferExchange should guarantee a
2623 // padding out of the ring buffers so that equal lengths are
2624 // available, so maxLen ought to increase from 0 only once
2625 mMaxFramesOutput = std::max(mMaxFramesOutput, len);
2626
2627 if ( !lastChannel )
2628 continue;
2629
2630 // Last channel of a track seen now
2631 len = mMaxFramesOutput;
2632
2633 // Realtime effect transformation of the sound used to happen here
2634 // but it is now done already on the producer side of the RingBuffer
2635
2636 // Mix the results with the existing output (software playthrough) and
2637 // apply panning. If post panning effects are desired, the panning would
2638 // need to be be split out from the mixing and applied in a separate step.
2639
2640 // Our channels aren't silent. We need to pass their data on.
2641 //
2642 // Note that there are two kinds of channel count.
2643 // c and chanCnt are counting channels in the Tracks.
2644 // chan (and numPlayBackChannels) is counting output channels on the device.
2645 // chan = 0 is left channel
2646 // chan = 1 is right channel.
2647 //
2648 // Each channel in the tracks can output to more than one channel on the device.
2649 // For example mono channels output to both left and right output channels.
2650 if (len > 0) for (int c = 0; c < chanCnt; c++)
2651 {
2652 vt = chans[c];
2653
2656 AddToOutputChannel( 0, outputMeterFloats, outputFloats,
2657 tempBufs[c], drop, len, vt);
2658
2661 AddToOutputChannel( 1, outputMeterFloats, outputFloats,
2662 tempBufs[c], drop, len, vt);
2663 }
2664
2666 if (dropQuickly) // no samples to process, they've been discarded
2667 continue;
2668
2669 chanCnt = 0;
2670 }
2671
2672 // Poke: If there are no playback tracks, then the earlier check
2673 // about the time indicator being past the end won't happen;
2674 // do it here instead (but not if looping or scrubbing)
2675 // PRL: Also consume from the single playback ring buffer
2676 if (numPlaybackTracks == 0) {
2677 mMaxFramesOutput = mPlaybackBuffers[0]->Discard(toGet);
2679 }
2680
2681 // wxASSERT( maxLen == toGet );
2682
2683 mLastPlaybackTimeMillis = ::wxGetUTCTimeMillis();
2684
2685 ClampBuffer( outputFloats, framesPerBuffer*numPlaybackChannels );
2686 if (outputMeterFloats != outputFloats)
2687 ClampBuffer( outputMeterFloats, framesPerBuffer*numPlaybackChannels );
2688
2689 return false;
2690}
2691
2692void AudioIoCallback::UpdateTimePosition(unsigned long framesPerBuffer)
2693{
2694 // Quick returns if next to nothing to do.
2695 if (mStreamToken <= 0)
2696 return;
2697
2698 // Update the position seen by drawing code
2701}
2702
2703// return true, IFF we have fully handled the callback.
2704//
2705// Copy from PortAudio input buffers to our intermediate recording buffers.
2706//
2708 constSamplePtr inputBuffer,
2709 unsigned long framesPerBuffer,
2710 const PaStreamCallbackFlags statusFlags,
2711 float * tempFloats
2712)
2713{
2714 const auto numPlaybackTracks = mPlaybackTracks.size();
2715 const auto numPlaybackChannels = mNumPlaybackChannels;
2716 const auto numCaptureChannels = mNumCaptureChannels;
2717
2718 // Quick returns if next to nothing to do.
2719 if (mStreamToken <= 0)
2720 return;
2721 if( !inputBuffer )
2722 return;
2723 if( numCaptureChannels <= 0 )
2724 return;
2725
2726 // If there are no playback tracks, and we are recording, then the
2727 // earlier checks for being past the end won't happen, so do it here.
2729 mCallbackReturn = paComplete;
2730 }
2731
2732 // The error likely from a too-busy CPU falling behind real-time data
2733 // is paInputOverflow
2734 bool inputError =
2735 (statusFlags & (paInputOverflow))
2736 && !(statusFlags & paPrimingOutput);
2737
2738 // But it seems it's easy to get false positives, at least on Mac
2739 // So we have not decided to enable this extra detection yet in
2740 // production
2741
2742 size_t len = framesPerBuffer;
2743 for(unsigned t = 0; t < numCaptureChannels; t++)
2744 len = std::min( len, mCaptureBuffers[t]->AvailForPut() );
2745
2746 if (mSimulateRecordingErrors && 100LL * rand() < RAND_MAX)
2747 // Make spurious errors for purposes of testing the error
2748 // reporting
2749 len = 0;
2750
2751 // A different symptom is that len < framesPerBuffer because
2752 // the other thread, executing TrackBufferExchange, isn't consuming fast
2753 // enough from mCaptureBuffers; maybe it's CPU-bound, or maybe the
2754 // storage device it writes is too slow
2755 if (mDetectDropouts &&
2756 ((mDetectUpstreamDropouts.load(std::memory_order_relaxed)
2757 && inputError) ||
2758 len < framesPerBuffer) ) {
2759 // Assume that any good partial buffer should be written leftmost
2760 // and zeroes will be padded after; label the zeroes.
2761 auto start = mPlaybackSchedule.GetTrackTime() +
2763 auto duration = (framesPerBuffer - len) / mRate;
2764 auto pLast = mLostCaptureIntervals.empty()
2765 ? nullptr : &mLostCaptureIntervals.back();
2766 if (pLast &&
2767 fabs(pLast->first + pLast->second - start) < 0.5/mRate)
2768 // Make one bigger interval, not two butting intervals
2769 pLast->second = start + duration - pLast->first;
2770 else
2771 mLostCaptureIntervals.emplace_back( start, duration );
2772 }
2773
2774 if (len < framesPerBuffer)
2775 {
2776 mLostSamples += (framesPerBuffer - len);
2777 wxPrintf(wxT("lost %d samples\n"), (int)(framesPerBuffer - len));
2778 }
2779
2780 if (len <= 0)
2781 return;
2782
2783 // We have an ASSERT in the AudioIO constructor to alert us to
2784 // possible issues with the (short*) cast. We'd have a problem if
2785 // sizeof(short) > sizeof(float) since our buffers are sized for floats.
2786 for(unsigned t = 0; t < numCaptureChannels; t++) {
2787
2788 // dmazzoni:
2789 // Un-interleave. Ugly special-case code required because the
2790 // capture channels could be in three different sample formats;
2791 // it'd be nice to be able to call CopySamples, but it can't
2792 // handle multiplying by the gain and then clipping. Bummer.
2793
2794 switch(mCaptureFormat) {
2795 case floatSample: {
2796 auto inputFloats = (const float *)inputBuffer;
2797 for(unsigned i = 0; i < len; i++)
2798 tempFloats[i] =
2799 inputFloats[numCaptureChannels*i+t];
2800 } break;
2801 case int24Sample:
2802 // We should never get here. Audacity's int24Sample format
2803 // is different from PortAudio's sample format and so we
2804 // make PortAudio return float samples when recording in
2805 // 24-bit samples.
2806 wxASSERT(false);
2807 break;
2808 case int16Sample: {
2809 auto inputShorts = (const short *)inputBuffer;
2810 short *tempShorts = (short *)tempFloats;
2811 for( unsigned i = 0; i < len; i++) {
2812 float tmp = inputShorts[numCaptureChannels*i+t];
2813 tmp = wxClip( -32768, tmp, 32767 );
2814 tempShorts[i] = (short)(tmp);
2815 }
2816 } break;
2817 } // switch
2818
2819 // JKC: mCaptureFormat must be for samples with sizeof(float) or
2820 // fewer bytes (because tempFloats is sized for floats). All
2821 // formats are 2 or 4 bytes, so we are OK.
2822 const auto put =
2823 mCaptureBuffers[t]->Put(
2824 (samplePtr)tempFloats, mCaptureFormat, len);
2825 // wxASSERT(put == len);
2826 // but we can't assert in this thread
2827 wxUnusedVar(put);
2828 mCaptureBuffers[t]->Flush();
2829 }
2830}
2831
2832
2833#if 0
2834// Record the reported latency from PortAudio.
2835// TODO: Don't recalculate this with every callback?
2836// 01/21/2009: Disabled until a better solution presents itself.
2837void OldCodeToCalculateLatency()
2838{
2839 // As of 06/17/2006, portaudio v19 returns inputBufferAdcTime set to
2840 // zero. It is being worked on, but for now we just can't do much
2841 // but follow the leader.
2842 //
2843 // 08/27/2006: too inconsistent for now...just leave it a zero.
2844 //
2845 // 04/16/2008: Looks like si->inputLatency comes back with something useful though.
2846 // This rearranged logic uses si->inputLatency, but if PortAudio fixes inputBufferAdcTime,
2847 // this code won't have to be modified to use it.
2848 // Also avoids setting mLastRecordingOffset except when simultaneously playing and recording.
2849 //
2850 if (numCaptureChannels > 0 && numPlaybackChannels > 0) // simultaneously playing and recording
2851 {
2852 if (timeInfo->inputBufferAdcTime > 0)
2853 mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
2854 else if (mLastRecordingOffset == 0.0)
2855 {
2856 const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
2857 mLastRecordingOffset = -si->inputLatency;
2858 }
2859 }
2860}
2861#endif
2862
2863
2864// return true, IFF we have fully handled the callback.
2865// Prime the output buffer with 0's, optionally adding in the playthrough.
2867 constSamplePtr inputBuffer,
2868 float *outputBuffer,
2869 unsigned long framesPerBuffer,
2870 float *outputMeterFloats
2871 )
2872{
2873 const auto numCaptureChannels = mNumCaptureChannels;
2874 const auto numPlaybackChannels = mNumPlaybackChannels;
2875
2876 // Quick returns if next to nothing to do.
2877 if( !outputBuffer )
2878 return;
2879 if( numPlaybackChannels <= 0 )
2880 return;
2881
2882 float *outputFloats = outputBuffer;
2883 for(unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
2884 outputFloats[i] = 0.0;
2885
2886 if (inputBuffer && mSoftwarePlaythrough) {
2888 numCaptureChannels,
2889 outputBuffer, framesPerBuffer);
2890 }
2891
2892 // Copy the results to outputMeterFloats if necessary
2893 if (outputMeterFloats != outputFloats) {
2894 for (unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
2895 outputMeterFloats[i] = outputFloats[i];
2896 }
2897 }
2898}
2899
2900/* Send data to recording VU meter if applicable */
2901// Also computes rms
2903 const float *inputSamples,
2904 unsigned long framesPerBuffer
2905 )
2906{
2907 const auto numCaptureChannels = mNumCaptureChannels;
2908 auto pInputMeter = mInputMeter.lock();
2909 if ( !pInputMeter )
2910 return;
2911 if( pInputMeter->IsMeterDisabled())
2912 return;
2913 pInputMeter->UpdateDisplay(
2914 numCaptureChannels, framesPerBuffer, inputSamples);
2915}
2916
2917/* Send data to playback VU meter if applicable */
2919 const float *outputMeterFloats,
2920 unsigned long framesPerBuffer)
2921{
2922 const auto numPlaybackChannels = mNumPlaybackChannels;
2923
2924 auto pOutputMeter = mOutputMeter.lock();
2925 if (!pOutputMeter)
2926 return;
2927 if( pOutputMeter->IsMeterDisabled() )
2928 return;
2929 if( !outputMeterFloats)
2930 return;
2931 pOutputMeter->UpdateDisplay(
2932 numPlaybackChannels, framesPerBuffer, outputMeterFloats);
2933
2934 //v Vaughan, 2011-02-25: Moved this update back to TrackPanel::OnTimer()
2935 // as it helps with playback issues reported by Bill and noted on Bug 258.
2936 // The problem there occurs if Software Playthrough is on.
2937 // Could conditionally do the update here if Software Playthrough is off,
2938 // and in TrackPanel::OnTimer() if Software Playthrough is on, but not now.
2939 // PRL 12 Jul 2015: and what was in TrackPanel::OnTimer is now handled by means of track panel timer events
2940 //MixerBoard* pMixerBoard = mOwningProject->GetMixerBoard();
2941 //if (pMixerBoard)
2942 // pMixerBoard->UpdateMeters(GetStreamTime(),
2943 // (pProj->GetControlToolBar()->GetLastPlayMode() == loopedPlay));
2944}
2945
2947 const auto numPlaybackTracks = mPlaybackTracks.size();
2948
2949 // MOVE_TO: CountSoloedTracks() function
2950 unsigned numSolo = 0;
2951 for(unsigned t = 0; t < numPlaybackTracks; t++ )
2952 if( mPlaybackTracks[t]->GetSolo() )
2953 numSolo++;
2954 auto range = Extensions();
2955 numSolo += std::accumulate(range.begin(), range.end(), 0,
2956 [](unsigned sum, auto &ext){
2957 return sum + ext.CountOtherSoloTracks(); });
2958 return numSolo;
2959}
2960
2961// TODO: Consider making the two Track status functions into functions of
2962// WaveTrack.
2963
2964// true IFF the track should be silent.
2965// The track may not yet be silent, since it may still be
2966// fading out.
2968{
2969 return IsPaused() || (!wt.GetSolo() && (
2970 // Cut if somebody else is soloing
2972 // Cut if we're muted (and not soloing)
2973 wt.GetMute()
2974 ));
2975}
2976
2977// This is about micro-fades.
2979{
2980 const auto channel = wt.GetChannelIgnoringPan();
2981 if ((channel == Track::LeftChannel || channel == Track::MonoChannel) &&
2982 wt.GetOldChannelGain(0) != 0.0)
2983 return false;
2984 if ((channel == Track::RightChannel || channel == Track::MonoChannel) &&
2985 wt.GetOldChannelGain(1) != 0.0)
2986 return false;
2987 return true;
2988}
2989
2991{
2992 const bool dropAllQuickly = std::all_of(
2993 mPlaybackTracks.begin(), mPlaybackTracks.end(),
2994 [&]( const std::shared_ptr< WaveTrack > &vt )
2995 { return
2996 TrackShouldBeSilent( *vt ) &&
2997 TrackHasBeenFadedOut( *vt ); }
2998 );
2999 return dropAllQuickly;
3000}
3001
3003{
3004 auto &factories = AudioIOExt::GetFactories();
3005 for (auto &factory: factories)
3006 if (auto pExt = factory(mPlaybackSchedule))
3007 mAudioIOExt.push_back( move(pExt) );
3008}
3009
3010
3012{
3013}
3014
3015
3017 constSamplePtr inputBuffer, float *outputBuffer,
3018 unsigned long framesPerBuffer,
3019 const PaStreamCallbackTimeInfo *timeInfo,
3020 const PaStreamCallbackFlags statusFlags, void * WXUNUSED(userData) )
3021{
3022 // Poll tracks for change of state. User might click mute and solo buttons.
3024 mCallbackReturn = paContinue;
3025
3026 if (IsPaused()
3027 // PRL: Why was this added? Was it only because of the mysterious
3028 // initial leading zeroes, now solved by setting mStreamToken early?
3029 // JKC: I think it's used for the MIDI time cursor. See comments
3030 // at head of file about AudioTime().
3031 || mStreamToken <= 0
3032 )
3033 mNumPauseFrames += framesPerBuffer;
3034
3035 for( auto &ext : Extensions() ) {
3036 ext.ComputeOtherTimings(mRate, IsPaused(),
3037 timeInfo,
3038 framesPerBuffer);
3039 ext.FillOtherBuffers(
3041 }
3042
3043 // ------ MEMORY ALLOCATIONS -----------------------------------------------
3044 // tempFloats will be a reusable scratch pad for (possibly format converted)
3045 // audio data. One temporary use is for the InputMeter data.
3046 const auto numPlaybackChannels = mNumPlaybackChannels;
3047 const auto numCaptureChannels = mNumCaptureChannels;
3048 float *tempFloats = (float *)alloca(framesPerBuffer*sizeof(float)*
3049 MAX(numCaptureChannels,numPlaybackChannels));
3050
3051 bool bVolEmulationActive =
3052 (outputBuffer && GetMixerOutputVol() != 1.0);
3053 // outputMeterFloats is the scratch pad for the output meter.
3054 // we can often reuse the existing outputBuffer and save on allocating
3055 // something new.
3056 float *outputMeterFloats = bVolEmulationActive ?
3057 (float *)alloca(framesPerBuffer*numPlaybackChannels * sizeof(float)) :
3058 outputBuffer;
3059 // ----- END of MEMORY ALLOCATIONS ------------------------------------------
3060
3061 if (inputBuffer && numCaptureChannels) {
3062 float *inputSamples;
3063
3064 if (mCaptureFormat == floatSample) {
3065 inputSamples = (float *) inputBuffer;
3066 }
3067 else {
3068 SamplesToFloats(reinterpret_cast<constSamplePtr>(inputBuffer),
3069 mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
3070 inputSamples = tempFloats;
3071 }
3072
3074 inputSamples,
3075 framesPerBuffer);
3076
3077 // This function may queue up a pause or resume.
3078 // TODO this is a bit dodgy as it toggles the Pause, and
3079 // relies on an idle event to have handled that, so could
3080 // queue up multiple toggle requests and so do nothing.
3081 // Eventually it will sort itself out by random luck, but
3082 // the net effect is a delay in starting/stopping sound activated
3083 // recording.
3085 inputSamples,
3086 framesPerBuffer);
3087 }
3088
3089 // Even when paused, we do playthrough.
3090 // Initialise output buffer to zero or to playthrough data.
3091 // Initialise output meter values.
3093 inputBuffer,
3094 outputBuffer,
3095 framesPerBuffer,
3096 outputMeterFloats);
3097
3098 // Test for no track audio to play (because we are paused and have faded out)
3099 if( IsPaused() && (( !mbMicroFades ) || AllTracksAlreadySilent() ))
3100 return mCallbackReturn;
3101
3102 // To add track output to output (to play sound on speaker)
3103 // possible exit, if we were seeking.
3105 outputBuffer,
3106 framesPerBuffer,
3107 outputMeterFloats))
3108 return mCallbackReturn;
3109
3110 // To move the cursor onwards. (uses mMaxFramesOutput)
3111 UpdateTimePosition(framesPerBuffer);
3112
3113 // To capture input into track (sound from microphone)
3115 inputBuffer,
3116 framesPerBuffer,
3117 statusFlags,
3118 tempFloats);
3119
3120 SendVuOutputMeterData( outputMeterFloats, framesPerBuffer);
3121
3122 return mCallbackReturn;
3123}
3124
3125
3126
3127
3128
3130{
3131 const int token = mStreamToken;
3132 wxMutexLocker locker(mSuspendAudioThread);
3133 if (token != mStreamToken)
3134 // This stream got destroyed while we waited for it
3135 return paAbort;
3136
3137 const auto numPlaybackTracks = mPlaybackTracks.size();
3138
3139 // Pause audio thread and wait for it to finish
3140 //
3141 // [PM] the following 8 lines of code could be probably replaced by
3142 // a single call to StopAudioThreadAndWait()
3143 //
3144 // CAUTION: when trying the above, you must also replace the setting of the
3145 // atomic before the return, with a call to StartAudioThread()
3146 //
3147 // If that works, then we can remove mAudioThreadTrackBufferExchangeLoopActive,
3148 // as it will become unused; consequently, the AudioThread loop would get simpler too.
3149 //
3151 .store(false, std::memory_order_relaxed);
3152
3154 .load(std::memory_order_relaxed ) )
3155 {
3156 using namespace std::chrono;
3157 std::this_thread::sleep_for(50ms);
3158 }
3159
3160 // Calculate the NEW time position, in the PortAudio callback
3161 const auto time =
3163
3165 mSeek = 0.0;
3166
3167
3168 // Reset mixer positions and flush buffers for all tracks
3169 for (auto &mixer : mPlaybackMixers)
3170 mixer->Reposition( time, true );
3171 for (size_t i = 0; i < numPlaybackTracks; i++)
3172 {
3173 const auto toDiscard =
3174 mPlaybackBuffers[i]->AvailForGet();
3175 const auto discarded =
3176 mPlaybackBuffers[i]->Discard( toDiscard );
3177 // wxASSERT( discarded == toDiscard );
3178 // but we can't assert in this thread
3179 wxUnusedVar(discarded);
3180 }
3181
3183
3184 // Reload the ring buffers
3186
3187 // Reenable the audio thread
3189 .store(true, std::memory_order_relaxed);
3190
3191 return paContinue;
3192}
3193
3195 int &callbackReturn, unsigned long len)
3196{
3197 if (IsPaused())
3198 return;
3199
3200 bool done =
3202 if (!done)
3203 return;
3204
3205 for( auto &ext : Extensions() )
3206 ext.SignalOtherCompletion();
3207 callbackReturn = paComplete;
3208}
3209
3211{
3212 // Down-cast and dereference are safe because only AudioIOCallback
3213 // populates the array
3214 return *static_cast<AudioIOExt*>(mIterator->get());
3215}
3216
3217
3219{
3220 mAudioThreadTrackBufferExchangeLoopRunning.store(true, std::memory_order_release);
3221}
3222
3224{
3225 while (mAudioThreadAcknowledge.load(std::memory_order_acquire) != Acknowledge::eStart)
3226 {
3227 using namespace std::chrono;
3228 std::this_thread::sleep_for(50ms);
3229 }
3230 mAudioThreadAcknowledge.store(Acknowledge::eNone, std::memory_order_release);
3231}
3232
3234{
3235 mAudioThreadTrackBufferExchangeLoopRunning.store(false, std::memory_order_release);
3236}
3237
3239{
3240 while (mAudioThreadAcknowledge.load(std::memory_order_acquire) != Acknowledge::eStop)
3241 {
3242 using namespace std::chrono;
3243 std::this_thread::sleep_for(50ms);
3244 }
3245 mAudioThreadAcknowledge.store(Acknowledge::eNone, std::memory_order_release);
3246}
3247
3248void AudioIoCallback::ProcessOnceAndWait(std::chrono::milliseconds sleepTime)
3249{
3251 .store(true, std::memory_order_release);
3252
3254 .load(std::memory_order_acquire))
3255 {
3256 using namespace std::chrono;
3257 std::this_thread::sleep_for(sleepTime);
3258 }
3259}
3260
3261
3262
3264{
3265 // Includes a test of mTime, used in the main thread
3266 return IsStreamActive() &&
3267 GetNumCaptureChannels() > 0 &&
3270}
wxT("CloseDown"))
void DefaultDelayedHandlerAction(AudacityException *pException)
A default template parameter for GuardedCall.
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
int audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
Definition: AudioIO.cpp:2400
static PaSampleFormat AudacityToPortAudioSampleFormat(sampleFormat format)
Definition: AudioIO.cpp:463
static void DoSoftwarePlaythrough(constSamplePtr inputBuffer, sampleFormat inputFormat, unsigned inputChannels, float *outputBuffer, unsigned long len)
Definition: AudioIO.cpp:2381
void ClampBuffer(float *pBuffer, unsigned long len)
Definition: AudioIO.cpp:2488
#define MAX(a, b)
Definition: AudioIO.cpp:2379
std::vector< std::shared_ptr< WaveTrack > > WaveTrackArray
Definition: AudioIO.h:49
int PaError
Definition: AudioIO.h:54
unsigned long PaStreamCallbackFlags
Definition: AudioIO.h:52
DoubleSetting AudioIOLatencyCorrection
DoubleSetting AudioIOPlaybackVolume
StringSetting AudioIOPlaybackDevice
DoubleSetting AudioIOLatencyDuration
StringSetting AudioIORecordingDevice
StringSetting AudioIOHost
IntSetting AudioIORecordChannels
#define BAD_STREAM_TIME
Definition: AudioIOBase.h:38
Abstract base class for hooks into audio playback procedures.
Toolkit-neutral facade for basic user interface services.
int min(int a, int b)
IntSetting DecibelScaleCutoff
Negation of this value is the lowest dB level that should be shown in dB scales.
Definition: Decibels.cpp:12
wxString PluginID
Definition: EffectManager.h:30
int format
Definition: ExportPCM.cpp:56
Type ExpGain(Type gain) noexcept
Definition: Gain.h:19
#define LAT1CTOWX(X)
Definition: Internat.h:160
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:431
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:543
constexpr size_t TimeQueueGrainSize
FileConfig * gPrefs
Definition: Prefs.cpp:71
wxString WarningDialogKey(const wxString &internalDialogName)
Definition: Prefs.cpp:469
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
accessors for certain important windows associated with each project
void ClearSamples(samplePtr dst, sampleFormat format, size_t start, size_t len)
void SamplesToFloats(constSamplePtr src, sampleFormat srcFormat, float *dst, size_t len, size_t srcStride, size_t dstStride)
Copy samples from any format into the widest format, which is 32 bit float, with no dithering.
sampleFormat
Definition: SampleFormat.h:29
@ floatSample
Definition: SampleFormat.h:34
@ int16Sample
Definition: SampleFormat.h:32
@ int24Sample
Definition: SampleFormat.h:33
char * samplePtr
Definition: SampleFormat.h:49
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:44
const char * constSamplePtr
Definition: SampleFormat.h:50
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::chrono::system_clock Clock
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
Base class for exceptions specially processed by the application.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
std::weak_ptr< Meter > mOutputMeter
Definition: AudioIOBase.h:261
PaStream * mPortStreamV19
Definition: AudioIOBase.h:258
static wxString HostName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:80
std::atomic< bool > mPaused
True if audio playback is paused.
Definition: AudioIOBase.h:249
double mRate
Audio playback rate in samples per second.
Definition: AudioIOBase.h:256
static std::vector< long > GetSupportedCaptureRates(int devIndex=-1, double rate=0.0)
Get a list of sample rates the input (recording) device supports.
bool IsMonitoring() const
Returns true if we're monitoring input (but not recording or playing actual audio)
static std::vector< long > GetSupportedPlaybackRates(int DevIndex=-1, double rate=0.0)
Get a list of sample rates the output (playback) device supports.
static std::unique_ptr< AudioIOBase > ugAudioIO
Definition: AudioIOBase.h:242
static double mCachedBestRateIn
Definition: AudioIOBase.h:283
void SetCaptureMeter(const std::shared_ptr< AudacityProject > &project, const std::weak_ptr< Meter > &meter)
static int getPlayDevIndex(const wxString &devName={})
get the index of the device selected in the preferences.
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:91
bool IsStreamActive() const
Returns true if the audio i/o is running at all, but not during cleanup.
bool IsBusy() const
Returns true if audio i/o is busy starting, stopping, playing, or recording.
void HandleDeviceChange()
update state after changing what audio devices are selected
void SetMixer(int inputSource)
static wxString DeviceName(const PaDeviceInfo *info)
Definition: AudioIOBase.cpp:73
int mStreamToken
Definition: AudioIOBase.h:252
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.
std::weak_ptr< AudacityProject > mOwningProject
Definition: AudioIOBase.h:246
bool mInputMixerWorks
Can we control the hardware input level?
Definition: AudioIOBase.h:275
bool IsPaused() const
Find out if playback / recording is currently paused.
std::weak_ptr< Meter > mInputMeter
Definition: AudioIOBase.h:260
static int getRecordDevIndex(const wxString &devName={})
get the index of the supplied (named) recording device, or the device selected in the preferences if ...
static Factories & GetFactories()
Definition: AudioIOExt.cpp:15
AudioIO uses the PortAudio library to play and record sound.
Definition: AudioIO.h:406
std::shared_ptr< AudacityProject > GetOwningProject() const
Definition: AudioIO.h:476
bool mDelayingActions
Definition: AudioIO.h:638
void StopStream() override
Stop recording, playback or input monitoring.
Definition: AudioIO.cpp:1305
void SetOwningProject(const std::shared_ptr< AudacityProject > &pProject)
Definition: AudioIO.cpp:678
bool IsCapturing() const
Definition: AudioIO.cpp:3263
bool InputMixerWorks()
Find out if the input hardware level control is available.
Definition: AudioIO.cpp:430
std::mutex mPostRecordingActionMutex
Definition: AudioIO.h:635
PostRecordingAction mPostRecordingAction
Definition: AudioIO.h:636
void TrackBufferExchange()
Definition: AudioIO.cpp:1794
void GetMixer(int *inputSource, float *inputVolume, float *playbackVolume)
Definition: AudioIO.cpp:403
static void Init()
Definition: AudioIO.cpp:198
void DrainRecordBuffers()
Second part of TrackBufferExchange.
Definition: AudioIO.cpp:2008
static void Deinit()
Definition: AudioIO.cpp:226
static AudioIO * Get()
Definition: AudioIO.cpp:133
void SetPaused(bool state)
Pause and un-pause playback and recording.
Definition: AudioIO.cpp:1575
bool StartPortAudioStream(const AudioIOStartStreamOptions &options, 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:476
std::shared_ptr< RealtimeEffectState > AddState(AudacityProject &project, Track *pTrack, const PluginID &id)
Forwards to RealtimeEffectManager::AddState with proper init scope.
Definition: AudioIO.cpp:352
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:1590
void FillPlayBuffers()
First part of TrackBufferExchange.
Definition: AudioIO.cpp:1800
AudioIO()
Definition: AudioIO.cpp:240
void DelayActions(bool recording)
Definition: AudioIO.cpp:1037
void SetMixer(int inputSource, float inputVolume, float playbackVolume)
Definition: AudioIO.cpp:383
std::shared_ptr< RealtimeEffectState > ReplaceState(AudacityProject &project, Track *pTrack, size_t index, const PluginID &id)
Forwards to RealtimeEffectManager::ReplaceState with proper init scope.
Definition: AudioIO.cpp:362
bool ProcessPlaybackSlices(std::optional< RealtimeEffects::ProcessingScope > &pScope, size_t available)
Definition: AudioIO.cpp:1878
~AudioIO()
Definition: AudioIO.cpp:319
void SetMeters()
Set the current VU meters - this should be done once after each call to StartStream currently.
Definition: AudioIO.cpp:1297
void CallAfterRecording(PostRecordingAction action)
Enqueue action for main thread idle time, not before the end of any recording in progress.
Definition: AudioIO.cpp:1047
int StartStream(const TransportTracks &tracks, double t0, double t1, double mixerLimit, const AudioIOStartStreamOptions &options)
Start recording or playing back audio.
Definition: AudioIO.cpp:742
bool DelayingActions() const
Definition: AudioIO.cpp:1042
bool IsAvailable(AudacityProject &project) const
Function to automatically set an acceptable volume.
Definition: AudioIO.cpp:1291
void StartStreamCleanup(bool bOnlyBuffers=false)
Clean up after StartStream if it fails.
Definition: AudioIO.cpp:1268
wxArrayString GetInputSourceNames()
Get the list of inputs to the current mixer device.
Definition: AudioIO.cpp:435
static void AudioThread(std::atomic< bool > &finish)
Sits in a thread loop reading and writing audio.
Definition: AudioIO.cpp:1686
void StartMonitoring(const AudioIOStartStreamOptions &options)
Start up Portaudio for capture and recording as needed for input monitoring and software playthrough ...
Definition: AudioIO.cpp:694
size_t GetCommonlyFreePlayback()
Get the number of audio samples free in all of the playback buffers.
Definition: AudioIO.cpp:1753
void ResetOwningProject()
Definition: AudioIO.cpp:689
std::function< void()> PostRecordingAction
Definition: AudioIO.h:466
static bool ValidateDeviceNames(const wxString &play, const wxString &rec)
Ensure selected device names are valid.
Definition: AudioIO.cpp:231
size_t GetCommonlyAvailCapture()
Get the number of audio samples ready in all of the recording buffers.
Definition: AudioIO.cpp:1782
double GetStreamTime()
During playback, the track time most recently played.
Definition: AudioIO.cpp:1668
wxString LastPaErrorString()
Definition: AudioIO.cpp:673
void TransformPlayBuffers(std::optional< RealtimeEffects::ProcessingScope > &scope)
Definition: AudioIO.cpp:1946
bool AllocateBuffers(const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate)
Allocate RingBuffer structures, and others, needed for playback and recording.
Definition: AudioIO.cpp:1075
void StartThread()
Definition: AudioIO.cpp:314
void RemoveState(AudacityProject &project, Track *pTrack, std::shared_ptr< RealtimeEffectState > pState)
Forwards to RealtimeEffectManager::RemoveState with proper init scope.
Definition: AudioIO.cpp:373
std::vector< std::unique_ptr< AudioIOExtBase > >::const_iterator mIterator
Definition: AudioIO.h:160
auto operator*() const -> AudioIOExt &
Definition: AudioIO.cpp:3210
static int mNextStreamToken
Definition: AudioIO.h:282
std::shared_ptr< AudioIOListener > GetListener() const
Definition: AudioIO.h:177
size_t GetCommonlyWrittenForPlayback()
Definition: AudioIO.cpp:1773
bool TrackShouldBeSilent(const WaveTrack &wt)
Definition: AudioIO.cpp:2967
void CallbackCheckCompletion(int &callbackReturn, unsigned long len)
Definition: AudioIO.cpp:3194
bool mbMicroFades
Definition: AudioIO.h:286
double mSeek
Definition: AudioIO.h:288
std::unique_ptr< TransportState > mpTransportState
Holds some state for duration of playback or recording.
Definition: AudioIO.h:388
wxMutex mSuspendAudioThread
Definition: AudioIO.h:357
AudioIOExtRange Extensions()
Definition: AudioIO.h:169
bool AllTracksAlreadySilent()
Definition: AudioIO.cpp:2990
float GetMixerOutputVol()
Definition: AudioIO.h:338
int AudioCallback(constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
Definition: AudioIO.cpp:3016
void CheckSoundActivatedRecordingLevel(float *inputSamples, unsigned long framesPerBuffer)
Definition: AudioIO.cpp:2419
PlaybackSchedule mPlaybackSchedule
Definition: AudioIO.h:386
RecordingSchedule mRecordingSchedule
Definition: AudioIO.h:385
std::vector< float * > mScratchPointers
pointing into mScratchBuffers
Definition: AudioIO.h:277
std::atomic< Acknowledge > mAudioThreadAcknowledge
Definition: AudioIO.h:314
std::atomic< bool > mFinishAudioThread
Definition: AudioIO.h:267
void UpdateTimePosition(unsigned long framesPerBuffer)
Definition: AudioIO.cpp:2692
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
Definition: AudioIO.h:293
std::atomic< bool > mAudioThreadTrackBufferExchangeLoopRunning
Definition: AudioIO.h:311
unsigned CountSoloingTracks()
Definition: AudioIO.cpp:2946
static double mCachedBestRateOut
Definition: AudioIO.h:351
std::vector< std::unique_ptr< Mixer > > mPlaybackMixers
Definition: AudioIO.h:279
PlaybackPolicy::Duration mPlaybackRingBufferSecs
Definition: AudioIO.h:289
bool TrackHasBeenFadedOut(const WaveTrack &wt)
Definition: AudioIO.cpp:2978
std::thread mAudioThread
Definition: AudioIO.h:266
int mCallbackReturn
Definition: AudioIO.h:189
std::atomic< bool > mAudioThreadTrackBufferExchangeLoopActive
Definition: AudioIO.h:312
void ClearRecordingException()
Definition: AudioIO.h:365
long mNumPauseFrames
How many frames of zeros were output due to pauses?
Definition: AudioIO.h:247
unsigned int mNumPlaybackChannels
Definition: AudioIO.h:307
void SetRecordingException()
Definition: AudioIO.h:363
std::atomic< bool > mForceFadeOut
Definition: AudioIO.h:328
void DrainInputBuffers(constSamplePtr inputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackFlags statusFlags, float *tempFloats)
Definition: AudioIO.cpp:2707
std::atomic< bool > mAudioThreadShouldCallTrackBufferExchangeOnce
Definition: AudioIO.h:310
wxLongLong mLastPlaybackTimeMillis
Definition: AudioIO.h:330
void SendVuInputMeterData(const float *inputSamples, unsigned long framesPerBuffer)
Definition: AudioIO.cpp:2902
std::vector< std::unique_ptr< AudioIOExtBase > > mAudioIOExt
Definition: AudioIOBase.h:323
void SendVuOutputMeterData(const float *outputMeterFloats, unsigned long framesPerBuffer)
Definition: AudioIO.cpp:2918
bool mDetectDropouts
Definition: AudioIO.h:370
void DoPlaythrough(constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
Definition: AudioIO.cpp:2866
void StopAudioThread()
Definition: AudioIO.cpp:3233
void WaitForAudioThreadStarted()
Definition: AudioIO.cpp:3223
void AddToOutputChannel(unsigned int chan, float *outputMeterFloats, float *outputFloats, const float *tempBuf, bool drop, unsigned long len, WaveTrack *vt)
Definition: AudioIO.cpp:2447
bool mSimulateRecordingErrors
Definition: AudioIO.h:378
int mbHasSoloTracks
Definition: AudioIO.h:188
WaveTrackArray mPlaybackTracks
Definition: AudioIO.h:274
PaError mLastPaError
Definition: AudioIO.h:334
bool FillOutputBuffers(float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
Definition: AudioIO.cpp:2499
static bool mCachedBestRatePlaying
Definition: AudioIO.h:352
bool mSoftwarePlaythrough
Definition: AudioIO.h:299
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
Definition: AudioIO.h:270
void SetListener(const std::shared_ptr< AudioIOListener > &listener)
Definition: AudioIO.cpp:2200
WaveTrackArray mCaptureTracks
Definition: AudioIO.h:271
int CallbackDoSeek()
Definition: AudioIO.cpp:3129
unsigned long mMaxFramesOutput
Definition: AudioIO.h:284
double mLastRecordingOffset
Not (yet) used; should perhaps be atomic when it is.
Definition: AudioIO.h:333
void StartAudioThread()
Definition: AudioIO.cpp:3218
size_t GetCommonlyReadyPlayback()
Get the number of audio samples ready in all of the playback buffers.
Definition: AudioIO.cpp:1764
std::atomic< bool > mDetectUpstreamDropouts
Definition: AudioIO.h:382
void ProcessOnceAndWait(std::chrono::milliseconds sleepTime=std::chrono::milliseconds(50))
Definition: AudioIO.cpp:3248
size_t mPlaybackQueueMinimum
Occupancy of the queue we try to maintain, with bigger batches if needed.
Definition: AudioIO.h:295
std::weak_ptr< AudioIOListener > mListener
Definition: AudioIO.h:346
wxAtomicInt mRecordingException
Definition: AudioIO.h:362
ArrayOf< std::unique_ptr< Resample > > mResample
Definition: AudioIO.h:269
double mCaptureRingBufferSecs
Definition: AudioIO.h:290
float mSilenceLevel
Definition: AudioIO.h:303
unsigned int mNumCaptureChannels
Definition: AudioIO.h:305
void SetMixerOutputVol(float value)
Definition: AudioIO.h:340
std::vector< std::pair< double, double > > mLostCaptureIntervals
Definition: AudioIO.h:368
void WaitForAudioThreadStopped()
Definition: AudioIO.cpp:3238
bool mPauseRec
True if Sound Activated Recording is enabled.
Definition: AudioIO.h:302
bool mUsingAlsa
Definition: AudioIO.h:348
double mFactor
Definition: AudioIO.h:283
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
Definition: AudioIO.h:273
double mMinCaptureSecsToCopy
Definition: AudioIO.h:297
unsigned long long mLostSamples
Definition: AudioIO.h:309
std::vector< SampleBuffer > mScratchBuffers
Definition: AudioIO.h:276
static bool mCachedBestRateCapturing
Definition: AudioIO.h:353
sampleFormat mCaptureFormat
Definition: AudioIO.h:308
static DeviceManager * Instance()
Gets the singleton instance.
std::chrono::duration< float > GetTimeSinceRescan()
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
std::vector< Input > Inputs
Definition: Mix.h:43
CallbackReturn Publish(const AudioIOEvent &message)
Send a message to connected callbacks.
Definition: Observer.h:207
bool GetSolo() const
Definition: Track.h:924
bool GetMute() const
Definition: Track.h:923
virtual BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule)
Provide hints for construction of playback RingBuffer objects.
virtual double OffsetTrackTime(PlaybackSchedule &schedule, double offset)
Called when the play head needs to jump a certain distance.
virtual bool AllowSeek(PlaybackSchedule &schedule)
Whether repositioning commands are allowed during playback.
virtual void Finalize(PlaybackSchedule &schedule)
Called after stopping of an audio stream or an unsuccessful start.
virtual void Initialize(PlaybackSchedule &schedule, double rate)
Called before starting an audio stream.
virtual PlaybackSlice GetPlaybackSlice(PlaybackSchedule &schedule, size_t available)
Choose length of one fetch of samples from tracks in a call to AudioIO::FillPlayBuffers.
virtual bool Done(PlaybackSchedule &schedule, unsigned long outputFrames)
Returns true if schedule.GetTrackTime() has reached the end of playback.
virtual std::chrono::milliseconds SleepInterval(PlaybackSchedule &schedule)
How long to wait between calls to AudioIO::TrackBufferExchange.
void Producer(PlaybackSchedule &schedule, PlaybackSlice slice)
Enqueue track time value advanced by the slice according to schedule's PlaybackPolicy.
double Consumer(size_t nSamples, double rate)
Find the track time value nSamples after the last consumed sample.
void Prime(double time)
Empty the queue and reassign the last produced time.
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
std::shared_ptr< RealtimeEffectState > AddState(RealtimeEffects::InitializationScope *pScope, Track *pTrack, const PluginID &id)
Main thread appends a global or per-track effect.
static RealtimeEffectManager & Get(AudacityProject &project)
std::shared_ptr< RealtimeEffectState > ReplaceState(RealtimeEffects::InitializationScope *pScope, Track *pTrack, size_t index, const PluginID &id)
Main thread replaces a global or per-track effect.
void RemoveState(RealtimeEffects::InitializationScope *pScope, Track *pTrack, std::shared_ptr< RealtimeEffectState > pState)
Main thread removes a global or per-track effect.
Brackets processing setup and cleanup in the main thread.
SampleBuffer & Allocate(size_t count, sampleFormat format)
Definition: SampleFormat.h:96
samplePtr ptr() const
Definition: SampleFormat.h:110
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:252
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:200
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
@ LeftChannel
Definition: Track.h:282
@ RightChannel
Definition: Track.h:283
@ MonoChannel
Definition: Track.h:284
bool IsLeader() const
Definition: Track.cpp:405
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1541
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
ChannelType GetChannelIgnoringPan() const override
Definition: WaveTrack.cpp:254
void SetOldChannelGain(int channel, float gain) override
Definition: WaveTrack.cpp:560
void Flush() override
Definition: WaveTrack.cpp:1846
float GetChannelGain(int channel) const override
Takes gain and pan into account.
Definition: WaveTrack.cpp:537
float GetOldChannelGain(int channel) const override
Definition: WaveTrack.cpp:555
#define lrint(dbl)
Definition: float_cast.h:169
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:254
void Release(wxWindow *handler)
PROJECT_RATE_API sampleFormat SampleFormatChoice()
static RegisteredToolbarFactory factory
struct holding stream options, including a pointer to the time warp info and AudioIOListener and whet...
Definition: AudioIOBase.h:44
std::function< std::chrono::milliseconds() > playbackStreamPrimer
Definition: AudioIOBase.h:70
std::shared_ptr< AudacityProject > pProject
Definition: AudioIOBase.h:54
std::weak_ptr< Meter > captureMeter
Definition: AudioIOBase.h:55
std::weak_ptr< Meter > playbackMeter
Definition: AudioIOBase.h:55
PRCrossfadeData * pCrossfadeData
Definition: AudioIOBase.h:65
std::optional< double > pStartTime
Definition: AudioIOBase.h:59
std::shared_ptr< AudioIOListener > listener
Definition: AudioIOBase.h:57
std::optional< RealtimeEffects::InitializationScope > mpRealtimeInitialization
Definition: AudioIO.cpp:165
TransportState(std::weak_ptr< AudacityProject > wOwningProject, const WaveTrackArray &playbackTracks, unsigned numPlaybackChannels, double sampleRate)
Definition: AudioIO.cpp:139
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:49
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...
Definition: MemoryX.h:173
double GetTrackTime() const
Get current track time value, unadjusted.
double mT0
Playback starts at offset of mT0, which is measured in seconds.
class PlaybackSchedule::TimeQueue mTimeQueue
void Init(double t0, double t1, const AudioIOStartStreamOptions &options, const RecordingSchedule *pRecordingSchedule)
void SetTrackTime(double time)
Set current track time value, unadjusted.
PlaybackPolicy & GetPolicy()
double TotalCorrection() const
double ToDiscard() const
double ToConsume() const
double Consumed() const
PRCrossfadeData mCrossfadeData
Definition: Dither.cpp:67
PlayableTrackConstArray otherPlayableTracks
Definition: AudioIO.h:81
WaveTrackConstArray prerollTracks
Definition: AudioIO.h:84
WaveTrackArray captureTracks
Definition: AudioIO.h:80
WaveTrackArray playbackTracks
Definition: AudioIO.h:79