From 0d316399db4cc814ba529a156aa75713c668599f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 5 Aug 2020 01:00:01 +0200 Subject: [PATCH] Add the LFO plotting tool --- tests/CMakeLists.txt | 3 + tests/PlotLFO.cpp | 100 ++++++++++++++++++++++++++++++++ tests/TestFiles/lfo_subwave.sfz | 19 ++++++ 3 files changed, 122 insertions(+) create mode 100644 tests/PlotLFO.cpp create mode 100644 tests/TestFiles/lfo_subwave.sfz diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4018edee..9abe75de 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -94,6 +94,9 @@ target_link_libraries(sfizz_plot_curve PRIVATE sfizz::sfizz) add_executable(sfizz_plot_wavetables PlotWavetables.cpp) target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::sfizz) +add_executable(sfizz_plot_lfo PlotLFO.cpp) +target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::sfizz) + add_executable(sfizz_file_instrument FileInstrument.cpp) target_link_libraries(sfizz_file_instrument PRIVATE sfizz::sfizz) diff --git a/tests/PlotLFO.cpp b/tests/PlotLFO.cpp new file mode 100644 index 00000000..c8f63e2f --- /dev/null +++ b/tests/PlotLFO.cpp @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +/** + This program generates the data file of a LFO output recorded for a fixed + duration. The file contains columns for each LFO in the SFZ region. + The columns are: Time, Lfo1, ... LfoN + One can use Gnuplot to display this data. + Example: + sfizz_plot_lfo file.sfz > lfo.dat + gnuplot + plot "lfo.dat" using 1:2 with lines + */ + +#include "sfizz/Synth.h" +#include "sfizz/LFO.h" +#include "sfizz/LFODescription.h" +#include +#include +#include +#include + +//============================================================================== + +static constexpr double sampleRate = 44100.0; // sample rate used to compute +static constexpr double duration = 5.0; // length in seconds + +/** + Print usage information + */ +static void usage() +{ + std::cerr << "Usage: sfizz_plot_lfo " "\n"; +} + +static std::vector lfoDescriptionFromSfzFile(const fs::path &sfzPath, bool &success) +{ + sfz::Synth synth; + + if (!synth.loadSfzFile(sfzPath)) { + std::cerr << "Cannot load the SFZ file.\n"; + success = false; + return {}; + } + + if (synth.getNumRegions() != 1) { + std::cerr << "The SFZ file must contain exactly one region.\n"; + success = false; + return {}; + } + + success = true; + return synth.getRegionView(0)->lfos; +} + +/** + Program which loads LFO configuration and generates plot data for the given duration. + */ +int main(int argc, char* argv[]) +{ + if (argc < 2 || argc > 2) { + usage(); + return 1; + } + + fs::path sfzPath = argv[1]; + bool success = false; + const std::vector desc = lfoDescriptionFromSfzFile(sfzPath, success); + if (!success) + return 1; + + size_t numLfos = desc.size(); + std::vector lfos(numLfos); + + for (size_t l = 0; l < numLfos; ++l) { + lfos[l].setSampleRate(sampleRate); + lfos[l].configure(&desc[l]); + } + + size_t numFrames = (size_t)std::ceil(sampleRate * duration); + std::vector outputMemory(numLfos * numFrames); + + std::vector> lfoOutputs(numLfos); + for (size_t l = 0; l < numLfos; ++l) { + lfoOutputs[l] = absl::MakeSpan(&outputMemory[l * numFrames], numFrames); + lfos[l].process(lfoOutputs[l]); + } + + for (size_t i = 0; i < numFrames; ++i) { + std::cout << (i / sampleRate); + for (size_t l = 0; l < numLfos; ++l) + std::cout << ' ' << lfoOutputs[l][i]; + std::cout << '\n'; + } + + return 0; +} diff --git a/tests/TestFiles/lfo_subwave.sfz b/tests/TestFiles/lfo_subwave.sfz new file mode 100644 index 00000000..80867c3d --- /dev/null +++ b/tests/TestFiles/lfo_subwave.sfz @@ -0,0 +1,19 @@ + +sample=*noise +lokey=0 +hikey=127 +cutoff=1000.0 +fil_type=brf_2p +lfo1_cutoff=1200.0 +// +lfo1_freq=1 +lfo1_phase=0.5 +lfo1_wave=3 +lfo1_delay=0.5 +lfo1_fade=0.5 +lfo1_wave2=1 +lfo1_offset2=0.2 +lfo1_ratio2=0.7 +lfo1_scale2=0.3 +// +lfo2_freq=0.5