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 =
1228 const size_t totalWidth = std::accumulate(
1230 [](
size_t acc,
const auto &pSequence){
1231 return acc + pSequence->NChannels(); });
1239 std::max<size_t>(1, totalWidth));
1247 reinterpret_cast<float*
>(buffer.ptr()));
1252 const auto &warpOptions =
1270 std::make_unique<RingBuffer>(
floatSample, playbackBufferSize);
1280 for (
size_t jj = 0, nChannels = pSequence->NChannels();
1281 jj < nChannels; ++jj
1288 assert(pSequence->FindChannelGroup());
1290 double startTime, endTime;
1297 .contains(pSequence))
1313 warpOptions, startTime, endTime, pSequence->NChannels(),
1323 const auto timeQueueSize = 1 +
1333 auto captureBufferSize =
1338 if(captureBufferSize < 100)
1359 catch(std::bad_alloc&)
1372 auto playbackBufferSize =
1412 return !pOwningProject || pOwningProject.get() == &
project;
1418 pInputMeter->Reset(
mRate,
true);
1420 pOutputMeter->Reset(
mRate,
true);
1425 auto cleanup =
finally ( [
this] {
1446#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1452 .load(std::memory_order_relaxed) )
1462 using namespace std::chrono;
1463 std::this_thread::sleep_for(milliseconds{latency + 50});
1500 #if defined(USE_PORTMIXER)
1503 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1504 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1505 mPreviousHWPlaythrough = -1.0;
1530 ext.StopOtherStream();
1600 std::optional<TransactionScope> pScope;
1602 pScope.emplace(*pOwningProject,
"Dropouts");
1604 auto &start = interval.first;
1605 auto duration = interval.second;
1608 sequence->InsertSilence(start, duration);
1616 pListener->OnCommitRecording();
1623 pInputMeter->Reset(
mRate,
false);
1626 pOutputMeter->Reset(
mRate,
false);
1632 pListener->OnAudioIOStopRecording();
1640 std::this_thread::yield();
1660 Publish({ pOwningProject.get(),
1679 pListener->OnAudioIORate(0);
1694 em.SetSuspended(state);
1698 mPaused.store(state, std::memory_order_relaxed);
1713 std::vector<long> rates;
1714 if (capturing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for capture"));
1715 if (playing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for playback"));
1716 wxLogDebug(
wxT(
"GetBestRate() suggested rate %.0lf Hz"),
sampleRate);
1718 if (capturing && !playing) {
1721 else if (playing && !capturing) {
1733 wxLogDebug(
wxT(
"GetBestRate() Returning %.0ld Hz"), rate);
1750 if (rates.empty()) {
1752 wxLogDebug(
wxT(
"GetBestRate() Error - no supported sample rates"));
1757 for (i = 0; i < (int)rates.size(); i++)
1759 if (rates[i] > rate) {
1761 wxLogDebug(
wxT(
"GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1767 wxLogDebug(
wxT(
"GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1768 retval = rates.back();
1799 enum class State { eUndefined, eOnce, eLoopRunning, eDoNothing, eMonitoring } lastState = State::eUndefined;
1801 while (!finish.load(std::memory_order_acquire)) {
1802 using Clock = std::chrono::steady_clock;
1803 auto loopPassStart = Clock::now();
1809 .store(
true, std::memory_order_relaxed);
1811 .load(std::memory_order_acquire) )
1815 .store(
false, std::memory_order_release);
1817 lastState = State::eOnce;
1820 .load(std::memory_order_relaxed))
1822 if (lastState != State::eLoopRunning)
1826 std::memory_order::memory_order_release);
1828 lastState = State::eLoopRunning;
1840 if ( (lastState == State::eLoopRunning)
1841 || (lastState == State::eMonitoring ) )
1846 std::memory_order::memory_order_release);
1848 lastState = State::eDoNothing;
1852 lastState = State::eMonitoring;
1857 .store(
false, std::memory_order_relaxed);
1859 std::this_thread::sleep_until( loopPassStart + interval );
1866 return std::accumulate(buffers.begin(), buffers.end(),
1867 std::numeric_limits<size_t>::max(),
1868 [pmf](
auto value,
auto &pBuffer){
1869 return std::min(value, (pBuffer.get()->*pmf)()); });
1877 return commonlyAvail -
std::min(
size_t(10), commonlyAvail);
1906 std::optional<RealtimeEffects::ProcessingScope> pScope;
1935 auto GetNeeded = [&]() ->
size_t {
1941 auto nNeeded = GetNeeded();
1960 auto available =
std::min( nAvailable,
1973 nNeeded = GetNeeded();
1983 std::optional<RealtimeEffects::ProcessingScope> &pScope,
size_t available)
1994 bool progress =
false;
1998 const auto &[frames, toProduce] = slice;
1999 progress = progress || toProduce > 0;
2009 size_t iSequence = 0;
2017 size_t produced = 0;
2019 produced = mixer->Process(toProduce);
2023 for (
size_t j = 0; j < nChannels; ++j) {
2024 auto warpedSamples = mixer->GetBuffer(j);
2026 warpedSamples,
floatSample, produced, frames - produced);
2038 available -= frames;
2042 frames, available );
2043 }
while (available && !done);
2051#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
2054 std::optional<RealtimeEffects::ProcessingScope> &pScope)
2067 const auto pGroup = vt->FindChannelGroup();
2071 const auto nChannels = std::min<size_t>(
2075 for (
unsigned iBlock : {0, 1}) {
2080 const auto pair = ringBuffer.GetUnflushed(iBlock);
2082 pointers[
iChannel] =
reinterpret_cast<float*
>(pair.first);
2088 assert(len == pair.second);
2098 memset((pointers[
iChannel++] = *scratch++), 0, len *
sizeof(
float));
2100 if (len && pScope) {
2101 auto discardable = pScope->Process(*pGroup, &pointers[0],
2109 auto discarded = ringBuffer.Unput(discardable);
2114 iBuffer += vt->NChannels();
2141 pSequence->RepairChannels();
2147 const auto remainingTime =
2150 const auto remainingSamples = remainingTime *
mRate;
2151 bool latencyCorrected =
true;
2153 double deltat = avail /
mRate;
2156 .load(std::memory_order_relaxed) ||
2159 bool newBlocks =
false;
2164 auto width = (*iter)->NChannels();
2172 width = (*iter)->NChannels();
2175 size_t discarded = 0;
2179 if (correction >= 0) {
2193 size_t size = floor(
2200 if (discarded <
size)
2203 latencyCorrected =
false;
2207 const float *pCrossfadeSrc =
nullptr;
2208 size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2215 totalCrossfadeLength = data.size();
2216 if (totalCrossfadeLength) {
2219 if (crossfadeStart < totalCrossfadeLength)
2220 pCrossfadeSrc = data.data() + crossfadeStart;
2224 wxASSERT(discarded <= avail);
2225 size_t toGet = avail - discarded;
2244 if (
double(
size) > remainingSamples)
2245 size = floor(remainingSamples);
2263 if (
double(toGet) > remainingSamples)
2264 toGet = floor(remainingSamples);
2265 const auto results =
2268 size = results.second;
2272 if (pCrossfadeSrc) {
2274 size_t crossfadeLength =
std::min(
size, totalCrossfadeLength - crossfadeStart);
2275 if (crossfadeLength) {
2276 auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2277 auto ratioStep = 1.0 / totalCrossfadeLength;
2278 auto pCrossfadeDst = (
float*)temp.
ptr();
2281 for (
size_t ii = 0; ii < crossfadeLength; ++ii) {
2282 *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2283 ++pCrossfadeSrc, ++pCrossfadeDst;
2291 newBlocks = (*iter)->Append(
iChannel,
2303 if (pListener && newBlocks)
2304 pListener->OnAudioIONewBlocks();
2325 const std::shared_ptr< AudioIOListener > &listener)
2334#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2338void AudioIO::AILAInitialize() {
2339 gPrefs->
Read(
wxT(
"/AudioIO/AutomatedInputLevelAdjustment"), &mAILAActive,
false);
2340 gPrefs->
Read(
wxT(
"/AudioIO/TargetPeak"), &mAILAGoalPoint, AILA_DEF_TARGET_PEAK);
2341 gPrefs->
Read(
wxT(
"/AudioIO/DeltaPeakVolume"), &mAILAGoalDelta, AILA_DEF_DELTA_PEAK);
2342 gPrefs->
Read(
wxT(
"/AudioIO/AnalysisTime"), &mAILAAnalysisTime, AILA_DEF_ANALYSIS_TIME);
2343 gPrefs->
Read(
wxT(
"/AudioIO/NumberAnalysis"), &mAILATotalAnalysis, AILA_DEF_NUMBER_ANALYSIS);
2344 mAILAGoalDelta /= 100.0;
2345 mAILAGoalPoint /= 100.0;
2346 mAILAAnalysisTime /= 1000.0;
2349 mAILAClipped =
false;
2350 mAILAAnalysisCounter = 0;
2351 mAILAChangeFactor = 1.0;
2352 mAILALastChangeType = 0;
2353 mAILATopLevel = 1.0;
2354 mAILAAnalysisEndTime = -1.0;
2357void AudioIO::AILADisable() {
2358 mAILAActive =
false;
2361bool AudioIO::AILAIsActive() {
2365void AudioIO::AILASetStartTime() {
2367 wxPrintf(
"START TIME %f\n\n", mAILAAbsolutStartTime);
2370double AudioIO::AILAGetLastDecisionTime() {
2371 return mAILAAnalysisEndTime;
2374void AudioIO::AILAProcess(
double maxPeak) {
2376 if (proj && mAILAActive) {
2378 mAILAClipped =
true;
2379 wxPrintf(
"clipped");
2382 mAILAMax = max(mAILAMax, maxPeak);
2384 if ((mAILATotalAnalysis == 0 || mAILAAnalysisCounter < mAILATotalAnalysis) &&
mPlaybackSchedule.
GetSequenceTime() - mAILALastStartTime >= mAILAAnalysisTime) {
2385 auto ToLinearIfDB = [](
double value,
int dbRange) {
2387 value = pow(10.0, (-(1.0-value) * dbRange)/20.0);
2393 double iv = (double) Px_GetInputVolume(mPortMixer);
2394 unsigned short changetype = 0;
2395 wxPrintf(
"mAILAAnalysisCounter:%d\n", mAILAAnalysisCounter);
2396 wxPrintf(
"\tmAILAClipped:%d\n", mAILAClipped);
2397 wxPrintf(
"\tmAILAMax (linear):%f\n", mAILAMax);
2398 wxPrintf(
"\tmAILAGoalPoint:%f\n", mAILAGoalPoint);
2399 wxPrintf(
"\tmAILAGoalDelta:%f\n", mAILAGoalDelta);
2400 wxPrintf(
"\tiv:%f\n", iv);
2401 wxPrintf(
"\tmAILAChangeFactor:%f\n", mAILAChangeFactor);
2402 if (mAILAClipped || mAILAMax > mAILAGoalPoint + mAILAGoalDelta) {
2403 wxPrintf(
"too high:\n");
2404 mAILATopLevel =
min(mAILATopLevel, iv);
2405 wxPrintf(
"\tmAILATopLevel:%f\n", mAILATopLevel);
2407 if (iv <= LOWER_BOUND) {
2409 if (mAILATotalAnalysis != 0) {
2410 mAILAActive =
false;
2413"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too high.") );
2415 wxPrintf(
"\talready min vol:%f\n", iv);
2418 float vol = (float) max(LOWER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2419 Px_SetInputVolume(mPortMixer, vol);
2421"Automated Recording Level Adjustment decreased the volume to %f.").Format( vol );
2424 wxPrintf(
"\tnew vol:%f\n", vol);
2425 float check = Px_GetInputVolume(mPortMixer);
2426 wxPrintf(
"\tverified %f\n", check);
2429 else if ( mAILAMax < mAILAGoalPoint - mAILAGoalDelta ) {
2431 wxPrintf(
"too low:\n");
2432 if (iv >= UPPER_BOUND || iv + 0.005 > mAILATopLevel) {
2434 if (mAILATotalAnalysis != 0) {
2435 mAILAActive =
false;
2438"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too low.") );
2440 wxPrintf(
"\talready max vol:%f\n", iv);
2443 float vol = (float)
min(UPPER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2444 if (vol > mAILATopLevel) {
2445 vol = (iv + mAILATopLevel)/2.0;
2446 wxPrintf(
"\tTruncated vol:%f\n", vol);
2448 Px_SetInputVolume(mPortMixer, vol);
2450"Automated Recording Level Adjustment increased the volume to %.2f.")
2454 wxPrintf(
"\tnew vol:%f\n", vol);
2455 float check = Px_GetInputVolume(mPortMixer);
2456 wxPrintf(
"\tverified %f\n", check);
2460 mAILAAnalysisCounter++;
2466 mAILAAnalysisEndTime = Pa_GetStreamTime(
mPortStreamV19) - mAILAAbsolutStartTime;
2468 wxPrintf(
"\tA decision was made @ %f\n", mAILAAnalysisEndTime);
2469 mAILAClipped =
false;
2472 if (changetype == 0)
2473 mAILAChangeFactor *= 0.8;
2474 else if (mAILALastChangeType == changetype)
2475 mAILAChangeFactor *= 1.1;
2477 mAILAChangeFactor *= 0.7;
2478 mAILALastChangeType = changetype;
2482 if (mAILAActive && mAILATotalAnalysis != 0 && mAILAAnalysisCounter >= mAILATotalAnalysis) {
2483 mAILAActive =
false;
2484 if (mAILAMax > mAILAGoalPoint + mAILAGoalDelta)
2487"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too high.") );
2488 else if (mAILAMax < mAILAGoalPoint - mAILAGoalDelta)
2491"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too low.") );
2494"Automated Recording Level Adjustment stopped. %.2f seems an acceptable volume.")
2495 .Format( Px_GetInputVolume(mPortMixer) );
2505 unsigned inputChannels,
2506 float *outputBuffer,
2509 for (
unsigned int i=0; i < inputChannels; i++) {
2510 auto inputPtr = inputBuffer + (i *
SAMPLE_SIZE(inputFormat));
2513 outputBuffer + i, len, inputChannels, 2);
2517 if (inputChannels == 1)
2518 for (
int i=0; i < len; i++)
2519 outputBuffer[2*i + 1] = outputBuffer[2*i];
2523 unsigned long framesPerBuffer,
2524 const PaStreamCallbackTimeInfo *timeInfo,
2528 return gAudioIO->AudioCallback(
2530 static_cast<float*
>(outputBuffer), framesPerBuffer,
2531 timeInfo, statusFlags, userData);
2542 float *inputSamples,
2543 unsigned long framesPerBuffer
2552 float sample = fabs(*(inputSamples++));
2553 if (sample > maxPeak) {
2559 if( bShouldBePaused !=
IsPaused() )
2563 pListener->OnSoundActivationThreshold();
2570 float * outputMeterFloats,
2571 float * outputFloats,
2572 const float * tempBuf,
2574 const unsigned long len,
2586 if (outputMeterFloats != outputFloats)
2587 for (
unsigned i = 0; i < len; ++i)
2588 outputMeterFloats[numPlaybackChannels*i+chan] +=
2595 float oldGain = channelGain;
2606 float deltaGain = (gain - oldGain) / len;
2607 for (
unsigned i = 0; i < len; i++)
2608 outputFloats[numPlaybackChannels*i+chan] += (oldGain + deltaGain * i) *tempBuf[i];
2613 for(
unsigned i = 0; i < len; i++)
2614 pBuffer[i] = std::clamp(pBuffer[i], -1.0f, 1.0f);
2624 float *outputBuffer,
2625 unsigned long framesPerBuffer,
2626 float *outputMeterFloats
2638 numPlaybackChannels <= 0) {
2645 float *outputFloats = outputBuffer;
2657 const auto tempBufs =
stackAllocate(
float *, numPlaybackChannels);
2660 for (
unsigned int c = 0; c < numPlaybackChannels; c++)
2682 bool discardable =
false;
2685 for (
unsigned tt = 0; tt < numPlaybackSequences; ++tt) {
2687 const auto width = vt->NChannels();
2690 if (width < numPlaybackChannels)
2692 memset(tempBufs[1], 0, framesPerBuffer *
sizeof(
float));
2699 discardable = discardable &&
2702 decltype(framesPerBuffer) len = 0;
2704 for (
size_t c = 0; c < width; ++c) {
2711 memset(tempBufs[c], 0, framesPerBuffer *
sizeof(
float));
2717 if (len < framesPerBuffer)
2724 memset((
void*)&tempBufs[c][len], 0,
2725 (framesPerBuffer - len) *
sizeof(
float));
2752 tempBufs[0], drop, len, *vt, gains[0]);
2756 const auto iBuffer = std::min<size_t>(1, width - 1);
2758 tempBufs[iBuffer], drop, len, *vt, gains[1]);
2770 if (numPlaybackSequences == 0) {
2779 ClampBuffer( outputFloats, framesPerBuffer*numPlaybackChannels );
2780 if (outputMeterFloats != outputFloats)
2781 ClampBuffer( outputMeterFloats, framesPerBuffer*numPlaybackChannels );
2803 unsigned long framesPerBuffer,
2816 if( numCaptureChannels <= 0 )
2828 (statusFlags & (paInputOverflow))
2829 && !(statusFlags & paPrimingOutput);
2835 size_t len = framesPerBuffer;
2836 for(
unsigned t = 0; t < numCaptureChannels; t++)
2851 len < framesPerBuffer) ) {
2856 auto duration = (framesPerBuffer - len) /
mRate;
2860 fabs(pLast->first + pLast->second - start) < 0.5/
mRate)
2862 pLast->second = start + duration - pLast->first;
2867 if (len < framesPerBuffer)
2870 wxPrintf(
wxT(
"lost %d samples\n"), (
int)(framesPerBuffer - len));
2879 for(
unsigned t = 0; t < numCaptureChannels; t++) {
2889 auto inputFloats = (
const float *)inputBuffer;
2890 for(
unsigned i = 0; i < len; i++)
2892 inputFloats[numCaptureChannels*i+t];
2902 auto inputShorts = (
const short *)inputBuffer;
2903 short *tempShorts = (
short *)tempFloats;
2904 for(
unsigned i = 0; i < len; i++) {
2905 float tmp = inputShorts[numCaptureChannels*i+t];
2906 tmp = std::clamp(tmp, -32768.0f, 32767.0f);
2907 tempShorts[i] = (short)(tmp);
2930void OldCodeToCalculateLatency()
2943 if (numCaptureChannels > 0 && numPlaybackChannels > 0)
2945 if (timeInfo->inputBufferAdcTime > 0)
2946 mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
2947 else if (mLastRecordingOffset == 0.0)
2949 const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
2950 mLastRecordingOffset = -si->inputLatency;
2961 float *outputBuffer,
2962 unsigned long framesPerBuffer,
2963 float *outputMeterFloats
2972 if( numPlaybackChannels <= 0 )
2975 float *outputFloats = outputBuffer;
2976 for(
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
2977 outputFloats[i] = 0.0;
2982 outputBuffer, framesPerBuffer);
2986 if (outputMeterFloats != outputFloats) {
2987 for (
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
2988 outputMeterFloats[i] = outputFloats[i];
2996 const float *inputSamples,
2997 unsigned long framesPerBuffer
3004 if( pInputMeter->IsMeterDisabled())
3006 pInputMeter->UpdateDisplay(
3007 numCaptureChannels, framesPerBuffer, inputSamples);
3012 const float *outputMeterFloats,
3013 unsigned long framesPerBuffer)
3020 if( pOutputMeter->IsMeterDisabled() )
3022 if( !outputMeterFloats)
3024 pOutputMeter->UpdateDisplay(
3025 numPlaybackChannels, framesPerBuffer, outputMeterFloats);
3043 unsigned numSolo = 0;
3044 for (
unsigned t = 0; t < numPlaybackSequences; t++ )
3048 numSolo += std::accumulate(range.begin(), range.end(), 0,
3049 [](
unsigned sum,
auto &ext){
3050 return sum + ext.CountOtherSolo(); });
3073 return gains[0] == 0.0 && gains[1] == 0.0;
3090 for (
auto &
factory: factories)
3103 unsigned long framesPerBuffer,
3104 const PaStreamCallbackTimeInfo *timeInfo,
3125 ext.FillOtherBuffers(
3135 framesPerBuffer * std::max(numCaptureChannels, numPlaybackChannels));
3137 bool bVolEmulationActive =
3142 const auto outputMeterFloats = bVolEmulationActive
3143 ?
stackAllocate(
float, framesPerBuffer * numPlaybackChannels)
3147 if (inputBuffer && numCaptureChannels) {
3148 float *inputSamples;
3151 inputSamples = (
float *) inputBuffer;
3155 mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
3156 inputSamples = tempFloats;
3236 .store(
false, std::memory_order_relaxed);
3239 .load(std::memory_order_relaxed ) )
3241 using namespace std::chrono;
3242 std::this_thread::sleep_for(50ms);
3255 mixer->Reposition( time,
true );
3257 const auto toDiscard = buffer->AvailForGet();
3258 const auto discarded = buffer->Discard( toDiscard );
3261 wxUnusedVar(discarded);
3271 .store(
true, std::memory_order_relaxed);
3277 int &callbackReturn,
unsigned long len)
3288 ext.SignalOtherCompletion();
3289 callbackReturn = paComplete;
3309 using namespace std::chrono;
3310 std::this_thread::sleep_for(50ms);
3324 using namespace std::chrono;
3325 std::this_thread::sleep_for(50ms);
3333 .store(
true, std::memory_order_release);
3336 .load(std::memory_order_acquire))
3338 using namespace std::chrono;
3339 std::this_thread::sleep_for(sleepTime);
3349 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.
void SetPaused(bool state)
Pause and un-pause playback and recording.
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 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()
void TransformPlayBuffers(std::optional< RealtimeEffects::ProcessingScope > &scope)
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)
bool AllSequencesAlreadySilent()
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)
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
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
void AddToOutputChannel(unsigned int chan, float *outputMeterFloats, float *outputFloats, const float *tempBuf, bool drop, unsigned long len, const PlayableSequence &ps, float &channelGain)
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 SequenceHasBeenFadedOut(const OldChannelGains &gains)
Returns true when playback buffer data from both channels is discardable.
bool mSimulateRecordingErrors
std::vector< OldChannelGains > mOldChannelGains
bool FillOutputBuffers(float *outputBuffer, unsigned long framesPerBuffer, float *outputMeterFloats)
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::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 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.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)
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 float GetChannelGain(int channel) const =0
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