From c57ab54c24a7aa7020cab12313553e224d8be485 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 14 Feb 2020 01:20:05 +0100 Subject: [PATCH] Extra samples in the wavetables, to help interpolations --- src/sfizz/Wavetables.cpp | 30 ++++++++++++++++++++++++++---- src/sfizz/Wavetables.h | 19 ++++++++++++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/sfizz/Wavetables.cpp b/src/sfizz/Wavetables.cpp index 058466d7..8f2251ee 100644 --- a/src/sfizz/Wavetables.cpp +++ b/src/sfizz/Wavetables.cpp @@ -143,17 +143,18 @@ WavetableRange WavetableRange::getRangeForFrequency(float f) } //------------------------------------------------------------------------------ +constexpr unsigned WavetableMulti::_tableExtra; + WavetableMulti WavetableMulti::createForHarmonicProfile( const HarmonicProfile& hp, unsigned tableSize, double refSampleRate) { WavetableMulti wm; - constexpr unsigned multiSize = wm.multiSize(); + constexpr unsigned multiSize = WavetableMulti::multiSize(); // amplitude to match ARIA's default generator output constexpr double amplitude = 0.25; - wm._tableSize = tableSize; - wm._multiData.reset(new float[tableSize * multiSize]); + wm.allocateStorage(tableSize); for (unsigned m = 0; m < multiSize; ++m) { WavetableRange range = WavetableRange::getRangeForOctave(m); @@ -165,13 +166,34 @@ WavetableMulti WavetableMulti::createForHarmonicProfile( // Therefore it's desired to cut harmonics at C=0.5*Fs/Fs'=0.5*Fs/(F*N). double cutoff = (0.5 * refSampleRate / tableSize) / freq; - float* ptr = &wm._multiData[m * tableSize]; + float* ptr = const_cast(wm.getTablePointer(m)); absl::Span table(ptr, tableSize); hp.generate(table, amplitude, cutoff); } + wm.fillExtra(); + return wm; } +void WavetableMulti::allocateStorage(unsigned tableSize) +{ + _multiData.reset(new float[(tableSize + _tableExtra) * multiSize()]()); + _tableSize = tableSize; +} + +void WavetableMulti::fillExtra() +{ + unsigned tableSize = _tableSize; + constexpr unsigned tableExtra = _tableExtra; + constexpr unsigned multiSize = WavetableMulti::multiSize(); + + for (unsigned m = 0; m < multiSize; ++m) { + float* ptr = const_cast(getTablePointer(m)); + for (unsigned i = 0; i < tableExtra; ++i) + ptr[tableSize + i] = ptr[i % tableSize]; + } +} + } // namespace sfz diff --git a/src/sfizz/Wavetables.h b/src/sfizz/Wavetables.h index 317d88ab..5accadf3 100644 --- a/src/sfizz/Wavetables.h +++ b/src/sfizz/Wavetables.h @@ -86,9 +86,7 @@ public: // get the N-th table in the multisample absl::Span getTable(unsigned index) const { - unsigned size = _tableSize; - const float* ptr = &_multiData[index * _tableSize]; - return { ptr, size }; + return { getTablePointer(index), _tableSize }; } // get the table which is adequate for a given playback frequency @@ -104,9 +102,24 @@ public: const HarmonicProfile& hp, unsigned tableSize, double refSampleRate = 44100.0); private: + // get a pointer to the beginning of the N-th table + const float* getTablePointer(unsigned index) const + { + return &_multiData[index * (_tableSize + _tableExtra)]; + } + + // allocate the internal data for tables of the given size + void allocateStorage(unsigned tableSize); + + // fill extra data at table ends with repetitions of the first samples + void fillExtra(); + // length of each individual table of the multisample unsigned _tableSize = 0; + // number X of extra elements, for safe interpolations up to X-th order. + static constexpr unsigned _tableExtra = 4; + // internal storage, having `multiSize` rows and `tableSize` columns. std::unique_ptr _multiData; };