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.

300 lines
8.4KB

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