// Copyright 2021 Jean Pierre Cimalando // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 // #include "ysfx.h" #include "ysfx_preset.hpp" #include "ysfx_utils.hpp" #include #include #include #include "WDL/lineparse.h" static void ysfx_preset_clear(ysfx_preset_t *preset); static ysfx_bank_t *ysfx_load_bank_from_rpl_text(const std::string &text); static void ysfx_parse_preset_from_rpl_blob(ysfx_preset_t *preset, const char *name, const std::vector &data); ysfx_bank_t *ysfx_load_bank(const char *path) { #if defined(_WIN32) std::wstring wpath = ysfx::widen(path); ysfx::FILE_u stream{_wfopen(wpath.c_str(), L"rb")}; #else ysfx::FILE_u stream{fopen(path, "rb")}; #endif if (!stream) return nullptr; std::string input; constexpr uint32_t max_input = 1u << 24; input.reserve(1u << 16); for (int ch; input.size() < max_input && (ch = fgetc(stream.get())) != EOF; ) { ch = (ch == '\r' || ch == '\n') ? ' ' : ch; input.push_back((unsigned char)ch); } if (ferror(stream.get())) return nullptr; stream.reset(); return ysfx_load_bank_from_rpl_text(input); } void ysfx_bank_free(ysfx_bank_t *bank) { if (!bank) return; delete[] bank->name; if (ysfx_preset_t *presets = bank->presets) { uint32_t count = bank->preset_count; for (uint32_t i = 0; i < count; ++i) ysfx_preset_clear(&presets[i]); delete[] presets; } delete bank; } static void ysfx_preset_clear(ysfx_preset_t *preset) { delete[] preset->name; preset->name = nullptr; ysfx_state_free(preset->state); preset->state = nullptr; } static ysfx_bank_t *ysfx_load_bank_from_rpl_text(const std::string &text) { LineParser parser; if (parser.parse(text.c_str()) < 0) return nullptr; /// std::vector preset_list; preset_list.reserve(256); auto list_cleanup = ysfx::defer([&preset_list]() { for (ysfx_preset_t &pst : preset_list) ysfx_preset_clear(&pst); }); /// int ntok = parser.getnumtokens(); int itok = 0; if (strcmp(" blob; blob.reserve(64 * 1024); for (const char *part; itok < ntok && strcmp(">", (part = parser.gettoken_str(itok++))) != 0; ) { std::vector blobChunk = ysfx::decode_base64(part); blob.insert(blob.end(), blobChunk.begin(), blobChunk.end()); } preset_list.emplace_back(); ysfx_preset_t &preset = preset_list.back(); ysfx_parse_preset_from_rpl_blob(&preset, preset_name, blob); } } /// ysfx_bank_u bank{new ysfx_bank_t{}}; bank->name = ysfx::strdup_using_new(bank_name); bank->presets = new ysfx_preset_t[(uint32_t)preset_list.size()]{}; bank->preset_count = (uint32_t)preset_list.size(); for (uint32_t i = (uint32_t)preset_list.size(); i-- > 0; ) { bank->presets[i] = preset_list[i]; preset_list.pop_back(); } return bank.release(); } static void ysfx_parse_preset_from_rpl_blob(ysfx_preset_t *preset, const char *name, const std::vector &data) { ysfx_state_t state{}; std::vector sliders; const char *text = (const char *)data.data(); size_t len = data.size(); // find the null terminator size_t pos = 0; while (pos < len && data[pos] != 0) ++pos; // skip null terminator if there was one // otherwise null-terminate the text std::string textbuf; if (pos < len) ++pos; else { textbuf.assign(text, len); text = textbuf.c_str(); } // whatever follows null is the raw serialization state.data = const_cast(&data[pos]); state.data_size = len - pos; // parse a line of 64 slider floats (or '-' if missing) LineParser parser; if (parser.parse(text) >= 0) { sliders.reserve(ysfx_max_sliders); for (uint32_t i = 0; i < 64; ++i) { const char *str = parser.gettoken_str(i); bool skip = str[0] == '-' && str[1] == '\0'; if (!skip) { ysfx_state_slider_t slider{}; slider.index = i; slider.value = (ysfx_real)ysfx::dot_atof(str); sliders.push_back(slider); } } state.sliders = sliders.data(); state.slider_count = (uint32_t)sliders.size(); } preset->name = ysfx::strdup_using_new(name); preset->state = ysfx_state_dup(&state); }