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.

153 lines
4.2KB

  1. #include <rtosc/subtree-serialize.h>
  2. #include <rtosc/ports.h>
  3. #include <rtosc/rtosc.h>
  4. #include <cstring>
  5. #include <cassert>
  6. using namespace rtosc;
  7. static void emplace_uint32_cpp(uint8_t *buffer, uint32_t d)
  8. {
  9. buffer[0] = ((d>>24) & 0xff);
  10. buffer[1] = ((d>>16) & 0xff);
  11. buffer[2] = ((d>>8) & 0xff);
  12. buffer[3] = ((d>>0) & 0xff);
  13. }
  14. /*
  15. * Append another message onto a bundle if the space permits it.
  16. * If insufficient space is available, then zero is returned and the buffer is
  17. * untouched.
  18. *
  19. * If this is useful it may be generalized to rtosc_bundle_append()
  20. */
  21. static size_t append_bundle(char *dst, const char *src,
  22. size_t max_len, size_t dst_len, size_t src_len)
  23. {
  24. assert(rtosc_message_length(src,src_len) == src_len);
  25. //Handle Edge case alignment
  26. //if(rtosc_bundle_elements(dst, dst_len) == 0)
  27. // dst_len -= 4;
  28. if(max_len < dst_len + src_len + 4 || dst_len == 0 || src_len == 0)
  29. return 0;
  30. emplace_uint32_cpp((uint8_t*)(dst+dst_len), src_len);
  31. memcpy(dst+dst_len+4, src, src_len);
  32. return dst_len + src_len + 4;
  33. }
  34. //This object captures the output of any given port by calling it through a no
  35. //argument message
  36. //Assuming that the loc field is set correctly the message stored here will be
  37. //able to be replayed to get an object to a previous state
  38. class VarCapture : public RtData
  39. {
  40. public:
  41. char buf[128];
  42. char location[128];
  43. char msg[128];
  44. const char *dummy;
  45. bool success;
  46. VarCapture(void)
  47. :dummy("/ser\0\0\0\0,\0\0\0")
  48. {
  49. memset(buf, 0, sizeof(buf));
  50. memset(location, 0, sizeof(buf));
  51. this->loc = location;
  52. success = false;
  53. }
  54. const char *capture(const Ports *p, const char *path, void *obj_)
  55. {
  56. this->loc = location;
  57. assert(this->loc == location);
  58. this->obj = obj_;
  59. location[0] = '/';
  60. strcpy(location+1, path);
  61. success = false;
  62. size_t len = rtosc_message(msg, 128, path, "");
  63. (void) len;
  64. assert(len);
  65. assert(!strchr(path, ':'));
  66. p->dispatch(msg, *this);
  67. return success ? buf : NULL;
  68. }
  69. virtual void reply(const char *path, const char *args, ...)
  70. {
  71. assert(!success);
  72. assert(*path);
  73. va_list va;
  74. va_start(va, args);
  75. size_t len = rtosc_vmessage(buf, 128, path, args, va);
  76. (void) len;
  77. assert(len != 0);
  78. success = true;
  79. va_end(va);
  80. }
  81. virtual void broadcast(const char *msg)
  82. {
  83. (void) msg;
  84. }
  85. };
  86. struct subtree_args_t
  87. {
  88. VarCapture v, vv;
  89. size_t len;
  90. char *buffer;
  91. size_t buffer_size;
  92. void *object;
  93. rtosc::Ports *ports;
  94. };
  95. size_t subtree_serialize(char *buffer, size_t buffer_size,
  96. void *object, rtosc::Ports *ports)
  97. {
  98. (void) object;
  99. assert(buffer);
  100. assert(ports);
  101. subtree_args_t args;
  102. args.v.obj = object;
  103. args.len = rtosc_bundle(buffer, buffer_size, 0xdeadbeef0a0b0c0dULL, 0);
  104. args.buffer = buffer;
  105. args.buffer_size = buffer_size;
  106. args.object = object;
  107. args.ports = ports;
  108. //TODO FIXME this is not currently RT safe at the moment
  109. walk_ports(ports, args.v.loc, 128, &args, [](const Port *p, const char *, void *dat) {
  110. if(p->meta().find("internal") != p->meta().end())
  111. return;
  112. subtree_args_t *args = (subtree_args_t*) dat;
  113. const char *buf = args->vv.capture(args->ports, args->v.loc+1, args->object);
  114. if(buf)
  115. args->len = append_bundle(args->buffer, buf, args->buffer_size, args->len,
  116. rtosc_message_length(buf, 128));
  117. });
  118. return args.len;
  119. }
  120. void subtree_deserialize(char *buffer, size_t buffer_size,
  121. void *object, rtosc::Ports *ports, RtData &d)
  122. {
  123. d.obj = object;
  124. //simply replay all objects seen here
  125. for(unsigned i=0; i<rtosc_bundle_elements(buffer, buffer_size); ++i) {
  126. const char *msg = rtosc_bundle_fetch(buffer, i);
  127. ports->dispatch(msg+1, d);
  128. }
  129. }