jack2 codebase
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.

301 lines
8.5KB

  1. /*
  2. Copyright (C) 2010 Devin Anderson
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include <cassert>
  16. #include <memory>
  17. #include <new>
  18. #include "JackMidiRawInputWriteQueue.h"
  19. #include "JackError.h"
  20. using Jack::JackMidiRawInputWriteQueue;
  21. JackMidiRawInputWriteQueue::
  22. JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue,
  23. size_t max_packet_data, size_t max_packets)
  24. {
  25. packet_queue = new JackMidiAsyncQueue(max_packet_data, max_packets);
  26. std::unique_ptr<JackMidiAsyncQueue> packet_queue_ptr(packet_queue);
  27. input_buffer = new jack_midi_data_t[max_packet_data];
  28. Clear();
  29. expected_bytes = 0;
  30. event_pending = false;
  31. input_buffer_size = max_packet_data;
  32. packet = 0;
  33. status_byte = 0;
  34. this->write_queue = write_queue;
  35. packet_queue_ptr.release();
  36. }
  37. JackMidiRawInputWriteQueue::~JackMidiRawInputWriteQueue()
  38. {
  39. delete[] input_buffer;
  40. delete packet_queue;
  41. }
  42. void
  43. JackMidiRawInputWriteQueue::Clear()
  44. {
  45. total_bytes = 0;
  46. unbuffered_bytes = 0;
  47. }
  48. Jack::JackMidiWriteQueue::EnqueueResult
  49. JackMidiRawInputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
  50. jack_midi_data_t *buffer)
  51. {
  52. return packet_queue->EnqueueEvent(time, size, buffer);
  53. }
  54. size_t
  55. JackMidiRawInputWriteQueue::GetAvailableSpace()
  56. {
  57. return packet_queue->GetAvailableSpace();
  58. }
  59. void
  60. JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes,
  61. size_t total_bytes)
  62. {
  63. jack_error("JackMidiRawInputWriteQueue::HandleBufferFailure - %d MIDI "
  64. "byte(s) of a %d byte message could not be buffered. The "
  65. "message has been dropped.", unbuffered_bytes, total_bytes);
  66. }
  67. void
  68. JackMidiRawInputWriteQueue::HandleEventLoss(jack_midi_event_t *event)
  69. {
  70. jack_error("JackMidiRawInputWriteQueue::HandleEventLoss - A %d byte MIDI "
  71. "event scheduled for frame '%d' could not be processed because "
  72. "the write queue cannot accommodate an event of that size. The "
  73. "event has been discarded.", event->size, event->time);
  74. }
  75. void
  76. JackMidiRawInputWriteQueue::HandleIncompleteMessage(size_t total_bytes)
  77. {
  78. jack_error("JackMidiRawInputWriteQueue::HandleIncompleteMessage - "
  79. "Discarding %d MIDI byte(s) of an incomplete message. The "
  80. "MIDI cable may have been unplugged.", total_bytes);
  81. }
  82. void
  83. JackMidiRawInputWriteQueue::HandleInvalidStatusByte(jack_midi_data_t byte)
  84. {
  85. jack_error("JackMidiRawInputWriteQueue::HandleInvalidStatusByte - "
  86. "Dropping invalid MIDI status byte '%x'.", (unsigned int) byte);
  87. }
  88. void
  89. JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd(size_t total_bytes)
  90. {
  91. jack_error("JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd - "
  92. "Received a sysex end byte without first receiving a sysex "
  93. "start byte. Discarding %d MIDI byte(s). The cable may have "
  94. "been unplugged.", total_bytes);
  95. }
  96. bool
  97. JackMidiRawInputWriteQueue::PrepareBufferedEvent(jack_nframes_t time)
  98. {
  99. bool result = ! unbuffered_bytes;
  100. if (! result) {
  101. HandleBufferFailure(unbuffered_bytes, total_bytes);
  102. } else {
  103. PrepareEvent(time, total_bytes, input_buffer);
  104. }
  105. Clear();
  106. if (status_byte >= 0xf0) {
  107. expected_bytes = 0;
  108. status_byte = 0;
  109. }
  110. return result;
  111. }
  112. bool
  113. JackMidiRawInputWriteQueue::PrepareByteEvent(jack_nframes_t time,
  114. jack_midi_data_t byte)
  115. {
  116. event_byte = byte;
  117. PrepareEvent(time, 1, &event_byte);
  118. return true;
  119. }
  120. void
  121. JackMidiRawInputWriteQueue::PrepareEvent(jack_nframes_t time, size_t size,
  122. jack_midi_data_t *buffer)
  123. {
  124. event.buffer = buffer;
  125. event.size = size;
  126. event.time = time;
  127. event_pending = true;
  128. }
  129. jack_nframes_t
  130. JackMidiRawInputWriteQueue::Process(jack_nframes_t boundary_frame)
  131. {
  132. if (event_pending) {
  133. if (! WriteEvent(boundary_frame)) {
  134. return event.time;
  135. }
  136. }
  137. if (! packet) {
  138. packet = packet_queue->DequeueEvent();
  139. }
  140. for (; packet; packet = packet_queue->DequeueEvent()) {
  141. for (; packet->size; (packet->buffer)++, (packet->size)--) {
  142. if (ProcessByte(packet->time, *(packet->buffer))) {
  143. if (! WriteEvent(boundary_frame)) {
  144. (packet->buffer)++;
  145. (packet->size)--;
  146. return event.time;
  147. }
  148. }
  149. }
  150. }
  151. return 0;
  152. }
  153. bool
  154. JackMidiRawInputWriteQueue::ProcessByte(jack_nframes_t time,
  155. jack_midi_data_t byte)
  156. {
  157. if (byte >= 0xf8) {
  158. // Realtime
  159. if (byte == 0xfd) {
  160. HandleInvalidStatusByte(byte);
  161. return false;
  162. }
  163. return PrepareByteEvent(time, byte);
  164. }
  165. if (byte == 0xf7) {
  166. // Sysex end
  167. if (status_byte == 0xf0) {
  168. RecordByte(byte);
  169. return PrepareBufferedEvent(time);
  170. }
  171. HandleUnexpectedSysexEnd(total_bytes);
  172. Clear();
  173. expected_bytes = 0;
  174. status_byte = 0;
  175. return false;
  176. }
  177. if (byte >= 0x80) {
  178. // Non-realtime status byte
  179. if (total_bytes) {
  180. HandleIncompleteMessage(total_bytes);
  181. Clear();
  182. }
  183. status_byte = byte;
  184. switch (byte & 0xf0) {
  185. case 0x80:
  186. case 0x90:
  187. case 0xa0:
  188. case 0xb0:
  189. case 0xe0:
  190. // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
  191. expected_bytes = 3;
  192. break;
  193. case 0xc0:
  194. case 0xd0:
  195. // Program Change, Channel Pressure
  196. expected_bytes = 2;
  197. break;
  198. case 0xf0:
  199. switch (byte) {
  200. case 0xf0:
  201. // Sysex
  202. expected_bytes = 0;
  203. break;
  204. case 0xf1:
  205. case 0xf3:
  206. // MTC Quarter Frame, Song Select
  207. expected_bytes = 2;
  208. break;
  209. case 0xf2:
  210. // Song Position
  211. expected_bytes = 3;
  212. break;
  213. case 0xf4:
  214. case 0xf5:
  215. // Undefined
  216. HandleInvalidStatusByte(byte);
  217. expected_bytes = 0;
  218. status_byte = 0;
  219. return false;
  220. case 0xf6:
  221. // Tune Request
  222. bool result = PrepareByteEvent(time, byte);
  223. if (result) {
  224. expected_bytes = 0;
  225. status_byte = 0;
  226. }
  227. return result;
  228. }
  229. }
  230. RecordByte(byte);
  231. return false;
  232. }
  233. // Data byte
  234. if (! status_byte) {
  235. // Data bytes without a status will be discarded.
  236. total_bytes++;
  237. unbuffered_bytes++;
  238. return false;
  239. }
  240. if (! total_bytes) {
  241. // Apply running status.
  242. RecordByte(status_byte);
  243. }
  244. RecordByte(byte);
  245. return (total_bytes == expected_bytes) ? PrepareBufferedEvent(time) :
  246. false;
  247. }
  248. void
  249. JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte)
  250. {
  251. if (total_bytes < input_buffer_size) {
  252. input_buffer[total_bytes] = byte;
  253. } else {
  254. unbuffered_bytes++;
  255. }
  256. total_bytes++;
  257. }
  258. bool
  259. JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame)
  260. {
  261. if ((! boundary_frame) || (event.time < boundary_frame)) {
  262. switch (write_queue->EnqueueEvent(&event)) {
  263. case BUFFER_TOO_SMALL:
  264. HandleEventLoss(&event);
  265. // Fallthrough on purpose
  266. case OK:
  267. event_pending = false;
  268. return true;
  269. default:
  270. // This is here to stop compilers from warning us about not
  271. // handling enumeration values.
  272. ;
  273. }
  274. }
  275. return false;
  276. }