Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
4.8KB

  1. // Copyright 2021 Jean Pierre Cimalando
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // SPDX-License-Identifier: Apache-2.0
  16. //
  17. #include "ysfx.h"
  18. #include "ysfx_preset.hpp"
  19. #include "ysfx_utils.hpp"
  20. #include <vector>
  21. #include <string>
  22. #include <cstring>
  23. #include "WDL/lineparse.h"
  24. static void ysfx_preset_clear(ysfx_preset_t *preset);
  25. static ysfx_bank_t *ysfx_load_bank_from_rpl_text(const std::string &text);
  26. static void ysfx_parse_preset_from_rpl_blob(ysfx_preset_t *preset, const char *name, const std::vector<uint8_t> &data);
  27. ysfx_bank_t *ysfx_load_bank(const char *path)
  28. {
  29. ysfx::FILE_u stream{fopen(path, "rb")};
  30. if (!stream)
  31. return nullptr;
  32. std::string input;
  33. constexpr uint32_t max_input = 1u << 24;
  34. input.reserve(1u << 16);
  35. for (int ch; input.size() < max_input && (ch = fgetc(stream.get())) != EOF; ) {
  36. ch = (ch == '\r' || ch == '\n') ? ' ' : ch;
  37. input.push_back((unsigned char)ch);
  38. }
  39. if (ferror(stream.get()))
  40. return nullptr;
  41. stream.reset();
  42. return ysfx_load_bank_from_rpl_text(input);
  43. }
  44. void ysfx_bank_free(ysfx_bank_t *bank)
  45. {
  46. if (!bank)
  47. return;
  48. delete[] bank->name;
  49. if (ysfx_preset_t *presets = bank->presets) {
  50. uint32_t count = bank->preset_count;
  51. for (uint32_t i = 0; i < count; ++i)
  52. ysfx_preset_clear(&presets[i]);
  53. delete[] presets;
  54. }
  55. delete bank;
  56. }
  57. static void ysfx_preset_clear(ysfx_preset_t *preset)
  58. {
  59. delete[] preset->name;
  60. preset->name = nullptr;
  61. ysfx_state_free(preset->state);
  62. preset->state = nullptr;
  63. }
  64. static ysfx_bank_t *ysfx_load_bank_from_rpl_text(const std::string &text)
  65. {
  66. LineParser parser;
  67. if (parser.parse(text.c_str()) < 0)
  68. return nullptr;
  69. ///
  70. std::vector<ysfx_preset_t> preset_list;
  71. preset_list.reserve(256);
  72. auto list_cleanup = ysfx::defer([&preset_list]() {
  73. for (ysfx_preset_t &pst : preset_list)
  74. ysfx_preset_clear(&pst);
  75. });
  76. ///
  77. int ntok = parser.getnumtokens();
  78. int itok = 0;
  79. if (strcmp("<REAPER_PRESET_LIBRARY", parser.gettoken_str(itok++)) != 0)
  80. return nullptr;
  81. const char *bank_name = parser.gettoken_str(itok++);
  82. std::string base64;
  83. base64.reserve(1024);
  84. while (itok < ntok) {
  85. if (strcmp("<PRESET", parser.gettoken_str(itok++)) == 0) {
  86. const char *preset_name = parser.gettoken_str(itok++);
  87. base64.clear();
  88. for (const char *part; itok < ntok &&
  89. strcmp(">", (part = parser.gettoken_str(itok++))) != 0; )
  90. base64.append(part);
  91. preset_list.emplace_back();
  92. ysfx_preset_t &preset = preset_list.back();
  93. ysfx_parse_preset_from_rpl_blob(
  94. &preset, preset_name,
  95. ysfx::decode_base64(base64.data(), base64.size()));
  96. }
  97. }
  98. ///
  99. ysfx_bank_u bank{new ysfx_bank_t{}};
  100. bank->name = ysfx::strdup_using_new(bank_name);
  101. bank->presets = new ysfx_preset_t[(uint32_t)preset_list.size()]{};
  102. bank->preset_count = (uint32_t)preset_list.size();
  103. for (uint32_t i = (uint32_t)preset_list.size(); i-- > 0; ) {
  104. bank->presets[i] = preset_list[i];
  105. preset_list.pop_back();
  106. }
  107. return bank.release();
  108. }
  109. static void ysfx_parse_preset_from_rpl_blob(ysfx_preset_t *preset, const char *name, const std::vector<uint8_t> &data)
  110. {
  111. ysfx_state_t state{};
  112. std::vector<ysfx_state_slider_t> sliders;
  113. size_t len = data.size();
  114. size_t pos = 0;
  115. while (pos < len && data[pos] != 0) ++pos;
  116. if (pos++ < len) {
  117. state.data = const_cast<uint8_t *>(&data[pos]);
  118. state.data_size = len - pos;
  119. LineParser parser;
  120. if (parser.parse((const char *)data.data()) >= 0) {
  121. sliders.reserve(ysfx_max_sliders);
  122. for (uint32_t i = 0; i < 64; ++i) {
  123. int success = false;
  124. ysfx_state_slider_t slider{};
  125. slider.index = i;
  126. slider.value = (ysfx_real)parser.gettoken_float(i, &success);
  127. if (success)
  128. sliders.push_back(slider);
  129. }
  130. state.sliders = sliders.data();
  131. state.slider_count = (uint32_t)sliders.size();
  132. }
  133. }
  134. preset->name = ysfx::strdup_using_new(name);
  135. preset->state = ysfx_state_dup(&state);
  136. }