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.

279 lines
8.5KB

  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_midi_port_info_t info;
  25. jack_nframes_t last_write_loc; /**< Used for both writing and mixdown */
  26. jack_nframes_t events_lost; /**< Number of events lost in this buffer */
  27. } jack_midi_port_info_private_t;
  28. typedef struct _jack_midi_port_internal_event {
  29. jack_nframes_t time;
  30. size_t size;
  31. size_t byte_offset;
  32. } jack_midi_port_internal_event_t;
  33. void
  34. jack_midi_reset_new_port(void *port_buffer,
  35. jack_nframes_t nframes)
  36. {
  37. jack_midi_port_info_private_t *info =
  38. (jack_midi_port_info_private_t *) port_buffer;
  39. info->info.event_count = 0;
  40. info->last_write_loc = 0;
  41. info->events_lost = 0;
  42. }
  43. jack_midi_port_info_t*
  44. jack_midi_port_get_info(void *port_buffer,
  45. jack_nframes_t nframes)
  46. {
  47. return (jack_midi_port_info_t *) port_buffer;
  48. }
  49. int
  50. jack_midi_event_get(jack_midi_event_t *event,
  51. void *port_buffer,
  52. jack_nframes_t event_idx,
  53. jack_nframes_t nframes)
  54. {
  55. jack_midi_port_internal_event_t *port_event;
  56. jack_midi_port_info_private_t *info =
  57. (jack_midi_port_info_private_t *) port_buffer;
  58. if (event_idx >= info->info.event_count)
  59. return ENODATA;
  60. port_event = (jack_midi_port_internal_event_t *) (info + 1);
  61. port_event += event_idx;
  62. event->time = port_event->time;
  63. event->size = port_event->size;
  64. event->buffer =
  65. ((jack_midi_data_t *) port_buffer) + port_event->byte_offset;
  66. return 0;
  67. }
  68. size_t
  69. jack_midi_max_event_size(void *port_buffer,
  70. jack_nframes_t nframes)
  71. {
  72. jack_midi_port_info_private_t *info =
  73. (jack_midi_port_info_private_t *) port_buffer;
  74. size_t buffer_size =
  75. nframes * sizeof(jack_default_audio_sample_t) / sizeof(unsigned char);
  76. /* (event_count + 1) below accounts for jack_midi_port_internal_event_t
  77. * which would be needed to store the next event */
  78. size_t used_size = sizeof(jack_midi_port_info_private_t)
  79. + info->last_write_loc
  80. + ((info->info.event_count + 1)
  81. * sizeof(jack_midi_port_internal_event_t));
  82. if (used_size > buffer_size)
  83. return 0;
  84. else
  85. return (buffer_size - used_size);
  86. }
  87. jack_midi_data_t*
  88. jack_midi_event_reserve(void *port_buffer,
  89. jack_nframes_t time,
  90. size_t data_size,
  91. jack_nframes_t nframes)
  92. {
  93. jack_midi_data_t *retbuf = (jack_midi_data_t *) port_buffer;
  94. /* FIXME: below line needs to know about buffer scale factor */
  95. jack_nframes_t buffer_size =
  96. nframes * sizeof(jack_default_audio_sample_t) / sizeof(unsigned char);
  97. jack_midi_port_info_private_t *info =
  98. (jack_midi_port_info_private_t *) port_buffer;
  99. jack_midi_port_internal_event_t *event_buffer =
  100. (jack_midi_port_internal_event_t *) (info + 1);
  101. /* Check if there is enough space in the buffer for the event. */
  102. if (info->last_write_loc + sizeof(jack_midi_port_info_private_t)
  103. + ((info->info.event_count + 1)
  104. * sizeof(jack_midi_port_internal_event_t))
  105. + data_size > buffer_size) {
  106. return NULL;
  107. } else {
  108. info->last_write_loc += data_size;
  109. retbuf = &retbuf[buffer_size - 1 - info->last_write_loc];
  110. event_buffer[info->info.event_count].time = time;
  111. event_buffer[info->info.event_count].size = data_size;
  112. event_buffer[info->info.event_count].byte_offset =
  113. buffer_size - 1 - info->last_write_loc;
  114. info->info.event_count += 1;
  115. return retbuf;
  116. }
  117. }
  118. int
  119. jack_midi_event_write(void *port_buffer,
  120. jack_nframes_t time,
  121. const jack_midi_data_t *data,
  122. size_t data_size,
  123. jack_nframes_t nframes)
  124. {
  125. jack_midi_data_t *retbuf =
  126. jack_midi_event_reserve(port_buffer, time, data_size, nframes);
  127. if (retbuf) {
  128. memcpy(retbuf, data, data_size);
  129. return 0;
  130. } else {
  131. return ENOBUFS;
  132. }
  133. }
  134. /* Can't check to make sure this port is an output anymore. If this gets
  135. * called on an input port, all clients after the client that calls it
  136. * will think there are no events in the buffer as the event count has
  137. * been reset.
  138. */
  139. void
  140. jack_midi_clear_buffer(void *port_buffer,
  141. jack_nframes_t nframes)
  142. {
  143. jack_midi_port_info_private_t *info =
  144. (jack_midi_port_info_private_t *) port_buffer;
  145. info->info.event_count = 0;
  146. info->last_write_loc = 0;
  147. info->events_lost = 0;
  148. }
  149. void
  150. jack_midi_port_mixdown(jack_port_t *port,
  151. jack_nframes_t nframes)
  152. {
  153. JSList *node;
  154. jack_port_t *input;
  155. jack_nframes_t num_events = 0;
  156. jack_nframes_t i = 0;
  157. int err = 0;
  158. /* The next (single) event to mix in to the buffer */
  159. jack_midi_port_info_private_t *earliest_info;
  160. jack_midi_port_internal_event_t *earliest_event;
  161. jack_midi_data_t *earliest_buffer;
  162. jack_midi_port_info_private_t *in_info; /* For finding next event */
  163. jack_midi_port_internal_event_t *in_events; /* Corresponds to in_info */
  164. jack_midi_port_info_private_t *out_info; /* Output 'buffer' */
  165. jack_midi_clear_buffer(port->mix_buffer, nframes);
  166. out_info = (jack_midi_port_info_private_t *) port->mix_buffer;
  167. /* This function uses jack_midi_port_info_private_t.last_write_loc of the
  168. * source ports to store indices of the last event read from that buffer
  169. * so far. This is OK because last_write_loc is used when writing events
  170. * to a buffer, which at this stage is already complete so the value
  171. * can be safely smashed. */
  172. /* Iterate through all connections to see how many events we need to mix,
  173. * and initialise their 'last event read' (last_write_loc) to 0 */
  174. for (node = port->connections; node; node = jack_slist_next(node)) {
  175. input = (jack_port_t *) node->data;
  176. in_info =
  177. (jack_midi_port_info_private_t *) jack_output_port_buffer(input);
  178. num_events += in_info->info.event_count;
  179. in_info->last_write_loc = 0;
  180. }
  181. /* Write the events in the order of their timestamps */
  182. for (i = 0; i < num_events; ++i) {
  183. earliest_info = NULL;
  184. earliest_event = NULL;
  185. earliest_buffer = NULL;
  186. /* Find the earliest unread event, to mix next
  187. * (search for an event earlier than earliest_event) */
  188. for (node = port->connections; node; node = jack_slist_next(node)) {
  189. in_info = (jack_midi_port_info_private_t *)
  190. jack_output_port_buffer(((jack_port_t *) node->data));
  191. in_events = (jack_midi_port_internal_event_t *) (in_info + 1);
  192. /* If there are unread events left in this port.. */
  193. if (in_info->info.event_count > in_info->last_write_loc) {
  194. /* .. and this event is the new earliest .. */
  195. if (earliest_info == NULL
  196. || in_events[in_info->last_write_loc].time
  197. <= earliest_event->time) {
  198. /* .. then set this event as the next earliest */
  199. earliest_info = in_info;
  200. earliest_event = (jack_midi_port_internal_event_t *)
  201. (&in_events[in_info->last_write_loc]);
  202. }
  203. }
  204. }
  205. if (earliest_info && earliest_event) {
  206. earliest_buffer = (jack_midi_data_t *) earliest_info;
  207. /* Write event to output */
  208. err = jack_midi_event_write(
  209. jack_port_buffer(port),
  210. earliest_event->time,
  211. &earliest_buffer[earliest_event->byte_offset],
  212. earliest_event->size,
  213. nframes);
  214. earliest_info->last_write_loc++;
  215. if (err) {
  216. out_info->events_lost = num_events - i;
  217. break;
  218. }
  219. }
  220. }
  221. assert(out_info->info.event_count == num_events - out_info->events_lost);
  222. }
  223. jack_nframes_t
  224. jack_midi_get_lost_event_count(void *port_buffer,
  225. jack_nframes_t nframes)
  226. {
  227. return ((jack_midi_port_info_private_t *) port_buffer)->events_lost;
  228. }