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.

307 lines
8.8KB

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