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.7KB

  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. using Jack::JackMidiRawInputWriteQueue;
  20. JackMidiRawInputWriteQueue::
  21. JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue,
  22. size_t max_packet_data, size_t max_packets)
  23. {
  24. packet_queue = new JackMidiAsyncQueue(max_packet_data, max_packets);
  25. std::auto_ptr<JackMidiAsyncQueue> packet_queue_ptr(packet_queue);
  26. input_ring = jack_ringbuffer_create(max_packet_data + 1);
  27. if (! input_ring) {
  28. throw std::bad_alloc();
  29. }
  30. jack_ringbuffer_mlock(input_ring);
  31. Clear();
  32. expected_bytes = 0;
  33. event_pending = false;
  34. packet = 0;
  35. status_byte = 0;
  36. this->write_queue = write_queue;
  37. packet_queue_ptr.release();
  38. }
  39. JackMidiRawInputWriteQueue::~JackMidiRawInputWriteQueue()
  40. {
  41. jack_ringbuffer_free(input_ring);
  42. delete packet_queue;
  43. }
  44. void
  45. JackMidiRawInputWriteQueue::Clear()
  46. {
  47. jack_ringbuffer_reset(input_ring);
  48. total_bytes = 0;
  49. unbuffered_bytes = 0;
  50. }
  51. Jack::JackMidiWriteQueue::EnqueueResult
  52. JackMidiRawInputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
  53. jack_midi_data_t *buffer)
  54. {
  55. return packet_queue->EnqueueEvent(time, size, buffer);
  56. }
  57. void
  58. JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes,
  59. size_t total_bytes)
  60. {
  61. jack_error("JackMidiRawInputWriteQueue::HandleBufferFailure - %d MIDI "
  62. "byte(s) of a %d byte message could not be buffered. The "
  63. "message has been dropped.", unbuffered_bytes, total_bytes);
  64. }
  65. void
  66. JackMidiRawInputWriteQueue::HandleEventLoss(jack_midi_event_t *event)
  67. {
  68. jack_error("JackMidiRawInputWriteQueue::HandleEventLoss - A %d byte MIDI "
  69. "event scheduled for frame '%d' could not be processed because "
  70. "the write queue cannot accomodate an event of that size. The "
  71. "event has been discarded.", event->size, event->time);
  72. }
  73. void
  74. JackMidiRawInputWriteQueue::HandleIncompleteMessage(size_t total_bytes)
  75. {
  76. jack_error("JackMidiRawInputWriteQueue::HandleIncompleteMessage - "
  77. "Discarding %d MIDI byte(s) of an incomplete message. The "
  78. "MIDI cable may have been unplugged.", total_bytes);
  79. }
  80. void
  81. JackMidiRawInputWriteQueue::HandleInvalidStatusByte(jack_midi_data_t byte)
  82. {
  83. jack_error("JackMidiRawInputWriteQueue::HandleInvalidStatusByte - "
  84. "Dropping invalid MIDI status byte '%x'.", (unsigned int) byte);
  85. }
  86. void
  87. JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd(size_t total_bytes)
  88. {
  89. jack_error("JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd - "
  90. "Received a sysex end byte without first receiving a sysex "
  91. "start byte. Discarding %d MIDI byte(s). The cable may have "
  92. "been unplugged.", total_bytes);
  93. }
  94. bool
  95. JackMidiRawInputWriteQueue::PrepareBufferedEvent(jack_nframes_t time)
  96. {
  97. bool result = ! unbuffered_bytes;
  98. if (! result) {
  99. HandleBufferFailure(unbuffered_bytes, total_bytes);
  100. } else {
  101. size_t size = jack_ringbuffer_read_space(input_ring);
  102. jack_ringbuffer_data_t vector[2];
  103. jack_ringbuffer_get_read_vector(input_ring, vector);
  104. // We don't worry about the second part of the vector, as we reset the
  105. // ringbuffer after each parsed message.
  106. PrepareEvent(time, size, (jack_midi_data_t *) vector[0].buf);
  107. }
  108. Clear();
  109. if (status_byte >= 0xf0) {
  110. expected_bytes = 0;
  111. status_byte = 0;
  112. }
  113. return result;
  114. }
  115. bool
  116. JackMidiRawInputWriteQueue::PrepareByteEvent(jack_nframes_t time,
  117. jack_midi_data_t byte)
  118. {
  119. event_byte = byte;
  120. PrepareEvent(time, 1, &event_byte);
  121. return true;
  122. }
  123. void
  124. JackMidiRawInputWriteQueue::PrepareEvent(jack_nframes_t time, size_t size,
  125. jack_midi_data_t *buffer)
  126. {
  127. event.buffer = buffer;
  128. event.size = size;
  129. event.time = time;
  130. event_pending = true;
  131. }
  132. jack_nframes_t
  133. JackMidiRawInputWriteQueue::Process(jack_nframes_t boundary_frame)
  134. {
  135. if (event_pending) {
  136. if (! WriteEvent(boundary_frame)) {
  137. return event.time;
  138. }
  139. }
  140. if (! packet) {
  141. packet = packet_queue->DequeueEvent();
  142. }
  143. for (; packet; packet = packet_queue->DequeueEvent()) {
  144. for (; packet->size; (packet->buffer)++, (packet->size)--) {
  145. if (ProcessByte(packet->time, *(packet->buffer))) {
  146. if (! WriteEvent(boundary_frame)) {
  147. (packet->buffer)++;
  148. (packet->size)--;
  149. return event.time;
  150. }
  151. }
  152. }
  153. }
  154. return 0;
  155. }
  156. bool
  157. JackMidiRawInputWriteQueue::ProcessByte(jack_nframes_t time,
  158. jack_midi_data_t byte)
  159. {
  160. if (byte >= 0xf8) {
  161. // Realtime
  162. if (byte == 0xfd) {
  163. HandleInvalidStatusByte(byte);
  164. return false;
  165. }
  166. return PrepareByteEvent(time, byte);
  167. }
  168. if (byte == 0xf7) {
  169. // Sysex end
  170. if (status_byte == 0xf0) {
  171. RecordByte(byte);
  172. return PrepareBufferedEvent(time);
  173. }
  174. HandleUnexpectedSysexEnd(total_bytes);
  175. Clear();
  176. expected_bytes = 0;
  177. status_byte = 0;
  178. return false;
  179. }
  180. if (byte >= 0x80) {
  181. // Non-realtime status byte
  182. if (total_bytes) {
  183. HandleIncompleteMessage(total_bytes);
  184. Clear();
  185. }
  186. status_byte = byte;
  187. switch (byte & 0xf0) {
  188. case 0x80:
  189. case 0x90:
  190. case 0xa0:
  191. case 0xb0:
  192. case 0xe0:
  193. // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
  194. expected_bytes = 3;
  195. break;
  196. case 0xc0:
  197. case 0xd0:
  198. // Program Change, Channel Pressure
  199. expected_bytes = 2;
  200. break;
  201. case 0xf0:
  202. switch (byte) {
  203. case 0xf0:
  204. // Sysex
  205. expected_bytes = 0;
  206. break;
  207. case 0xf1:
  208. case 0xf3:
  209. // MTC Quarter Frame, Song Select
  210. expected_bytes = 2;
  211. break;
  212. case 0xf2:
  213. // Song Position
  214. expected_bytes = 3;
  215. break;
  216. case 0xf4:
  217. case 0xf5:
  218. // Undefined
  219. HandleInvalidStatusByte(byte);
  220. expected_bytes = 0;
  221. status_byte = 0;
  222. return false;
  223. case 0xf6:
  224. // Tune Request
  225. bool result = PrepareByteEvent(time, byte);
  226. if (result) {
  227. expected_bytes = 0;
  228. status_byte = 0;
  229. }
  230. return result;
  231. }
  232. }
  233. RecordByte(byte);
  234. return false;
  235. }
  236. // Data byte
  237. if (! status_byte) {
  238. // Data bytes without a status will be discarded.
  239. total_bytes++;
  240. unbuffered_bytes++;
  241. return false;
  242. }
  243. if (! total_bytes) {
  244. // Apply running status.
  245. RecordByte(status_byte);
  246. }
  247. RecordByte(byte);
  248. return (total_bytes == expected_bytes) ? PrepareBufferedEvent(time) :
  249. false;
  250. }
  251. void
  252. JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte)
  253. {
  254. if (jack_ringbuffer_write(input_ring, (const char *) &byte, 1) != 1) {
  255. unbuffered_bytes++;
  256. }
  257. total_bytes++;
  258. }
  259. bool
  260. JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame)
  261. {
  262. if ((! boundary_frame) || (event.time < boundary_frame)) {
  263. switch (write_queue->EnqueueEvent(&event)) {
  264. case BUFFER_TOO_SMALL:
  265. HandleEventLoss(&event);
  266. // Fallthrough on purpose
  267. case OK:
  268. event_pending = false;
  269. return true;
  270. default:
  271. // This is here to stop compilers from warning us about not
  272. // handling enumeration values.
  273. ;
  274. }
  275. }
  276. return false;
  277. }