commit 2258a2ae0949108091d9dd4cbc3e74b5b48acaff
parent d6ad291f810ce14b24935a1c475cb02bd49445d3
Author: Matt Demanett <matt@demanett.net>
Date: Sat, 5 Sep 2020 18:22:11 -0400
RANALYZER: fix crash if sample rate very high; increase buffer size to 32K if SR is 192K or higher; etc. #116
Diffstat:
9 files changed, 61 insertions(+), 18 deletions(-)
diff --git a/README-prerelease.md b/README-prerelease.md
@@ -895,7 +895,7 @@ RANALYZER is a frequency response analyzer: it passes a test signal to another m
**This module is primarily useful to plugin developers**, especially when developing filters. Of course anyone may use it, to investigate the response of some module, or to tune a filter bank, or what have you.
-By default, will produce a one-shot test signal, emitted at SEND, upon receipt of a trigger (manual or CV) at the TRIG inputs. The duration of the test signal is always 16384 samples; thus the duration in time will depend on Rack's current sample rate. The same number of samples is collected from RETURN, if it is patched. Both signals are converted to the frequency domain and displayed (test in green, response in magenta).
+By default, will produce a one-shot test signal, emitted at SEND, upon receipt of a trigger (manual or CV) at the TRIG inputs. The duration of the test signal is always 16384 samples (32768 if Rack's sample rate is 192K or higher); thus the duration in time will depend on Rack's current sample rate. The same number of samples is collected from RETURN, if it is patched. Both signals are converted to the frequency domain and displayed (test in green, response in magenta).
The test signal is a swept sine wave (or "chirp", see <a href="#chirp">CHIRP</a>), with an exponential (if the EXP toggle is on) or linear sweep. The start and end frequencies for sine sweep are set by the FREQ1 and FREQ2 knobs, each with a range in hertz from 1 to the Nyquist rate (half the sampling rate); if FREQ1 is less than FREQ2 the sweep is upwards in frequency, downwards otherwise.
diff --git a/src/Ranalyzer.cpp b/src/Ranalyzer.cpp
@@ -22,6 +22,12 @@ void Ranalyzer::sampleRateChange() {
_sampleTime = 1.0f / _sampleRate;
_maxFrequency = roundf(maxFrequencyNyquistRatio * _sampleRate);
_chirp.setSampleRate(_sampleRate);
+ if (_sampleRate >= 192000.0f) {
+ _core.setParams(1, AnalyzerCore::QUALITY_FIXED_32K, AnalyzerCore::WINDOW_NONE);
+ }
+ else {
+ _core.setParams(1, AnalyzerCore::QUALITY_FIXED_16K, AnalyzerCore::WINDOW_NONE);
+ }
}
json_t* Ranalyzer::toJson(json_t* root) {
@@ -84,7 +90,7 @@ void Ranalyzer::processAll(const ProcessArgs& args) {
_run = true;
_bufferCount = _currentReturnSampleDelay = _returnSampleDelay;
_chirp.reset();
- _chirp.setParams(_frequency1, _frequency2, (float)_core.size() / _sampleRate, !_exponential);
+ _chirp.setParams(_frequency1, _frequency2, (double)_core.size() / (double)_sampleRate, !_exponential);
_triggerPulseGen.trigger(0.001f);
}
}
diff --git a/src/Ranalyzer.hpp b/src/Ranalyzer.hpp
@@ -101,7 +101,6 @@ struct Ranalyzer : AnalyzerBase {
configParam(DELAY_PARAM, 2.0f, (float)maxResponseDelay, 2.0f, "Return sample delay");
_skinnable = false;
- _core.setParams(1, AnalyzerCore::QUALITY_FIXED_16K, AnalyzerCore::WINDOW_NONE);
}
void reset() override;
diff --git a/src/analyzer_base.cpp b/src/analyzer_base.cpp
@@ -120,6 +120,9 @@ SpectrumAnalyzer::Size AnalyzerCore::size() {
case QUALITY_FIXED_16K: {
return SpectrumAnalyzer::SIZE_16384;
}
+ case QUALITY_FIXED_32K: {
+ return SpectrumAnalyzer::SIZE_32768;
+ }
default:;
}
diff --git a/src/analyzer_base.hpp b/src/analyzer_base.hpp
@@ -71,7 +71,8 @@ struct AnalyzerCore {
QUALITY_ULTRA,
QUALITY_HIGH,
QUALITY_GOOD,
- QUALITY_FIXED_16K
+ QUALITY_FIXED_16K,
+ QUALITY_FIXED_32K
};
enum Window {
diff --git a/src/dsp/analyzer.cpp b/src/dsp/analyzer.cpp
@@ -65,3 +65,18 @@ FFT16384::~FFT16384() {
void FFT16384::do_fft(float* out, float* in) {
((FIXED_FFT16384*)_fft)->do_fft(out, in);
}
+
+
+typedef ffft::FFTRealFixLen<15> FIXED_FFT32768;
+
+FFT32768::FFT32768() {
+ _fft = new FIXED_FFT32768();
+}
+
+FFT32768::~FFT32768() {
+ delete (FIXED_FFT32768*)_fft;
+}
+
+void FFT32768::do_fft(float* out, float* in) {
+ ((FIXED_FFT32768*)_fft)->do_fft(out, in);
+}
diff --git a/src/dsp/analyzer.hpp b/src/dsp/analyzer.hpp
@@ -117,6 +117,14 @@ struct FFT16384 {
void do_fft(float* out, float* in);
};
+struct FFT32768 {
+ void* _fft = NULL;
+ FFT32768();
+ ~FFT32768();
+
+ void do_fft(float* out, float* in);
+};
+
struct SpectrumAnalyzer : OverlappingBuffer<float> {
enum Size {
SIZE_128 = 128,
@@ -126,9 +134,10 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
SIZE_2048 = 2048,
SIZE_4096 = 4096,
SIZE_8192 = 8192,
- SIZE_16384 = 16384
+ SIZE_16384 = 16384,
+ SIZE_32768 = 32768
};
- static constexpr Size maxSize = SIZE_16384;
+ static constexpr Size maxSize = SIZE_32768;
enum Overlap {
OVERLAP_1 = 1,
@@ -150,6 +159,7 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
FFT4096* _fft4096;
FFT8192* _fft8192;
FFT16384* _fft16384;
+ FFT32768* _fft32768;
Window* _window;
float* _windowOut;
float* _fftOut;
@@ -168,6 +178,7 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
, _fft4096(NULL)
, _fft8192(NULL)
, _fft16384(NULL)
+ , _fft32768(NULL)
, _window(NULL)
, _windowOut(NULL)
, _fftOut(new float[_size])
@@ -192,6 +203,10 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
_fft16384 = new FFT16384();
break;
}
+ case SIZE_32768: {
+ _fft32768 = new FFT32768();
+ break;
+ }
default: {
_fft = new ffft::FFTReal<float>(size);
}
@@ -235,6 +250,9 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
if (_fft16384) {
delete _fft16384;
}
+ if (_fft32768) {
+ delete _fft32768;
+ }
if (_window) {
delete _window;
@@ -262,6 +280,9 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
else if (_fft16384) {
_fft16384->do_fft(_fftOut, input);
}
+ else if (_fft32768) {
+ _fft32768->do_fft(_fftOut, input);
+ }
else {
_fft->do_fft(_fftOut, input);
}
diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp
@@ -358,7 +358,7 @@ void ChirpOscillator::reset() {
}
-void PureChirpOscillator::setParams(float frequency1, float frequency2, float time, bool linear) {
+void PureChirpOscillator::setParams(float frequency1, float frequency2, double time, bool linear) {
frequency1 = std::max(minFrequency, std::min(frequency1, 0.99f * 0.5f * _sampleRate));
frequency2 = std::max(minFrequency, std::min(frequency2, 0.99f * 0.5f * _sampleRate));
assert(time >= minTimeSeconds);
@@ -373,7 +373,7 @@ void PureChirpOscillator::setParams(float frequency1, float frequency2, float ti
}
void PureChirpOscillator::_sampleRateChanged() {
- _sampleTime = 1.0f / _sampleRate;
+ _sampleTime = 1.0 / (double)_sampleRate;
update();
}
@@ -386,7 +386,7 @@ void PureChirpOscillator::update() {
float PureChirpOscillator::_next() {
_complete = false;
- if (_time > _Time) {
+ if (_Time - _time < _sampleTime) {
_time = 0.0f;
_complete = true;
}
@@ -402,7 +402,7 @@ float PureChirpOscillator::_next() {
else {
phase = 2.0 * M_PI * (double)_f1 * ((pow(_k, (double)_time) - 1.0) * _invlogk);
}
- return _phasor.nextForPhase(Phasor::radiansToPhase(phase));
+ return sinf(phase);
}
void PureChirpOscillator::reset() {
diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp
@@ -334,7 +334,7 @@ struct SineBankOscillator : Oscillator {
struct ChirpOscillator : OscillatorGenerator {
static constexpr float minFrequency = 1.0f;
- static constexpr float minTimeSeconds = 0.025f;
+ static constexpr float minTimeSeconds = 0.01f;
SineTableOscillator _oscillator;
float _f1 = -1.0f;
@@ -369,16 +369,15 @@ struct ChirpOscillator : OscillatorGenerator {
struct PureChirpOscillator : OscillatorGenerator {
static constexpr float minFrequency = 1.0f;
- static constexpr float minTimeSeconds = 0.025f;
+ static constexpr float minTimeSeconds = 0.01f;
- TablePhasor _phasor;
float _f1 = -1.0f;
float _f2 = -1.0f;
- float _Time = -1.0f;
+ double _Time = -1.0;
bool _linear = false;
- float _sampleTime = 0.0f;
- float _time = 0.0f;
+ double _sampleTime = 0.0f;
+ double _time = 0.0f;
bool _complete = false;
double _c = 0.0;
double _k = 0.0;
@@ -391,14 +390,13 @@ struct PureChirpOscillator : OscillatorGenerator {
float time = 1.0f,
bool linear = true
)
- : _phasor(StaticSineTable::table(), sampleRate, frequency1)
{
setParams(frequency1, frequency2, time, linear);
}
inline bool isCycleComplete() { return _complete; }
inline bool isCycleNearlyComplete(float seconds) { return _time > _Time - seconds; }
- void setParams(float frequency1, float frequency2, float time, bool linear);
+ void setParams(float frequency1, float frequency2, double time, bool linear);
void _sampleRateChanged() override;
void update();
float _next() override;