Fix some warnings, support random seed

This commit is contained in:
Geraint 2023-05-06 23:03:18 +01:00
parent 37db3a75a4
commit d1bc2e358d

View File

@ -16,6 +16,7 @@ template<typename Sample=float>
struct SignalsmithStretch { struct SignalsmithStretch {
SignalsmithStretch() : randomEngine(std::random_device{}()) {} SignalsmithStretch() : randomEngine(std::random_device{}()) {}
SignalsmithStretch(long seed) : randomEngine(seed) {}
int blockSamples() const { int blockSamples() const {
return stft.windowSize(); return stft.windowSize();
@ -165,10 +166,10 @@ struct SignalsmithStretch {
} }
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
auto bands = bandsForChannel(c); auto channelBands = bandsForChannel(c);
auto &&spectrumBands = stft.spectrum[c]; auto &&spectrumBands = stft.spectrum[c];
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < stft.bands(); ++b) {
bands[b].input = signalsmith::perf::mul(spectrumBands[b], rotCentreSpectrum[b]); channelBands[b].input = signalsmith::perf::mul(spectrumBands[b], rotCentreSpectrum[b]);
} }
} }
@ -188,10 +189,10 @@ struct SignalsmithStretch {
stft.analyse(c, timeBuffer); stft.analyse(c, timeBuffer);
} }
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
auto bands = bandsForChannel(c); auto channelBands = bandsForChannel(c);
auto &&spectrumBands = stft.spectrum[c]; auto &&spectrumBands = stft.spectrum[c];
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < stft.bands(); ++b) {
bands[b].prevInput = signalsmith::perf::mul(spectrumBands[b], rotCentreSpectrum[b]); channelBands[b].prevInput = signalsmith::perf::mul(spectrumBands[b], rotCentreSpectrum[b]);
} }
} }
} }
@ -201,10 +202,10 @@ struct SignalsmithStretch {
processSpectrum(newSpectrum, timeFactor); processSpectrum(newSpectrum, timeFactor);
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
auto bands = bandsForChannel(c); auto channelBands = bandsForChannel(c);
auto &&spectrumBands = stft.spectrum[c]; auto &&spectrumBands = stft.spectrum[c];
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < stft.bands(); ++b) {
spectrumBands[b] = signalsmith::perf::mul<true>(bands[b].output, rotCentreSpectrum[b]); spectrumBands[b] = signalsmith::perf::mul<true>(channelBands[b].output, rotCentreSpectrum[b]);
} }
} }
}); });
@ -338,13 +339,14 @@ private:
void processSpectrum(bool newSpectrum, Sample timeFactor) { void processSpectrum(bool newSpectrum, Sample timeFactor) {
int bands = stft.bands(); int bands = stft.bands();
timeFactor = std::max<Sample>(timeFactor, 1/maxCleanStretch);
bool randomTimeFactor = (timeFactor > maxCleanStretch); bool randomTimeFactor = (timeFactor > maxCleanStretch);
std::uniform_real_distribution<Sample> timeFactorDist(maxCleanStretch*2 - timeFactor, timeFactor); std::uniform_real_distribution<Sample> timeFactorDist(maxCleanStretch*2 - timeFactor, timeFactor);
if (newSpectrum) { if (newSpectrum) {
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
auto bins = bandsForChannel(c); auto bins = bandsForChannel(c);
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
auto &bin = bins[b]; auto &bin = bins[b];
bin.prevOutput = signalsmith::perf::mul(bin.prevOutput, rotPrevInterval[b]); bin.prevOutput = signalsmith::perf::mul(bin.prevOutput, rotPrevInterval[b]);
bin.prevInput = signalsmith::perf::mul(bin.prevInput, rotPrevInterval[b]); bin.prevInput = signalsmith::perf::mul(bin.prevInput, rotPrevInterval[b]);
@ -355,13 +357,13 @@ private:
Sample smoothingBins = Sample(stft.fftSize())/stft.interval(); Sample smoothingBins = Sample(stft.fftSize())/stft.interval();
int longVerticalStep = std::round(smoothingBins); int longVerticalStep = std::round(smoothingBins);
findPeaks(smoothingBins); findPeaks(smoothingBins);
updateOutputMap(smoothingBins); updateOutputMap();
// Preliminary output prediction from phase-vocoder // Preliminary output prediction from phase-vocoder
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
Band *bins = bandsForChannel(c); Band *bins = bandsForChannel(c);
auto *predictions = predictionsForChannel(c); auto *predictions = predictionsForChannel(c);
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
auto mapPoint = outputMap[b]; auto mapPoint = outputMap[b];
int lowIndex = std::floor(mapPoint.inputBin); int lowIndex = std::floor(mapPoint.inputBin);
Sample fracIndex = mapPoint.inputBin - std::floor(mapPoint.inputBin); Sample fracIndex = mapPoint.inputBin - std::floor(mapPoint.inputBin);
@ -395,7 +397,7 @@ private:
} }
// Re-predict using phase differences between frequencies // Re-predict using phase differences between frequencies
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
// Find maximum-energy channel and calculate that // Find maximum-energy channel and calculate that
int maxChannel = 0; int maxChannel = 0;
Sample maxEnergy = predictionsForChannel(0)[b].energy; Sample maxEnergy = predictionsForChannel(0)[b].energy;
@ -411,7 +413,6 @@ private:
auto &prediction = predictions[b]; auto &prediction = predictions[b];
auto *bins = bandsForChannel(maxChannel); auto *bins = bandsForChannel(maxChannel);
auto &outputBin = bins[b]; auto &outputBin = bins[b];
auto mapPoint = outputMap[b];
Complex phase = 0; Complex phase = 0;
@ -426,12 +427,12 @@ private:
} }
} }
// Downwards vertical steps // Downwards vertical steps
if (b < stft.bands() - 1) { if (b < bands - 1) {
auto &upPrediction = predictions[b + 1]; auto &upPrediction = predictions[b + 1];
auto &upBin = bins[b + 1]; auto &upBin = bins[b + 1];
phase += signalsmith::perf::mul<true>(upBin.output, upPrediction.shortVerticalTwist); phase += signalsmith::perf::mul<true>(upBin.output, upPrediction.shortVerticalTwist);
if (b < stft.bands() - longVerticalStep) { if (b < bands - longVerticalStep) {
auto &longUpPrediction = predictions[b + longVerticalStep]; auto &longUpPrediction = predictions[b + longVerticalStep];
auto &longUpBin = bins[b + longVerticalStep]; auto &longUpBin = bins[b + longVerticalStep];
phase += signalsmith::perf::mul<true>(longUpBin.output, longUpPrediction.longVerticalTwist); phase += signalsmith::perf::mul<true>(longUpBin.output, longUpPrediction.longVerticalTwist);
@ -465,26 +466,27 @@ private:
// Produces smoothed energy across all channels // Produces smoothed energy across all channels
void smoothEnergy(Sample smoothingBins) { void smoothEnergy(Sample smoothingBins) {
int bands = stft.bands();
Sample smoothingSlew = 1/(1 + smoothingBins*Sample(0.5)); Sample smoothingSlew = 1/(1 + smoothingBins*Sample(0.5));
for (auto &e : energy) e = 0; for (auto &e : energy) e = 0;
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
Band *bins = bandsForChannel(c); Band *bins = bandsForChannel(c);
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
Sample e = std::norm(bins[b].input); Sample e = std::norm(bins[b].input);
bins[b].inputEnergy = e; // Used for interpolating prediction energy bins[b].inputEnergy = e; // Used for interpolating prediction energy
energy[b] += e; energy[b] += e;
} }
} }
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
smoothedEnergy[b] = energy[b]; smoothedEnergy[b] = energy[b];
} }
Sample e = 0; Sample e = 0;
for (int repeat = 0; repeat < 2; ++repeat) { for (int repeat = 0; repeat < 2; ++repeat) {
for (int b = stft.bands() - 1; b >= 0; --b) { for (int b = bands - 1; b >= 0; --b) {
e += (smoothedEnergy[b] - e)*smoothingSlew; e += (smoothedEnergy[b] - e)*smoothingSlew;
smoothedEnergy[b] = e; smoothedEnergy[b] = e;
} }
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
e += (smoothedEnergy[b] - e)*smoothingSlew; e += (smoothedEnergy[b] - e)*smoothingSlew;
smoothedEnergy[b] = e; smoothedEnergy[b] = e;
} }
@ -506,12 +508,12 @@ private:
peaks.resize(0); peaks.resize(0);
int start = 0; int start = 0, bands = stft.bands();
while (start < stft.bands()) { while (start < bands) {
if (energy[start] > smoothedEnergy[start]) { if (energy[start] > smoothedEnergy[start]) {
int end = start; int end = start;
Sample bandSum = 0, energySum = 0; Sample bandSum = 0, energySum = 0;
while (end < stft.bands() && energy[end] > smoothedEnergy[end]) { while (end < bands && energy[end] > smoothedEnergy[end]) {
bandSum += end*energy[end]; bandSum += end*energy[end];
energySum += energy[end]; energySum += energy[end];
++end; ++end;
@ -526,15 +528,16 @@ private:
} }
} }
void updateOutputMap(Sample peakWidthBins) { void updateOutputMap() {
int bands = stft.bands();
if (peaks.empty()) { if (peaks.empty()) {
for (int b = 0; b < stft.bands(); ++b) { for (int b = 0; b < bands; ++b) {
outputMap[b] = {Sample(b), 1}; outputMap[b] = {Sample(b), 1};
} }
return; return;
} }
Sample bottomOffset = peaks[0].input - peaks[0].output; Sample bottomOffset = peaks[0].input - peaks[0].output;
for (int b = 0; b < std::min<int>(stft.bands(), std::ceil(peaks[0].output)); ++b) { for (int b = 0; b < std::min<int>(bands, std::ceil(peaks[0].output)); ++b) {
outputMap[b] = {b + bottomOffset, 1}; outputMap[b] = {b + bottomOffset, 1};
} }
// Interpolate between points // Interpolate between points
@ -545,7 +548,7 @@ private:
Sample outScale = next.input - next.output - prev.input + prev.output; Sample outScale = next.input - next.output - prev.input + prev.output;
Sample gradScale = outScale*rangeScale; Sample gradScale = outScale*rangeScale;
int startBin = std::max<int>(0, std::ceil(prev.output)); int startBin = std::max<int>(0, std::ceil(prev.output));
int endBin = std::min<int>(stft.bands(), std::ceil(next.output)); int endBin = std::min<int>(bands, std::ceil(next.output));
for (int b = startBin; b < endBin; ++b) { for (int b = startBin; b < endBin; ++b) {
Sample r = (b - prev.output)*rangeScale; Sample r = (b - prev.output)*rangeScale;
Sample h = r*r*(3 - 2*r); Sample h = r*r*(3 - 2*r);
@ -558,7 +561,7 @@ private:
} }
} }
Sample topOffset = peaks.back().input - peaks.back().output; Sample topOffset = peaks.back().input - peaks.back().output;
for (int b = std::max<int>(0, peaks.back().output); b < stft.bands(); ++b) { for (int b = std::max<int>(0, peaks.back().output); b < bands; ++b) {
outputMap[b] = {b + topOffset, 1}; outputMap[b] = {b + topOffset, 1};
} }
} }