90#include <wx/wxcrtvararg.h>
95#if defined(__WXMAC__) || defined(__WXMSW__)
115#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
116 #define LOWER_BOUND 0.0
117 #define UPPER_BOUND 1.0
131 unsigned numPlaybackChannels,
double sampleRate)
133 if (
auto pOwningProject = wOwningProject.lock();
134 pOwningProject && numPlaybackChannels > 0) {
138 move(wOwningProject),
sampleRate, numPlaybackChannels);
140 for (
size_t i = 0, cnt = playbackSequences.size(); i < cnt; ++i) {
142 const auto vt = playbackSequences[i].get();
143 const auto pGroup = vt ? vt->FindChannelGroup() :
nullptr;
144 if (!(pGroup && pGroup->IsLeader())) {
149 ->AddGroup(*pGroup, numPlaybackChannels,
sampleRate);
165 #undef REALTIME_ALSA_THREAD
168 #undef REALTIME_ALSA_THREAD
171#ifdef REALTIME_ALSA_THREAD
172#include "pa_linux_alsa.h"
176 unsigned long framesPerBuffer,
177 const PaStreamCallbackTimeInfo *timeInfo,
191 pAudioIO->StartThread();
196 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
205 const PaDeviceInfo *info = Pa_GetDeviceInfo(i);
226 return pInfo !=
nullptr && rInfo !=
nullptr && pInfo->hostApi == rInfo->hostApi;
231 if (!std::atomic<double>{}.is_lock_free()) {
242 wxASSERT(
sizeof(
short ) <=
sizeof(
float ));
245 .store(
false, std::memory_order_relaxed);
247 .store(
false, std::memory_order_relaxed);
249 .store(
false, std::memory_order_relaxed);
257#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
271 if (err != paNoError) {
272 auto errStr =
XO(
"Could not find any audio devices.\n");
273 errStr +=
XO(
"You will not be able to play or record audio.\n\n");
274 wxString paErrStr =
LAT1CTOWX(Pa_GetErrorText(err));
275 if (!paErrStr.empty())
276 errStr +=
XO(
"Error: %s").Format( paErrStr );
284 .IconStyle(Icon::Error)
285 .ButtonStyle(Button::Ok));
293#if defined(USE_PORTMIXER)
295 mPreviousHWPlaythrough = -1.0;
318#if defined(USE_PORTMIXER)
321 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
322 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
323 mPreviousHWPlaythrough = -1.0;
325 Px_CloseMixer(mPortMixer);
343std::shared_ptr<RealtimeEffectState>
347 assert(!pGroup || pGroup->
IsLeader());
355std::shared_ptr<RealtimeEffectState>
359 assert(!pGroup || pGroup->
IsLeader());
370 const std::shared_ptr<RealtimeEffectState> pState)
380 float playbackVolume)
385#if defined(USE_PORTMIXER)
386 PxMixer *mixer = mPortMixer;
390 float oldRecordVolume = Px_GetInputVolume(mixer);
393 if( oldRecordVolume != recordVolume )
394 Px_SetInputVolume(mixer, recordVolume);
400 float *playbackVolume)
404#if defined(USE_PORTMIXER)
406 PxMixer *mixer = mPortMixer;
410 *recordDevice = Px_GetCurrentInputSource(mixer);
413 *recordVolume = Px_GetInputVolume(mixer);
415 *recordVolume = 1.0f;
423 *recordVolume = 1.0f;
433#if defined(USE_PORTMIXER)
435 wxArrayString deviceNames;
439 int numSources = Px_GetNumInputSources(mPortMixer);
440 for(
int source = 0; source < numSources; source++ )
441 deviceNames.push_back(wxString(wxSafeConvertMB2WX(Px_GetInputSourceName(mPortMixer, source))));
445 wxLogDebug(
wxT(
"AudioIO::GetInputSourceNames(): PortMixer not initialised!"));
473 unsigned int numPlaybackChannels,
unsigned int numCaptureChannels)
478 bool success =
false;
479 auto cleanup =
finally([&]{
501 auto captureFormat_saved = captureFormat;
517 bool usePlayback =
false, useCapture =
false;
518 PaStreamParameters playbackParameters{};
519 PaStreamParameters captureParameters{};
523 if( numPlaybackChannels > 0)
531 const PaDeviceInfo *playbackDeviceInfo;
532 playbackDeviceInfo = Pa_GetDeviceInfo( playbackParameters.device );
534 if( playbackDeviceInfo == NULL )
538 playbackParameters.sampleFormat = paFloat32;
539 playbackParameters.hostApiSpecificStreamInfo = NULL;
543 playbackParameters.suggestedLatency =
544 playbackDeviceInfo->defaultLowOutputLatency;
551 const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo(playbackDeviceInfo->hostApi);
552 bool isWASAPI = (hostInfo && hostInfo->type == paWASAPI);
553 playbackParameters.suggestedLatency = isWASAPI ? 0.0 : latencyDuration/1000.0;
559 if( numCaptureChannels > 0)
563 const PaDeviceInfo *captureDeviceInfo;
568 captureDeviceInfo = Pa_GetDeviceInfo( captureParameters.device );
570 if( captureDeviceInfo == NULL )
573 captureParameters.sampleFormat =
576 captureParameters.hostApiSpecificStreamInfo = NULL;
580 captureParameters.suggestedLatency =
581 captureDeviceInfo->defaultHighInputLatency;
583 captureParameters.suggestedLatency = latencyDuration/1000.0;
588 const auto deviceInfo = usePlayback ?
589 Pa_GetDeviceInfo(playbackParameters.device) :
590 Pa_GetDeviceInfo(captureParameters.device);
592 if (deviceInfo !=
nullptr)
594 const auto hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
610 float oldRecordVolume = Px_GetInputVolume(mPortMixer);
617 int* lpUserData = (captureFormat_saved ==
int24Sample) ? &userData : NULL;
622 unsigned int maxTries = 1;
625 using namespace std::chrono;
631 for (
unsigned int tries = 0; tries < maxTries; tries++) {
633 useCapture ? &captureParameters : NULL,
634 usePlayback ? &playbackParameters : NULL,
635 mRate, paFramesPerBufferUnspecified,
642 const auto outputLatency =
648 (latencyDuration / 1000.0) :
650 stream->outputLatency;
668 wxLogDebug(
"Attempt %u to open capture stream failed with: %d", 1 + tries,
mLastPaError);
669 using namespace std::chrono;
670 std::this_thread::sleep_for(1s);
676 Px_SetInputVolume(mPortMixer, oldRecordVolume);
682 if (Px_SupportsPlaythrough(mPortMixer)) {
683 bool playthrough =
false;
685 mPreviousHWPlaythrough = Px_GetPlaythrough(mPortMixer);
690 Px_SetPlaythrough(mPortMixer, 1.0);
692 Px_SetPlaythrough(mPortMixer, 0.0);
699#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
702 wxPowerResource::Acquire(wxPOWER_RESOURCE_SCREEN,
_(
"Audacity Audio"));
715 const std::shared_ptr<AudacityProject> &pProject )
739 int playbackChannels = 0;
742 playbackChannels = 2;
750 static_cast<unsigned int>(playbackChannels),
751 static_cast<unsigned int>(captureChannels));
756 auto msg =
XO(
"Error opening recording device.\nError code: %s")
759 XO(
"Error"), msg,
wxT(
"Error_opening_sound_device"),
776 pListener->OnAudioIORate((
int)
mRate);
781 double t0,
double t1,
double mixerLimit,
787 [](
const auto &pSequence){
789 pSequence ? pSequence->FindChannelGroup() : nullptr;
790 return pGroup && pGroup->IsLeader(); }
823 using namespace std::chrono;
824 std::this_thread::sleep_for(50ms);
832 gPrefs->
Read(
wxT(
"/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
834 if(silenceLevelDB < -dBRange)
836 silenceLevelDB = -dBRange + 3;
868 auto cleanupSequences =
finally([&]{
874 ext.AbortOtherStream();
892 unsigned int playbackChannels = 0;
893 size_t numCaptureChannels = 0;
895 double captureRate = 44100.0;
901 playbackChannels = 2;
904 playbackChannels = 2;
907 numCaptureChannels = accumulate(
909 [](
auto acc,
const auto &pSequence) {
910 return acc + pSequence->NChannels();
921 captureFormat = sequence0->GetSampleFormat();
922 captureRate = sequence0->GetRate();
926 pListener->OnAudioIOStartRecording();
940#ifdef EXPERIMENTAL_MIDI_OUT
942 successAudio = successAudio &&
943 std::all_of(range.begin(), range.end(),
944 [
this, &sequences, t0](
auto &ext){
945 return ext.StartOtherStream(sequences,
946 (mPortStreamV19 != NULL && mLastPaError == paNoError)
947 ? Pa_GetStreamInfo(mPortStreamV19) : nullptr,
952 if (pListener && numCaptureChannels > 0)
953 pListener->OnAudioIOStopRecording();
960 double mixerStart = t0;
962 mixerStart =
std::min( mixerStart, *pStartTime );
964 mixerStart, mixerLimit, options.
rate))
971#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
978 const auto time = *pStartTime;
986 mixer->Reposition( time );
998 .store(
true, std::memory_order_release);
1001 .load(std::memory_order_acquire)) {
1002 using namespace std::chrono;
1003 auto interval = 50ms;
1007 std::this_thread::sleep_for(interval);
1012#ifdef REALTIME_ALSA_THREAD
1050 if( err != paNoError )
1057 pListener->OnAudioIOStopRecording();
1069 pListener->OnAudioIORate((
int)
mRate);
1107 nextAction = std::move(action)
1108 ]{ prevAction(); nextAction(); };
1127 bool success =
false;
1128 auto cleanup =
finally([&]{
1155 wxASSERT( playbackTime >= 0 );
1175 auto playbackBufferSize =
1185 const size_t totalWidth = std::accumulate(
1187 [](
size_t acc,
const auto &pSequence){
1188 return acc + pSequence->NChannels(); });
1196 std::max<size_t>(1, totalWidth));
1204 reinterpret_cast<float*
>(buffer.ptr()));
1209 const auto &warpOptions =
1227 std::make_unique<RingBuffer>(
floatSample, playbackBufferSize);
1237 for (
size_t jj = 0, nChannels = pSequence->NChannels();
1238 jj < nChannels; ++jj
1245 assert(pSequence->FindChannelGroup());
1246 assert(pSequence->FindChannelGroup()->IsLeader());
1248 double startTime, endTime;
1255 .contains(pSequence))
1271 warpOptions, startTime, endTime, pSequence->NChannels(),
1281 const auto timeQueueSize = 1 +
1291 auto captureBufferSize =
1296 if(captureBufferSize < 100)
1317 catch(std::bad_alloc&)
1330 auto playbackBufferSize =
1370 return !pOwningProject || pOwningProject.get() == &
project;
1376 pInputMeter->Reset(
mRate,
true);
1378 pOutputMeter->Reset(
mRate,
true);
1383 auto cleanup =
finally ( [
this] {
1404#if (defined(__WXMAC__) || defined(__WXMSW__)) && wxCHECK_VERSION(3,1,0)
1410 .load(std::memory_order_relaxed) )
1420 using namespace std::chrono;
1421 std::this_thread::sleep_for(milliseconds{latency + 50});
1458 #if defined(USE_PORTMIXER)
1461 if (Px_SupportsPlaythrough(mPortMixer) && mPreviousHWPlaythrough >= 0.0)
1462 Px_SetPlaythrough(mPortMixer, mPreviousHWPlaythrough);
1463 mPreviousHWPlaythrough = -1.0;
1488 ext.StopOtherStream();
1558 std::optional<TransactionScope> pScope;
1560 pScope.emplace(*pOwningProject,
"Dropouts");
1562 auto &start = interval.first;
1563 auto duration = interval.second;
1566 sequence->InsertSilence(start, duration);
1574 pListener->OnCommitRecording();
1581 pInputMeter->Reset(
mRate,
false);
1584 pOutputMeter->Reset(
mRate,
false);
1591 pListener->OnAudioIOStopRecording();
1599 std::this_thread::yield();
1619 Publish({ pOwningProject.get(),
1636 pListener->OnAudioIORate(0);
1651 em.SetSuspended(state);
1655 mPaused.store(state, std::memory_order_relaxed);
1670 std::vector<long> rates;
1671 if (capturing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for capture"));
1672 if (playing) wxLogDebug(
wxT(
"AudioIO::GetBestRate() for playback"));
1673 wxLogDebug(
wxT(
"GetBestRate() suggested rate %.0lf Hz"),
sampleRate);
1675 if (capturing && !playing) {
1678 else if (playing && !capturing) {
1690 wxLogDebug(
wxT(
"GetBestRate() Returning %.0ld Hz"), rate);
1707 if (rates.empty()) {
1709 wxLogDebug(
wxT(
"GetBestRate() Error - no supported sample rates"));
1714 for (i = 0; i < (int)rates.size(); i++)
1716 if (rates[i] > rate) {
1718 wxLogDebug(
wxT(
"GetBestRate() Returning next higher rate - %.0ld Hz"), rates[i]);
1724 wxLogDebug(
wxT(
"GetBestRate() Returning highest rate - %.0ld Hz"), rates.back());
1725 retval = rates.back();
1756 enum class State { eUndefined, eOnce, eLoopRunning, eDoNothing, eMonitoring } lastState = State::eUndefined;
1758 while (!finish.load(std::memory_order_acquire)) {
1759 using Clock = std::chrono::steady_clock;
1760 auto loopPassStart = Clock::now();
1766 .store(
true, std::memory_order_relaxed);
1768 .load(std::memory_order_acquire) )
1772 .store(
false, std::memory_order_release);
1774 lastState = State::eOnce;
1777 .load(std::memory_order_relaxed))
1779 if (lastState != State::eLoopRunning)
1783 std::memory_order::memory_order_release);
1785 lastState = State::eLoopRunning;
1797 if ( (lastState == State::eLoopRunning)
1798 || (lastState == State::eMonitoring ) )
1803 std::memory_order::memory_order_release);
1805 lastState = State::eDoNothing;
1809 lastState = State::eMonitoring;
1814 .store(
false, std::memory_order_relaxed);
1816 std::this_thread::sleep_until( loopPassStart + interval );
1823 return std::accumulate(buffers.begin(), buffers.end(),
1824 std::numeric_limits<size_t>::max(),
1825 [pmf](
auto value,
auto &pBuffer){
1826 return std::min(value, (pBuffer.get()->*pmf)()); });
1834 return commonlyAvail -
std::min(
size_t(10), commonlyAvail);
1863 std::optional<RealtimeEffects::ProcessingScope> pScope;
1892 auto GetNeeded = [&]() ->
size_t {
1898 auto nNeeded = GetNeeded();
1917 auto available =
std::min( nAvailable,
1930 nNeeded = GetNeeded();
1940 std::optional<RealtimeEffects::ProcessingScope> &pScope,
size_t available)
1951 bool progress =
false;
1955 const auto &[frames, toProduce] = slice;
1956 progress = progress || toProduce > 0;
1966 size_t iSequence = 0;
1974 size_t produced = 0;
1976 produced = mixer->Process(toProduce);
1980 for (
size_t j = 0; j < nChannels; ++j) {
1981 auto warpedSamples = mixer->GetBuffer(j);
1983 warpedSamples,
floatSample, produced, frames - produced);
1995 available -= frames;
1999 frames, available );
2000 }
while (available && !done);
2008#define stackAllocate(T, count) static_cast<T*>(alloca(count * sizeof(T)))
2011 std::optional<RealtimeEffects::ProcessingScope> &pScope)
2024 const auto pGroup = vt->FindChannelGroup();
2028 const auto nChannels = std::min<size_t>(
2032 for (
unsigned iBlock : {0, 1}) {
2037 const auto pair = ringBuffer.GetUnflushed(iBlock);
2039 pointers[
iChannel] =
reinterpret_cast<float*
>(pair.first);
2045 assert(len == pair.second);
2055 memset((pointers[
iChannel++] = *scratch++), 0, len *
sizeof(
float));
2057 if (len && pScope) {
2058 auto discardable = pScope->Process(*pGroup, &pointers[0],
2066 auto discarded = ringBuffer.Unput(discardable);
2071 iBuffer += vt->NChannels();
2102 const auto remainingTime =
2105 const auto remainingSamples = remainingTime *
mRate;
2106 bool latencyCorrected =
true;
2108 double deltat = avail /
mRate;
2111 .load(std::memory_order_relaxed) ||
2114 bool newBlocks =
false;
2119 auto width = (*iter)->NChannels();
2126 width = (*iter)->NChannels();
2129 size_t discarded = 0;
2133 if (correction >= 0) {
2147 size_t size = floor(
2154 if (discarded <
size)
2157 latencyCorrected =
false;
2161 const float *pCrossfadeSrc =
nullptr;
2162 size_t crossfadeStart = 0, totalCrossfadeLength = 0;
2169 totalCrossfadeLength = data.size();
2170 if (totalCrossfadeLength) {
2173 if (crossfadeStart < totalCrossfadeLength)
2174 pCrossfadeSrc = data.data() + crossfadeStart;
2178 wxASSERT(discarded <= avail);
2179 size_t toGet = avail - discarded;
2198 if (
double(
size) > remainingSamples)
2199 size = floor(remainingSamples);
2217 if (
double(toGet) > remainingSamples)
2218 toGet = floor(remainingSamples);
2219 const auto results =
2222 size = results.second;
2226 if (pCrossfadeSrc) {
2228 size_t crossfadeLength =
std::min(
size, totalCrossfadeLength - crossfadeStart);
2229 if (crossfadeLength) {
2230 auto ratio = double(crossfadeStart) / totalCrossfadeLength;
2231 auto ratioStep = 1.0 / totalCrossfadeLength;
2232 auto pCrossfadeDst = (
float*)temp.
ptr();
2235 for (
size_t ii = 0; ii < crossfadeLength; ++ii) {
2236 *pCrossfadeDst = ratio * *pCrossfadeDst + (1.0 - ratio) * *pCrossfadeSrc;
2237 ++pCrossfadeSrc, ++pCrossfadeDst;
2245 newBlocks = (*iter)->Append(
2257 if (pListener && newBlocks)
2258 pListener->OnAudioIONewBlocks();
2279 const std::shared_ptr< AudioIOListener > &listener)
2288#ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT
2292void AudioIO::AILAInitialize() {
2293 gPrefs->
Read(
wxT(
"/AudioIO/AutomatedInputLevelAdjustment"), &mAILAActive,
false);
2294 gPrefs->
Read(
wxT(
"/AudioIO/TargetPeak"), &mAILAGoalPoint, AILA_DEF_TARGET_PEAK);
2295 gPrefs->
Read(
wxT(
"/AudioIO/DeltaPeakVolume"), &mAILAGoalDelta, AILA_DEF_DELTA_PEAK);
2296 gPrefs->
Read(
wxT(
"/AudioIO/AnalysisTime"), &mAILAAnalysisTime, AILA_DEF_ANALYSIS_TIME);
2297 gPrefs->
Read(
wxT(
"/AudioIO/NumberAnalysis"), &mAILATotalAnalysis, AILA_DEF_NUMBER_ANALYSIS);
2298 mAILAGoalDelta /= 100.0;
2299 mAILAGoalPoint /= 100.0;
2300 mAILAAnalysisTime /= 1000.0;
2303 mAILAClipped =
false;
2304 mAILAAnalysisCounter = 0;
2305 mAILAChangeFactor = 1.0;
2306 mAILALastChangeType = 0;
2307 mAILATopLevel = 1.0;
2308 mAILAAnalysisEndTime = -1.0;
2311void AudioIO::AILADisable() {
2312 mAILAActive =
false;
2315bool AudioIO::AILAIsActive() {
2319void AudioIO::AILASetStartTime() {
2321 wxPrintf(
"START TIME %f\n\n", mAILAAbsolutStartTime);
2324double AudioIO::AILAGetLastDecisionTime() {
2325 return mAILAAnalysisEndTime;
2328void AudioIO::AILAProcess(
double maxPeak) {
2330 if (proj && mAILAActive) {
2332 mAILAClipped =
true;
2333 wxPrintf(
"clipped");
2336 mAILAMax = max(mAILAMax, maxPeak);
2338 if ((mAILATotalAnalysis == 0 || mAILAAnalysisCounter < mAILATotalAnalysis) &&
mPlaybackSchedule.
GetSequenceTime() - mAILALastStartTime >= mAILAAnalysisTime) {
2339 auto ToLinearIfDB = [](
double value,
int dbRange) {
2341 value = pow(10.0, (-(1.0-value) * dbRange)/20.0);
2347 double iv = (double) Px_GetInputVolume(mPortMixer);
2348 unsigned short changetype = 0;
2349 wxPrintf(
"mAILAAnalysisCounter:%d\n", mAILAAnalysisCounter);
2350 wxPrintf(
"\tmAILAClipped:%d\n", mAILAClipped);
2351 wxPrintf(
"\tmAILAMax (linear):%f\n", mAILAMax);
2352 wxPrintf(
"\tmAILAGoalPoint:%f\n", mAILAGoalPoint);
2353 wxPrintf(
"\tmAILAGoalDelta:%f\n", mAILAGoalDelta);
2354 wxPrintf(
"\tiv:%f\n", iv);
2355 wxPrintf(
"\tmAILAChangeFactor:%f\n", mAILAChangeFactor);
2356 if (mAILAClipped || mAILAMax > mAILAGoalPoint + mAILAGoalDelta) {
2357 wxPrintf(
"too high:\n");
2358 mAILATopLevel =
min(mAILATopLevel, iv);
2359 wxPrintf(
"\tmAILATopLevel:%f\n", mAILATopLevel);
2361 if (iv <= LOWER_BOUND) {
2363 if (mAILATotalAnalysis != 0) {
2364 mAILAActive =
false;
2367"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too high.") );
2369 wxPrintf(
"\talready min vol:%f\n", iv);
2372 float vol = (float) max(LOWER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2373 Px_SetInputVolume(mPortMixer, vol);
2375"Automated Recording Level Adjustment decreased the volume to %f.").Format( vol );
2378 wxPrintf(
"\tnew vol:%f\n", vol);
2379 float check = Px_GetInputVolume(mPortMixer);
2380 wxPrintf(
"\tverified %f\n", check);
2383 else if ( mAILAMax < mAILAGoalPoint - mAILAGoalDelta ) {
2385 wxPrintf(
"too low:\n");
2386 if (iv >= UPPER_BOUND || iv + 0.005 > mAILATopLevel) {
2388 if (mAILATotalAnalysis != 0) {
2389 mAILAActive =
false;
2392"Automated Recording Level Adjustment stopped. It was not possible to optimize it more. Still too low.") );
2394 wxPrintf(
"\talready max vol:%f\n", iv);
2397 float vol = (float)
min(UPPER_BOUND, iv+(mAILAGoalPoint-mAILAMax)*mAILAChangeFactor);
2398 if (vol > mAILATopLevel) {
2399 vol = (iv + mAILATopLevel)/2.0;
2400 wxPrintf(
"\tTruncated vol:%f\n", vol);
2402 Px_SetInputVolume(mPortMixer, vol);
2404"Automated Recording Level Adjustment increased the volume to %.2f.")
2408 wxPrintf(
"\tnew vol:%f\n", vol);
2409 float check = Px_GetInputVolume(mPortMixer);
2410 wxPrintf(
"\tverified %f\n", check);
2414 mAILAAnalysisCounter++;
2420 mAILAAnalysisEndTime = Pa_GetStreamTime(
mPortStreamV19) - mAILAAbsolutStartTime;
2422 wxPrintf(
"\tA decision was made @ %f\n", mAILAAnalysisEndTime);
2423 mAILAClipped =
false;
2426 if (changetype == 0)
2427 mAILAChangeFactor *= 0.8;
2428 else if (mAILALastChangeType == changetype)
2429 mAILAChangeFactor *= 1.1;
2431 mAILAChangeFactor *= 0.7;
2432 mAILALastChangeType = changetype;
2436 if (mAILAActive && mAILATotalAnalysis != 0 && mAILAAnalysisCounter >= mAILATotalAnalysis) {
2437 mAILAActive =
false;
2438 if (mAILAMax > mAILAGoalPoint + mAILAGoalDelta)
2441"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too high.") );
2442 else if (mAILAMax < mAILAGoalPoint - mAILAGoalDelta)
2445"Automated Recording Level Adjustment stopped. The total number of analyses has been exceeded without finding an acceptable volume. Still too low.") );
2448"Automated Recording Level Adjustment stopped. %.2f seems an acceptable volume.")
2449 .Format( Px_GetInputVolume(mPortMixer) );
2459 unsigned inputChannels,
2460 float *outputBuffer,
2463 for (
unsigned int i=0; i < inputChannels; i++) {
2464 auto inputPtr = inputBuffer + (i *
SAMPLE_SIZE(inputFormat));
2467 outputBuffer + i, len, inputChannels, 2);
2471 if (inputChannels == 1)
2472 for (
int i=0; i < len; i++)
2473 outputBuffer[2*i + 1] = outputBuffer[2*i];
2477 unsigned long framesPerBuffer,
2478 const PaStreamCallbackTimeInfo *timeInfo,
2482 return gAudioIO->AudioCallback(
2484 static_cast<float*
>(outputBuffer), framesPerBuffer,
2485 timeInfo, statusFlags, userData);
2496 float *inputSamples,
2497 unsigned long framesPerBuffer
2506 float sample = fabs(*(inputSamples++));
2507 if (sample > maxPeak) {
2513 if( bShouldBePaused !=
IsPaused() )
2517 pListener->OnSoundActivationThreshold();
2524 float * outputMeterFloats,
2525 float * outputFloats,
2526 const float * tempBuf,
2528 const unsigned long len,
2540 if (outputMeterFloats != outputFloats)
2541 for (
unsigned i = 0; i < len; ++i)
2542 outputMeterFloats[numPlaybackChannels*i+chan] +=
2549 float oldGain = channelGain;
2560 float deltaGain = (gain - oldGain) / len;
2561 for (
unsigned i = 0; i < len; i++)
2562 outputFloats[numPlaybackChannels*i+chan] += (oldGain + deltaGain * i) *tempBuf[i];
2567 for(
unsigned i = 0; i < len; i++)
2568 pBuffer[i] = std::clamp(pBuffer[i], -1.0f, 1.0f);
2578 float *outputBuffer,
2579 unsigned long framesPerBuffer,
2580 float *outputMeterFloats
2592 numPlaybackChannels <= 0) {
2599 float *outputFloats = outputBuffer;
2611 const auto tempBufs =
stackAllocate(
float *, numPlaybackChannels);
2614 for (
unsigned int c = 0; c < numPlaybackChannels; c++)
2636 bool discardable =
false;
2639 for (
unsigned tt = 0; tt < numPlaybackSequences; ++tt) {
2641 const auto width = vt->NChannels();
2644 if (width < numPlaybackChannels)
2646 memset(tempBufs[1], 0, framesPerBuffer *
sizeof(
float));
2653 discardable = discardable &&
2656 decltype(framesPerBuffer) len = 0;
2658 for (
size_t c = 0; c < width; ++c) {
2668 if (len < framesPerBuffer)
2675 memset((
void*)&tempBufs[c][len], 0,
2676 (framesPerBuffer - len) *
sizeof(
float));
2703 tempBufs[0], drop, len, *vt, gains[0]);
2707 const auto iBuffer = std::min<size_t>(1, width - 1);
2709 tempBufs[iBuffer], drop, len, *vt, gains[1]);
2721 if (numPlaybackSequences == 0) {
2730 ClampBuffer( outputFloats, framesPerBuffer*numPlaybackChannels );
2731 if (outputMeterFloats != outputFloats)
2732 ClampBuffer( outputMeterFloats, framesPerBuffer*numPlaybackChannels );
2754 unsigned long framesPerBuffer,
2767 if( numCaptureChannels <= 0 )
2779 (statusFlags & (paInputOverflow))
2780 && !(statusFlags & paPrimingOutput);
2786 size_t len = framesPerBuffer;
2787 for(
unsigned t = 0; t < numCaptureChannels; t++)
2802 len < framesPerBuffer) ) {
2807 auto duration = (framesPerBuffer - len) /
mRate;
2811 fabs(pLast->first + pLast->second - start) < 0.5/
mRate)
2813 pLast->second = start + duration - pLast->first;
2818 if (len < framesPerBuffer)
2821 wxPrintf(
wxT(
"lost %d samples\n"), (
int)(framesPerBuffer - len));
2830 for(
unsigned t = 0; t < numCaptureChannels; t++) {
2840 auto inputFloats = (
const float *)inputBuffer;
2841 for(
unsigned i = 0; i < len; i++)
2843 inputFloats[numCaptureChannels*i+t];
2853 auto inputShorts = (
const short *)inputBuffer;
2854 short *tempShorts = (
short *)tempFloats;
2855 for(
unsigned i = 0; i < len; i++) {
2856 float tmp = inputShorts[numCaptureChannels*i+t];
2857 tmp = std::clamp(tmp, -32768.0f, 32767.0f);
2858 tempShorts[i] = (short)(tmp);
2881void OldCodeToCalculateLatency()
2894 if (numCaptureChannels > 0 && numPlaybackChannels > 0)
2896 if (timeInfo->inputBufferAdcTime > 0)
2897 mLastRecordingOffset = timeInfo->inputBufferAdcTime - timeInfo->outputBufferDacTime;
2898 else if (mLastRecordingOffset == 0.0)
2900 const PaStreamInfo* si = Pa_GetStreamInfo( mPortStreamV19 );
2901 mLastRecordingOffset = -si->inputLatency;
2912 float *outputBuffer,
2913 unsigned long framesPerBuffer,
2914 float *outputMeterFloats
2923 if( numPlaybackChannels <= 0 )
2926 float *outputFloats = outputBuffer;
2927 for(
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
2928 outputFloats[i] = 0.0;
2933 outputBuffer, framesPerBuffer);
2937 if (outputMeterFloats != outputFloats) {
2938 for (
unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i) {
2939 outputMeterFloats[i] = outputFloats[i];
2947 const float *inputSamples,
2948 unsigned long framesPerBuffer
2955 if( pInputMeter->IsMeterDisabled())
2957 pInputMeter->UpdateDisplay(
2958 numCaptureChannels, framesPerBuffer, inputSamples);
2963 const float *outputMeterFloats,
2964 unsigned long framesPerBuffer)
2971 if( pOutputMeter->IsMeterDisabled() )
2973 if( !outputMeterFloats)
2975 pOutputMeter->UpdateDisplay(
2976 numPlaybackChannels, framesPerBuffer, outputMeterFloats);
2994 unsigned numSolo = 0;
2995 for (
unsigned t = 0; t < numPlaybackSequences; t++ )
2999 numSolo += std::accumulate(range.begin(), range.end(), 0,
3000 [](
unsigned sum,
auto &ext){
3001 return sum + ext.CountOtherSolo(); });
3024 return gains[0] == 0.0 && gains[1] == 0.0;
3041 for (
auto &
factory: factories)
3054 unsigned long framesPerBuffer,
3055 const PaStreamCallbackTimeInfo *timeInfo,
3076 ext.FillOtherBuffers(
3086 framesPerBuffer * std::max(numCaptureChannels, numPlaybackChannels));
3088 bool bVolEmulationActive =
3093 const auto outputMeterFloats = bVolEmulationActive
3094 ?
stackAllocate(
float, framesPerBuffer * numPlaybackChannels)
3098 if (inputBuffer && numCaptureChannels) {
3099 float *inputSamples;
3102 inputSamples = (
float *) inputBuffer;
3106 mCaptureFormat, tempFloats, framesPerBuffer * numCaptureChannels);
3107 inputSamples = tempFloats;
3187 .store(
false, std::memory_order_relaxed);
3190 .load(std::memory_order_relaxed ) )
3192 using namespace std::chrono;
3193 std::this_thread::sleep_for(50ms);
3206 mixer->Reposition( time,
true );
3208 const auto toDiscard = buffer->AvailForGet();
3209 const auto discarded = buffer->Discard( toDiscard );
3212 wxUnusedVar(discarded);
3222 .store(
true, std::memory_order_relaxed);
3228 int &callbackReturn,
unsigned long len)
3239 ext.SignalOtherCompletion();
3240 callbackReturn = paComplete;
3260 using namespace std::chrono;
3261 std::this_thread::sleep_for(50ms);
3275 using namespace std::chrono;
3276 std::this_thread::sleep_for(50ms);
3284 .store(
true, std::memory_order_release);
3287 .load(std::memory_order_acquire))
3289 using namespace std::chrono;
3290 std::this_thread::sleep_for(sleepTime);
3300 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.
virtual bool IsLeader() const =0
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
static RegisteredToolbarFactory factory
struct holding stream options, including a pointer to the time warp info and AudioIOListener and whet...
std::function< std::chrono::milliseconds() > playbackStreamPrimer
std::shared_ptr< AudacityProject > pProject
std::weak_ptr< Meter > captureMeter
std::weak_ptr< Meter > playbackMeter
PRCrossfadeData * pCrossfadeData
std::optional< double > pStartTime
std::shared_ptr< AudioIOListener > listener
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