|
- // 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 <vector>
- #include <string>
- #include <cstring>
-
- #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<uint8_t> &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<ysfx_preset_t> 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("<REAPER_PRESET_LIBRARY", parser.gettoken_str(itok++)) != 0)
- return nullptr;
-
- const char *bank_name = parser.gettoken_str(itok++);
-
- while (itok < ntok) {
- if (strcmp("<PRESET", parser.gettoken_str(itok++)) == 0) {
- const char *preset_name = parser.gettoken_str(itok++);
-
- std::vector<uint8_t> blob;
- blob.reserve(64 * 1024);
-
- for (const char *part; itok < ntok &&
- strcmp(">", (part = parser.gettoken_str(itok++))) != 0; )
- {
- std::vector<uint8_t> 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<uint8_t> &data)
- {
- ysfx_state_t state{};
- std::vector<ysfx_state_slider_t> 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<uint8_t *>(&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);
- }
|