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.

ysfx_midi.cpp 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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_midi.hpp"
  18. #include <cstring>
  19. #include <cassert>
  20. void ysfx_midi_reserve(ysfx_midi_buffer_t *midi, uint32_t capacity, bool extensible)
  21. {
  22. std::vector<uint8_t> data;
  23. data.reserve(capacity);
  24. std::swap(data, midi->data);
  25. midi->extensible = extensible;
  26. ysfx_midi_rewind(midi);
  27. }
  28. void ysfx_midi_clear(ysfx_midi_buffer_t *midi)
  29. {
  30. midi->data.clear();
  31. ysfx_midi_rewind(midi);
  32. }
  33. bool ysfx_midi_push(ysfx_midi_buffer_t *midi, const ysfx_midi_event_t *event)
  34. {
  35. if (event->size > ysfx_midi_message_max_size)
  36. return false;
  37. if (event->bus >= ysfx_max_midi_buses)
  38. return false;
  39. ysfx_midi_header_t header;
  40. if (!midi->extensible) {
  41. size_t writable = midi->data.capacity() - midi->data.size();
  42. if (writable < sizeof(header) + event->size)
  43. return false;
  44. }
  45. const uint8_t *data = event->data;
  46. const uint8_t *headp = (const uint8_t *)&header;
  47. header.bus = event->bus;
  48. header.offset = event->offset;
  49. header.size = event->size;
  50. midi->data.insert(midi->data.end(), headp, headp + sizeof(header));
  51. midi->data.insert(midi->data.end(), data, data + header.size);
  52. return true;
  53. }
  54. void ysfx_midi_rewind(ysfx_midi_buffer_t *midi)
  55. {
  56. midi->read_pos = 0;
  57. for (uint32_t i = 0; i < ysfx_max_midi_buses; ++i)
  58. midi->read_pos_for_bus[i] = 0;
  59. }
  60. bool ysfx_midi_get_next(ysfx_midi_buffer_t *midi, ysfx_midi_event_t *event)
  61. {
  62. size_t *pos_ptr = &midi->read_pos;
  63. size_t pos = *pos_ptr;
  64. size_t avail = midi->data.size() - pos;
  65. ysfx_midi_header_t header;
  66. if (avail == 0)
  67. return false;
  68. assert(avail >= sizeof(header));
  69. memcpy(&header, &midi->data[pos], sizeof(header));
  70. assert(avail >= sizeof(header) + header.size);
  71. event->bus = header.bus;
  72. event->offset = header.offset;
  73. event->size = header.size;
  74. event->data = &midi->data[pos + sizeof(header)];
  75. *pos_ptr = pos + (sizeof(header) + header.size);
  76. return true;
  77. }
  78. bool ysfx_midi_get_next_from_bus(ysfx_midi_buffer_t *midi, uint32_t bus, ysfx_midi_event_t *event)
  79. {
  80. if (bus >= ysfx_max_midi_buses)
  81. return false;
  82. size_t *pos_ptr = &midi->read_pos_for_bus[bus];
  83. size_t pos = *pos_ptr;
  84. size_t avail = midi->data.size() - pos;
  85. ysfx_midi_header_t header;
  86. bool found = false;
  87. while (!found && avail > 0) {
  88. assert(avail >= sizeof(header));
  89. memcpy(&header, &midi->data[pos], sizeof(header));
  90. assert(avail >= sizeof(header) + header.size);
  91. found = header.bus == bus;
  92. if (!found) {
  93. pos += sizeof(header) + header.size;
  94. avail -= sizeof(header) + header.size;
  95. }
  96. }
  97. if (!found) {
  98. *pos_ptr = pos;
  99. return false;
  100. }
  101. event->bus = header.bus;
  102. event->offset = header.offset;
  103. event->size = header.size;
  104. event->data = &midi->data[pos + sizeof(header)];
  105. *pos_ptr = pos + (sizeof(header) + header.size);
  106. return true;
  107. }
  108. bool ysfx_midi_push_begin(ysfx_midi_buffer_t *midi, uint32_t bus, uint32_t offset, ysfx_midi_push_t *mp)
  109. {
  110. ysfx_midi_header_t header;
  111. mp->midi = midi;
  112. mp->start = midi->data.size();
  113. mp->count = 0;
  114. mp->eob = false;
  115. if (!midi->extensible) {
  116. size_t writable = midi->data.capacity() - midi->data.size();
  117. if (writable < sizeof(header)) {
  118. mp->eob = true;
  119. return false;
  120. }
  121. }
  122. header.bus = bus;
  123. header.offset = offset;
  124. header.size = 0;
  125. const uint8_t *headp = (const uint8_t *)&header;
  126. midi->data.insert(midi->data.end(), headp, headp + sizeof(header));
  127. return true;
  128. }
  129. bool ysfx_midi_push_data(ysfx_midi_push_t *mp, const uint8_t *data, uint32_t size)
  130. {
  131. if (mp->eob)
  132. return false;
  133. if (size > ysfx_midi_message_max_size || mp->count + size > ysfx_midi_message_max_size) {
  134. mp->eob = true;
  135. return false;
  136. }
  137. ysfx_midi_buffer_t *midi = mp->midi;
  138. if (!midi->extensible) {
  139. size_t writable = midi->data.capacity() - midi->data.size();
  140. if (writable < size) {
  141. mp->eob = true;
  142. return false;
  143. }
  144. }
  145. midi->data.insert(midi->data.end(), data, data + size);
  146. mp->count += size;
  147. return true;
  148. }
  149. bool ysfx_midi_push_end(ysfx_midi_push_t *mp)
  150. {
  151. if (mp->eob) {
  152. mp->midi->data.resize(mp->start);
  153. return false;
  154. }
  155. ysfx_midi_header_t header;
  156. uint8_t *headp = &mp->midi->data[mp->start];
  157. memcpy(&header, headp, sizeof(header));
  158. header.size = mp->count;
  159. memcpy(headp, &header, sizeof(header));
  160. return true;
  161. }
  162. //------------------------------------------------------------------------------
  163. uint32_t ysfx_midi_sizeof(uint8_t id)
  164. {
  165. if ((id >> 7) == 0) {
  166. return 0;
  167. }
  168. else if ((id >> 4) != 0b1111) {
  169. static const uint8_t sizetable[8] = {
  170. 3, 3, 3, 3, 2, 2, 3,
  171. };
  172. return sizetable[(id >> 4) & 0b111];
  173. }
  174. else {
  175. static const uint8_t sizetable[16] = {
  176. 0, 2, 3, 2, 1, 1, 1, 0,
  177. 1, 1, 1, 1, 1, 1, 1, 1,
  178. };
  179. return sizetable[id & 0b1111];
  180. }
  181. }