diff --git a/tests/PlotLFO.cpp b/tests/PlotLFO.cpp index d8c535cc..06ccc553 100644 --- a/tests/PlotLFO.cpp +++ b/tests/PlotLFO.cpp @@ -18,16 +18,23 @@ #include "sfizz/Synth.h" #include "sfizz/LFO.h" #include "sfizz/LFODescription.h" +#include "sfizz/MathHelpers.h" #include "cxxopts.hpp" #include #include #include #include +#ifdef _WIN32 +#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 +#endif +#include //============================================================================== static double sampleRate = 1000.0; // sample rate used to compute static double duration = 5.0; // length in seconds +static std::string outputFilename; +static bool saveFlac = false; static std::vector lfoDescriptionFromSfzFile(const fs::path &sfzPath, bool &success) { @@ -59,6 +66,8 @@ int main(int argc, char* argv[]) options.add_options() ("s,samplerate", "Sample rate", cxxopts::value(sampleRate)) ("d,duration", "Duration", cxxopts::value(duration)) + ("o,output", "Output file", cxxopts::value(outputFilename)) + ("F,flac", "Save output as FLAC", cxxopts::value(saveFlac)) ("h,help", "Print usage") ; options.positional_help("sfz-file"); @@ -119,11 +128,72 @@ int main(int argc, char* argv[]) 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'; + if (saveFlac) { + if (outputFilename.empty()) { + std::cerr << "Please indicate the audio file to save.\n"; + return 1; + } + + fs::path outputPath = fs::u8path(outputFilename); + SndfileHandle snd( +#ifndef _WIN32 + outputPath.c_str(), +#else + outputPath.wstring().c_str(), +#endif + SFM_WRITE, SF_FORMAT_FLAC|SF_FORMAT_PCM_16, numLfos, sampleRate); + + std::unique_ptr frame(new float[numLfos]); + size_t numClips = 0; + + for (size_t i = 0; i < numFrames; ++i) { + for (size_t l = 0; l < numLfos; ++l) { + float orig = lfoOutputs[l][i]; + float clamped = clamp(orig, -1.0f, 1.0f); + numClips += clamped != orig; + frame[l] = clamped; + } + snd.writef(frame.get(), 1); + } + snd.writeSync(); + + if (snd.error()) { + std::error_code ec; + fs::remove(outputPath, ec); + std::cerr << "Could not save audio to the output file.\n"; + return 1; + } + + if (numClips > 0) + std::cerr << "Warning: the audio output has been clipped on " << numClips << " frames.\n"; + } + else { + std::ostream* os = &std::cout; + fs::ofstream of; + + fs::path outputPath; + if (!outputFilename.empty()) { + outputPath = fs::u8path(outputFilename); + of.open(outputPath); + os = &of; + } + + for (size_t i = 0; i < numFrames; ++i) { + *os << (i / sampleRate); + for (size_t l = 0; l < numLfos; ++l) + *os << ' ' << lfoOutputs[l][i]; + *os << '\n'; + } + + if (os == &of) { + of.flush(); + if (!of) { + std::error_code ec; + fs::remove(outputPath, ec); + std::cerr << "Could not save data to the output file.\n"; + return 1; + } + } } return 0;