Skip to content

Commit

Permalink
Fix MiniCliffEQ crash on non-thread safe FFTW3 routine calls
Browse files Browse the repository at this point in the history
This fixes the crash when 2 or more instances of MiniCliffEQ is launched, then host calls `OverlapSaveConvolver::setFir()` by resetting or initialization.

On FFTW 3.3.10 manual section 5.4 Thread safety, it says that "the only thread-safe routine in FFTW is fftw_execute (and the new-array variants thereof)." I have no idea if all the VST 3 hosts are initializing plugins in a single thread.
  • Loading branch information
ryukau committed Jun 29, 2022
1 parent 14918f2 commit 18f49d9
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 13 deletions.
16 changes: 9 additions & 7 deletions MiniCliffEQ/source/dsp/fftconvolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,11 @@ class OverlapSaveConvolver {
std::complex<float> *spc;
std::complex<float> *fir;
float *flt; // filtered.
float *coefficient;

std::array<fftwf_plan, nBuffer> forwardPlan;
fftwf_plan inversePlan;
fftwf_plan firPlan;

size_t front = 0;
std::array<size_t, nBuffer> wptr{};
Expand All @@ -131,6 +133,9 @@ class OverlapSaveConvolver {
spc = (std::complex<float> *)fftwf_malloc(sizeof(std::complex<float>) * spcSize);
flt = (float *)fftwf_malloc(sizeof(float) * bufSize);

coefficient = (float *)fftwf_malloc(sizeof(float) * bufSize);
std::fill(coefficient, coefficient + bufSize, float(0));

fir = (std::complex<float> *)fftwf_malloc(sizeof(std::complex<float>) * spcSize);
std::fill(fir, fir + spcSize, std::complex<float>(0, 0));

Expand All @@ -140,34 +145,31 @@ class OverlapSaveConvolver {
}
inversePlan = fftwf_plan_dft_c2r_1d(
int(bufSize), reinterpret_cast<fftwf_complex *>(spc), flt, FFTW_ESTIMATE);
firPlan = fftwf_plan_dft_r2c_1d(
int(bufSize), coefficient, reinterpret_cast<fftwf_complex *>(fir), FFTW_ESTIMATE);
}

~OverlapSaveConvolver()
{
for (auto &fp : forwardPlan) fftwf_destroy_plan(fp);
fftwf_destroy_plan(inversePlan);
fftwf_destroy_plan(firPlan);

for (auto &bf : buf) fftwf_free(bf);
fftwf_free(spc);
fftwf_free(fir);
fftwf_free(flt);
fftwf_free(coefficient);
}

void setFir(std::vector<float> &source, size_t start, size_t end)
{
float *coefficient = (float *)fftwf_malloc(sizeof(float) * bufSize);
std::copy(source.begin() + start, source.begin() + end, coefficient);
std::fill(coefficient + half, coefficient + bufSize, float(0));

// FFT scaling.
for (size_t idx = 0; idx < half; ++idx) coefficient[idx] /= float(bufSize);

auto firPlan = fftwf_plan_dft_r2c_1d(
int(bufSize), coefficient, reinterpret_cast<fftwf_complex *>(fir), FFTW_ESTIMATE);
fftwf_execute(firPlan);

fftwf_destroy_plan(firPlan);
fftwf_free(coefficient);
}

void reset()
Expand Down
8 changes: 4 additions & 4 deletions MiniCliffEQ/source/version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
#define SUB_VERSION_STR "1"
#define SUB_VERSION_INT 1

#define RELEASE_NUMBER_STR "6"
#define RELEASE_NUMBER_INT 6
#define RELEASE_NUMBER_STR "7"
#define RELEASE_NUMBER_INT 7

#define BUILD_NUMBER_STR "6"
#define BUILD_NUMBER_INT 6
#define BUILD_NUMBER_STR "7"
#define BUILD_NUMBER_INT 7

#define FULL_VERSION_STR \
MAJOR_VERSION_STR "." SUB_VERSION_STR "." RELEASE_NUMBER_STR "." BUILD_NUMBER_STR
Expand Down
4 changes: 3 additions & 1 deletion docs/manual/MiniCliffEQ/MiniCliffEQ_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ lang: en

MiniCliffEQ is a linear phase FIR filter with 2^15 = 32768 taps. Latency is improved from initial version, however it still exceeds 0.34 seconds in 48000 Hz sampling rate. The primary purpose is to suppress direct current. It can also be used as very sharp low-pass, high-pass, low-shelf, and high-shelf filter.

- [Download MiniCliffEQ 0.1.6 - VST® 3 (github.com)](https://github.com/ryukau/VSTPlugins/releases/download/UhhyouPlugins0.39.0/MiniCliffEQ_0.1.6.zip) <img
- [Download MiniCliffEQ 0.1.7 - VST® 3 (github.com)](https://github.com/ryukau/VSTPlugins/releases/download/UhhyouPlugins0.40.0/MiniCliffEQ_0.1.7.zip) <img
src="img/VST_Compatible_Logo_Steinberg_negative.svg"
alt="VST compatible logo."
width="60px"
Expand Down Expand Up @@ -219,6 +219,8 @@ LP Gain \[dB\]
: Gain of lowpass output.

## Change Log
- 0.1.7
- Fixed crash when FIR filter is refreshed at the same time on 2 or more instances of MiniCliffEQ.
- 0.1.6
- Changed convolution algorithm to reduce CPU load spikes.
- 0.1.5
Expand Down
4 changes: 3 additions & 1 deletion docs/manual/MiniCliffEQ/MiniCliffEQ_ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ lang: ja

<ruby>MiniCliffEQ<rt>ミニ クリフ イーキュー</rt></ruby> はタップ数 2^15 = 32768 の FIR フィルタです。初期バージョンからは改善しましたが、それでもタップ数が多いのでレイテンシがサンプリング周波数 48000 Hz のときに 0.34 秒を超えます。主な用途は直流信号 (DC) の抑制ですが、とても急峻なローパス、ハイパス、ローシェルフ、ハイシェルフフィルタとしても使えます。

- [MiniCliffEQ 0.1.6 をダウンロード - VST® 3 (github.com)](https://github.com/ryukau/VSTPlugins/releases/download/UhhyouPlugins0.39.0/MiniCliffEQ_0.1.6.zip) <img
- [MiniCliffEQ 0.1.7 をダウンロード - VST® 3 (github.com)](https://github.com/ryukau/VSTPlugins/releases/download/UhhyouPlugins0.40.0/MiniCliffEQ_0.1.7.zip) <img
src="img/VST_Compatible_Logo_Steinberg_negative.svg"
alt="VST compatible logo."
width="60px"
Expand Down Expand Up @@ -218,6 +218,8 @@ LP Gain \[dB\]
: ローパス出力のゲインです。

## チェンジログ
- 0.1.7
- 2 つ以上のインスタンスの FIR フィルタが同時にリフレッシュされたときにクラッシュするバグを修正。
- 0.1.6
- CPU 負荷のスパイクを低減するために畳み込みのアルゴリズムを変更。
- 0.1.5
Expand Down

0 comments on commit 18f49d9

Please sign in to comment.