Attempt to "fade in" phase resets on return to unity, so as to return to an approximate pass-through without too audible a click

This commit is contained in:
Chris Cannam
2022-06-17 15:01:26 +01:00
parent bcdd1149df
commit 380cad53b4
4 changed files with 104 additions and 30 deletions

View File

@@ -147,37 +147,37 @@ public:
const BinSegmenter::Segmentation &segmentation,
const BinSegmenter::Segmentation &prevSegmentation,
const BinSegmenter::Segmentation &nextSegmentation,
bool specialCaseUnity,
double meanMagnitude,
int unityCount,
Guidance &guidance) const {
bool hadPhaseReset = guidance.phaseReset.present;
guidance.phaseReset.present = false;
guidance.kick.present = false;
guidance.preKick.present = false;
guidance.highUnlocked.present = false;
guidance.phaseReset.present = false;
guidance.channelLock.present = false;
double nyquist = m_parameters.sampleRate / 2.0;
guidance.fftBands[0].fftSize = roundUp(int(ceil(nyquist/8.0)));
guidance.fftBands[1].fftSize = roundUp(int(ceil(nyquist/16.0)));
guidance.fftBands[2].fftSize = roundUp(int(ceil(nyquist/32.0)));
if (specialCaseUnity && (fabs(ratio - 1.0) < 1.0e-6)) {
guidance.fftBands[0].f0 = 0.0;
guidance.fftBands[0].f1 = 0.0;
guidance.fftBands[1].f0 = 0.0;
guidance.fftBands[1].f1 = m_minHigher;
guidance.fftBands[2].f0 = m_minHigher;
guidance.fftBands[2].f1 = nyquist;
for (int i = 0; i < int(sizeof(guidance.phaseLockBands) /
sizeof(guidance.phaseLockBands[0])); ++i) {
guidance.phaseLockBands[i].p = 0;
guidance.phaseLockBands[i].beta = 1.0;
guidance.phaseLockBands[i].f0 = nyquist;
guidance.phaseLockBands[i].f1 = nyquist;
}
guidance.phaseLockBands[0].f0 = 0.0;
guidance.phaseLockBands[0].f1 = nyquist;
guidance.channelLock.present = false;
// This is a vital stop case for PhaseAdvance
guidance.phaseLockBands[3].f1 = nyquist;
if (meanMagnitude < 1.0e-6) {
updateForSilence(guidance);
return;
}
if (unityCount > 0) {
updateForUnity(guidance,
hadPhaseReset,
unityCount,
magnitudes,
segmentation);
return;
}
@@ -351,7 +351,69 @@ protected:
value = 1 << bits;
return value;
}
void updateForSilence(Guidance &guidance) const {
// std::cout << "phase reset on silence" << std::endl;
double nyquist = m_parameters.sampleRate / 2.0;
guidance.fftBands[0].f0 = 0.0;
guidance.fftBands[0].f1 = 0.0;
guidance.fftBands[1].f0 = 0.0;
guidance.fftBands[1].f1 = nyquist;
guidance.fftBands[2].f0 = nyquist;
guidance.fftBands[2].f1 = nyquist;
guidance.phaseReset.present = true;
guidance.phaseReset.f0 = 0.0;
guidance.phaseReset.f1 = nyquist;
}
void updateForUnity(Guidance &guidance,
bool hadPhaseReset,
uint32_t unityCount,
const double *const magnitudes,
const BinSegmenter::Segmentation &segmentation) const {
// std::cout << "unity" << std::endl;
double nyquist = m_parameters.sampleRate / 2.0;
guidance.fftBands[0].f0 = 0.0;
guidance.fftBands[0].f1 = m_minLower;
guidance.fftBands[1].f0 = m_minLower;
guidance.fftBands[1].f1 = m_minHigher;
guidance.fftBands[2].f0 = m_minHigher;
guidance.fftBands[2].f1 = nyquist;
guidance.phaseReset.present = true;
if (!hadPhaseReset) {
guidance.phaseReset.f0 = 16000.0;
guidance.phaseReset.f1 = nyquist;
// std::cout << "f0 = " << guidance.phaseReset.f0 << std::endl;
return;
} else {
guidance.phaseReset.f0 *= 0.9;
guidance.phaseReset.f1 *= 1.1;
}
if (guidance.phaseReset.f0 < segmentation.residualAbove) {
guidance.phaseReset.f0 = std::min(guidance.phaseReset.f0,
segmentation.percussiveAbove);
}
if (guidance.phaseReset.f1 > 16000.0) {
guidance.phaseReset.f1 = nyquist;
}
if (guidance.phaseReset.f0 < 100.0) {
guidance.phaseReset.f0 = 0.0;
}
// if (guidance.phaseReset.f0 > 0.0) {
// std::cout << unityCount << ": f0 = " << guidance.phaseReset.f0
// << ", f1 = " << guidance.phaseReset.f1 << std::endl;
// }
}
bool checkPotentialKick(const double *const magnitudes,
const double *const prevMagnitudes) const {
int b = binForFrequency(200.0, m_configuration.classificationFftSize,

View File

@@ -186,19 +186,20 @@ public:
++phaseLockBand;
}
double ph = 0.0;
if (inhop == outhop) {
ph = m_unlocked[c][i];
} else if (inRange(f, g->phaseReset) || inRange(f, g->kick)) {
if (inRange(f, g->phaseReset) || inRange(f, g->kick)) {
ph = phase[c][i];
} else if (inhop == outhop) {
ph = m_unlocked[c][i];
} else if (inRange (f, g->highUnlocked)) {
ph = m_unlocked[c][i];
} else {
int peak = m_currentPeaks[c][i];
int prevPeak = m_prevPeaks[c][peak];
int peakCh = c;
if (inRange (f, g->channelLock)) {
if (inRange(f, g->channelLock)) {
int other = m_greatestChannel[i];
if (other != c) {
if (other != c &&
inRange(f, guidance[other]->channelLock)) {
int otherPeak = m_currentPeaks[other][i];
int otherPrevPeak = m_prevPeaks[other][otherPeak];
if (otherPrevPeak == prevPeak) {
@@ -216,7 +217,7 @@ public:
double(g->phaseLockBands[phaseLockBand].beta);
ph = peakNew + beta * diff;
}
outPhase[c][i] = ph;
outPhase[c][i] = princarg(ph);
}
}

View File

@@ -40,7 +40,9 @@ R3StretcherImpl::R3StretcherImpl(Parameters parameters,
m_guideConfiguration(m_guide.getConfiguration()),
m_channelAssembly(m_parameters.channels),
m_inhop(1),
m_prevInhop(1),
m_prevOuthop(1),
m_unityCount(0),
m_startSkip(0),
m_studyInputDuration(0),
m_totalTargetDuration(0),
@@ -826,9 +828,16 @@ R3StretcherImpl::analyseChannel(int c, int inhop, int prevInhop, int prevOuthop)
std::cout << std::endl;
}
*/
bool specialCaseUnity = true;
double ratio = getEffectiveRatio();
if (fabs(ratio - 1.0) < 1.0e-6) {
++m_unityCount;
} else {
m_unityCount = 0;
}
m_guide.updateGuidance(getEffectiveRatio(),
m_guide.updateGuidance(ratio,
prevOuthop,
classifyScale->mag.data(),
classifyScale->prevMag.data(),
@@ -836,7 +845,8 @@ R3StretcherImpl::analyseChannel(int c, int inhop, int prevInhop, int prevOuthop)
cd->segmentation,
cd->prevSegmentation,
cd->nextSegmentation,
specialCaseUnity,
v_mean(classifyScale->mag.data() + 1, classify/2),
m_unityCount,
cd->guidance);
/*
if (c == 0) {

View File

@@ -281,6 +281,7 @@ protected:
std::atomic<int> m_inhop;
int m_prevInhop;
int m_prevOuthop;
uint32_t m_unityCount;
int m_startSkip;
size_t m_studyInputDuration;