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

298 lines
9.0KB

  1. /*
  2. Copyright (C) 2004-2006 Ian Esten
  3. Copyright (C) 2006 Dave Robillard
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. #include <assert.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <errno.h>
  20. #include <jack/jack.h>
  21. #include <jack/midiport.h>
  22. #include <jack/port.h>
  23. typedef struct _jack_midi_port_info_private {
  24. jack_nframes_t nframes; /**< Number of frames in buffer */
  25. size_t buffer_size; /**< Size of buffer in bytes */
  26. jack_nframes_t event_count; /**< Number of events stored in this buffer */
  27. jack_nframes_t last_write_loc; /**< Used for both writing and mixdown */
  28. jack_nframes_t events_lost; /**< Number of events lost in this buffer */
  29. } jack_midi_port_info_private_t;
  30. typedef struct _jack_midi_port_internal_event {
  31. int32_t time;
  32. jack_shmsize_t size;
  33. jack_shmsize_t byte_offset;
  34. } jack_midi_port_internal_event_t;
  35. /* jack_midi_port_functions.buffer_init */
  36. static void
  37. jack_midi_buffer_init(void *port_buffer,
  38. size_t buffer_size,
  39. jack_nframes_t nframes)
  40. {
  41. jack_midi_port_info_private_t *info =
  42. (jack_midi_port_info_private_t *) port_buffer;
  43. /* We can also add some magic field to midi buffer to validate client calls */
  44. info->nframes = nframes;
  45. info->buffer_size = buffer_size;
  46. info->event_count = 0;
  47. info->last_write_loc = 0;
  48. info->events_lost = 0;
  49. }
  50. jack_nframes_t
  51. jack_midi_get_event_count(void *port_buffer)
  52. {
  53. jack_midi_port_info_private_t *info =
  54. (jack_midi_port_info_private_t *) port_buffer;
  55. return info->event_count;
  56. }
  57. int
  58. jack_midi_event_get(jack_midi_event_t *event,
  59. void *port_buffer,
  60. jack_nframes_t event_idx)
  61. {
  62. jack_midi_port_internal_event_t *port_event;
  63. jack_midi_port_info_private_t *info =
  64. (jack_midi_port_info_private_t *) port_buffer;
  65. if (event_idx >= info->event_count)
  66. return ENODATA;
  67. port_event = (jack_midi_port_internal_event_t *) (info + 1);
  68. port_event += event_idx;
  69. event->time = port_event->time;
  70. event->size = port_event->size;
  71. event->buffer =
  72. ((jack_midi_data_t *) port_buffer) + port_event->byte_offset;
  73. return 0;
  74. }
  75. size_t
  76. jack_midi_max_event_size(void *port_buffer)
  77. {
  78. jack_midi_port_info_private_t *info =
  79. (jack_midi_port_info_private_t *) port_buffer;
  80. size_t buffer_size =
  81. info->buffer_size;
  82. /* (event_count + 1) below accounts for jack_midi_port_internal_event_t
  83. * which would be needed to store the next event */
  84. size_t used_size = sizeof(jack_midi_port_info_private_t)
  85. + info->last_write_loc
  86. + ((info->event_count + 1)
  87. * sizeof(jack_midi_port_internal_event_t));
  88. if (used_size > buffer_size)
  89. return 0;
  90. else
  91. return (buffer_size - used_size);
  92. }
  93. jack_midi_data_t*
  94. jack_midi_event_reserve(void *port_buffer,
  95. jack_nframes_t time,
  96. size_t data_size)
  97. {
  98. jack_midi_data_t *retbuf = (jack_midi_data_t *) port_buffer;
  99. jack_midi_port_info_private_t *info =
  100. (jack_midi_port_info_private_t *) port_buffer;
  101. jack_midi_port_internal_event_t *event_buffer =
  102. (jack_midi_port_internal_event_t *) (info + 1);
  103. size_t buffer_size =
  104. info->buffer_size;
  105. if (time < 0 || time >= info->nframes)
  106. goto failed;
  107. if (info->event_count > 0 && time < event_buffer[info->event_count-1].time)
  108. goto failed;
  109. /* Check if data_size is >0 and there is enough space in the buffer for the event. */
  110. if (data_size <=0 ||
  111. info->last_write_loc + sizeof(jack_midi_port_info_private_t)
  112. + ((info->event_count + 1)
  113. * sizeof(jack_midi_port_internal_event_t))
  114. + data_size > buffer_size) {
  115. goto failed;
  116. } else {
  117. info->last_write_loc += data_size;
  118. retbuf = &retbuf[buffer_size - 1 - info->last_write_loc];
  119. event_buffer[info->event_count].time = time;
  120. event_buffer[info->event_count].size = data_size;
  121. event_buffer[info->event_count].byte_offset =
  122. buffer_size - 1 - info->last_write_loc;
  123. info->event_count += 1;
  124. return retbuf;
  125. }
  126. failed:
  127. info->events_lost++;
  128. return NULL;
  129. }
  130. int
  131. jack_midi_event_write(void *port_buffer,
  132. jack_nframes_t time,
  133. const jack_midi_data_t *data,
  134. size_t data_size)
  135. {
  136. jack_midi_data_t *retbuf =
  137. jack_midi_event_reserve(port_buffer, time, data_size);
  138. if (retbuf) {
  139. memcpy(retbuf, data, data_size);
  140. return 0;
  141. } else {
  142. return ENOBUFS;
  143. }
  144. }
  145. /* Can't check to make sure this port is an output anymore. If this gets
  146. * called on an input port, all clients after the client that calls it
  147. * will think there are no events in the buffer as the event count has
  148. * been reset.
  149. */
  150. void
  151. jack_midi_clear_buffer(void *port_buffer)
  152. {
  153. jack_midi_port_info_private_t *info =
  154. (jack_midi_port_info_private_t *) port_buffer;
  155. info->event_count = 0;
  156. info->last_write_loc = 0;
  157. info->events_lost = 0;
  158. }
  159. /* jack_midi_port_functions.mixdown */
  160. static void
  161. jack_midi_port_mixdown(jack_port_t *port, jack_nframes_t nframes)
  162. {
  163. JSList *node;
  164. jack_port_t *input;
  165. jack_nframes_t num_events = 0;
  166. jack_nframes_t i = 0;
  167. int err = 0;
  168. jack_nframes_t lost_events = 0;
  169. /* The next (single) event to mix in to the buffer */
  170. jack_midi_port_info_private_t *earliest_info;
  171. jack_midi_port_internal_event_t *earliest_event;
  172. jack_midi_data_t *earliest_buffer;
  173. jack_midi_port_info_private_t *in_info; /* For finding next event */
  174. jack_midi_port_internal_event_t *in_events; /* Corresponds to in_info */
  175. jack_midi_port_info_private_t *out_info; /* Output 'buffer' */
  176. jack_midi_clear_buffer(port->mix_buffer);
  177. out_info = (jack_midi_port_info_private_t *) port->mix_buffer;
  178. /* This function uses jack_midi_port_info_private_t.last_write_loc of the
  179. * source ports to store indices of the last event read from that buffer
  180. * so far. This is OK because last_write_loc is used when writing events
  181. * to a buffer, which at this stage is already complete so the value
  182. * can be safely smashed. */
  183. /* Iterate through all connections to see how many events we need to mix,
  184. * and initialise their 'last event read' (last_write_loc) to 0 */
  185. for (node = port->connections; node; node = jack_slist_next(node)) {
  186. input = (jack_port_t *) node->data;
  187. in_info =
  188. (jack_midi_port_info_private_t *) jack_output_port_buffer(input);
  189. num_events += in_info->event_count;
  190. lost_events += in_info->events_lost;
  191. in_info->last_write_loc = 0;
  192. }
  193. /* Write the events in the order of their timestamps */
  194. for (i = 0; i < num_events; ++i) {
  195. earliest_info = NULL;
  196. earliest_event = NULL;
  197. earliest_buffer = NULL;
  198. /* Find the earliest unread event, to mix next
  199. * (search for an event earlier than earliest_event) */
  200. for (node = port->connections; node; node = jack_slist_next(node)) {
  201. in_info = (jack_midi_port_info_private_t *)
  202. jack_output_port_buffer(((jack_port_t *) node->data));
  203. in_events = (jack_midi_port_internal_event_t *) (in_info + 1);
  204. /* If there are unread events left in this port.. */
  205. if (in_info->event_count > in_info->last_write_loc) {
  206. /* .. and this event is the new earliest .. */
  207. /* NOTE: that's why we compare time with <, not <= */
  208. if (earliest_info == NULL
  209. || in_events[in_info->last_write_loc].time
  210. < earliest_event->time) {
  211. /* .. then set this event as the next earliest */
  212. earliest_info = in_info;
  213. earliest_event = (jack_midi_port_internal_event_t *)
  214. (&in_events[in_info->last_write_loc]);
  215. }
  216. }
  217. }
  218. if (earliest_info && earliest_event) {
  219. earliest_buffer = (jack_midi_data_t *) earliest_info;
  220. /* Write event to output */
  221. err = jack_midi_event_write(
  222. jack_port_buffer(port),
  223. earliest_event->time,
  224. &earliest_buffer[earliest_event->byte_offset],
  225. earliest_event->size);
  226. earliest_info->last_write_loc++;
  227. if (err) {
  228. out_info->events_lost = num_events - i;
  229. break;
  230. }
  231. }
  232. }
  233. assert(out_info->event_count == num_events - out_info->events_lost);
  234. // inherit total lost events count from all connected ports.
  235. out_info->events_lost += lost_events;
  236. }
  237. jack_nframes_t
  238. jack_midi_get_lost_event_count(void *port_buffer)
  239. {
  240. return ((jack_midi_port_info_private_t *) port_buffer)->events_lost;
  241. }
  242. jack_port_functions_t jack_builtin_midi_functions = {
  243. .buffer_init = jack_midi_buffer_init,
  244. .mixdown = jack_midi_port_mixdown,
  245. };