C++ API Reference RNBO: src/RNBO_Presets.h Source File

RNBO: src/RNBO_Presets.h Source File

Go to the documentation of this file.
1 //
2 // RNBO_Presets.h
3 //
4 
5 #ifndef _RNBO_Presets_H_
6 #define _RNBO_Presets_H_
7 
8 #ifdef RNBO_NOSTL
9 #define RNBO_NOPRESETS
10 #endif // RNBO_NOSTL
11 
12 #include "RNBO_PatcherState.h"
13 
14 #ifdef RNBO_NOPRESETS
15 
16 namespace RNBO {
17  using Preset = PatcherState;
18  using PresetCallback = void(*);
19  using UniquePresetPtr = void*;
20  using PresetPtr = std::shared_ptr<Preset>;
21  using ConstPresetPtr = std::shared_ptr<const Preset>;
22 
23  class DummyPreset : public PatcherState
24  {
25  public:
26  bool isDummy() const override { return true; }
27  };
28 }
29 
30 #else
31 
32 #include "RNBO_Debug.h"
33 
34 RNBO_PUSH_DISABLE_WARNINGS
35 #include "3rdparty/json/json.hpp"
36 RNBO_POP_DISABLE_WARNINGS
37 
38 #include "RNBO_Utils.h"
39 #include "RNBO_ExternalData.h"
40 
41 #include "3rdparty/cppcodec/base64_rfc4648.hpp"
42 
43 using base64 = cppcodec::base64_rfc4648;
44 
51 namespace RNBO {
52 
53  using PresetMap = StateMap;
54 
60 
67  using PresetPtr = std::shared_ptr<Preset>;
68 
73  using PresetCallback = std::function<void(std::shared_ptr<const Preset>)>;
74 
81  using ConstPresetPtr = std::shared_ptr<const Preset>;
82 
87  std::string name;
88  PresetPtr preset;
89  };
90 
91  class DummyPreset : public PatcherState
92  {
93  public:
94  bool isDummy() const override { return true; }
95  };
96 
97 #ifdef RNBO_NOSTL
99 #else
100 
106  using UniquePresetPtr = std::unique_ptr<Preset>;
107 #endif // RNBO_NOSTL
108 
109 #ifndef RNBO_NOJSONPRESETS
110 
111  using Json = nlohmann::json;
112 
113  static Json convertPresetToJSONObj(const Preset& preset) {
114  Json json;
115  for (auto const& entry : preset) {
116  const char *key = entry.first.c_str();
117  auto type = entry.second.getType();
118  switch (type) {
119  case ValueHolder::FLOAT: {
120  float value = (float)entry.second;
121  json[key] = value;
122  break;
123  }
124  case ValueHolder::DOUBLE: {
125  double value = (double)entry.second;
126  json[key] = value;
127  break;
128  }
129  case ValueHolder::LIST: {
130  Json j;
131  const list& value = entry.second;
132  for (size_t i = 0; i < value.length; i++) {
133  j.push_back(value[i]);
134  }
135  json[key] = j;
136  break;
137  }
138  case ValueHolder::STRING: {
139  const char * str = entry.second;
140  json[key] = str;
141  break;
142  }
143  case ValueHolder::SUBSTATE: {
144  const Preset& subPreset = entry.second;
145  json[key] = convertPresetToJSONObj(subPreset);
146  break;
147  }
149  Index size = entry.second.getSubStateMapSize();
150  if (size) {
151  Json j;
152  for (Index i = 0; i < size; i++) {
153  const Preset& subPreset = entry.second[i];
154  j.push_back(convertPresetToJSONObj(subPreset));
155  }
156  json[key] = j;
157  }
158  break;
159  }
160  case ValueHolder::UINT32: {
161  UInt32 value = (UInt32)entry.second;
162  json[key] = value;
163  break;
164  }
165  case ValueHolder::UINT64: {
166  UInt64 value = (UInt64)entry.second;
167  json[key] = value;
168  break;
169  }
170  case ValueHolder::BUFFER: {
171  SerializedBuffer& buffer = (SerializedBuffer&)entry.second;
172 
173  Json binJson;
174  binJson["binary"] = true;
175  std::string binaryString = base64::encode(buffer.data, buffer.sizeInBytes);
176  binJson["data"] = binaryString;
177 
178  Json typeJson;
179  switch (buffer.type.type) {
180  case DataType::Untyped:
181  typeJson["type"] = "Untyped";
182  break;
184  typeJson["type"] = "Float32AudioBuffer";
185  break;
187  typeJson["type"] = "Float64AudioBuffer";
188  break;
190  typeJson["type"] = "TypedArray";
191  break;
193  RNBO_ASSERT(false); // we must not ever have a serialized buffer with undetermined bitness
194  break;
195  }
196 
197  if (buffer.type.type == DataType::Float32AudioBuffer || buffer.type.type == DataType::Float64AudioBuffer) {
198  typeJson["channels"] = buffer.type.audioBufferInfo.channels;
199  typeJson["samplerate"] = buffer.type.audioBufferInfo.samplerate;
200  }
201 
202  binJson["type"] = typeJson;
203  json[key] = binJson;
204  break;
205  }
206  case ValueHolder::NONE:
207  case ValueHolder::EXTERNAL:
208  case ValueHolder::EVENTTARGET:
209  case ValueHolder::DATAREF:
210  case ValueHolder::MULTIREF:
211  case ValueHolder::SIGNAL:
212  case ValueHolder::BOOLEAN:
213  case ValueHolder::INTVALUE:
214  default:
215  // we do only support numbers, lists and substates
216  RNBO_ASSERT(false);
217  }
218  }
219 
220  return json;
221  }
222 
223  ATTRIBUTE_UNUSED
224  static std::string convertPresetToJSON(const Preset& preset) {
225  return convertPresetToJSONObj(preset).dump();
226  }
227 
228  static void convertJSONObjToPreset(Json& json, Preset& preset) {
229  for (Json::iterator it = json.begin(); it != json.end(); it++) {
230  const char* key = it.key().c_str();
231  if (it->is_number()) {
232  number value = it.value();
233  preset[key] = value;
234  }
235  else if (it->is_string()) {
236  std::string value = it.value();
237  preset[key] = value.c_str();
238  }
239  else if (it->is_array()) {
240  Json& j = *it;
241  if (j.size() > 0) {
242  if (j[0].is_number()) {
243  list value;
244  for (Index i = 0; i < j.size(); i++) {
245  value.push(j[i]);
246  }
247  preset[key] = value;
248  }
249  else if (j[0].is_object()) {
250  for (Index i = 0; i < j.size(); i++) {
251  Preset& subPreset = preset[key][i];
252  convertJSONObjToPreset(j[i], subPreset);
253  }
254  }
255  }
256  }
257  else if (it->is_object()) {
258  Json& j = *it;
259  if (j.contains("binary") && j["binary"] == true) {
260  SerializedBuffer buffer;
261 
262  if (j.contains("data") && j["data"].is_string()) {
263  std::string data = j["data"];
264  size_t size = base64::decoded_max_size(data.length());
265 
266  buffer.data = (uint8_t *)malloc(size);
267  buffer.sizeInBytes = base64::decode(buffer.data, size, data);
268  }
269 
270  if (j.contains("type") && j["type"].is_object()) {
271  auto& typeJson = j.at("type");
272  std::string type = typeJson["type"];
273  if (type == "Float32AudioBuffer") {
274  buffer.type = Float32AudioBuffer(typeJson["channels"], typeJson["samplerate"]);
275  }
276  else if (type == "Float64AudioBuffer") {
277  buffer.type = Float64AudioBuffer(typeJson["channels"], typeJson["samplerate"]);
278  }
279  else if (type == "TypedArray") {
280  DataType t;
281  t.type = DataType::TypedArray;
282  buffer.type = t;
283  }
284  else {
285  buffer.type = UntypedDataBuffer();
286  }
287  }
288 
289  preset[key] = buffer;
290  }
291  else {
292  Preset& subPreset = preset.getSubState(key);
293  convertJSONObjToPreset(j, subPreset);
294  }
295  }
296  }
297  }
298 
299  ATTRIBUTE_UNUSED
300  static void convertJSONArrayToPresetList(std::string jsonString, std::vector<std::shared_ptr<NamedPresetEntry>>& presetList) {
301  Json json = Json::parse(jsonString);
302  for (Json::iterator it = json.begin(); it != json.end(); it++) {
303  if (it->is_object()) {
304  Json& j = *it;
305  std::shared_ptr<NamedPresetEntry> entry(new NamedPresetEntry);
306  std::string name = j["name"];
307  Json presetPayload = j["preset"];
308  entry->name = name;
309  PresetPtr preset = std::make_shared<Preset>();
310  convertJSONObjToPreset(presetPayload, *preset);
311  entry->preset = preset;
312  presetList.push_back(entry);
313  }
314  }
315  }
316 
317  ATTRIBUTE_UNUSED
318  static UniquePresetPtr convertJSONToPreset(std::string jsonString) {
319  UniquePresetPtr preset = make_unique<Preset>();
320  Json json = Json::parse(jsonString);
321  convertJSONObjToPreset(json, *preset);
322  return preset;
323  }
324 
325  ATTRIBUTE_UNUSED
326  static void copyPreset(const Preset& src, Preset &dst)
327  {
328  for (auto const& entry : src) {
329  const char *key = entry.first.c_str();
330  auto type = entry.second.getType();
331  switch (type) {
332  case ValueHolder::FLOAT: {
333  float value = (float)entry.second;
334  dst[key] = value;
335  break;
336  }
337  case ValueHolder::DOUBLE: {
338  double value = (double)entry.second;
339  dst[key] = value;
340  break;
341  }
342  case ValueHolder::UINT32: {
343  UInt32 value = (UInt32)entry.second;
344  dst[key] = value;
345  break;
346  }
347  case ValueHolder::UINT64: {
348  UInt64 value = (UInt64)entry.second;
349  dst[key] = value;
350  break;
351  }
352  case ValueHolder::LIST: {
353  Json j;
354  const list& srclist = entry.second;
355  list dstlist;
356  for (Index i = 0; i < srclist.length; i++) {
357  dstlist.push(srclist[i]);
358  }
359  dst[key] = dstlist;
360  break;
361  }
362  case ValueHolder::SUBSTATE: {
363  const Preset& preset = entry.second;
364  copyPreset(preset, dst[key]);
365  break;
366  }
368  Index size = entry.second.getSubStateMapSize();
369  if (size) {
370  for (Index i = 0; i < size; i++) {
371  const Preset& preset = entry.second[i];
372  Preset& dstSubPreset = dst[key][i];
373  copyPreset(preset, dstSubPreset);
374  }
375  }
376  break;
377  }
378  case ValueHolder::STRING:
379  //presetid
380  RNBO_ASSERT(strcmp(key, "__presetid") == 0);
381  break;
382  case ValueHolder::BUFFER: {
383  SerializedBuffer tmp = (SerializedBuffer&)entry.second;
384  dst[key] = tmp;
385  break;
386  }
387  case ValueHolder::NONE:
388  case ValueHolder::EXTERNAL:
389  case ValueHolder::EVENTTARGET:
390  case ValueHolder::DATAREF:
391  case ValueHolder::MULTIREF:
392  case ValueHolder::SIGNAL:
393  case ValueHolder::BOOLEAN:
394  case ValueHolder::INTVALUE:
395  default:
396  // we do only support numbers, lists and substates
397  RNBO_ASSERT(false);
398  break;
399  }
400  }
401  }
402 
403 #endif // RNBO_NOJSONPRESETS
404 
405 } // namespace RNBO
406 
407 #endif // RNBO_NOPRESETS
408 
409 #endif // _RNBO_Presets_H_