Detect out-of-range samples on output and restart with lower gain
This commit is contained in:
@@ -121,6 +121,8 @@ int main(int argc, char **argv)
|
|||||||
SoftDetector
|
SoftDetector
|
||||||
} detector = CompoundDetector;
|
} detector = CompoundDetector;
|
||||||
|
|
||||||
|
bool ignoreClipping = false;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int optionIndex = 0;
|
int optionIndex = 0;
|
||||||
|
|
||||||
@@ -155,6 +157,7 @@ int main(int argc, char **argv)
|
|||||||
{ "timemap", 1, 0, 'M' },
|
{ "timemap", 1, 0, 'M' },
|
||||||
{ "freqmap", 1, 0, 'Q' },
|
{ "freqmap", 1, 0, 'Q' },
|
||||||
{ "pitchmap", 1, 0, 'C' },
|
{ "pitchmap", 1, 0, 'C' },
|
||||||
|
{ "ignore-clipping", 0, 0, 'i' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,6 +196,7 @@ int main(int argc, char **argv)
|
|||||||
case 'M': timeMapFile = optarg; break;
|
case 'M': timeMapFile = optarg; break;
|
||||||
case 'Q': freqMapFile = optarg; freqOrPitchMapSpecified = true; break;
|
case 'Q': freqMapFile = optarg; freqOrPitchMapSpecified = true; break;
|
||||||
case 'C': pitchMapFile = optarg; freqOrPitchMapSpecified = true; break;
|
case 'C': pitchMapFile = optarg; freqOrPitchMapSpecified = true; break;
|
||||||
|
case 'i': ignoreClipping = true; break;
|
||||||
default: help = true; break;
|
default: help = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,6 +287,8 @@ int main(int argc, char **argv)
|
|||||||
cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl;
|
cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl;
|
||||||
cerr << " --centre-focus Preserve focus of centre material in stereo" << endl;
|
cerr << " --centre-focus Preserve focus of centre material in stereo" << endl;
|
||||||
cerr << " (at a cost in width and individual channel quality)" << endl;
|
cerr << " (at a cost in width and individual channel quality)" << endl;
|
||||||
|
cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl;
|
||||||
|
cerr << " with reduced gain if clipping occurs" << endl;
|
||||||
cerr << endl;
|
cerr << endl;
|
||||||
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
|
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
|
||||||
cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
|
cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
|
||||||
@@ -554,14 +560,24 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
RubberBandStretcher::setDefaultDebugLevel(debug);
|
RubberBandStretcher::setDefaultDebugLevel(debug);
|
||||||
|
|
||||||
|
size_t countIn = 0, countOut = 0;
|
||||||
|
|
||||||
|
float gain = 1.f;
|
||||||
|
bool successful = false;
|
||||||
|
|
||||||
|
while (!successful) { // we may have to repeat with a modified
|
||||||
|
// gain, if clipping occurs
|
||||||
|
successful = true;
|
||||||
|
|
||||||
RubberBandStretcher ts(sfinfo.samplerate, channels, options,
|
RubberBandStretcher ts(sfinfo.samplerate, channels, options,
|
||||||
ratio, frequencyshift);
|
ratio, frequencyshift);
|
||||||
|
|
||||||
ts.setExpectedInputDuration(sfinfo.frames);
|
ts.setExpectedInputDuration(sfinfo.frames);
|
||||||
|
|
||||||
float *fbuf = new float[channels * ibs];
|
float *fbuf = new float[channels * ibs];
|
||||||
float **ibuf = new float *[channels];
|
float **ibuf = new float *[channels];
|
||||||
for (size_t i = 0; i < channels; ++i) ibuf[i] = new float[ibs];
|
for (size_t i = 0; i < channels; ++i) {
|
||||||
|
ibuf[i] = new float[ibs];
|
||||||
|
}
|
||||||
|
|
||||||
int frame = 0;
|
int frame = 0;
|
||||||
int percent = 0;
|
int percent = 0;
|
||||||
@@ -618,7 +634,9 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
std::map<size_t, double>::const_iterator freqMapItr = freqMap.begin();
|
std::map<size_t, double>::const_iterator freqMapItr = freqMap.begin();
|
||||||
|
|
||||||
size_t countIn = 0, countOut = 0;
|
countIn = 0;
|
||||||
|
countOut = 0;
|
||||||
|
bool clipping = false;
|
||||||
|
|
||||||
while (frame < sfinfo.frames) {
|
while (frame < sfinfo.frames) {
|
||||||
|
|
||||||
@@ -645,7 +663,9 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((count = sf_readf_float(sndfile, fbuf, thisBlockSize)) < 0) break;
|
if ((count = sf_readf_float(sndfile, fbuf, thisBlockSize)) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
countIn += count;
|
countIn += count;
|
||||||
|
|
||||||
@@ -677,19 +697,19 @@ int main(int argc, char **argv)
|
|||||||
float *fobf = new float[channels * avail];
|
float *fobf = new float[channels * avail];
|
||||||
for (size_t c = 0; c < channels; ++c) {
|
for (size_t c = 0; c < channels; ++c) {
|
||||||
for (int i = 0; i < avail; ++i) {
|
for (int i = 0; i < avail; ++i) {
|
||||||
float value = obf[c][i];
|
float value = gain * obf[c][i];
|
||||||
|
if (ignoreClipping) { // i.e. just clamp, don't bail out
|
||||||
if (value > 1.f) value = 1.f;
|
if (value > 1.f) value = 1.f;
|
||||||
if (value < -1.f) value = -1.f;
|
if (value < -1.f) value = -1.f;
|
||||||
|
} else {
|
||||||
|
if (value >= 1.f || value < -1.f) {
|
||||||
|
clipping = true;
|
||||||
|
gain = (0.999f / fabsf(obf[c][i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
fobf[i * channels + c] = value;
|
fobf[i * channels + c] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cout << "fobf mean: ";
|
|
||||||
// double d = 0;
|
|
||||||
// for (int i = 0; i < avail; ++i) {
|
|
||||||
// d += fobf[i];
|
|
||||||
// }
|
|
||||||
// d /= avail;
|
|
||||||
// cout << d << endl;
|
|
||||||
sf_writef_float(sndfileOut, fobf, avail);
|
sf_writef_float(sndfileOut, fobf, avail);
|
||||||
delete[] fobf;
|
delete[] fobf;
|
||||||
for (size_t i = 0; i < channels; ++i) {
|
for (size_t i = 0; i < channels; ++i) {
|
||||||
@@ -698,6 +718,17 @@ int main(int argc, char **argv)
|
|||||||
delete[] obf;
|
delete[] obf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clipping) {
|
||||||
|
if (!quiet) {
|
||||||
|
cerr << "NOTE: Clipping detected at output sample "
|
||||||
|
<< countOut << ", restarting with "
|
||||||
|
<< "reduced gain of " << gain
|
||||||
|
<< " (supply --ignore-clipping to avoid this)" << endl;
|
||||||
|
}
|
||||||
|
successful = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (frame == 0 && !realtime && !quiet) {
|
if (frame == 0 && !realtime && !quiet) {
|
||||||
cerr << "Pass 2: Processing..." << endl;
|
cerr << "Pass 2: Processing..." << endl;
|
||||||
}
|
}
|
||||||
@@ -713,6 +744,12 @@ int main(int argc, char **argv)
|
|||||||
frame += thisBlockSize;
|
frame += thisBlockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!successful) {
|
||||||
|
sf_seek(sndfile, 0, SEEK_SET);
|
||||||
|
sf_seek(sndfileOut, 0, SEEK_SET);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
cerr << "\r " << endl;
|
cerr << "\r " << endl;
|
||||||
}
|
}
|
||||||
@@ -734,7 +771,7 @@ int main(int argc, char **argv)
|
|||||||
float *fobf = new float[channels * avail];
|
float *fobf = new float[channels * avail];
|
||||||
for (size_t c = 0; c < channels; ++c) {
|
for (size_t c = 0; c < channels; ++c) {
|
||||||
for (int i = 0; i < avail; ++i) {
|
for (int i = 0; i < avail; ++i) {
|
||||||
float value = obf[c][i];
|
float value = gain * obf[c][i];
|
||||||
if (value > 1.f) value = 1.f;
|
if (value > 1.f) value = 1.f;
|
||||||
if (value < -1.f) value = -1.f;
|
if (value < -1.f) value = -1.f;
|
||||||
fobf[i * channels + c] = value;
|
fobf[i * channels + c] = value;
|
||||||
@@ -751,6 +788,7 @@ int main(int argc, char **argv)
|
|||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sf_close(sndfile);
|
sf_close(sndfile);
|
||||||
sf_close(sndfileOut);
|
sf_close(sndfileOut);
|
||||||
|
|||||||
Reference in New Issue
Block a user