From 1d43578335e2dd8dca7cf6eb21fd0809ca775fe2 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 14 Oct 2026 19:16:45 +0200 Subject: [PATCH] Expose optional live source tracking through SoundTouch --- .../include/soundtouch/SoundTouch.h | 10 ++++++ .../source/SoundTouch/SoundTouch.cpp | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/lib/soundtouch-master/include/soundtouch/SoundTouch.h b/lib/soundtouch-master/include/soundtouch/SoundTouch.h index 079d4094..dd98fe0f 100644 --- a/lib/soundtouch-master/include/soundtouch/SoundTouch.h +++ b/lib/soundtouch-master/include/soundtouch/SoundTouch.h @@ -67,6 +67,7 @@ #include "FIFOSamplePipe.h" #include "STTypes.h" +#include "SourceSpan.h" namespace soundtouch { @@ -197,6 +198,8 @@ private: /// 'virtualPitch' parameters. void calcEffectiveRateAndTempo(); + bool sourceProfileSupported() const; + protected : /// Number of channels uint channels; @@ -211,6 +214,13 @@ public: SoundTouch(); ~SoundTouch() override; + /* uTun: подключать после настройки, до первого putSamples либо после clear. + * Поддерживается float PCM, unity pitch/rate, cubic interpolation, AA off, mono/stereo. + * Ошибка сообщает Invalid и возвращает false. Изменение профиля после начала и flush + * инвалидируют карту; clear начинает новую. nullptr отключает события в любой момент. + * События описывают произведённый выход, включая ещё не прочитанные receiveSamples данные. */ + bool setSourceCallback(SourceCallback callback, void* context); + /// Get SoundTouch library version string static const char *getVersionString(); diff --git a/lib/soundtouch-master/source/SoundTouch/SoundTouch.cpp b/lib/soundtouch-master/source/SoundTouch/SoundTouch.cpp index 0eda80ae..f04b564d 100644 --- a/lib/soundtouch-master/source/SoundTouch/SoundTouch.cpp +++ b/lib/soundtouch-master/source/SoundTouch/SoundTouch.cpp @@ -117,6 +117,28 @@ SoundTouch::~SoundTouch() delete pTDStretch; } +bool SoundTouch::sourceProfileSupported() const +{ +#if defined(SOUNDTOUCH_FLOAT_SAMPLES) && !defined(SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER) + return rate == 1.0 && virtualPitch == 1.0 && channels >= 1 && channels <= 2 + && bSrateSet && pRateTransposer->unitySourceOffset() >= 0; +#else + return false; +#endif +} + +bool SoundTouch::setSourceCallback(SourceCallback callback, void* context) +{ + if (!callback) { pTDStretch->setSourceCallback(nullptr, nullptr, 0); return true; } + if (samplesExpectedOut != 0 || !sourceProfileSupported()) + { + callback(context, {SourceKind::Invalid, samplesExpectedOut != 0 ? SourceError::LateAttach : SourceError::Profile}); + return false; + } + pTDStretch->setSourceCallback(callback, context, (unsigned)pRateTransposer->unitySourceOffset()); + return true; +} + /// Get SoundTouch library version string const char *SoundTouch::getVersionString() @@ -139,6 +161,8 @@ void SoundTouch::setChannels(uint numChannels) { if (!verifyNumberOfChannels(numChannels)) return; + if (samplesExpectedOut != 0) pTDStretch->invalidateSource(SourceError::Reconfigure); + channels = numChannels; pRateTransposer->setChannels((int)numChannels); pTDStretch->setChannels((int)numChannels); @@ -223,6 +247,8 @@ void SoundTouch::calcEffectiveRateAndTempo() tempo = virtualTempo / virtualPitch; rate = virtualPitch * virtualRate; + if (rate != 1.0 || virtualPitch != 1.0) pTDStretch->invalidateSource(SourceError::Profile); + if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); @@ -266,6 +292,7 @@ void SoundTouch::calcEffectiveRateAndTempo() // Sets sample rate. void SoundTouch::setSampleRate(uint srate) { + if (samplesExpectedOut != 0) pTDStretch->invalidateSource(SourceError::Reconfigure); // set sample rate, leave other tempo changer parameters as they are. pTDStretch->setParameters((int)srate); bSrateSet = true; @@ -285,6 +312,8 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined"); } + if (!sourceProfileSupported()) pTDStretch->invalidateSource(SourceError::Profile); + // accumulate how many samples are expected out from processing, given the current // processing setting samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo); @@ -317,6 +346,8 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) // in the middle of a sound stream. void SoundTouch::flush() { + // Padding и обрезка финального выхода не входят в контракт live-карты. + pTDStretch->invalidateSource(SourceError::Flush); int i; int numStillExpected; SAMPLETYPE *buff = new SAMPLETYPE[128 * channels]; @@ -350,6 +381,8 @@ void SoundTouch::flush() // 'SETTING_...' defines for available setting ID's. bool SoundTouch::setSetting(int settingId, int value) { + if (samplesExpectedOut != 0 && settingId != SETTING_USE_QUICKSEEK) + pTDStretch->invalidateSource(SourceError::Reconfigure); int sampleRate, sequenceMs, seekWindowMs, overlapMs; // read current tdstretch routine parameters