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.

316 lines
11KB

  1. /*
  2. Copyright (C) 2004 Ian Esten
  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 <stdio.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <jack/jack.h>
  19. #include <jack/midiport.h>
  20. #include <jack/port.h>
  21. /* even though the new implementation with byte offsets being stored instead of
  22. * pointers, last_write_loc can't be removed as it gets used in the mixdown
  23. * function. */
  24. typedef struct _jack_midi_port_info_private
  25. {
  26. jack_midi_port_info_t info;
  27. jack_nframes_t last_write_loc;
  28. char last_status; /* status byte for last event in buffer */
  29. jack_nframes_t events_lost; /* number of events lost in this buffer.
  30. * mixdown is the only place that sets
  31. * this for now */
  32. } jack_midi_port_info_private_t;
  33. typedef struct _jack_midi_port_internal_event
  34. {
  35. jack_nframes_t time;
  36. size_t size;
  37. size_t byte_offset;
  38. } jack_midi_port_internal_event_t;
  39. jack_midi_port_info_t*
  40. jack_midi_port_get_info(void* port_buffer, jack_nframes_t nframes)
  41. {
  42. return (jack_midi_port_info_t*)port_buffer;
  43. }
  44. int
  45. jack_midi_event_get(jack_midi_event_t* event, void* port_buffer, jack_nframes_t event_idx, jack_nframes_t nframes)
  46. {
  47. jack_midi_port_internal_event_t* port_event;
  48. jack_midi_port_info_private_t* info = (jack_midi_port_info_private_t*)port_buffer;
  49. if(event_idx >= info->info.event_count)
  50. return ENODATA;
  51. port_event = (jack_midi_port_internal_event_t*)(info+1);
  52. port_event += event_idx;
  53. event->time = port_event->time;
  54. event->size = port_event->size;
  55. event->buffer = ((jack_midi_data_t*)port_buffer) + port_event->byte_offset;
  56. return 0;
  57. }
  58. jack_midi_data_t*
  59. jack_midi_event_reserve(void* port_buffer, jack_nframes_t time, size_t data_size, jack_nframes_t nframes)
  60. {
  61. jack_midi_data_t* retbuf = (jack_midi_data_t*)port_buffer;
  62. /* bad: below line needs to know about buffer scale factor */
  63. jack_nframes_t buffer_size = nframes*sizeof(jack_default_audio_sample_t)/sizeof(unsigned char);
  64. jack_midi_port_info_private_t* info = (jack_midi_port_info_private_t*)port_buffer;
  65. jack_midi_port_internal_event_t* event_buffer = (jack_midi_port_internal_event_t*)(info + 1);
  66. /* check there is enough space in the buffer for the event. */
  67. if(info->last_write_loc + sizeof(jack_midi_port_info_private_t)
  68. + (info->info.event_count + 1) * sizeof(jack_midi_port_internal_event_t)
  69. + data_size > buffer_size)
  70. return NULL;
  71. else
  72. {
  73. info->last_write_loc += data_size;
  74. retbuf = &retbuf[buffer_size - 1 - info->last_write_loc];
  75. event_buffer[info->info.event_count].time = time;
  76. event_buffer[info->info.event_count].size = data_size;
  77. event_buffer[info->info.event_count].byte_offset = buffer_size - 1 - info->last_write_loc;
  78. info->info.event_count += 1;
  79. return retbuf;
  80. }
  81. }
  82. int
  83. jack_midi_event_write(void* port_buffer, jack_nframes_t time, jack_midi_data_t* data, size_t data_size, jack_nframes_t nframes)
  84. {
  85. jack_midi_data_t* retbuf = jack_midi_event_reserve(port_buffer, time, data_size, nframes);
  86. if(retbuf)
  87. {
  88. memcpy(retbuf, data, data_size);
  89. return 0;
  90. }
  91. else
  92. return ENOBUFS;
  93. }
  94. /*jack_midi_data_t jack_midi_get_last_status_byte(void* port_buffer, jack_nframes_t nframes)
  95. {
  96. return ((jack_midi_port_info_private_t*)(port_buffer))->last_status;
  97. }*/
  98. jack_midi_data_t jack_midi_get_status_before_event_n(void* port_buffer, jack_nframes_t event_index, jack_nframes_t nframes)
  99. {
  100. jack_midi_data_t* event_buf = (jack_midi_data_t*)port_buffer;
  101. jack_midi_port_info_private_t* info = (jack_midi_port_info_private_t*)port_buffer;
  102. jack_midi_port_internal_event_t* event_buffer = (jack_midi_port_internal_event_t*)(info + 1);
  103. /* safeguard against unitialised ports */
  104. if(info->info.event_count * sizeof(jack_midi_port_internal_event_t) + sizeof(jack_midi_port_info_private_t)
  105. > nframes * sizeof(jack_default_audio_sample_t))
  106. return 0;
  107. /* don't know what to do here, so we return 0 */
  108. if(event_index >= info->info.event_count)
  109. return 0;
  110. if(info->info.event_count > 0)
  111. {
  112. event_index -= 1;
  113. while( (event_index >= 0)
  114. && (event_buf[event_buffer[event_index].byte_offset] < 0x80)
  115. && (event_buf[event_buffer[event_index].byte_offset] > 0xf7) )
  116. event_index--;
  117. if(event_index >= 0)
  118. return event_buf[event_buffer[event_index].byte_offset];
  119. }
  120. /* all the events in the port are running status, so we return the previous buffers last
  121. * status byte */
  122. return info->last_status;
  123. }
  124. /* this function can be got rid of now, as the above function replaces it and is more general */
  125. static jack_midi_data_t get_last_status_byte(void* port_buffer, jack_nframes_t nframes)
  126. {
  127. int event_index = 0;
  128. jack_midi_data_t* event_buf = (jack_midi_data_t*)port_buffer;
  129. jack_midi_port_info_private_t* info = (jack_midi_port_info_private_t*)port_buffer;
  130. jack_midi_port_internal_event_t* event_buffer = (jack_midi_port_internal_event_t*)(info + 1);
  131. /* safeguard against unitialised ports */
  132. if(info->info.event_count * sizeof(jack_midi_port_internal_event_t) + sizeof(jack_midi_port_info_private_t)
  133. > nframes * sizeof(jack_default_audio_sample_t))
  134. return 0;
  135. if(info->info.event_count > 0)
  136. {
  137. event_index = info->info.event_count - 1;
  138. while( (event_index >= 0)
  139. && (event_buf[event_buffer[event_index].byte_offset] < 0x80)
  140. && (event_buf[event_buffer[event_index].byte_offset] > 0xf7) )
  141. event_index--;
  142. if(event_index >= 0)
  143. return event_buf[event_buffer[event_index].byte_offset];
  144. }
  145. return info->last_status;
  146. }
  147. /* can't check to make sure this port is an output anymore. if this gets
  148. * called on an input port, all clients after the client that calls it
  149. * will think there are no events in the buffer as the event count has
  150. * been reset
  151. * TODO: this function must take note of system realtime messages and
  152. * skip them when updating last_status. done. */
  153. void jack_midi_clear_buffer(void* port_buffer, jack_nframes_t nframes)
  154. {
  155. jack_midi_port_info_private_t* info = (jack_midi_port_info_private_t*)port_buffer;
  156. if(port_buffer == NULL)
  157. {
  158. /* fprintf(stderr, "Error: port_buffer in jack_midi_clear_buffer is NULL!\n");*/
  159. return;
  160. }
  161. /* find the last status byte in the buffer for use in the mixdown function */
  162. /* this code is dangerous when used on a freshly allocated buffer that has
  163. * not has jack_midi_reset_new_port called on it, because the event_count
  164. * may be some huge number... */
  165. info->last_status = get_last_status_byte(port_buffer, nframes);
  166. info->info.event_count = 0;
  167. info->last_write_loc = 0;
  168. info->events_lost = 0;
  169. }
  170. void jack_midi_reset_new_port(void* port_buffer, jack_nframes_t nframes)
  171. {
  172. jack_midi_port_info_private_t* info = (jack_midi_port_info_private_t*)port_buffer;
  173. info->info.event_count = 0;
  174. info->last_write_loc = 0;
  175. info->last_status = 0;
  176. info->events_lost = 0;
  177. }
  178. void jack_midi_port_mixdown (jack_port_t *port, jack_nframes_t nframes)
  179. {
  180. JSList *node;
  181. jack_port_t *input;
  182. jack_nframes_t num_events = 0, i = 0;
  183. int err = 0;
  184. /* smallest_info is for the data buffer holding the next event */
  185. jack_midi_port_info_private_t *in_info, *out_info, *smallest_info;
  186. /* smallest_event is for the event buffer holding the next event */
  187. jack_midi_port_internal_event_t *in_events, *smallest_event, *out_events;
  188. /* for assembling new events if running status is interrupted */
  189. jack_midi_data_t new_event_buf[3];
  190. jack_midi_data_t *smallest_buffer = NULL;
  191. out_info = (jack_midi_port_info_private_t*)port->mix_buffer;
  192. out_events = (jack_midi_port_internal_event_t*)(out_info + 1);
  193. /* cache last status byte */
  194. out_info->last_status = get_last_status_byte(port->mix_buffer, nframes);
  195. out_info->info.event_count = 0;
  196. /* initialise smallest_info to point to the first port buffer */
  197. smallest_info = (jack_midi_port_info_private_t*)jack_output_port_buffer((jack_port_t*)(port->connections->data));
  198. smallest_event = (jack_midi_port_internal_event_t*)(smallest_info + 1);
  199. /* in this loop we can use last_write_loc in jack_midi_port_info_private_t
  200. * to store indexes of the last event read from that buffer. this is ok
  201. * because last_write_loc is used when writing events to a buffer, which
  202. * is already complete.
  203. */
  204. for(node = port->connections; node; node = jack_slist_next (node))
  205. {
  206. input = (jack_port_t *) node->data;
  207. in_info = (jack_midi_port_info_private_t*)jack_output_port_buffer (input);
  208. num_events += in_info->info.event_count;
  209. in_info->last_write_loc = 0;
  210. /* look to see if first event in each buffer is running status */
  211. }
  212. printf(" jack_midi_port_mixdown got %d events\n", num_events);
  213. while(i<num_events)
  214. {
  215. node = port->connections;
  216. /* had something else to do here, to do with smallest_info/buf? */
  217. while(node)
  218. {
  219. in_info = (jack_midi_port_info_private_t*)jack_output_port_buffer (((jack_port_t *) node->data));
  220. in_events = (jack_midi_port_internal_event_t*)(in_info + 1);
  221. /* make sure there are events left in this port */
  222. if(in_info->info.event_count > in_info->last_write_loc)
  223. {
  224. /* (first_event_in_buffer_timestamp < smallest_timestamp_event) */
  225. if(in_events[in_info->last_write_loc].time <= smallest_event[smallest_info->last_write_loc].time)
  226. {
  227. smallest_info = in_info;
  228. smallest_event = (jack_midi_port_internal_event_t*)(&in_events[in_info->last_write_loc]);
  229. smallest_buffer = (jack_midi_data_t*)in_info;
  230. }
  231. }
  232. /* else buffer has no events remaining in it */
  233. node = jack_slist_next(node);
  234. }
  235. /* write event to output port.
  236. * things to consider:
  237. * if event is running status, make sure previous event in its port is of the same
  238. * type as the last event in the output port.
  239. */
  240. /* test to see if this event is running status, or 1 byte realtime msg */
  241. if( (smallest_buffer[smallest_event[smallest_info->last_write_loc].byte_offset] < 0x80)
  242. && ((*new_event_buf = get_last_status_byte((void*)smallest_info, nframes))
  243. != get_last_status_byte((void*)port->mix_buffer, nframes)) )
  244. {
  245. memcpy(new_event_buf + 1,
  246. &smallest_buffer[smallest_event[smallest_info->last_write_loc].byte_offset],
  247. smallest_event[smallest_info->last_write_loc].size);
  248. err = jack_midi_event_write(jack_output_port_buffer((jack_port_t*)node->data),
  249. smallest_event[smallest_info->last_write_loc].time,
  250. new_event_buf,
  251. smallest_event[smallest_info->last_write_loc].size + 1,
  252. nframes);
  253. }
  254. else
  255. {
  256. err = jack_midi_event_write(jack_output_port_buffer((jack_port_t*)node->data),
  257. smallest_event[smallest_info->last_write_loc].time,
  258. &smallest_buffer[smallest_event[smallest_info->last_write_loc].byte_offset],
  259. smallest_event[smallest_info->last_write_loc].size,
  260. nframes);
  261. }
  262. if(err < 0)
  263. {
  264. out_info->events_lost = num_events - i - 1;
  265. break;
  266. }
  267. else
  268. i++;
  269. }
  270. }
  271. jack_nframes_t jack_midi_get_lost_event_count(void* port_buffer, jack_nframes_t nframes)
  272. {
  273. return ((jack_midi_port_info_private_t*)port_buffer)->events_lost;
  274. }