From bb9d6cf66e8f9f66d6c2b99dcf3483c1c93d4719 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 15 May 2020 17:10:07 +0200 Subject: [PATCH 1/2] Add the preprocessor tool for sfz files --- devtools/CMakeLists.txt | 3 ++ devtools/Preprocessor.cpp | 69 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 devtools/Preprocessor.cpp diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt index e4250d9c..399bb479 100644 --- a/devtools/CMakeLists.txt +++ b/devtools/CMakeLists.txt @@ -13,3 +13,6 @@ if(JACK_FOUND AND TARGET Qt5::Widgets) target_link_libraries(sfizz_capture_eg PRIVATE sfizz-sndfile Qt5::Widgets ${JACK_LIBRARIES}) set_target_properties(sfizz_capture_eg PROPERTIES AUTOUIC ON) endif() + +add_executable(sfizz_preprocessor Preprocessor.cpp) +target_link_libraries(sfizz_preprocessor sfizz_parser) diff --git a/devtools/Preprocessor.cpp b/devtools/Preprocessor.cpp new file mode 100644 index 00000000..c1a81748 --- /dev/null +++ b/devtools/Preprocessor.cpp @@ -0,0 +1,69 @@ +// 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 reads a SFZ file, and outputs it back into a single file + with all the includes and definitions processed. + + It can serve to facilitate identifying problems, whether these are related to + the parser or complicated instrument structures. + */ + +#include "parser/Parser.h" +#include + +class MyParserListener : public sfz::Parser::Listener { +public: + explicit MyParserListener(sfz::Parser& parser) + : _parser(parser) + { + } + +protected: + void onParseFullBlock(const std::string& header, const std::vector& opcodes) override + { + std::cout << '\n'; + std::cout << '<' << header << '>' << '\n'; + for (const sfz::Opcode& opc : opcodes) + std::cout << opc.opcode << '=' << opc.value << '\n'; + } + + void onParseError(const sfz::SourceRange& range, const std::string& message) override + { + const auto relativePath = range.start.filePath->lexically_relative(_parser.originalDirectory()); + std::cerr << "Parse error in " << relativePath << " at line " << range.start.lineNumber + 1 << ": " << message << '\n'; + } + + void onParseWarning(const sfz::SourceRange& range, const std::string& message) override + { + const auto relativePath = range.start.filePath->lexically_relative(_parser.originalDirectory()); + std::cerr << "Parse warning in " << relativePath << " at line " << range.start.lineNumber + 1 << ": " << message << '\n'; + } + +private: + sfz::Parser& _parser; +}; + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + std::cerr << "Please indicate the SFZ file path.\n"; + return 1; + } + + const fs::path sfzFilePath { argv[1] }; + + sfz::Parser parser; + MyParserListener listener(parser); + + parser.setListener(&listener); + parser.parseFile(argv[1]); + + if (parser.getErrorCount() > 0) + return 1; + + return 0; +} From 19fc5d65b6cd66be3d52963b3595bf20701076bb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 29 May 2020 02:18:53 +0200 Subject: [PATCH 2/2] Add option handling, and external definitions --- devtools/Preprocessor.cpp | 49 +++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/devtools/Preprocessor.cpp b/devtools/Preprocessor.cpp index c1a81748..f9dbfba6 100644 --- a/devtools/Preprocessor.cpp +++ b/devtools/Preprocessor.cpp @@ -13,6 +13,8 @@ */ #include "parser/Parser.h" +#include "../tests/cxxopts.hpp" +#include "absl/strings/string_view.h" #include class MyParserListener : public sfz::Parser::Listener { @@ -49,18 +51,57 @@ private: int main(int argc, char *argv[]) { - if (argc != 2) { + cxxopts::Options options("sfizz_preprocess", "Preprocess SFZ files"); + + options.positional_help(""); + + options.add_options() + ("D,define", "Add external definition", cxxopts::value>()) + ("i,input", "Input SFZ file", cxxopts::value()) + ("h,help", "Print usage"); + + options.parse_positional({"input"}); + + std::unique_ptr resultPtr; + try { + resultPtr = absl::make_unique(options.parse(argc, argv)); + } catch (cxxopts::OptionException& ex) { + std::cerr << ex.what() << "\n"; + return 1; + } + cxxopts::ParseResult& result = *resultPtr; + + if (result.count("help")) { + std::cerr << options.help() << "\n"; + return 0; + } + + if (!result.count("input")) { std::cerr << "Please indicate the SFZ file path.\n"; return 1; } - const fs::path sfzFilePath { argv[1] }; + const fs::path sfzFilePath { result["input"].as() }; sfz::Parser parser; MyParserListener listener(parser); - parser.setListener(&listener); - parser.parseFile(argv[1]); + + if (result.count("define")) { + auto& definitions = result["define"].as>(); + for (absl::string_view definition : definitions) { + size_t pos = definition.find('='); + if (pos == definition.npos) { + std::cerr << "The definition is malformed, should be key=value.\n"; + return 1; + } + absl::string_view key = definition.substr(0, pos); + absl::string_view val = definition.substr(pos + 1); + parser.addExternalDefinition(key, val); + } + } + + parser.parseFile(sfzFilePath); if (parser.getErrorCount() > 0) return 1;