86#include "pa_win_wasapi.h"
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
134 unsigned numPlaybackChannels,
double sampleRate)
136 if (
auto pOwningProject = wOwningProject.lock();
137 pOwningProject && numPlaybackChannels > 0) {
141 move(wOwningProject),
sampleRate, numPlaybackChannels);
143 for (
size_t i = 0, cnt = playbackSequences.size(); i < cnt; ++i) {
145 const auto vt = playbackSequences[i].get();
146 const auto pGroup = vt ? vt->FindChannelGroup() :
nullptr;
152 ->AddGroup(*pGroup, numPlaybackChannels,
sampleRate);
168 #undef REALTIME_ALSA_THREAD
171 #undef REALTIME_ALSA_THREAD
174#ifdef REALTIME_ALSA_THREAD
175#include "pa_linux_alsa.h"
179 unsigned long framesPerBuffer,
180 const PaStreamCallbackTimeInfo *timeInfo,
194 pAudioIO->StartThread();
199 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
208 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
229 return pInfo !=
nullptr && rInfo !=
nullptr && pInfo->hostApi == rInfo->hostApi;
234 if (!std::atomic<double>{}.is_lock_free()) {
245 wxASSERT(
sizeof(
short ) <=
sizeof(
float ));
248 .store(
false, std::memory_order_relaxed);
250 .store(
false, std::memory_order_relaxed);
252 .store(
false, std::memory_order_relaxed);
260#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
274 if (err != paNoError) {
275 auto errStr =
XO(
"Could not find any audio devices.\n");
276 errStr +=
XO(
"You will not be able to play or record audio.\n\n");
277 wxString paErrStr =
LAT1CTOWX(Pa_GetErrorText(err));
278 if (!paErrStr.empty())
279 errStr +=
XO(
"Error: %s").Format( paErrStr );
287 .IconStyle(Icon::Error)
288 .ButtonStyle(Button::Ok));
296#if defined(USE_PORTMIXER)
298 mPreviousHWPlaythrough = -1.0;
321#if defined(USE_PORTMIXER)
324 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
325 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
326 mPreviousHWPlaythrough = -1.0;
328 Px_CloseMixer(mPortMixer);
346std::shared_ptr<RealtimeEffectState>
357std::shared_ptr<RealtimeEffectState>
371 const std::shared_ptr<RealtimeEffectState> pState)
381 float playbackVolume)
386#if defined(USE_PORTMIXER)
387 PxMixer *mixer = mPortMixer;
391 float oldRecordVolume = Px_GetInputVolume(mixer);
394 if( oldRecordVolume != recordVolume )
395 Px_SetInputVolume(mixer, recordVolume);
401 float *playbackVolume)
405#if defined(USE_PORTMIXER)
407 PxMixer *mixer = mPortMixer;
411 *recordDevice = Px_GetCurrentInputSource(mixer);
414 *recordVolume = Px_GetInputVolume(mixer);
416 *recordVolume = 1.0f;
424 *recordVolume = 1.0f;
434#if defined(USE_PORTMIXER)
436 wxArrayString deviceNames;
440 int numSources = Px_GetNumInputSources(mPortMixer);
441 for(
int source = 0; source < numSources; source++ )
442 deviceNames.push_back(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
446 wxLogDebug(
wxT(
"AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
474 unsigned int numPlaybackChannels,
unsigned int numCaptureChannels)
479 bool success =
false;
480 auto cleanup =
finally([&]{
505 bool isStreamBidirectional = (numCaptureChannels > 0) && (numPlaybackChannels > 0);
506 bool isUnsupportedSampleRate = isStreamBidirectional && (
mRate == 0.0);
512 auto captureFormat_saved = captureFormat;
534 bool usePlayback =
false, useCapture =
false;
535 PaStreamParameters playbackParameters{};
536 PaStreamParameters captureParameters{};
539 PaWasapiStreamInfo wasapiStreamInfo{};
544 if( numPlaybackChannels > 0)
552 const PaDeviceInfo *playbackDeviceInfo;
553 playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
555 if( playbackDeviceInfo == NULL )
559 playbackParameters.sampleFormat = paFloat32;
560 playbackParameters.hostApiSpecificStreamInfo = NULL;
563 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
564 bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
570 if (isWASAPI && isUnsupportedSampleRate)
572 wasapiStreamInfo.size =
sizeof(PaWasapiStreamInfo);
573 wasapiStreamInfo.hostApiType = paWASAPI;
574 wasapiStreamInfo.version = 1;
575 wasapiStreamInfo.flags = paWinWasapiAutoConvert;
577 playbackParameters.hostApiSpecificStreamInfo = &wasapiStreamInfo;
582 playbackParameters.suggestedLatency =
583 playbackDeviceInfo->defaultLowOutputLatency;
590 playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
596 if( numCaptureChannels > 0)
600 const PaDeviceInfo *captureDeviceInfo;
605 captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
607 if( captureDeviceInfo == NULL )
610 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(captureDeviceInfo->hostApi);
611 bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
615 if (isWASAPI && isUnsupportedSampleRate)
616 mRate = captureDeviceInfo->defaultSampleRate;
618 captureParameters.sampleFormat =
621 captureParameters.hostApiSpecificStreamInfo = NULL;
625 captureParameters.suggestedLatency =
626 captureDeviceInfo->defaultHighInputLatency;
628 captureParameters.suggestedLatency = latencyDuration/1000.0;
633 const auto deviceInfo = usePlayback ?
634 Pa_GetDeviceInfo(playbackParameters.device) :
635 Pa_GetDeviceInfo(captureParameters.device);
637 if (deviceInfo !=
nullptr)
639 const auto hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
655 float oldRecordVolume = Px_GetInputVolume(mPortMixer);
662 int* lpUserData = (captureFormat_saved ==
int24Sample) ? &userData : NULL;
667 unsigned int maxTries = 1;
670 using namespace std::chrono;
676 for (
unsigned int tries = 0; tries < maxTries; tries++) {
678 useCapture ? &captureParameters : NULL,
679 usePlayback ? &playbackParameters : NULL,
680 mRate, paFramesPerBufferUnspecified,
687 const auto outputLatency =
693 (latencyDuration / 1000.0) :
695 stream->outputLatency;
713 wxLogDebug(
"Attempt %u to open capture stream failed with: %d", 1 + tries,
mLastPaError);
714 using namespace std::chrono;
715 std::this_thread::sleep_for(1s);
721 Px_SetInputVolume(mPortMixer, oldRecordVolume);
727 if (Px_SupportsPlaythrough(mPortMixer)) {
728 bool playthrough =
false;
730 mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
735 Px_SetPlaythrough(mPortMixer, 1.0);
737 Px_SetPlaythrough(mPortMixer, 0.0);
744#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
747 wxPowerResource::Acquire(wxPOWER_RESOURCE_SCREEN,
_(
"Audacity Audio"));
760 const std::shared_ptr<AudacityProject> &pProject )
784 int playbackChannels = 0;
787 playbackChannels = 2;
795 static_cast<unsigned int>(playbackChannels),
796 static_cast<unsigned int>(captureChannels));
801 auto msg =
XO(
"Error opening recording device.\nError code: %s")
804 XO(
"Error"), msg,
wxT(
"Error_opening_sound_device"),
821 pListener->OnAudioIORate((
int)
mRate);
826 double t0,
double t1,
double mixerLimit,
832 [](
const auto &pSequence){
834 pSequence ? pSequence->FindChannelGroup() : nullptr;
868 using namespace std::chrono;
869 std::this_thread::sleep_for(50ms);
877 gPrefs->
Read(
wxT(
"/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
879 if(silenceLevelDB < -dBRange)
881 silenceLevelDB = -dBRange + 3;
913 auto cleanupSequences =
finally([&]{
919 ext.AbortOtherStream();
937 unsigned int playbackChannels = 0;
938 size_t numCaptureChannels = 0;
940 double captureRate = 44100.0;
946 playbackChannels = 2;
949 playbackChannels = 2;
952 numCaptureChannels = accumulate(
954 [](
auto acc,
const auto &pSequence) {
955 return acc + pSequence->NChannels();
966 captureFormat = sequence0->GetSampleFormat();
967 captureRate = sequence0->GetRate();
971 pListener->OnAudioIOStartRecording();
986 successAudio = successAudio &&
987 std::all_of(range.begin(), range.end(),
988 [
this, &sequences, t0](
auto &ext){
989 return ext.StartOtherStream(sequences,
990 (mPortStreamV19 != NULL && mLastPaError == paNoError)
991 ? Pa_GetStreamInfo(mPortStreamV19) : nullptr,
995 if (pListener && numCaptureChannels > 0)
996 pListener->OnAudioIOStopRecording();
1003 double mixerStart = t0;
1005 mixerStart =
std::min( mixerStart, *pStartTime );
1007 mixerStart, mixerLimit, options.
rate))
1014#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
1021 const auto time = *pStartTime;
1029 mixer->Reposition( time );
1041 .store(
true, std::memory_order_release);
1044 .load(std::memory_order_acquire)) {
1045 using namespace std::chrono;
1046 auto interval = 50ms;
1050 std::this_thread::sleep_for(interval);
1055#ifdef REALTIME_ALSA_THREAD
1093 if( err != paNoError )
1100 pListener->OnAudioIOStopRecording();
1112 pListener->OnAudioIORate((
int)
mRate);
1150 nextAction = std::move(action)
1151 ]{ prevAction(); nextAction(); };
1170 bool success =
false;
1171 auto cleanup =
finally([&]{
1198 wxASSERT( playbackTime >= 0 );
1218 auto playbackBufferSize =
1242 0, [](
int n,
auto& seq) { return n + seq->NChannels(); }
1245 buffer.reserve(playbackBufferSize);
1249 buffer.reserve(playbackBufferSize);
1258 reinterpret_cast<float*
>(buffer.ptr()));
1266 [=]{ return std::make_unique<RingBuffer>(floatSample, playbackBufferSize); }
1271 const auto &warpOptions =
1293 assert(pSequence->FindChannelGroup());
1295 double startTime, endTime;
1302 .contains(pSequence))
1315 std::move(mixSequences), std::nullopt,
1317 false, warpOptions, startTime, endTime,
1318 pSequence->NChannels(),
1328 const auto timeQueueSize = 1 +
1338 auto captureBufferSize =
1343 if(captureBufferSize < 100)
1364 catch(std::bad_alloc&)
1377 auto playbackBufferSize =
1417 return !pOwningProject || pOwningProject.get() == &
project;
1423 pInputMeter->Reset(
mRate,
true);
1425 pOutputMeter->Reset(
mRate,
true);
1430 auto cleanup =
finally ( [
this] {
1451#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1457 .load(std::memory_order_relaxed) )
1467 using namespace std::chrono;
1468 std::this_thread::sleep_for(milliseconds{latency + 50});
1505 #if defined(USE_PORTMIXER)
1508 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1509 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1510 mPreviousHWPlaythrough = -1.0;
1535 ext.StopOtherStream();
1605 std::optional<TransactionScope> pScope;
1607 pScope.emplace(*pOwningProject,
"Dropouts");
1609 auto &start = interval.first;
1610 auto duration = interval.second;
1613 sequence->InsertSilence(start, duration);
1621 pListener->OnCommitRecording();
1628 pInputMeter->Reset(
mRate,
false);
1631 pOutputMeter->Reset(
mRate,
false);
1637 pListener->OnAudioIOStopRecording();
1645 std::this_thread::yield();
1665 Publish({ pOwningProject.get(),
1684 pListener->OnAudioIORate(0);
1699 em.SetSuspended(state);
1703 mPaused.store(state, std::memory_order_relaxed);
1721 std::vector<long> rates;
1722 if (capturing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for capture"));
1723 if (playing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for playback"));
1724 wxLogDebug(
wxT(
"GetBestRate() suggested rate %.0lf Hz"),
sampleRate);
1726 if (capturing && !playing) {
1729 else if (playing && !capturing) {
1741 wxLogDebug(
wxT(
"GetBestRate() Returning %.0ld Hz"), rate);
1758 if (rates.empty()) {
1760 wxLogDebug(
wxT(
"GetBestRate() Error - no supported sample rates"));
1765 for (i = 0; i < (int)rates.size(); i++)
1767 if (rates[i] > rate) {
1769 wxLogDebug(
wxT(
"GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1775 wxLogDebug(
wxT(
"GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1776 retval = rates.back();
1807 enum class State { eUndefined, eOnce, eLoopRunning, eDoNothing, eMonitoring } lastState = State::eUndefined;
1809 while (!finish.load(std::memory_order_acquire)) {
1810 using Clock = std::chrono::steady_clock;
1811 auto loopPassStart = Clock::now();
1817 .store(
true, std::memory_order_relaxed);
1819 .load(std::memory_order_acquire) )
1823 .store(
false, std::memory_order_release);
1825 lastState = State::eOnce;
1828 .load(std::memory_order_relaxed))
1830 if (lastState != State::eLoopRunning)
1834 std::memory_order::memory_order_release);
1836 lastState = State::eLoopRunning;
1848 if ( (lastState == State::eLoopRunning)
1849 || (lastState == State::eMonitoring ) )
1854 std::memory_order::memory_order_release);
1856 lastState = State::eDoNothing;
1860 lastState = State::eMonitoring;
1865 .store(
false, std::memory_order_relaxed);
1867 std::this_thread::sleep_until( loopPassStart + interval );
1874 return std::accumulate(buffers.begin(), buffers.end(),
1875 std::numeric_limits<size_t>::max(),
1876 [pmf](
auto value,
auto &pBuffer){
1877 return std::min(value, (pBuffer.get()->*pmf)()); });
1885 return commonlyAvail -
std::min(
size_t(10), commonlyAvail);
1914 std::optional<RealtimeEffects::ProcessingScope> pScope;
1943 auto GetNeeded = [&]() ->
size_t {
1949 auto nNeeded = GetNeeded();
1968 auto available =
std::min( nAvailable,
1981 nNeeded = GetNeeded();
1990#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
1993 std::optional<RealtimeEffects::ProcessingScope> &pScope,
size_t available)
2004 bool progress =
false;
2015 const auto &[frames, toProduce] = slice;
2016 progress = progress || toProduce > 0;
2026 size_t iSequence = 0;
2034 size_t produced = 0;
2037 produced = mixer->Process(toProduce);
2044 for (
size_t j = 0; j < nChannels; ++j)
2052 buffer.resize(buffer.size() + frames, 0);
2054 const auto warpedSamples = mixer->GetBuffer(j);
2056 reinterpret_cast<const float*
>(warpedSamples),
2058 buffer.data() + appendPos);
2060 buffer.data() + appendPos + produced,
2065 iBuffer += nChannels;
2070 available -= frames;
2077 frames, available );
2078 }
while (available && !done);
2090 int bufferIndex = 0;
2095 const auto channelGroup = seq->FindChannelGroup();
2107 const auto offset = processingBufferOffsets[bufferIndex];
2113 for(
unsigned i = 0; i < seq->NChannels(); ++i)
2119 pointers[i] = *scratch++;
2120 std::fill_n(pointers[i], len, .0f);
2123 const auto discardable = pScope->Process(channelGroup, &pointers[0],
2130 for(
int i = 0; i < seq->NChannels(); ++i)
2133 buffer.erase(buffer.begin() + offset, buffer.begin() + offset + discardable);
2137 std::fill_n(buffer.data() + offset, len - discardable, 0);
2142 bufferIndex += seq->NChannels();
2149 auto samplesAvailable = std::min_element(
2152 [](
auto& first,
auto& second) { return first.size() < second.size(); }
2157 if(samplesAvailable == 0)
2161 auto cleanup =
finally([=] {
2170 buffer.resize(samplesAvailable, 0);
2174 unsigned bufferIndex = 0;
2178 const auto numChannels = seq->NChannels();
2181 for(
unsigned n = 0; n < seq->NChannels(); ++n)
2183 const auto gain = seq->GetChannelGain(n);
2184 for(
unsigned i = 0; i < samplesAvailable; ++i)
2188 else if(numChannels == 1)
2193 const auto gain = seq->GetChannelGain(n);
2194 for(
unsigned i = 0; i < samplesAvailable; ++i)
2198 bufferIndex += seq->NChannels();
2204 buffer.erase(buffer.begin(), buffer.begin() + samplesAvailable);
2209 size_t masterBufferOffset = 0;
2216 masterBufferOffset = pScope->Process(
2225 samplesAvailable -= masterBufferOffset;
2228 if(samplesAvailable == 0)
2232 unsigned bufferIndex = 0;
2236 reinterpret_cast<constSamplePtr>(buffer.data()) + masterBufferOffset *
sizeof(
float),
2273 pSequence->RepairChannels();
2279 const auto remainingTime =
2282 const auto remainingSamples = remainingTime *
mRate;
2283 bool latencyCorrected =
true;
2285 double deltat = avail /
mRate;
2288 .load(std::memory_order_relaxed) ||
2291 bool newBlocks =
false;
2296 auto width = (*iter)->NChannels();
2304 width = (*iter)->NChannels();
2307 size_t discarded = 0;
2311 if (correction >= 0) {
2325 size_t size = floor(
2332 if (discarded <
size)
2335 latencyCorrected =
false;
2339 const float *pCrossfadeSrc =
nullptr;
2340 size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2347 totalCrossfadeLength = data.size();
2348 if (totalCrossfadeLength) {
2351 if (crossfadeStart < totalCrossfadeLength)
2352 pCrossfadeSrc = data.data() + crossfadeStart;
2356 wxASSERT(discarded <= avail);
2357 size_t toGet = avail - discarded;
2376 if (
double(
size) > remainingSamples)
2377 size = floor(remainingSamples);
2395 if (
double(toGet) > remainingSamples)
2396 toGet = floor(remainingSamples);
2397 const auto results =
2400 size = results.second;
2404 if (pCrossfadeSrc) {
2406 size_t crossfadeLength =
std::min(
size, totalCrossfadeLength - crossfadeStart);
2407 if (crossfadeLength) {
2408 auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2409 auto ratioStep = 1.0 / totalCrossfadeLength;
2410 auto pCrossfadeDst = (
float*)temp.
ptr();
2413 for (
size_t ii = 0; ii < crossfadeLength; ++ii) {
2414 *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2415 ++pCrossfadeSrc, ++pCrossfadeDst;
2423 newBlocks = (*iter)->Append(
iChannel,
2435 if (pListener && newBlocks)
2436 pListener->OnAudioIONewBlocks();
2457 const std::shared_ptr< AudioIOListener > &listener)
2466#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2470void AudioIO::AILAInitialize() {
2471 gPrefs->
Read(
wxT(
"/AudioIO/AutomatedInputLevelAdjustment"), &mAILAActive,
false);
2472 gPrefs->
Read(
wxT(
"/AudioIO/TargetPeak"), &mAILAGoalPoint, AILA_DEF_TARGET_PEAK);
2473 gPrefs->
Read(
wxT(
"/AudioIO/DeltaPeakVolume"), &mAILAGoalDelta, AILA_DEF_DELTA_PEAK);
2474 gPrefs->
Read(
wxT(
"/AudioIO/AnalysisTime"), &mAILAAnalysisTime, AILA_DEF_ANALYSIS_TIME);
2475 gPrefs->
Read(
wxT(
"/AudioIO/NumberAnalysis"), &mAILATotalAnalysis, AILA_DEF_NUMBER_ANALYSIS);
2476 mAILAGoalDelta /= 100.0;
2477 mAILAGoalPoint /= 100.0;
2478 mAILAAnalysisTime /= 1000.0;
2481 mAILAClipped =
false;
2482 mAILAAnalysisCounter = 0;
2483 mAILAChangeFactor = 1.0;
2484 mAILALastChangeType = 0;
2485 mAILATopLevel = 1.0;
2486 mAILAAnalysisEndTime = -1.0;
2489void AudioIO::AILADisable() {
2490 mAILAActive =
false;
2493bool AudioIO::AILAIsActive() {
2497void AudioIO::AILASetStartTime() {
2499 wxPrintf(
"START TIME %f\n\n", mAILAAbsolutStartTime);
2502double AudioIO::AILAGetLastDecisionTime() {
2503 return mAILAAnalysisEndTime;
2506void AudioIO::AILAProcess(
double maxPeak) {
2508 if (proj && mAILAActive) {
2510 mAILAClipped =
true;
2511 wxPrintf(
"clipped");
2514 mAILAMax = max(mAILAMax, maxPeak);
2516 if ((mAILATotalAnalysis == 0 || mAILAAnalysisCounter < mAILATotalAnalysis) &&
mPlaybackSchedule.
GetSequenceTime() - mAILALastStartTime >= mAILAAnalysisTime) {
2517 auto ToLinearIfDB = [](
double value,
int dbRange) {
2519 value = pow(10.0, (-(1.0-value) * dbRange)/20.0);
2525 double iv = (double) Px_GetInputVolume(mPortMixer);
2526 unsigned short changetype = 0;
2527 wxPrintf(
"mAILAAnalysisCounter:%d\n", mAILAAnalysisCounter);
2528 wxPrintf(
"\tmAILAClipped:%d\n", mAILAClipped);
2529 wxPrintf(
"\tmAILAMax (linear):%f\n", mAILAMax);
2530 wxPrintf(
"\tmAILAGoalPoint:%f\n", mAILAGoalPoint);
2531 wxPrintf(
"\tmAILAGoalDelta:%f\n", mAILAGoalDelta);
2532 wxPrintf(
"\tiv:%f\n", iv);
2533 wxPrintf(
"\tmAILAChangeFactor:%f\n", mAILAChangeFactor);
2534 if (mAILAClipped || mAILAMax > mAILAGoalPoint + mAILAGoalDelta) {
2535 wxPrintf(
"too high:\n");
2536 mAILATopLevel =
min(mAILATopLevel, iv);
2537 wxPrintf(
"\tmAILATopLevel:%f\n", mAILATopLevel);
2539 if (iv <= LOWER_BOUND) {
2541 if (mAILATotalAnalysis != 0) {
2542 mAILAActive =
false;
2545"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too high.") );
2547 wxPrintf(
"\talready min vol:%f\n", iv);
2550 float vol = (float) max(LOWER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2551 Px_SetInputVolume(mPortMixer, vol);
2553"Automated Recording Level Adjustment decreased the volume to %f.").Format( vol );
2556 wxPrintf(
"\tnew vol:%f\n", vol);
2557 float check = Px_GetInputVolume(mPortMixer);
2558 wxPrintf(
"\tverified %f\n", check);
2561 else if ( mAILAMax < mAILAGoalPoint - mAILAGoalDelta ) {
2563 wxPrintf(
"too low:\n");
2564 if (iv >= UPPER_BOUND || iv + 0.005 > mAILATopLevel) {
2566 if (mAILATotalAnalysis != 0) {
2567 mAILAActive =
false;
2570"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too low.") );
2572 wxPrintf(
"\talready max vol:%f\n", iv);
2575 float vol = (float)
min(UPPER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2576 if (vol > mAILATopLevel) {
2577 vol = (iv + mAILATopLevel)/2.0;
2578 wxPrintf(
"\tTruncated vol:%f\n", vol);
2580 Px_SetInputVolume(mPortMixer, vol);
2582"Automated Recording Level Adjustment increased the volume to %.2f.")
2586 wxPrintf(
"\tnew vol:%f\n", vol);
2587 float check = Px_GetInputVolume(mPortMixer);
2588 wxPrintf(
"\tverified %f\n", check);
2592 mAILAAnalysisCounter++;
2598 mAILAAnalysisEndTime = Pa_GetStreamTime(
mPortStreamV19) - mAILAAbsolutStartTime;
2600 wxPrintf(
"\tA decision was made @ %f\n", mAILAAnalysisEndTime);
2601 mAILAClipped =
false;
2604 if (changetype == 0)
2605 mAILAChangeFactor *= 0.8;
2606 else if (mAILALastChangeType == changetype)
2607 mAILAChangeFactor *= 1.1;
2609 mAILAChangeFactor *= 0.7;
2610 mAILALastChangeType = changetype;
2614 if (mAILAActive && mAILATotalAnalysis != 0 && mAILAAnalysisCounter >= mAILATotalAnalysis) {
2615 mAILAActive =
false;
2616 if (mAILAMax > mAILAGoalPoint + mAILAGoalDelta)
2619"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too high.") );
2620 else if (mAILAMax < mAILAGoalPoint - mAILAGoalDelta)
2623"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too low.") );
2626"Automated Recording Level Adjustment stopped. %.2f seems an acceptable volume.")
2627 .Format( Px_GetInputVolume(mPortMixer) );
2637 unsigned inputChannels,
2638 float *outputBuffer,
2641 for (
unsigned int i=0; i < inputChannels; i++) {
2642 auto inputPtr = inputBuffer + (i *
SAMPLE_SIZE(inputFormat));
2645 outputBuffer + i, len, inputChannels, 2);
2649 if (inputChannels == 1)
2650 for (
int i=0; i < len; i++)
2651 outputBuffer[2*i + 1] = outputBuffer[2*i];
2655 unsigned long framesPerBuffer,
2656 const PaStreamCallbackTimeInfo *timeInfo,
2660 return gAudioIO->AudioCallback(
2662 static_cast<float*
>(outputBuffer), framesPerBuffer,
2663 timeInfo, statusFlags, userData);
2674 float *inputSamples,
2675 unsigned long framesPerBuffer
2684 float sample = fabs(*(inputSamples++));
2685 if (sample > maxPeak) {
2691 if( bShouldBePaused !=
IsPaused() )
2695 pListener->OnSoundActivationThreshold();
2701 for(
unsigned i = 0; i < len; i++)
2702 pBuffer[i] = std::clamp(pBuffer[i], -1.0f, 1.0f);
2712 float *outputFloats,
2713 unsigned long framesPerBuffer,
2714 float *outputMeterFloats
2725 numPlaybackChannels <= 0) {
2747 if (numPlaybackSequences == 0) {
2768 const auto tempBufs =
stackAllocate(
float *, numPlaybackChannels);
2771 for (
unsigned int c = 0; c < numPlaybackChannels; c++)
2779 for(
unsigned n = 0; n < numPlaybackChannels; ++n)
2782 reinterpret_cast<samplePtr>(tempBufs[n]),
2786 if(len < framesPerBuffer)
2794 memset((
void*)&tempBufs[n][len], 0,
2795 (framesPerBuffer - len) *
sizeof(
float));
2821 if(outputMeterFloats != outputFloats)
2823 for (
unsigned i = 0; i < len; ++i)
2824 outputMeterFloats[numPlaybackChannels*i+n] +=
2825 gain*tempBufs[n][i];
2837 const float deltaGain = (gain - oldGain) / len;
2838 for (
unsigned i = 0; i < len; i++)
2840 outputFloats[numPlaybackChannels * i + n] +=
2841 (oldGain + deltaGain * i) * tempBufs[n][i];
2853 ClampBuffer( outputFloats, framesPerBuffer*numPlaybackChannels );
2854 if (outputMeterFloats != outputFloats)
2855 ClampBuffer( outputMeterFloats, framesPerBuffer*numPlaybackChannels );
2877 unsigned long framesPerBuffer,
2890 if( numCaptureChannels <= 0 )
2902 (statusFlags & (paInputOverflow))
2903 && !(statusFlags & paPrimingOutput);
2909 size_t len = framesPerBuffer;
2910 for(
unsigned t = 0; t < numCaptureChannels; t++)
2925 len < framesPerBuffer) ) {
2930 auto duration = (framesPerBuffer - len) /
mRate;
2934 fabs(pLast->first + pLast->second - start) < 0.5/
mRate)
2936 pLast->second = start + duration - pLast->first;
2941 if (len < framesPerBuffer)
2944 wxPrintf(
wxT(
"lost %d samples\n"), (
int)(framesPerBuffer - len));
2953 for(
unsigned t = 0; t < numCaptureChannels; t++) {
2963 auto inputFloats = (
const float *)inputBuffer;
2964 for(
unsigned i = 0; i < len; i++)
2966 inputFloats[numCaptureChannels*i+t];
2976 auto inputShorts = (
const short *)inputBuffer;
2977 short *tempShorts = (
short *)tempFloats;
2978 for(
unsigned i = 0; i < len; i++) {
2979 float tmp = inputShorts[numCaptureChannels*i+t];
2980 tmp = std::clamp(tmp, -32768.0f, 32767.0f);
2981 tempShorts[i] = (short)(tmp);
3004void OldCodeToCalculateLatency()
3017 if (numCaptureChannels > 0 && numPlaybackChannels > 0)
3019 if (timeInfo->inputBufferAdcTime > 0)
3020 mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
3021 else if (mLastRecordingOffset == 0.0)
3023 const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
3024 mLastRecordingOffset = -si->inputLatency;
3035 float *outputBuffer,
3036 unsigned long framesPerBuffer,
3037 float *outputMeterFloats
3046 if( numPlaybackChannels <= 0 )
3049 float *outputFloats = outputBuffer;
3050 for(
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
3051 outputFloats[i] = 0.0;
3056 outputBuffer, framesPerBuffer);
3060 if (outputMeterFloats != outputFloats) {
3061 for (
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
3062 outputMeterFloats[i] = outputFloats[i];
3070 const float *inputSamples,
3071 unsigned long framesPerBuffer
3078 if( pInputMeter->IsMeterDisabled())
3080 pInputMeter->UpdateDisplay(
3081 numCaptureChannels, framesPerBuffer, inputSamples);
3086 const float *outputMeterFloats,
3087 unsigned long framesPerBuffer)
3094 if( pOutputMeter->IsMeterDisabled() )
3096 if( !outputMeterFloats)
3098 pOutputMeter->UpdateDisplay(
3099 numPlaybackChannels, framesPerBuffer, outputMeterFloats);
3117 unsigned numSolo = 0;
3118 for (
unsigned t = 0; t < numPlaybackSequences; t++ )
3122 numSolo += std::accumulate(range.begin(), range.end(), 0,
3123 [](
unsigned sum,
auto &ext){
3124 return sum + ext.CountOtherSolo(); });
3147 for (
auto &
factory: factories)
3160 unsigned long framesPerBuffer,
3161 const PaStreamCallbackTimeInfo *timeInfo,
3182 ext.FillOtherBuffers(
3192 framesPerBuffer * std::max(numCaptureChannels, numPlaybackChannels));
3194 bool bVolEmulationActive =
3199 const auto outputMeterFloats = bVolEmulationActive
3200 ?
stackAllocate(
float, framesPerBuffer * numPlaybackChannels)
3204 if (inputBuffer && numCaptureChannels) {
3205 float *inputSamples;
3208 inputSamples = (
float *) inputBuffer;
3212 mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
3213 inputSamples = tempFloats;
3289 .store(
false, std::memory_order_relaxed);
3292 .load(std::memory_order_relaxed ) )
3294 using namespace std::chrono;
3295 std::this_thread::sleep_for(50ms);
3308 mixer->Reposition( time,
true );
3310 const auto toDiscard = buffer->AvailForGet();
3311 const auto discarded = buffer->Discard( toDiscard );
3314 wxUnusedVar(discarded);
3324 .store(
true, std::memory_order_relaxed);
3330 int &callbackReturn,
unsigned long len)
3341 ext.SignalOtherCompletion();
3342 callbackReturn = paComplete;
3362 using namespace std::chrono;
3363 std::this_thread::sleep_for(50ms);
3377 using namespace std::chrono;
3378 std::this_thread::sleep_for(50ms);
3386 .store(
true, std::memory_order_release);
3389 .load(std::memory_order_acquire))
3391 using namespace std::chrono;
3392 std::this_thread::sleep_for(sleepTime);
3402 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)
#define stackAllocate(T, count)
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.
std::vector< std::shared_ptr< const PlayableSequence > > ConstPlayableSequences
Toolkit-neutral facade for basic user interface services.
Abstract class ChannelGroup with two discrete iterable dimensions, channels and intervals; subclasses...
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
audacity::BasicSettings * gPrefs
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
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
bool AllocateBuffers(const AudioIOStartStreamOptions &options, const TransportSequences &sequences, double t0, double t1, double sampleRate)
Allocate RingBuffer structures, and others, needed for playback and recording.
void GetMixer(int *inputSource, float *inputVolume, float *playbackVolume)
int StartStream(const TransportSequences &sequences, double t0, double t1, double mixerLimit, const AudioIOStartStreamOptions &options)
Start recording or playing back audio.
void DrainRecordBuffers()
Second part of SequenceBufferExchange.
bool StartPortAudioStream(const AudioIOStartStreamOptions &options, unsigned int numPlaybackChannels, unsigned int numCaptureChannels)
Opens the portaudio stream(s) used to do playback or recording (or both) through.
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 SequenceBufferExchange.
void DelayActions(bool recording)
void SetMixer(int inputSource, float inputVolume, float playbackVolume)
bool ProcessPlaybackSlices(std::optional< RealtimeEffects::ProcessingScope > &pScope, size_t available)
void RemoveState(AudacityProject &project, ChannelGroup *pGroup, std::shared_ptr< RealtimeEffectState > pState)
Forwards to RealtimeEffectManager::RemoveState with proper init scope.
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.
bool DelayingActions() const
bool IsAvailable(AudacityProject &project) const
Function to automatically set an acceptable volume.
std::shared_ptr< RealtimeEffectState > AddState(AudacityProject &project, ChannelGroup *pGroup, const PluginID &id)
Forwards to RealtimeEffectManager::AddState with proper init scope.
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
std::shared_ptr< RealtimeEffectState > ReplaceState(AudacityProject &project, ChannelGroup *pGroup, size_t index, const PluginID &id)
Forwards to RealtimeEffectManager::ReplaceState with proper init scope.
void SetPaused(bool state, bool publish=false)
Pause and un-pause playback and recording.
void SequenceBufferExchange()
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 sequence time most recently played.
wxString LastPaErrorString()
std::vector< std::unique_ptr< AudioIOExtBase > >::const_iterator mIterator
auto operator*() const -> AudioIOExt &
unsigned CountSoloingSequences()
std::atomic< bool > mAudioThreadSequenceBufferExchangeLoopRunning
static int mNextStreamToken
std::shared_ptr< AudioIOListener > GetListener() const
size_t GetCommonlyWrittenForPlayback()
size_t mNumPlaybackChannels
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()
std::atomic< bool > mAudioThreadShouldCallSequenceBufferExchangeOnce
std::vector< std::unique_ptr< Resample > > mResample
float GetMixerOutputVol()
int AudioCallback(constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
void CheckSoundActivatedRecordingLevel(float *inputSamples, unsigned long framesPerBuffer)
PlaybackSchedule mPlaybackSchedule
RecordingSchedule mRecordingSchedule
std::vector< float * > mScratchPointers
pointing into mScratchBuffers
std::atomic< Acknowledge > mAudioThreadAcknowledge
std::atomic< bool > mFinishAudioThread
void UpdateTimePosition(unsigned long framesPerBuffer)
size_t mPlaybackSamplesToCopy
Preferred batch size for replenishing the playback RingBuffer.
static double mCachedBestRateOut
std::vector< std::unique_ptr< Mixer > > mPlaybackMixers
PlaybackPolicy::Duration mPlaybackRingBufferSecs
std::vector< std::vector< float > > mProcessingBuffers
std::atomic< bool > mAudioThreadSequenceBufferExchangeLoopActive
static size_t MinValue(const RingBuffers &buffers, size_t(RingBuffer::*pmf)() const)
void ClearRecordingException()
long mNumPauseFrames
How many frames of zeros were output due to pauses?
bool SequenceShouldBeSilent(const PlayableSequence &ps)
void SetRecordingException()
std::atomic< bool > mForceFadeOut
void DrainInputBuffers(constSamplePtr inputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackFlags statusFlags, float *tempFloats)
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)
RingBuffers mCaptureBuffers
void DoPlaythrough(constSamplePtr inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
void WaitForAudioThreadStarted()
bool mSimulateRecordingErrors
static bool mCachedBestRatePlaying
bool mSoftwarePlaythrough
RecordableSequences mCaptureSequences
void SetListener(const std::shared_ptr< AudioIOListener > &listener)
RingBuffers mPlaybackBuffers
std::vector< std::unique_ptr< RingBuffer > > RingBuffers
unsigned long mMaxFramesOutput
ConstPlayableSequences mPlaybackSequences
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))
size_t mPlaybackQueueMinimum
Occupancy of the queue we try to maintain, with bigger batches if needed.
std::weak_ptr< AudioIOListener > mListener
wxAtomicInt mRecordingException
double mCaptureRingBufferSecs
size_t mNumCaptureChannels
void SetMixerOutputVol(float value)
std::vector< std::vector< float > > mMasterBuffers
bool FillOutputBuffers(float *outputFloats, unsigned long framesPerBuffer, float *outputMeterFloats)
std::vector< std::pair< double, double > > mLostCaptureIntervals
void WaitForAudioThreadStopped()
bool mPauseRec
True if Sound Activated Recording is enabled.
double mMinCaptureSecsToCopy
unsigned long long mLostSamples
std::vector< SampleBuffer > mScratchBuffers
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()
std::vector< Input > Inputs
CallbackReturn Publish(const AudioIOEvent &message)
Send a message to connected callbacks.
virtual BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule)
Provide hints for construction of playback RingBuffer objects.
virtual double OffsetSequenceTime(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 bool Done(PlaybackSchedule &schedule, unsigned long outputFrames)
Returns true if schedule.GetSequenceTime() 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::SequenceBufferExchange.
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())
static RealtimeEffectManager & Get(AudacityProject &project)
static constexpr ChannelGroup * MasterGroup
void RemoveState(RealtimeEffects::InitializationScope *pScope, ChannelGroup *pGroup, std::shared_ptr< RealtimeEffectState > pState)
Main thread removes a global or per-group effect.
std::shared_ptr< RealtimeEffectState > ReplaceState(RealtimeEffects::InitializationScope *pScope, ChannelGroup *pGroup, size_t index, const PluginID &id)
Main thread replaces a global or per-group effect.
std::shared_ptr< RealtimeEffectState > AddState(RealtimeEffects::InitializationScope *pScope, ChannelGroup *pGroup, const PluginID &id)
Main thread appends a global or per-group effect.
Brackets processing setup and cleanup in the main thread.
Holds streamed audio samples.
size_t WrittenForGet() const
Reader may concurrently cause a decrease of what this returns.
size_t AvailForPut() const
size_t AvailForGet() const
SampleBuffer & Allocate(size_t count, sampleFormat format)
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 */
virtual bool Flush() noexcept=0
virtual bool Read(const wxString &key, bool *value) const =0
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()
constexpr auto sampleRate
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
TransportState(std::weak_ptr< AudacityProject > wOwningProject, const ConstPlayableSequences &playbackSequences, unsigned numPlaybackChannels, double sampleRate)
std::optional< RealtimeEffects::InitializationScope > mpRealtimeInitialization
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...
virtual bool GetSolo() const =0
May vary asynchronously.
virtual bool GetMute() const =0
May vary asynchronously.
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 SetSequenceTime(double time)
Set current track time value, unadjusted.
class AUDIO_IO_API PlaybackSchedule::TimeQueue mTimeQueue
double GetSequenceTime() const
Get current track time value, unadjusted.
PlaybackPolicy & GetPolicy()
double TotalCorrection() const
double mLatencyCorrection
PRCrossfadeData mCrossfadeData
RecordableSequences captureSequences
ConstPlayableSequences prerollSequences
std::vector< std::shared_ptr< const OtherPlayableSequence > > otherPlayableSequences
ConstPlayableSequences playbackSequences