93#include <wx/wxcrtvararg.h>
98#if defined(__WXMAC__) || defined(__WXMSW__)
118#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
119 #define LOWER_BOUND 0.0
120 #define UPPER_BOUND 1.0
127 TrackList &trackList,
bool selectedOnly,
bool nonWaveToo)
132 for (
auto pTrack : range)
135#ifdef EXPERIMENTAL_MIDI_OUT
139 for (
auto pTrack : range)
140 if (!track_cast<const SampleTrack *>(pTrack))
155 unsigned numPlaybackChannels,
double sampleRate)
157 if (
auto pOwningProject = wOwningProject.lock();
158 pOwningProject && numPlaybackChannels > 0) {
162 move(wOwningProject), sampleRate, numPlaybackChannels);
164 for (
size_t i = 0, cnt = playbackTracks.size(); i < cnt;) {
166 auto vt = playbackTracks[i].get();
174 ->AddTrack(*vt, numPlaybackChannels, sampleRate);
190 #undef REALTIME_ALSA_THREAD
193 #undef REALTIME_ALSA_THREAD
196#ifdef REALTIME_ALSA_THREAD
197#include "pa_linux_alsa.h"
201 unsigned long framesPerBuffer,
202 const PaStreamCallbackTimeInfo *timeInfo,
216 pAudioIO->StartThread();
219 if (
gPrefs->Read(
wxT(
"AudioIO/RecordingDevice"),
wxT(
"")).empty()) {
221 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
228 if (
gPrefs->Read(
wxT(
"AudioIO/PlaybackDevice"),
wxT(
"")).empty()) {
230 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
251 return pInfo !=
nullptr && rInfo !=
nullptr && pInfo->hostApi == rInfo->hostApi;
256 if (!std::atomic<double>{}.is_lock_free()) {
267 wxASSERT(
sizeof(
short ) <=
sizeof(
float ));
270 .store(
false, std::memory_order_relaxed);
272 .store(
false, std::memory_order_relaxed);
274 .store(
false, std::memory_order_relaxed);
282#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
296 if (err != paNoError) {
297 auto errStr =
XO(
"Could not find any audio devices.\n");
298 errStr +=
XO(
"You will not be able to play or record audio.\n\n");
299 wxString paErrStr =
LAT1CTOWX(Pa_GetErrorText(err));
300 if (!paErrStr.empty())
301 errStr +=
XO(
"Error: %s").Format( paErrStr );
309 .IconStyle(Icon::Error)
310 .ButtonStyle(Button::Ok));
318#if defined(USE_PORTMIXER)
320 mPreviousHWPlaythrough = -1.0;
343#if defined(USE_PORTMIXER)
346 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
347 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
348 mPreviousHWPlaythrough = -1.0;
350 Px_CloseMixer(mPortMixer);
368std::shared_ptr<RealtimeEffectState>
378std::shared_ptr<RealtimeEffectState>
391 Track *pTrack,
const std::shared_ptr<RealtimeEffectState> pState)
401 float playbackVolume)
406#if defined(USE_PORTMIXER)
407 PxMixer *mixer = mPortMixer;
411 float oldRecordVolume = Px_GetInputVolume(mixer);
414 if( oldRecordVolume != recordVolume )
415 Px_SetInputVolume(mixer, recordVolume);
421 float *playbackVolume)
425#if defined(USE_PORTMIXER)
427 PxMixer *mixer = mPortMixer;
431 *recordDevice = Px_GetCurrentInputSource(mixer);
434 *recordVolume = Px_GetInputVolume(mixer);
436 *recordVolume = 1.0f;
444 *recordVolume = 1.0f;
454#if defined(USE_PORTMIXER)
456 wxArrayString deviceNames;
460 int numSources = Px_GetNumInputSources(mPortMixer);
461 for(
int source = 0; source < numSources; source++ )
462 deviceNames.push_back(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
466 wxLogDebug(
wxT(
"AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
494 unsigned int numPlaybackChannels,
495 unsigned int numCaptureChannels,
498 auto sampleRate = options.
rate;
501 bool success =
false;
502 auto cleanup =
finally([&]{
518 mRate =
GetBestRate(numCaptureChannels > 0, numPlaybackChannels > 0, sampleRate);
523 auto captureFormat_saved = captureFormat;
539 bool usePlayback =
false, useCapture =
false;
540 PaStreamParameters playbackParameters{};
541 PaStreamParameters captureParameters{};
545 if( numPlaybackChannels > 0)
553 const PaDeviceInfo *playbackDeviceInfo;
554 playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
556 if( playbackDeviceInfo == NULL )
560 playbackParameters.sampleFormat = paFloat32;
561 playbackParameters.hostApiSpecificStreamInfo = NULL;
565 playbackParameters.suggestedLatency =
566 playbackDeviceInfo->defaultLowOutputLatency;
573 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
574 bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
575 playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
581 if( numCaptureChannels > 0)
586 const PaDeviceInfo *captureDeviceInfo;
591 captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
593 if( captureDeviceInfo == NULL )
596 captureParameters.sampleFormat =
599 captureParameters.hostApiSpecificStreamInfo = NULL;
603 captureParameters.suggestedLatency =
604 captureDeviceInfo->defaultHighInputLatency;
606 captureParameters.suggestedLatency = latencyDuration/1000.0;
611 const auto deviceInfo = usePlayback ?
612 Pa_GetDeviceInfo(playbackParameters.device) :
613 Pa_GetDeviceInfo(captureParameters.device);
615 mUsingAlsa = deviceInfo && deviceInfo->hostApi == paALSA;
624 float oldRecordVolume = Px_GetInputVolume(mPortMixer);
631 int* lpUserData = (captureFormat_saved ==
int24Sample) ? &userData : NULL;
636 unsigned int maxTries = 1;
639 using namespace std::chrono;
645 for (
unsigned int tries = 0; tries < maxTries; tries++) {
647 useCapture ? &captureParameters : NULL,
648 usePlayback ? &playbackParameters : NULL,
649 mRate, paFramesPerBufferUnspecified,
672 wxLogDebug(
"Attempt %u to open capture stream failed with: %d", 1 + tries,
mLastPaError);
673 using namespace std::chrono;
674 std::this_thread::sleep_for(1s);
680 Px_SetInputVolume(mPortMixer, oldRecordVolume);
686 if (Px_SupportsPlaythrough(mPortMixer)) {
687 bool playthrough =
false;
689 mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
694 Px_SetPlaythrough(mPortMixer, 1.0);
696 Px_SetPlaythrough(mPortMixer, 0.0);
703#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
706 wxPowerResource::Acquire(wxPOWER_RESOURCE_SCREEN,
_(
"Audacity Audio"));
719 const std::shared_ptr<AudacityProject> &pProject )
743 int playbackChannels = 0;
746 playbackChannels = 2;
752 (
unsigned int)captureChannels,
758 auto msg =
XO(
"Error opening recording device.\nError code: %s")
761 XO(
"Error"), msg,
wxT(
"Error_opening_sound_device"),
778 pListener->OnAudioIORate((
int)
mRate);
783 double t0,
double t1,
double mixerLimit,
816 using namespace std::chrono;
817 std::this_thread::sleep_for(50ms);
825 gPrefs->Read(
wxT(
"/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
827 if(silenceLevelDB < -dBRange)
829 silenceLevelDB = -dBRange + 3;
861 auto cleanupTracks =
finally([&]{
867 ext.AbortOtherStream();
885 unsigned int playbackChannels = 0;
886 unsigned int captureChannels = 0;
893 playbackChannels = 2;
896 playbackChannels = 2;
914 pListener->OnAudioIOStartRecording();
920 captureChannels, captureFormat);
926#ifdef EXPERIMENTAL_MIDI_OUT
928 successAudio = successAudio &&
929 std::all_of(range.begin(), range.end(),
930 [
this, &tracks, t0](
auto &ext){
931 return ext.StartOtherStream( tracks,
932 (mPortStreamV19 != NULL && mLastPaError == paNoError)
933 ? Pa_GetStreamInfo(mPortStreamV19) : nullptr,
938 if (pListener && captureChannels > 0)
939 pListener->OnAudioIOStopRecording();
946 double mixerStart = t0;
948 mixerStart =
std::min( mixerStart, *pStartTime );
950 mixerStart, mixerLimit, options.
rate ) )
957#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
964 const auto time = *pStartTime;
972 mixer->Reposition( time );
984 .store(
true, std::memory_order_release);
987 .load(std::memory_order_acquire)) {
988 using namespace std::chrono;
989 auto interval = 50ms;
993 std::this_thread::sleep_for(interval);
998#ifdef REALTIME_ALSA_THREAD
1036 if( err != paNoError )
1043 pListener->OnAudioIOStopRecording();
1055 pListener->OnAudioIORate((
int)
mRate);
1093 nextAction = std::move(action)
1094 ]{ prevAction(); nextAction(); };
1111 const TransportTracks &tracks,
double t0,
double t1,
double sampleRate )
1113 bool success =
false;
1114 auto cleanup =
finally([&]{
1141 wxASSERT( playbackTime >= 0 );
1161 auto playbackBufferSize =
1181 reinterpret_cast<float*
>(buffer.ptr()));
1186 const auto &warpOptions =
1204 std::make_unique<RingBuffer>(
floatSample, playbackBufferSize);
1214 std::make_unique<RingBuffer>(
floatSample, playbackBufferSize);
1216 if (pTrack->IsLeader()) {
1218 double startTime, endTime;
1237 TrackList::Channels<const SampleTrack>(pTrack.get());
1238 for (
auto channel : range)
1239 mixTracks.push_back(
1245 warpOptions, startTime, endTime, range.size(),
1256 const auto timeQueueSize = 1 +
1266 auto captureBufferSize =
1271 if(captureBufferSize < 100)
1291 catch(std::bad_alloc&)
1304 auto playbackBufferSize =
1344 return !pOwningProject || pOwningProject.get() == &project;
1350 pInputMeter->Reset(
mRate,
true);
1352 pOutputMeter->Reset(
mRate,
true);
1357 auto cleanup =
finally ( [
this] {
1378#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1384 .load(std::memory_order_relaxed) )
1394 using namespace std::chrono;
1395 std::this_thread::sleep_for(milliseconds{latency + 50});
1432 #if defined(USE_PORTMIXER)
1435 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1436 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1437 mPreviousHWPlaythrough = -1.0;
1462 ext.StopOtherStream();
1539 std::optional<TransactionScope> pScope;
1541 pScope.emplace(*pOwningProject,
"Dropouts");
1543 auto &start = interval.first;
1544 auto duration = interval.second;
1547 track->SyncLockAdjust(start, start + duration);
1556 pListener->OnCommitRecording();
1563 pInputMeter->Reset(
mRate,
false);
1566 pOutputMeter->Reset(
mRate,
false);
1573 pListener->OnAudioIOStopRecording();
1581 std::this_thread::yield();
1601 Publish({ pOwningProject.get(),
1618 pListener->OnAudioIORate(0);
1633 em.SetSuspended(state);
1637 mPaused.store(state, std::memory_order_relaxed);
1652 std::vector<long> rates;
1653 if (capturing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for capture"));
1654 if (playing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for playback"));
1655 wxLogDebug(
wxT(
"GetBestRate() suggested rate %.0lf Hz"), sampleRate);
1657 if (capturing && !playing) {
1660 else if (playing && !capturing) {
1669 long rate = (long)sampleRate;
1672 wxLogDebug(
wxT(
"GetBestRate() Returning %.0ld Hz"), rate);
1689 if (rates.empty()) {
1691 wxLogDebug(
wxT(
"GetBestRate() Error - no supported sample rates"));
1696 for (i = 0; i < (int)rates.size(); i++)
1698 if (rates[i] > rate) {
1700 wxLogDebug(
wxT(
"GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1706 wxLogDebug(
wxT(
"GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1707 retval = rates.back();
1738 enum class State { eUndefined, eOnce, eLoopRunning, eDoNothing, eMonitoring } lastState = State::eUndefined;
1740 while (!finish.load(std::memory_order_acquire)) {
1741 using Clock = std::chrono::steady_clock;
1742 auto loopPassStart = Clock::now();
1748 .store(
true, std::memory_order_relaxed);
1750 .load(std::memory_order_acquire) )
1754 .store(
false, std::memory_order_release);
1756 lastState = State::eOnce;
1759 .load(std::memory_order_relaxed))
1761 if (lastState != State::eLoopRunning)
1765 std::memory_order::memory_order_release);
1767 lastState = State::eLoopRunning;
1779 if ( (lastState == State::eLoopRunning)
1780 || (lastState == State::eMonitoring ) )
1785 std::memory_order::memory_order_release);
1787 lastState = State::eDoNothing;
1791 lastState = State::eMonitoring;
1796 .store(
false, std::memory_order_relaxed);
1798 std::this_thread::sleep_until( loopPassStart + interval );
1807 commonlyAvail =
std::min(commonlyAvail,
1811 return commonlyAvail -
std::min(
size_t(10), commonlyAvail);
1818 commonlyAvail =
std::min(commonlyAvail,
1820 return commonlyAvail;
1827 commonlyAvail =
std::min(commonlyAvail,
1829 return commonlyAvail;
1836 commonlyAvail =
std::min(commonlyAvail,
1838 return commonlyAvail;
1852 std::optional<RealtimeEffects::ProcessingScope> pScope;
1881 auto GetNeeded = [&]() ->
size_t {
1887 auto nNeeded = GetNeeded();
1900 for (
size_t i = 0; i < std::max(
size_t{1},
mPlaybackTracks.size()); ++i)
1906 auto available =
std::min( nAvailable,
1919 nNeeded = GetNeeded();
1929 std::optional<RealtimeEffects::ProcessingScope> &pScope,
size_t available)
1940 bool progress =
false;
1944 const auto &[frames, toProduce] = slice;
1945 progress = progress || toProduce > 0;
1960 size_t produced = 0;
1962 produced = mixer->Process( toProduce );
1964 for(
size_t j = 0, nChannels =
1966 j < nChannels; ++i, ++j
1968 auto warpedSamples = mixer->GetBuffer(j);
1970 warpedSamples,
floatSample, produced, frames - produced);
1982 available -= frames;
1986 frames, available );
1987 }
while (available && !done);
1997 std::optional<RealtimeEffects::ProcessingScope> &pScope)
2006 for (
unsigned t = 0; t < numPlaybackTracks; ++t) {
2008 if (!(vt && vt->IsLeader()))
2011 const auto nChannels = std::min<size_t>(
2015 for (
unsigned iBlock : {0, 1}) {
2017 size_t iChannel = 0;
2018 for (; iChannel < nChannels; ++iChannel) {
2021 ringBuffer.GetUnflushed(iBlock);
2023 pointers[iChannel] =
reinterpret_cast<float*
>(pair.first);
2029 assert(len == pair.second);
2039 memset((pointers[iChannel++] = *scratch++), 0, len *
sizeof(
float));
2041 if (len && pScope) {
2042 auto discardable = pScope->Process( *vt, &pointers[0],
2048 for (; iChannel < nChannels; ++iChannel) {
2050 auto discarded = ringBuffer.Unput(discardable);
2085 const auto remainingTime =
2088 const auto remainingSamples = remainingTime *
mRate;
2089 bool latencyCorrected =
true;
2091 double deltat = avail /
mRate;
2094 .load(std::memory_order_relaxed) ||
2097 bool newBlocks =
false;
2103 for(
size_t i = 0; i < numChannels; i++ )
2107 size_t discarded = 0;
2111 if (correction >= 0) {
2125 size_t size = floor(
2132 if (discarded <
size)
2135 latencyCorrected =
false;
2139 const float *pCrossfadeSrc =
nullptr;
2140 size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2146 totalCrossfadeLength = data.size();
2147 if (totalCrossfadeLength) {
2150 if (crossfadeStart < totalCrossfadeLength)
2151 pCrossfadeSrc = data.data() + crossfadeStart;
2155 wxASSERT(discarded <= avail);
2156 size_t toGet = avail - discarded;
2175 if (
double(
size) > remainingSamples)
2176 size = floor(remainingSamples);
2194 if (
double(toGet) > remainingSamples)
2195 toGet = floor(remainingSamples);
2196 const auto results =
2199 size = results.second;
2203 if (pCrossfadeSrc) {
2205 size_t crossfadeLength =
std::min(
size, totalCrossfadeLength - crossfadeStart);
2206 if (crossfadeLength) {
2207 auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2208 auto ratioStep = 1.0 / totalCrossfadeLength;
2209 auto pCrossfadeDst = (
float*)temp.
ptr();
2212 for (
size_t ii = 0; ii < crossfadeLength; ++ii) {
2213 *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2214 ++pCrossfadeSrc, ++pCrossfadeDst;
2234 if (pListener && newBlocks)
2256 const std::shared_ptr< AudioIOListener > &listener)
2265#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2269void AudioIO::AILAInitialize() {
2270 gPrefs->Read(
wxT(
"/AudioIO/AutomatedInputLevelAdjustment"), &mAILAActive,
false);
2271 gPrefs->Read(
wxT(
"/AudioIO/TargetPeak"), &mAILAGoalPoint, AILA_DEF_TARGET_PEAK);
2272 gPrefs->Read(
wxT(
"/AudioIO/DeltaPeakVolume"), &mAILAGoalDelta, AILA_DEF_DELTA_PEAK);
2273 gPrefs->Read(
wxT(
"/AudioIO/AnalysisTime"), &mAILAAnalysisTime, AILA_DEF_ANALYSIS_TIME);
2274 gPrefs->Read(
wxT(
"/AudioIO/NumberAnalysis"), &mAILATotalAnalysis, AILA_DEF_NUMBER_ANALYSIS);
2275 mAILAGoalDelta /= 100.0;
2276 mAILAGoalPoint /= 100.0;
2277 mAILAAnalysisTime /= 1000.0;
2280 mAILAClipped =
false;
2281 mAILAAnalysisCounter = 0;
2282 mAILAChangeFactor = 1.0;
2283 mAILALastChangeType = 0;
2284 mAILATopLevel = 1.0;
2285 mAILAAnalysisEndTime = -1.0;
2288void AudioIO::AILADisable() {
2289 mAILAActive =
false;
2292bool AudioIO::AILAIsActive() {
2296void AudioIO::AILASetStartTime() {
2298 wxPrintf(
"START TIME %f\n\n", mAILAAbsolutStartTime);
2301double AudioIO::AILAGetLastDecisionTime() {
2302 return mAILAAnalysisEndTime;
2305void AudioIO::AILAProcess(
double maxPeak) {
2307 if (proj && mAILAActive) {
2309 mAILAClipped =
true;
2310 wxPrintf(
"clipped");
2313 mAILAMax = max(mAILAMax, maxPeak);
2315 if ((mAILATotalAnalysis == 0 || mAILAAnalysisCounter < mAILATotalAnalysis) &&
mPlaybackSchedule.
GetTrackTime() - mAILALastStartTime >= mAILAAnalysisTime) {
2316 auto ToLinearIfDB = [](
double value,
int dbRange) {
2318 value = pow(10.0, (-(1.0-value) * dbRange)/20.0);
2324 double iv = (double) Px_GetInputVolume(mPortMixer);
2325 unsigned short changetype = 0;
2326 wxPrintf(
"mAILAAnalysisCounter:%d\n", mAILAAnalysisCounter);
2327 wxPrintf(
"\tmAILAClipped:%d\n", mAILAClipped);
2328 wxPrintf(
"\tmAILAMax (linear):%f\n", mAILAMax);
2329 wxPrintf(
"\tmAILAGoalPoint:%f\n", mAILAGoalPoint);
2330 wxPrintf(
"\tmAILAGoalDelta:%f\n", mAILAGoalDelta);
2331 wxPrintf(
"\tiv:%f\n", iv);
2332 wxPrintf(
"\tmAILAChangeFactor:%f\n", mAILAChangeFactor);
2333 if (mAILAClipped || mAILAMax > mAILAGoalPoint + mAILAGoalDelta) {
2334 wxPrintf(
"too high:\n");
2335 mAILATopLevel =
min(mAILATopLevel, iv);
2336 wxPrintf(
"\tmAILATopLevel:%f\n", mAILATopLevel);
2338 if (iv <= LOWER_BOUND) {
2340 if (mAILATotalAnalysis != 0) {
2341 mAILAActive =
false;
2344"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too high.") );
2346 wxPrintf(
"\talready min vol:%f\n", iv);
2349 float vol = (float) max(LOWER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2350 Px_SetInputVolume(mPortMixer, vol);
2352"Automated Recording Level Adjustment decreased the volume to %f.").Format( vol );
2355 wxPrintf(
"\tnew vol:%f\n", vol);
2356 float check = Px_GetInputVolume(mPortMixer);
2357 wxPrintf(
"\tverified %f\n", check);
2360 else if ( mAILAMax < mAILAGoalPoint - mAILAGoalDelta ) {
2362 wxPrintf(
"too low:\n");
2363 if (iv >= UPPER_BOUND || iv + 0.005 > mAILATopLevel) {
2365 if (mAILATotalAnalysis != 0) {
2366 mAILAActive =
false;
2369"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too low.") );
2371 wxPrintf(
"\talready max vol:%f\n", iv);
2374 float vol = (float)
min(UPPER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2375 if (vol > mAILATopLevel) {
2376 vol = (iv + mAILATopLevel)/2.0;
2377 wxPrintf(
"\tTruncated vol:%f\n", vol);
2379 Px_SetInputVolume(mPortMixer, vol);
2381"Automated Recording Level Adjustment increased the volume to %.2f.")
2385 wxPrintf(
"\tnew vol:%f\n", vol);
2386 float check = Px_GetInputVolume(mPortMixer);
2387 wxPrintf(
"\tverified %f\n", check);
2391 mAILAAnalysisCounter++;
2397 mAILAAnalysisEndTime = Pa_GetStreamTime(
mPortStreamV19) - mAILAAbsolutStartTime;
2399 wxPrintf(
"\tA decision was made @ %f\n", mAILAAnalysisEndTime);
2400 mAILAClipped =
false;
2403 if (changetype == 0)
2404 mAILAChangeFactor *= 0.8;
2405 else if (mAILALastChangeType == changetype)
2406 mAILAChangeFactor *= 1.1;
2408 mAILAChangeFactor *= 0.7;
2409 mAILALastChangeType = changetype;
2413 if (mAILAActive && mAILATotalAnalysis != 0 && mAILAAnalysisCounter >= mAILATotalAnalysis) {
2414 mAILAActive =
false;
2415 if (mAILAMax > mAILAGoalPoint + mAILAGoalDelta)
2418"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too high.") );
2419 else if (mAILAMax < mAILAGoalPoint - mAILAGoalDelta)
2422"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too low.") );
2425"Automated Recording Level Adjustment stopped. %.2f seems an acceptable volume.")
2426 .Format( Px_GetInputVolume(mPortMixer) );
2434#define MAX(a,b) ((a) > (b) ? (a) : (b))
2438 unsigned inputChannels,
2439 float *outputBuffer,
2442 for (
unsigned int i=0; i < inputChannels; i++) {
2443 auto inputPtr = inputBuffer + (i *
SAMPLE_SIZE(inputFormat));
2446 outputBuffer + i, len, inputChannels, 2);
2450 if (inputChannels == 1)
2451 for (
int i=0; i < len; i++)
2452 outputBuffer[2*i + 1] = outputBuffer[2*i];
2456 unsigned long framesPerBuffer,
2457 const PaStreamCallbackTimeInfo *timeInfo,
2461 return gAudioIO->AudioCallback(
2463 static_cast<float*
>(outputBuffer), framesPerBuffer,
2464 timeInfo, statusFlags, userData);
2475 float *inputSamples,
2476 unsigned long framesPerBuffer
2485 float sample = fabs(*(inputSamples++));
2486 if (sample > maxPeak) {
2492 if( bShouldBePaused !=
IsPaused() )
2496 pListener->OnSoundActivationThreshold();
2503 float * outputMeterFloats,
2504 float * outputFloats,
2505 const float * tempBuf,
2520 if (outputMeterFloats != outputFloats)
2521 for (
unsigned i = 0; i < len; ++i)
2522 outputMeterFloats[numPlaybackChannels*i+chan] +=
2529 float oldGain = gains[chan];
2530 if( gain != oldGain )
2538 float deltaGain = (gain - oldGain) / len;
2539 for (
unsigned i = 0; i < len; i++)
2540 outputFloats[numPlaybackChannels*i+chan] += (oldGain + deltaGain * i) *tempBuf[i];
2545 for(
unsigned i = 0; i < len; i++)
2546 pBuffer[i] = std::clamp(pBuffer[i], -1.0f, 1.0f);
2556 float *outputBuffer,
2557 unsigned long framesPerBuffer,
2558 float *outputMeterFloats
2570 numPlaybackChannels <= 0) {
2577 float *outputFloats = outputBuffer;
2590 numPlaybackChannels *
sizeof(
const SampleTrack *));
2593 float **tempBufs = (
float **) alloca(numPlaybackChannels *
sizeof(
float *));
2596 for (
unsigned int c = 0; c < numPlaybackChannels; c++)
2597 tempBufs[c] = (
float *) alloca(framesPerBuffer *
sizeof(
float));
2620 bool dropQuickly =
false;
2621 for (
unsigned t = 0; t < numPlaybackTracks; t++)
2624 chans[chanCnt] = vt;
2629 t + 1 < numPlaybackTracks
2635 bool firstChannel = vt->IsLeader();
2636 bool lastChannel = !nextTrack || nextTrack->IsLeader();
2641 if ( lastChannel && (numPlaybackChannels>1)) {
2643 memset(tempBufs[1], 0, framesPerBuffer *
sizeof(
float));
2650 dropQuickly = dropQuickly &&
2653 decltype(framesPerBuffer) len = 0;
2667 if (len < framesPerBuffer)
2674 memset((
void*)&tempBufs[chanCnt][len], 0,
2675 (framesPerBuffer - len) *
sizeof(
float));
2711 if (len > 0)
for (
int c = 0; c < chanCnt; c++)
2718 tempBufs[c], drop, len, vt, *oldgains[c % 2]);
2723 tempBufs[c], drop, len, vt, *oldgains[c % 2]);
2737 if (numPlaybackTracks == 0) {
2746 ClampBuffer( outputFloats, framesPerBuffer*numPlaybackChannels );
2747 if (outputMeterFloats != outputFloats)
2748 ClampBuffer( outputMeterFloats, framesPerBuffer*numPlaybackChannels );
2770 unsigned long framesPerBuffer,
2784 if( numCaptureChannels <= 0 )
2796 (statusFlags & (paInputOverflow))
2797 && !(statusFlags & paPrimingOutput);
2803 size_t len = framesPerBuffer;
2804 for(
unsigned t = 0; t < numCaptureChannels; t++)
2819 len < framesPerBuffer) ) {
2824 auto duration = (framesPerBuffer - len) /
mRate;
2828 fabs(pLast->first + pLast->second - start) < 0.5/
mRate)
2830 pLast->second = start + duration - pLast->first;
2835 if (len < framesPerBuffer)
2838 wxPrintf(
wxT(
"lost %d samples\n"), (
int)(framesPerBuffer - len));
2847 for(
unsigned t = 0; t < numCaptureChannels; t++) {
2857 auto inputFloats = (
const float *)inputBuffer;
2858 for(
unsigned i = 0; i < len; i++)
2860 inputFloats[numCaptureChannels*i+t];
2870 auto inputShorts = (
const short *)inputBuffer;
2871 short *tempShorts = (
short *)tempFloats;
2872 for(
unsigned i = 0; i < len; i++) {
2873 float tmp = inputShorts[numCaptureChannels*i+t];
2874 tmp = std::clamp(tmp, -32768.0f, 32767.0f);
2875 tempShorts[i] = (short)(tmp);
2898void OldCodeToCalculateLatency()
2911 if (numCaptureChannels > 0 && numPlaybackChannels > 0)
2913 if (timeInfo->inputBufferAdcTime > 0)
2914 mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
2915 else if (mLastRecordingOffset == 0.0)
2917 const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
2918 mLastRecordingOffset = -si->inputLatency;
2929 float *outputBuffer,
2930 unsigned long framesPerBuffer,
2931 float *outputMeterFloats
2940 if( numPlaybackChannels <= 0 )
2943 float *outputFloats = outputBuffer;
2944 for(
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
2945 outputFloats[i] = 0.0;
2950 outputBuffer, framesPerBuffer);
2954 if (outputMeterFloats != outputFloats) {
2955 for (
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
2956 outputMeterFloats[i] = outputFloats[i];
2964 const float *inputSamples,
2965 unsigned long framesPerBuffer
2972 if( pInputMeter->IsMeterDisabled())
2974 pInputMeter->UpdateDisplay(
2975 numCaptureChannels, framesPerBuffer, inputSamples);
2980 const float *outputMeterFloats,
2981 unsigned long framesPerBuffer)
2988 if( pOutputMeter->IsMeterDisabled() )
2990 if( !outputMeterFloats)
2992 pOutputMeter->UpdateDisplay(
2993 numPlaybackChannels, framesPerBuffer, outputMeterFloats);
3011 unsigned numSolo = 0;
3012 for(
unsigned t = 0; t < numPlaybackTracks; t++ )
3016 numSolo += std::accumulate(range.begin(), range.end(), 0,
3017 [](
unsigned sum,
auto &ext){
3018 return sum + ext.CountOtherSoloTracks(); });
3066 for (
auto &
factory: factories)
3079 unsigned long framesPerBuffer,
3080 const PaStreamCallbackTimeInfo *timeInfo,
3100 ext.FillOtherBuffers(
3109 float *tempFloats = (
float *)alloca(framesPerBuffer*
sizeof(
float)*
3110 MAX(numCaptureChannels,numPlaybackChannels));
3112 bool bVolEmulationActive =
3117 float *outputMeterFloats = bVolEmulationActive ?
3118 (
float *)alloca(framesPerBuffer*numPlaybackChannels *
sizeof(
float)) :
3122 if (inputBuffer && numCaptureChannels) {
3123 float *inputSamples;
3126 inputSamples = (
float *) inputBuffer;
3130 mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
3131 inputSamples = tempFloats;
3212 .store(
false, std::memory_order_relaxed);
3215 .load(std::memory_order_relaxed ) )
3217 using namespace std::chrono;
3218 std::this_thread::sleep_for(50ms);
3231 mixer->Reposition( time,
true );
3232 for (
size_t i = 0; i < numPlaybackTracks; i++)
3234 const auto toDiscard =
3236 const auto discarded =
3240 wxUnusedVar(discarded);
3250 .store(
true, std::memory_order_relaxed);
3256 int &callbackReturn,
unsigned long len)
3267 ext.SignalOtherCompletion();
3268 callbackReturn = paComplete;
3288 using namespace std::chrono;
3289 std::this_thread::sleep_for(50ms);
3303 using namespace std::chrono;
3304 std::this_thread::sleep_for(50ms);
3312 .store(
true, std::memory_order_release);
3315 .load(std::memory_order_acquire))
3317 using namespace std::chrono;
3318 std::this_thread::sleep_for(sleepTime);
3328 GetNumCaptureChannels() > 0 &&
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 audacityAudioCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
static PaSampleFormat AudacityToPortAudioSampleFormat(sampleFormat format)
BoolSetting SoundActivatedRecord
static void DoSoftwarePlaythrough(constSamplePtr inputBuffer, sampleFormat inputFormat, unsigned inputChannels, float *outputBuffer, unsigned long len)
void ClampBuffer(float *pBuffer, unsigned long len)
std::vector< std::shared_ptr< const SampleTrack > > SampleTrackConstArray
unsigned long PaStreamCallbackFlags
DoubleSetting AudioIOLatencyCorrection
DoubleSetting AudioIOPlaybackVolume
StringSetting AudioIOPlaybackDevice
DoubleSetting AudioIOLatencyDuration
StringSetting AudioIORecordingDevice
StringSetting AudioIOHost
IntSetting AudioIORecordChannels
Abstract base class for hooks into audio playback procedures.
Toolkit-neutral facade for basic user interface services.
IntSetting DecibelScaleCutoff
Negation of this value is the lowest dB level that should be shown in dB scales.
Type ExpGain(Type gain) noexcept
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
constexpr size_t TimeQueueGrainSize
wxString WarningDialogKey(const wxString &internalDialogName)
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
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)
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...
std::weak_ptr< Meter > mOutputMeter
PaStream * mPortStreamV19
static wxString HostName(const PaDeviceInfo *info)
std::atomic< bool > mPaused
True if audio playback is paused.
double mRate
Audio playback rate in samples per second.
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
static double mCachedBestRateIn
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()
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)
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
bool mInputMixerWorks
Can we control the hardware input level?
bool IsPaused() const
Find out if playback / recording is currently paused.
std::weak_ptr< Meter > mInputMeter
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()
AudioIO uses the PortAudio library to play and record sound.
std::shared_ptr< AudacityProject > GetOwningProject() const
void StopStream() override
Stop recording, playback or input monitoring.
void SetOwningProject(const std::shared_ptr< AudacityProject > &pProject)
bool InputMixerWorks()
Find out if the input hardware level control is available.
std::mutex mPostRecordingActionMutex
PostRecordingAction mPostRecordingAction
void TrackBufferExchange()
void GetMixer(int *inputSource, float *inputVolume, float *playbackVolume)
void DrainRecordBuffers()
Second part of TrackBufferExchange.
void SetPaused(bool state)
Pause and un-pause playback and recording.
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.
std::shared_ptr< RealtimeEffectState > AddState(AudacityProject &project, Track *pTrack, const PluginID &id)
Forwards to RealtimeEffectManager::AddState with proper init scope.
double GetBestRate(bool capturing, bool playing, double sampleRate)
Return a valid sample rate that is supported by the current I/O device(s).
void FillPlayBuffers()
First part of TrackBufferExchange.
void DelayActions(bool recording)
void SetMixer(int inputSource, float inputVolume, float playbackVolume)
std::shared_ptr< RealtimeEffectState > ReplaceState(AudacityProject &project, Track *pTrack, size_t index, const PluginID &id)
Forwards to RealtimeEffectManager::ReplaceState with proper init scope.
bool ProcessPlaybackSlices(std::optional< RealtimeEffects::ProcessingScope > &pScope, size_t available)
void SetMeters()
Set the current VU meters - this should be done once after each call to StartStream currently.
void CallAfterRecording(PostRecordingAction action)
Enqueue action for main thread idle time, not before the end of any recording in progress.
int StartStream(const TransportTracks &tracks, double t0, double t1, double mixerLimit, const AudioIOStartStreamOptions &options)
Start recording or playing back audio.
bool DelayingActions() const
bool IsAvailable(AudacityProject &project) const
Function to automatically set an acceptable volume.
void StartStreamCleanup(bool bOnlyBuffers=false)
Clean up after StartStream if it fails.
wxArrayString GetInputSourceNames()
Get the list of inputs to the current mixer device.
static void AudioThread(std::atomic< bool > &finish)
Sits in a thread loop reading and writing audio.
void StartMonitoring(const AudioIOStartStreamOptions &options)
Start up Portaudio for capture and recording as needed for input monitoring and software playthrough ...
size_t GetCommonlyFreePlayback()
Get the number of audio samples free in all of the playback buffers.
void ResetOwningProject()
std::function< void()> PostRecordingAction
static bool ValidateDeviceNames(const wxString &play, const wxString &rec)
Ensure selected device names are valid.
size_t GetCommonlyAvailCapture()
Get the number of audio samples ready in all of the recording buffers.
double GetStreamTime()
During playback, the track time most recently played.
wxString LastPaErrorString()
void TransformPlayBuffers(std::optional< RealtimeEffects::ProcessingScope > &scope)
bool AllocateBuffers(const AudioIOStartStreamOptions &options, const TransportTracks &tracks, double t0, double t1, double sampleRate)
Allocate RingBuffer structures, and others, needed for playback and recording.
void RemoveState(AudacityProject &project, Track *pTrack, std::shared_ptr< RealtimeEffectState > pState)
Forwards to RealtimeEffectManager::RemoveState with proper init scope.
std::vector< std::unique_ptr< AudioIOExtBase > >::const_iterator mIterator
auto operator*() const -> AudioIOExt &
static int mNextStreamToken
std::shared_ptr< AudioIOListener > GetListener() const
bool TrackShouldBeSilent(const SampleTrack &wt)
size_t GetCommonlyWrittenForPlayback()
void CallbackCheckCompletion(int &callbackReturn, unsigned long len)
std::unique_ptr< TransportState > mpTransportState
Holds some state for duration of playback or recording.
wxMutex mSuspendAudioThread
AudioIOExtRange Extensions()
bool AllTracksAlreadySilent()
float GetMixerOutputVol()
int AudioCallback(constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
std::array< float, 2 > OldChannelGains
void CheckSoundActivatedRecordingLevel(float *inputSamples, unsigned long framesPerBuffer)
PlaybackSchedule mPlaybackSchedule
RecordingSchedule mRecordingSchedule
std::vector< float * > mScratchPointers
pointing into mScratchBuffers
std::atomic< Acknowledge > mAudioThreadAcknowledge
WritableSampleTrackArray mCaptureTracks
std::atomic< bool > mFinishAudioThread
void UpdateTimePosition(unsigned long framesPerBuffer)
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
std::atomic< bool > mAudioThreadTrackBufferExchangeLoopRunning
unsigned CountSoloingTracks()
static double mCachedBestRateOut
std::vector< std::unique_ptr< Mixer > > mPlaybackMixers
PlaybackPolicy::Duration mPlaybackRingBufferSecs
std::atomic< bool > mAudioThreadTrackBufferExchangeLoopActive
void ClearRecordingException()
long mNumPauseFrames
How many frames of zeros were output due to pauses?
unsigned int mNumPlaybackChannels
void SetRecordingException()
std::atomic< bool > mForceFadeOut
void DrainInputBuffers(constSamplePtr inputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackFlags statusFlags, float *tempFloats)
std::atomic< bool > mAudioThreadShouldCallTrackBufferExchangeOnce
wxLongLong mLastPlaybackTimeMillis
void SendVuInputMeterData(const float *inputSamples, unsigned long framesPerBuffer)
std::vector< std::unique_ptr< AudioIOExtBase > > mAudioIOExt
size_t mHardwarePlaybackLatencyFrames
Hardware output latency in frames.
void SendVuOutputMeterData(const float *outputMeterFloats, unsigned long framesPerBuffer)
void DoPlaythrough(constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
void WaitForAudioThreadStarted()
bool mSimulateRecordingErrors
std::vector< OldChannelGains > mOldChannelGains
bool FillOutputBuffers(float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
static bool mCachedBestRatePlaying
bool mSoftwarePlaythrough
ArrayOf< std::unique_ptr< RingBuffer > > mCaptureBuffers
void SetListener(const std::shared_ptr< AudioIOListener > &listener)
void AddToOutputChannel(unsigned int chan, float *outputMeterFloats, float *outputFloats, const float *tempBuf, bool drop, unsigned long len, const SampleTrack *vt, OldChannelGains &gains)
unsigned long mMaxFramesOutput
double mLastRecordingOffset
Not (yet) used; should perhaps be atomic when it is.
size_t GetCommonlyReadyPlayback()
Get the number of audio samples ready in all of the playback buffers.
std::atomic< bool > mDetectUpstreamDropouts
void ProcessOnceAndWait(std::chrono::milliseconds sleepTime=std::chrono::milliseconds(50))
bool TrackHasBeenFadedOut(const SampleTrack &wt, const OldChannelGains &gains)
size_t mPlaybackQueueMinimum
Occupancy of the queue we try to maintain, with bigger batches if needed.
std::weak_ptr< AudioIOListener > mListener
wxAtomicInt mRecordingException
ArrayOf< std::unique_ptr< Resample > > mResample
double mCaptureRingBufferSecs
unsigned int mNumCaptureChannels
void SetMixerOutputVol(float value)
std::vector< std::pair< double, double > > mLostCaptureIntervals
void WaitForAudioThreadStopped()
bool mPauseRec
True if Sound Activated Recording is enabled.
ArrayOf< std::unique_ptr< RingBuffer > > mPlaybackBuffers
double mMinCaptureSecsToCopy
unsigned long long mLostSamples
std::vector< SampleBuffer > mScratchBuffers
SampleTrackConstArray mPlaybackTracks
static bool mCachedBestRateCapturing
sampleFormat mCaptureFormat
This specialization of Setting for bool adds a Toggle method to negate the saved value.
static DeviceManager * Instance()
Gets the singleton instance.
std::chrono::duration< float > GetTimeSinceRescan()
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
std::vector< Input > Inputs
CallbackReturn Publish(const AudioIOEvent &message)
Send a message to connected callbacks.
AudioTrack subclass that can also be audibly replayed by the program.
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.
std::chrono::duration< double > Duration
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)
virtual float GetChannelGain(int channel) const =0
Takes gain and pan into account.
virtual ChannelType GetChannelIgnoringPan() const =0
bool Write(const T &value)
Write value to config and return true if successful.
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
Abstract base class for an object holding data associated with points on a time axis.
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
auto Any() -> TrackIterRange< TrackType >
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
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.
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
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...
std::function< std::chrono::milliseconds() > playbackStreamPrimer
std::shared_ptr< AudacityProject > pProject
std::weak_ptr< Meter > captureMeter
std::weak_ptr< Meter > playbackMeter
PRCrossfadeData * pCrossfadeData
std::optional< double > pStartTime
std::shared_ptr< AudioIOListener > listener
std::optional< RealtimeEffects::InitializationScope > mpRealtimeInitialization
TransportState(std::weak_ptr< AudacityProject > wOwningProject, const SampleTrackConstArray &playbackTracks, unsigned numPlaybackChannels, double sampleRate)
Options for variations of error dialogs; the default is for modal dialogs.
MessageBoxOptions && Caption(TranslatableString caption_) &&
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...
double GetTrackTime() const
Get current track time value, unadjusted.
double mT0
Playback starts at offset of mT0, which is measured in seconds.
void Init(double t0, double t1, const AudioIOStartStreamOptions &options, const RecordingSchedule *pRecordingSchedule)
void SetTrackTime(double time)
Set current track time value, unadjusted.
class AUDIO_IO_API PlaybackSchedule::TimeQueue mTimeQueue
PlaybackPolicy & GetPolicy()
double TotalCorrection() const
double mLatencyCorrection
PRCrossfadeData mCrossfadeData
SampleTrackConstArray prerollTracks
PlayableTrackConstArray otherPlayableTracks
TransportTracks()=default
WritableSampleTrackArray captureTracks
SampleTrackConstArray playbackTracks