diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a1b1b80e2..3ce90a3b2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,3 +43,64 @@ if ( LIBSNDFILE_HASVORBIS ) ADD_FLUID_TEST(test_sf3_sfont_loading) ADD_FLUID_SF_DUMP_TEST(VintageDreamsWaves-v2.sf3) endif ( LIBSNDFILE_HASVORBIS ) + + +# Prepare the manual test suite down here +if(NOT DEFINED GENERAL_USER_GS2) + add_custom_target(check_manual + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red "In order to run the manual test suite, you need to set variable GENERAL_USER_GS2 to the path of the soundfont.") +else() + + set(IIR_FILTER_RENDER_DIR "${CMAKE_CURRENT_BINARY_DIR}/manual/iir_filter") + + if(LIBSNDFILE_SUPPORT) + set(FEXT "wav") + else() + set(FEXT "raw") + endif() + + # Add an empty pseudo target + add_custom_target(check_manual) + + add_custom_target(create_iir_dir + COMMAND ${CMAKE_COMMAND} -E make_directory ${IIR_FILTER_RENDER_DIR}) + + add_custom_target(render1415 + COMMAND fluidsynth -R 0 -C 0 -g 1 -F ${IIR_FILTER_RENDER_DIR}/1415_the-nervous-filter.${FEXT} "The Nervous Filter trimmed.mid" ${GENERAL_USER_GS2} + COMMENT "Rendering testfile of issue 1415" + DEPENDS fluidsynth create_iir_dir + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/manual/iir_filter/1415_the-nervous-filter/ + VERBATIM + ) + + add_custom_target(render1417 + COMMAND fluidsynth -R 0 -C 0 -g 1 -F ${IIR_FILTER_RENDER_DIR}/1417_filter-envelope-noise.${FEXT} filter-envelope-noise.mid ${GENERAL_USER_GS2} + COMMENT "Rendering testfile of issue 1417" + DEPENDS fluidsynth create_iir_dir + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/manual/iir_filter/1417_filter-envelope-noise/ + VERBATIM + ) + + add_custom_target(render1424 + COMMAND fluidsynth -R 0 -C 0 -g 1 -F ${IIR_FILTER_RENDER_DIR}/1424_clicks-on-ModEnv-FilterFc-change.${FEXT} 1424.mid echo_drops.sf2 + COMMENT "Rendering testfile of issue 1424" + DEPENDS fluidsynth create_iir_dir + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/ + VERBATIM + ) + + add_custom_target(render1427 + COMMAND fluidsynth -R 0 -C 0 -g 5 -F ${IIR_FILTER_RENDER_DIR}/1427_high-Q-note-cutoff.${FEXT} high_Q_note_cutoff_test.mid high_Q_note_cutoff_test.sf2 + COMMENT "Rendering testfile of issue 1427" + DEPENDS fluidsynth create_iir_dir + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/manual/iir_filter/1427_high-Q-note-cutoff/ + VERBATIM + ) + + # Add a dependency so that rendering targets depends on check_manual + add_dependencies(check_manual render1415) + add_dependencies(check_manual render1417) + add_dependencies(check_manual render1424) + add_dependencies(check_manual render1427) + +endif() diff --git a/test/manual/iir_filter/1415_the-nervous-filter/.gitattributes b/test/manual/iir_filter/1415_the-nervous-filter/.gitattributes new file mode 100644 index 000000000..6f4a0fef5 --- /dev/null +++ b/test/manual/iir_filter/1415_the-nervous-filter/.gitattributes @@ -0,0 +1,4 @@ +*.ogg filter=lfs diff=lfs merge=lfs -text +*.flac filter=lfs diff=lfs merge=lfs -text +*.wav filter=lfs diff=lfs merge=lfs -text +*.sf2 filter=lfs diff=lfs merge=lfs -text diff --git a/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter trimmed.mid b/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter trimmed.mid new file mode 100644 index 000000000..a853ab088 Binary files /dev/null and b/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter trimmed.mid differ diff --git a/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter trimmed.ogg b/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter trimmed.ogg new file mode 100644 index 000000000..d834a7118 --- /dev/null +++ b/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter trimmed.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f76d1efe07305045b1c2add718b2bf682f76043bae5bca743372e560cb21974 +size 89539 diff --git a/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter.mid b/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter.mid new file mode 100644 index 000000000..4443978ad Binary files /dev/null and b/test/manual/iir_filter/1415_the-nervous-filter/The Nervous Filter.mid differ diff --git a/test/manual/iir_filter/1417_filter-envelope-noise/.gitattributes b/test/manual/iir_filter/1417_filter-envelope-noise/.gitattributes new file mode 100644 index 000000000..6a0d372f1 --- /dev/null +++ b/test/manual/iir_filter/1417_filter-envelope-noise/.gitattributes @@ -0,0 +1,5 @@ +filter-envelope-noise-1345[[:space:]]reverted.flac filter=lfs diff=lfs merge=lfs -text +filter-envelope-noise-FluidSynth[[:space:]]2.4.flac filter=lfs diff=lfs merge=lfs -text +filter-envelope-noise.mid filter=lfs diff=lfs merge=lfs -text +*.flac filter=lfs diff=lfs merge=lfs -text +*.sf2 filter=lfs diff=lfs merge=lfs -text diff --git a/test/manual/iir_filter/1417_filter-envelope-noise/filter envelope-noise-Roland SC8820.flac b/test/manual/iir_filter/1417_filter-envelope-noise/filter envelope-noise-Roland SC8820.flac new file mode 100755 index 000000000..08322a487 --- /dev/null +++ b/test/manual/iir_filter/1417_filter-envelope-noise/filter envelope-noise-Roland SC8820.flac @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bea148b158f8932b8ca74d4e1246492115d01361c2192156c41820388cee6b9e +size 406106 diff --git a/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise-1345 reverted.flac b/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise-1345 reverted.flac new file mode 100755 index 000000000..3abd442cf --- /dev/null +++ b/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise-1345 reverted.flac @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62579bbbaab0ae97b873e666102741a72e05bd6322c4c8fb64dbc8062def73f1 +size 415449 diff --git a/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise-FluidSynth 2.4.flac b/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise-FluidSynth 2.4.flac new file mode 100755 index 000000000..79dd125fb --- /dev/null +++ b/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise-FluidSynth 2.4.flac @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:415e71eff4668d1d6261a652cacee2ead5202637b40bd87f2a2cd3cf488c8a11 +size 472080 diff --git a/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise.mid b/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise.mid new file mode 100755 index 000000000..d0cae2d09 --- /dev/null +++ b/test/manual/iir_filter/1417_filter-envelope-noise/filter-envelope-noise.mid @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7423868b1028c96e2068176a9122a37f31113bed86002ff35091e9e80a2f497b +size 662 diff --git a/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/.gitattributes b/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/.gitattributes new file mode 100644 index 000000000..4be35afce --- /dev/null +++ b/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/.gitattributes @@ -0,0 +1 @@ +echo_drops.sf2 filter=lfs diff=lfs merge=lfs -text diff --git a/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/1424.mid b/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/1424.mid new file mode 100644 index 000000000..a65a2ef36 Binary files /dev/null and b/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/1424.mid differ diff --git a/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/echo_drops.sf2 b/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/echo_drops.sf2 new file mode 100644 index 000000000..d018fcf1d --- /dev/null +++ b/test/manual/iir_filter/1424_clicks-on-ModEnv-FilterFc-change/echo_drops.sf2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:832763abda84a34030f272a608918cfb1e51a5cf52eccc9c88691f938827f725 +size 16835580 diff --git a/test/manual/iir_filter/1427_high-Q-note-cutoff/.gitattributes b/test/manual/iir_filter/1427_high-Q-note-cutoff/.gitattributes new file mode 100644 index 000000000..26fae88dd --- /dev/null +++ b/test/manual/iir_filter/1427_high-Q-note-cutoff/.gitattributes @@ -0,0 +1,3 @@ +high_Q_note_cutoff_test.sf2 filter=lfs diff=lfs merge=lfs -text +fluidsynth_iir-tests.flac filter=lfs diff=lfs merge=lfs -text +high_Q_note_cutoff_test.mid filter=lfs diff=lfs merge=lfs -text diff --git a/test/manual/iir_filter/1427_high-Q-note-cutoff/fluidsynth_iir-tests.flac b/test/manual/iir_filter/1427_high-Q-note-cutoff/fluidsynth_iir-tests.flac new file mode 100755 index 000000000..c74958755 --- /dev/null +++ b/test/manual/iir_filter/1427_high-Q-note-cutoff/fluidsynth_iir-tests.flac @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c198b5b32c3a8516f049c4e7e6cfee764b0855595fdda46750f92c614808d940 +size 224675 diff --git a/test/manual/iir_filter/1427_high-Q-note-cutoff/high_Q_note_cutoff_test.mid b/test/manual/iir_filter/1427_high-Q-note-cutoff/high_Q_note_cutoff_test.mid new file mode 100755 index 000000000..a882f2b7e --- /dev/null +++ b/test/manual/iir_filter/1427_high-Q-note-cutoff/high_Q_note_cutoff_test.mid @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d17f36961affa6f913a40398800b58872bc4a4d57019a8467dce72715950d8c8 +size 100 diff --git a/test/manual/iir_filter/1427_high-Q-note-cutoff/high_Q_note_cutoff_test.sf2 b/test/manual/iir_filter/1427_high-Q-note-cutoff/high_Q_note_cutoff_test.sf2 new file mode 100755 index 000000000..669d6d257 --- /dev/null +++ b/test/manual/iir_filter/1427_high-Q-note-cutoff/high_Q_note_cutoff_test.sf2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6636a4c9344de49c7b040017f1e0381c95150a2cf5d0f6a3b1178a154bbc7064 +size 235772 diff --git a/test/manual/iir_filter/interactive_biquad_lowpass.m b/test/manual/iir_filter/interactive_biquad_lowpass.m new file mode 100644 index 000000000..0c53abec7 --- /dev/null +++ b/test/manual/iir_filter/interactive_biquad_lowpass.m @@ -0,0 +1,86 @@ +# +# This Matlab script implements an interactive Bode plot of fluidsynth's IIR filter. +# To run it, just call interactive_biquad_lowpass() and a window will open up, allowing +# you to adjust the cutoff frequency and Q. +# Note that Q is in linear range here! +# +function interactive_biquad_lowpass() + % Initial values + f_c = 1000; % Initial cutoff frequency in Hz + Q = 0.707; % Initial quality factor + f_s = 48000; % Sampling frequency in Hz + + % Create the figure + hFig = figure('Name', 'Interactive Biquad Lowpass Filter', 'NumberTitle', 'off'); + + % Create axes for the magnitude and phase plots + hAxesMag = subplot(2, 1, 1, 'Parent', hFig); + hAxesPhase = subplot(2, 1, 2, 'Parent', hFig); + + % Plot the initial response + plot_response(hAxesMag, hAxesPhase, f_c, Q, f_s); + + % Create slider for cutoff frequency + uicontrol('Style', 'text', 'Position', [20 20 150 20], 'String', 'Cutoff Frequency (Hz)'); + hSliderFc = uicontrol('Style', 'slider', 'Min', 100, 'Max', 20000, 'Value', f_c, ... + 'Position', [20 40 300 20]); + hTextFc = uicontrol('Style', 'text', 'Position', [330 40 50 20], 'String', num2str(f_c)); + + % Create slider for quality factor + uicontrol('Style', 'text', 'Position', [20 80 150 20], 'String', 'Quality Factor (Q)'); + hSliderQ = uicontrol('Style', 'slider', 'Min', 0.1, 'Max', 100, 'Value', Q, ... + 'Position', [20 100 300 20]); + hTextQ = uicontrol('Style', 'text', 'Position', [330 100 50 20], 'String', num2str(Q)); + + % Add listeners for both sliders + addlistener(hSliderFc, 'Value', 'PreSet', @(src, event) update_plot(hAxesMag, hAxesPhase, hSliderFc, hSliderQ, f_s, hTextFc, hTextQ)); + addlistener(hSliderQ, 'Value', 'PreSet', @(src, event) update_plot(hAxesMag, hAxesPhase, hSliderFc, hSliderQ, f_s, hTextFc, hTextQ)); +end + +function update_plot(hAxesMag, hAxesPhase, hSliderFc, hSliderQ, f_s, hTextFc, hTextQ) + % Get the current values from the sliders + f_c = get(hSliderFc, 'Value'); + Q = get(hSliderQ, 'Value'); + + % Update the text displays + set(hTextFc, 'String', num2str(f_c, '%.1f')); % Display cutoff frequency + set(hTextQ, 'String', num2str(Q, '%.2f')); % Display quality factor + + % Update the plot with the new values + plot_response(hAxesMag, hAxesPhase, f_c, Q, f_s); +end + +function plot_response(hAxesMag, hAxesPhase, f_c, Q, f_s) + % Design the biquad lowpass filter + w0 = 2 * pi * f_c / f_s; + alpha = sin(w0) / (2 * Q); + + b0 = (1 - cos(w0)) / 2; + b1 = 1 - cos(w0); + b2 = (1 - cos(w0)) / 2; + a0 = 1 + alpha; + a1 = -2 * cos(w0); + a2 = 1 - alpha; + + % Normalize coefficients + b = [b0 / a0, b1 / a0, b2 / a0]; + a = [1, a1 / a0, a2 / a0]; + + % Compute the frequency response + [h, w] = freqz(b, a, 1024, f_s); + + % Clear the axes and plot the new response + cla(hAxesMag); + plot(hAxesMag, w, 20*log10(abs(h))); + title(hAxesMag, 'Magnitude Response'); + xlabel(hAxesMag, 'Frequency (Hz)'); + ylabel(hAxesMag, 'Magnitude (dB)'); + grid(hAxesMag, 'on'); + + cla(hAxesPhase); + plot(hAxesPhase, w, angle(h) * (180/pi)); + title(hAxesPhase, 'Phase Response'); + xlabel(hAxesPhase, 'Frequency (Hz)'); + ylabel(hAxesPhase, 'Phase (degrees)'); + grid(hAxesPhase, 'on'); +end