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);
1717 if (capturing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for capture"));
1718 if (playing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for playback"));
1719 wxLogDebug(
wxT(
"GetBestRate() suggested rate %.0lf Hz"),
sampleRate);
1721 long requestedRate =
static_cast<long>(
sampleRate);
1722 long supportedRate = 0;
1724 if (capturing && !playing) {
1727 else if (playing && !capturing) {
1738 if (supportedRate == 0) {
1740 wxLogDebug(
wxT(
"GetBestRate() Error - no supported sample rates"));
1742 else if (supportedRate != requestedRate) {
1743 wxLogDebug(
wxT(
"GetBestRate() Returning highest supported rate - %.0ld Hz"), supportedRate);
1750 return supportedRate;
1773 enum class State { eUndefined, eOnce, eLoopRunning, eDoNothing, eMonitoring } lastState = State::eUndefined;
1775 while (!finish.load(std::memory_order_acquire)) {
1776 using Clock = std::chrono::steady_clock;
1777 auto loopPassStart = Clock::now();
1783 .store(
true, std::memory_order_relaxed);
1785 .load(std::memory_order_acquire) )
1789 .store(
false, std::memory_order_release);
1791 lastState = State::eOnce;
1794 .load(std::memory_order_relaxed))
1796 if (lastState != State::eLoopRunning)
1800 std::memory_order::memory_order_release);
1802 lastState = State::eLoopRunning;
1814 if ( (lastState == State::eLoopRunning)
1815 || (lastState == State::eMonitoring ) )
1820 std::memory_order::memory_order_release);
1822 lastState = State::eDoNothing;
1826 lastState = State::eMonitoring;
1831 .store(
false, std::memory_order_relaxed);
1833 std::this_thread::sleep_until( loopPassStart + interval );
1840 return std::accumulate(buffers.begin(), buffers.end(),
1841 std::numeric_limits<size_t>::max(),
1842 [pmf](
auto value,
auto &pBuffer){
1843 return std::min(value, (pBuffer.get()->*pmf)()); });
1851 return commonlyAvail -
std::min(
size_t(10), commonlyAvail);
1880 std::optional<RealtimeEffects::ProcessingScope> pScope;
1909 auto GetNeeded = [&]() ->
size_t {
1915 auto nNeeded = GetNeeded();
1934 auto available =
std::min( nAvailable,
1947 nNeeded = GetNeeded();
1956#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
1959 std::optional<RealtimeEffects::ProcessingScope> &pScope,
size_t available)
1970 bool progress =
false;
1981 const auto &[frames, toProduce] = slice;
1982 progress = progress || toProduce > 0;
1992 size_t iSequence = 0;
2000 size_t produced = 0;
2003 produced = mixer->Process(toProduce);
2010 for (
size_t j = 0; j < nChannels; ++j)
2018 buffer.resize(buffer.size() + frames, 0);
2020 const auto warpedSamples = mixer->GetBuffer(j);
2022 reinterpret_cast<const float*
>(warpedSamples),
2024 buffer.data() + appendPos);
2026 buffer.data() + appendPos + produced,
2031 iBuffer += nChannels;
2036 available -= frames;
2043 frames, available );
2044 }
while (available && !done);
2056 int bufferIndex = 0;
2061 const auto channelGroup = seq->FindChannelGroup();
2073 const auto offset = processingBufferOffsets[bufferIndex];
2085 pointers[i] = *scratch++;
2086 std::fill_n(pointers[i], len, .0f);
2089 const auto discardable = pScope->Process(channelGroup, &pointers[0],
2096 for(
int i = 0; i < seq->NChannels(); ++i)
2099 buffer.erase(buffer.begin() + offset, buffer.begin() + offset + discardable);
2103 std::fill_n(buffer.data() + offset, len - discardable, 0);
2108 bufferIndex += seq->NChannels();
2115 auto samplesAvailable = std::min_element(
2118 [](
auto& first,
auto& second) { return first.size() < second.size(); }
2123 if(samplesAvailable == 0)
2127 auto cleanup =
finally([=] {
2136 buffer.resize(samplesAvailable, 0);
2140 unsigned bufferIndex = 0;
2144 const auto numChannels = seq->NChannels();
2149 const auto volume = seq->GetChannelVolume(n);
2150 for(
unsigned i = 0; i < samplesAvailable; ++i)
2154 else if(numChannels == 1)
2159 const auto volume = seq->GetChannelVolume(n);
2160 for(
unsigned i = 0; i < samplesAvailable; ++i)
2164 bufferIndex += seq->NChannels();
2170 buffer.erase(buffer.begin(), buffer.begin() + samplesAvailable);
2175 size_t masterBufferOffset = 0;
2182 masterBufferOffset = pScope->Process(
2191 samplesAvailable -= masterBufferOffset;
2194 if(samplesAvailable == 0)
2198 unsigned bufferIndex = 0;
2202 reinterpret_cast<constSamplePtr>(buffer.data()) + masterBufferOffset *
sizeof(
float),
2236 pSequence->RepairChannels();
2242 const auto remainingTime =
2245 const auto remainingSamples = remainingTime *
mRate;
2246 bool latencyCorrected =
true;
2248 double deltat = avail /
mRate;
2251 .load(std::memory_order_relaxed) ||
2254 bool newBlocks =
false;
2259 auto width = (*iter)->NChannels();
2267 width = (*iter)->NChannels();
2270 size_t discarded = 0;
2274 if (correction >= 0) {
2288 size_t size = floor(
2295 if (discarded <
size)
2298 latencyCorrected =
false;
2302 const float *pCrossfadeSrc =
nullptr;
2303 size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2310 totalCrossfadeLength = data.size();
2311 if (totalCrossfadeLength) {
2314 if (crossfadeStart < totalCrossfadeLength)
2315 pCrossfadeSrc = data.data() + crossfadeStart;
2319 wxASSERT(discarded <= avail);
2320 size_t toGet = avail - discarded;
2339 if (
double(
size) > remainingSamples)
2340 size = floor(remainingSamples);
2358 if (
double(toGet) > remainingSamples)
2359 toGet = floor(remainingSamples);
2360 const auto results =
2363 size = results.second;
2367 if (pCrossfadeSrc) {
2369 size_t crossfadeLength =
std::min(
size, totalCrossfadeLength - crossfadeStart);
2370 if (crossfadeLength) {
2371 auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2372 auto ratioStep = 1.0 / totalCrossfadeLength;
2373 auto pCrossfadeDst = (
float*)temp.
ptr();
2376 for (
size_t ii = 0; ii < crossfadeLength; ++ii) {
2377 *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2378 ++pCrossfadeSrc, ++pCrossfadeDst;
2386 newBlocks = (*iter)->Append(
iChannel,
2398 if (pListener && newBlocks)
2399 pListener->OnAudioIONewBlocks();
2420 const std::shared_ptr< AudioIOListener > &listener)
2429#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2433void AudioIO::AILAInitialize() {
2434 gPrefs->
Read(
wxT(
"/AudioIO/AutomatedInputLevelAdjustment"), &mAILAActive,
false);
2435 gPrefs->
Read(
wxT(
"/AudioIO/TargetPeak"), &mAILAGoalPoint, AILA_DEF_TARGET_PEAK);
2436 gPrefs->
Read(
wxT(
"/AudioIO/DeltaPeakVolume"), &mAILAGoalDelta, AILA_DEF_DELTA_PEAK);
2437 gPrefs->
Read(
wxT(
"/AudioIO/AnalysisTime"), &mAILAAnalysisTime, AILA_DEF_ANALYSIS_TIME);
2438 gPrefs->
Read(
wxT(
"/AudioIO/NumberAnalysis"), &mAILATotalAnalysis, AILA_DEF_NUMBER_ANALYSIS);
2439 mAILAGoalDelta /= 100.0;
2440 mAILAGoalPoint /= 100.0;
2441 mAILAAnalysisTime /= 1000.0;
2444 mAILAClipped =
false;
2445 mAILAAnalysisCounter = 0;
2446 mAILAChangeFactor = 1.0;
2447 mAILALastChangeType = 0;
2448 mAILATopLevel = 1.0;
2449 mAILAAnalysisEndTime = -1.0;
2452void AudioIO::AILADisable() {
2453 mAILAActive =
false;
2456bool AudioIO::AILAIsActive() {
2460void AudioIO::AILASetStartTime() {
2462 wxPrintf(
"START TIME %f\n\n", mAILAAbsolutStartTime);
2465double AudioIO::AILAGetLastDecisionTime() {
2466 return mAILAAnalysisEndTime;
2469void AudioIO::AILAProcess(
double maxPeak) {
2471 if (proj && mAILAActive) {
2473 mAILAClipped =
true;
2474 wxPrintf(
"clipped");
2477 mAILAMax = max(mAILAMax, maxPeak);
2479 if ((mAILATotalAnalysis == 0 || mAILAAnalysisCounter < mAILATotalAnalysis) &&
mPlaybackSchedule.
GetSequenceTime() - mAILALastStartTime >= mAILAAnalysisTime) {
2480 auto ToLinearIfDB = [](
double value,
int dbRange) {
2482 value = pow(10.0, (-(1.0-value) * dbRange)/20.0);
2488 double iv = (double) Px_GetInputVolume(mPortMixer);
2489 unsigned short changetype = 0;
2490 wxPrintf(
"mAILAAnalysisCounter:%d\n", mAILAAnalysisCounter);
2491 wxPrintf(
"\tmAILAClipped:%d\n", mAILAClipped);
2492 wxPrintf(
"\tmAILAMax (linear):%f\n", mAILAMax);
2493 wxPrintf(
"\tmAILAGoalPoint:%f\n", mAILAGoalPoint);
2494 wxPrintf(
"\tmAILAGoalDelta:%f\n", mAILAGoalDelta);
2495 wxPrintf(
"\tiv:%f\n", iv);
2496 wxPrintf(
"\tmAILAChangeFactor:%f\n", mAILAChangeFactor);
2497 if (mAILAClipped || mAILAMax > mAILAGoalPoint + mAILAGoalDelta) {
2498 wxPrintf(
"too high:\n");
2499 mAILATopLevel =
min(mAILATopLevel, iv);
2500 wxPrintf(
"\tmAILATopLevel:%f\n", mAILATopLevel);
2502 if (iv <= LOWER_BOUND) {
2504 if (mAILATotalAnalysis != 0) {
2505 mAILAActive =
false;
2508"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too high.") );
2510 wxPrintf(
"\talready min vol:%f\n", iv);
2513 float vol = (float) max(LOWER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2514 Px_SetInputVolume(mPortMixer, vol);
2516"Automated Recording Level Adjustment decreased the volume to %f.").Format( vol );
2519 wxPrintf(
"\tnew vol:%f\n", vol);
2520 float check = Px_GetInputVolume(mPortMixer);
2521 wxPrintf(
"\tverified %f\n", check);
2524 else if ( mAILAMax < mAILAGoalPoint - mAILAGoalDelta ) {
2526 wxPrintf(
"too low:\n");
2527 if (iv >= UPPER_BOUND || iv + 0.005 > mAILATopLevel) {
2529 if (mAILATotalAnalysis != 0) {
2530 mAILAActive =
false;
2533"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too low.") );
2535 wxPrintf(
"\talready max vol:%f\n", iv);
2538 float vol = (float)
min(UPPER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2539 if (vol > mAILATopLevel) {
2540 vol = (iv + mAILATopLevel)/2.0;
2541 wxPrintf(
"\tTruncated vol:%f\n", vol);
2543 Px_SetInputVolume(mPortMixer, vol);
2545"Automated Recording Level Adjustment increased the volume to %.2f.")
2549 wxPrintf(
"\tnew vol:%f\n", vol);
2550 float check = Px_GetInputVolume(mPortMixer);
2551 wxPrintf(
"\tverified %f\n", check);
2555 mAILAAnalysisCounter++;
2561 mAILAAnalysisEndTime = Pa_GetStreamTime(
mPortStreamV19) - mAILAAbsolutStartTime;
2563 wxPrintf(
"\tA decision was made @ %f\n", mAILAAnalysisEndTime);
2564 mAILAClipped =
false;
2567 if (changetype == 0)
2568 mAILAChangeFactor *= 0.8;
2569 else if (mAILALastChangeType == changetype)
2570 mAILAChangeFactor *= 1.1;
2572 mAILAChangeFactor *= 0.7;
2573 mAILALastChangeType = changetype;
2577 if (mAILAActive && mAILATotalAnalysis != 0 && mAILAAnalysisCounter >= mAILATotalAnalysis) {
2578 mAILAActive =
false;
2579 if (mAILAMax > mAILAGoalPoint + mAILAGoalDelta)
2582"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too high.") );
2583 else if (mAILAMax < mAILAGoalPoint - mAILAGoalDelta)
2586"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too low.") );
2589"Automated Recording Level Adjustment stopped. %.2f seems an acceptable volume.")
2590 .Format( Px_GetInputVolume(mPortMixer) );
2600 unsigned inputChannels,
2601 float *outputBuffer,
2604 for (
unsigned int i=0; i < inputChannels; i++) {
2605 auto inputPtr = inputBuffer + (i *
SAMPLE_SIZE(inputFormat));
2608 outputBuffer + i, len, inputChannels, 2);
2612 if (inputChannels == 1)
2613 for (
int i=0; i < len; i++)
2614 outputBuffer[2*i + 1] = outputBuffer[2*i];
2618 unsigned long framesPerBuffer,
2619 const PaStreamCallbackTimeInfo *timeInfo,
2623 return gAudioIO->AudioCallback(
2625 static_cast<float*
>(outputBuffer), framesPerBuffer,
2626 timeInfo, statusFlags, userData);
2637 float *inputSamples,
2638 unsigned long framesPerBuffer
2647 float sample = fabs(*(inputSamples++));
2648 if (sample > maxPeak) {
2654 if( bShouldBePaused !=
IsPaused() )
2658 pListener->OnSoundActivationThreshold();
2664 for(
unsigned i = 0; i < len; i++)
2665 pBuffer[i] = std::clamp(pBuffer[i], -1.0f, 1.0f);
2675 float *outputFloats,
2676 unsigned long framesPerBuffer,
2677 float *outputMeterFloats
2688 numPlaybackChannels <= 0) {
2710 if (numPlaybackSequences == 0) {
2731 const auto tempBufs =
stackAllocate(
float *, numPlaybackChannels);
2734 for (
unsigned int c = 0; c < numPlaybackChannels; c++)
2740 playbackVolume = 0.0;
2742 for(
unsigned n = 0; n < numPlaybackChannels; ++n)
2745 reinterpret_cast<samplePtr>(tempBufs[n]),
2749 if(len < framesPerBuffer)
2757 memset((
void*)&tempBufs[n][len], 0,
2758 (framesPerBuffer - len) *
sizeof(
float));
2784 if(outputMeterFloats != outputFloats)
2786 for (
unsigned i = 0; i < len; ++i)
2787 outputMeterFloats[numPlaybackChannels*i+n] +=
2788 playbackVolume*tempBufs[n][i];
2794 oldVolume = playbackVolume;
2800 const float deltaVolume = (playbackVolume - oldVolume) / len;
2801 for (
unsigned i = 0; i < len; i++)
2803 outputFloats[numPlaybackChannels * i + n] +=
2804 (oldVolume + deltaVolume * i) * tempBufs[n][i];
2816 ClampBuffer( outputFloats, framesPerBuffer*numPlaybackChannels );
2817 if (outputMeterFloats != outputFloats)
2818 ClampBuffer( outputMeterFloats, framesPerBuffer*numPlaybackChannels );
2840 unsigned long framesPerBuffer,
2853 if( numCaptureChannels <= 0 )
2865 (statusFlags & (paInputOverflow))
2866 && !(statusFlags & paPrimingOutput);
2872 size_t len = framesPerBuffer;
2873 for(
unsigned t = 0; t < numCaptureChannels; t++)
2888 len < framesPerBuffer) ) {
2893 auto duration = (framesPerBuffer - len) /
mRate;
2897 fabs(pLast->first + pLast->second - start) < 0.5/
mRate)
2899 pLast->second = start + duration - pLast->first;
2904 if (len < framesPerBuffer)
2907 wxPrintf(
wxT(
"lost %d samples\n"), (
int)(framesPerBuffer - len));
2916 for(
unsigned t = 0; t < numCaptureChannels; t++) {
2926 auto inputFloats = (
const float *)inputBuffer;
2927 for(
unsigned i = 0; i < len; i++)
2929 inputFloats[numCaptureChannels*i+t];
2939 auto inputShorts = (
const short *)inputBuffer;
2940 short *tempShorts = (
short *)tempFloats;
2941 for(
unsigned i = 0; i < len; i++) {
2942 float tmp = inputShorts[numCaptureChannels*i+t];
2943 tmp = std::clamp(tmp, -32768.0f, 32767.0f);
2944 tempShorts[i] = (short)(tmp);
2967void OldCodeToCalculateLatency()
2980 if (numCaptureChannels > 0 && numPlaybackChannels > 0)
2982 if (timeInfo->inputBufferAdcTime > 0)
2983 mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
2984 else if (mLastRecordingOffset == 0.0)
2986 const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
2987 mLastRecordingOffset = -si->inputLatency;
2998 float *outputBuffer,
2999 unsigned long framesPerBuffer,
3000 float *outputMeterFloats
3009 if( numPlaybackChannels <= 0 )
3012 float *outputFloats = outputBuffer;
3013 for(
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
3014 outputFloats[i] = 0.0;
3019 outputBuffer, framesPerBuffer);
3023 if (outputMeterFloats != outputFloats) {
3024 for (
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
3025 outputMeterFloats[i] = outputFloats[i];
3033 const float *inputSamples,
3034 unsigned long framesPerBuffer
3041 if( pInputMeter->IsMeterDisabled())
3043 pInputMeter->UpdateDisplay(
3044 numCaptureChannels, framesPerBuffer, inputSamples);
3049 const float *outputMeterFloats,
3050 unsigned long framesPerBuffer)
3057 if( pOutputMeter->IsMeterDisabled() )
3059 if( !outputMeterFloats)
3061 pOutputMeter->UpdateDisplay(
3062 numPlaybackChannels, framesPerBuffer, outputMeterFloats);
3080 unsigned numSolo = 0;
3081 for (
unsigned t = 0; t < numPlaybackSequences; t++ )
3085 numSolo += std::accumulate(range.begin(), range.end(), 0,
3086 [](
unsigned sum,
auto &ext){
3087 return sum + ext.CountOtherSolo(); });
3110 for (
auto &
factory: factories)
3123 unsigned long framesPerBuffer,
3124 const PaStreamCallbackTimeInfo *timeInfo,
3145 ext.FillOtherBuffers(
3155 framesPerBuffer * std::max(numCaptureChannels, numPlaybackChannels));
3157 bool bVolEmulationActive =
3162 const auto outputMeterFloats = bVolEmulationActive
3163 ?
stackAllocate(
float, framesPerBuffer * numPlaybackChannels)
3167 if (inputBuffer && numCaptureChannels) {
3168 float *inputSamples;
3171 inputSamples = (
float *) inputBuffer;
3175 mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
3176 inputSamples = tempFloats;
3252 .store(
false, std::memory_order_relaxed);
3255 .load(std::memory_order_relaxed ) )
3257 using namespace std::chrono;
3258 std::this_thread::sleep_for(50ms);
3271 mixer->Reposition( time,
true );
3273 const auto toDiscard = buffer->AvailForGet();
3274 const auto discarded = buffer->Discard( toDiscard );
3277 wxUnusedVar(discarded);
3287 .store(
true, std::memory_order_relaxed);
3293 int &callbackReturn,
unsigned long len)
3304 ext.SignalOtherCompletion();
3305 callbackReturn = paComplete;
3325 using namespace std::chrono;
3326 std::this_thread::sleep_for(50ms);
3340 using namespace std::chrono;
3341 std::this_thread::sleep_for(50ms);
3349 .store(
true, std::memory_order_release);
3352 .load(std::memory_order_acquire))
3354 using namespace std::chrono;
3355 std::this_thread::sleep_for(sleepTime);
3365 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.
static long GetClosestSupportedPlaybackRate(int devIndex, long rate)
Find the closest supported sample rate for given playback device.
double mRate
Audio playback rate in samples per second.
bool IsMonitoring() const
Returns true if we're monitoring input (but not recording or playing actual audio)
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)
std::weak_ptr< AudacityProject > mOwningProject
static long GetClosestSupportedSampleRate(int playDevice, int recDevice, long rate)
Find the closest supported sample rate for given playback and recording devices.
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 long GetClosestSupportedCaptureRate(int devIndex, long rate)
Find the closest supported sample rate for given recording device.
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