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.

377 lines
9.0KB

  1. /*
  2. JACK transport client interface -- runs in the client process.
  3. Copyright (C) 2001-2003 Paul Davis
  4. Copyright (C) 2003 Jack O'Quin
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public License
  7. as published by the Free Software Foundation; either version 2.1
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this program; if not, write to the Free
  15. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  16. 02111-1307, USA.
  17. */
  18. #include <config.h>
  19. #include <errno.h>
  20. #include <math.h>
  21. #include <jack/internal.h>
  22. #include "local.h"
  23. /********************* Internal functions *********************/
  24. static inline void
  25. jack_read_frame_time (const jack_client_t *client, jack_frame_timer_t *copy)
  26. {
  27. int tries = 0;
  28. do {
  29. /* throttle the busy wait if we don't get
  30. the answer very quickly.
  31. */
  32. if (tries > 10) {
  33. usleep (20);
  34. tries = 0;
  35. }
  36. *copy = client->engine->frame_timer;
  37. tries++;
  38. } while (copy->guard1 != copy->guard2);
  39. }
  40. /* copy a JACK transport position structure (thread-safe) */
  41. void
  42. jack_transport_copy_position (jack_position_t *from, jack_position_t *to)
  43. {
  44. int tries = 0;
  45. long timeout = 1000000;
  46. do {
  47. /* throttle the busy wait if we don't get the answer
  48. * very quickly. */
  49. if (tries > 10) {
  50. usleep (20);
  51. tries = 0;
  52. /* debug code to avoid system hangs... */
  53. if (--timeout == 0) {
  54. jack_error("infinte loop copying position");
  55. abort();
  56. }
  57. }
  58. *to = *from;
  59. tries++;
  60. } while (to->usecs != to->guard_usecs);
  61. }
  62. static inline int
  63. jack_transport_request_new_pos (jack_client_t *client, jack_position_t *pos)
  64. {
  65. jack_control_t *eng = client->engine;
  66. //JOQ: check validity of input
  67. /* carefully copy requested postion into shared memory */
  68. pos->guard_usecs = pos->usecs = jack_get_microseconds();
  69. jack_transport_copy_position (pos, &eng->request_time);
  70. return 0;
  71. }
  72. void
  73. jack_call_sync_client (jack_client_t *client)
  74. {
  75. jack_client_control_t *control = client->control;
  76. jack_control_t *eng = client->engine;
  77. if (eng->new_pos || !control->sync_ready) {
  78. if (control->sync_cb (eng->transport_state,
  79. &eng->current_time,
  80. control->sync_arg)) {
  81. control->sync_ready = 1;
  82. eng->sync_cycle--;
  83. }
  84. }
  85. }
  86. void
  87. jack_call_timebase_master (jack_client_t *client)
  88. {
  89. jack_client_control_t *control = client->control;
  90. jack_control_t *eng = client->engine;
  91. int new_pos;
  92. if (client->new_timebase) { /* first time after being set? */
  93. client->new_timebase = 0;
  94. new_pos = 1;
  95. } else
  96. new_pos = eng->new_pos;
  97. if ((eng->transport_state == JackTransportRolling) || new_pos) {
  98. control->timebase_cb (eng->transport_state,
  99. control->nframes,
  100. &eng->pending_time,
  101. new_pos,
  102. control->timebase_arg);
  103. }
  104. }
  105. /************************* API functions *************************/
  106. jack_nframes_t
  107. jack_frames_since_cycle_start (const jack_client_t *client)
  108. {
  109. float usecs;
  110. jack_control_t *eng = client->engine;
  111. usecs = jack_get_microseconds() - eng->current_time.usecs;
  112. return (jack_nframes_t) floor ((((float) eng->current_time.frame_rate)
  113. / 1000000.0f) * usecs);
  114. }
  115. jack_nframes_t
  116. jack_frame_time (const jack_client_t *client)
  117. {
  118. jack_frame_timer_t current;
  119. float usecs;
  120. jack_nframes_t elapsed;
  121. jack_control_t *eng = client->engine;
  122. jack_read_frame_time (client, &current);
  123. usecs = jack_get_microseconds() - current.stamp;
  124. elapsed = (jack_nframes_t)
  125. floor ((((float) eng->current_time.frame_rate)
  126. / 1000000.0f) * usecs);
  127. return current.frames + elapsed;
  128. }
  129. unsigned long
  130. jack_get_sample_rate (jack_client_t *client)
  131. {
  132. return client->engine->current_time.frame_rate;
  133. }
  134. int
  135. jack_set_sample_rate_callback (jack_client_t *client,
  136. JackSampleRateCallback callback, void *arg)
  137. {
  138. if (client->control->active) {
  139. jack_error ("You cannot set callbacks on an active client.");
  140. return -1;
  141. }
  142. client->control->srate_arg = arg;
  143. client->control->srate = callback;
  144. /* Now invoke it */
  145. callback (client->engine->current_time.frame_rate, arg);
  146. return 0;
  147. }
  148. int
  149. jack_release_timebase (jack_client_t *client)
  150. {
  151. int rc;
  152. jack_request_t req;
  153. jack_client_control_t *ctl = client->control;
  154. req.type = ResetTimeBaseClient;
  155. req.x.client_id = ctl->id;
  156. rc = jack_client_deliver_request (client, &req);
  157. if (rc == 0) {
  158. ctl->timebase_cb = NULL;
  159. ctl->timebase_arg = NULL;
  160. }
  161. return rc;
  162. }
  163. int
  164. jack_set_sync_callback (jack_client_t *client,
  165. JackSyncCallback sync_callback, void *arg)
  166. {
  167. jack_client_control_t *ctl = client->control;
  168. jack_request_t req;
  169. int rc;
  170. req.type = SetSyncClient;
  171. req.x.client_id = ctl->id;
  172. rc = jack_client_deliver_request (client, &req);
  173. if (rc == 0) {
  174. ctl->sync_cb = sync_callback;
  175. ctl->sync_arg = arg;
  176. }
  177. return rc;
  178. }
  179. int
  180. jack_set_sync_timeout (jack_client_t *client, jack_nframes_t timeout)
  181. {
  182. return ENOSYS; /* this is a stub */
  183. }
  184. int
  185. jack_set_timebase_callback (jack_client_t *client, int conditional,
  186. JackTimebaseCallback timebase_cb, void *arg)
  187. {
  188. int rc;
  189. jack_request_t req;
  190. jack_client_control_t *ctl = client->control;
  191. req.type = SetTimeBaseClient;
  192. req.x.timebase.client_id = ctl->id;
  193. req.x.timebase.conditional = conditional;
  194. rc = jack_client_deliver_request (client, &req);
  195. if (rc == 0) {
  196. client->new_timebase = 1;
  197. ctl->timebase_arg = arg;
  198. ctl->timebase_cb = timebase_cb;
  199. }
  200. return rc;
  201. }
  202. int
  203. jack_transport_goto_frame (jack_client_t *client, jack_nframes_t frame)
  204. {
  205. jack_position_t pos;
  206. pos.frame = frame;
  207. pos.valid = 0;
  208. return jack_transport_request_new_pos (client, &pos);
  209. }
  210. jack_transport_state_t
  211. jack_transport_query (jack_client_t *client, jack_position_t *pos)
  212. {
  213. jack_control_t *eng = client->engine;
  214. /* the guarded copy makes this function work in any thread */
  215. jack_transport_copy_position (&eng->current_time, pos);
  216. return eng->transport_state;
  217. }
  218. int
  219. jack_transport_reposition (jack_client_t *client, jack_position_t *pos)
  220. {
  221. /* copy the input, so we don't modify the input argument */
  222. jack_position_t tmp = *pos;
  223. return jack_transport_request_new_pos (client, &tmp);
  224. }
  225. void
  226. jack_transport_start (jack_client_t *client)
  227. {
  228. client->engine->transport_cmd = TransportCommandPlay;
  229. }
  230. void
  231. jack_transport_stop (jack_client_t *client)
  232. {
  233. client->engine->transport_cmd = TransportCommandStop;
  234. }
  235. #ifdef OLD_TRANSPORT
  236. /************* Compatibility with old transport API. *************/
  237. int
  238. jack_engine_takeover_timebase (jack_client_t *client)
  239. {
  240. jack_request_t req;
  241. req.type = SetTimeBaseClient;
  242. req.x.timebase.client_id = client->control->id;
  243. req.x.timebase.conditional = 0;
  244. return jack_client_deliver_request (client, &req);
  245. }
  246. void
  247. jack_get_transport_info (jack_client_t *client,
  248. jack_transport_info_t *info)
  249. {
  250. jack_control_t *eng = client->engine;
  251. info->usecs = eng->current_time.usecs;
  252. info->frame_rate = eng->current_time.frame_rate;
  253. info->transport_state = eng->transport_state;
  254. info->frame = eng->current_time.frame;
  255. info->valid = (eng->current_time.valid |
  256. JackTransportState | JackTransportPosition);
  257. if (info->valid & JackPositionBBT) {
  258. info->bar = eng->current_time.bar;
  259. info->beat = eng->current_time.beat;
  260. info->tick = eng->current_time.tick;
  261. info->bar_start_tick = eng->current_time.bar_start_tick;
  262. info->beats_per_bar = eng->current_time.beats_per_bar;
  263. info->beat_type = eng->current_time.beat_type;
  264. info->ticks_per_beat = eng->current_time.ticks_per_beat;
  265. info->beats_per_minute = eng->current_time.beats_per_minute;
  266. }
  267. }
  268. void
  269. jack_set_transport_info (jack_client_t *client,
  270. jack_transport_info_t *info)
  271. {
  272. jack_control_t *eng = client->engine;
  273. //JOQ: check that this is the timebase master?
  274. //JOQ: check that this is the process thread?
  275. /* is there a new state? */
  276. if ((info->valid & JackTransportState) &&
  277. (info->transport_state != eng->transport_state)) {
  278. if (info->transport_state == JackTransportStopped)
  279. eng->transport_cmd = TransportCommandStop;
  280. else if (info->transport_state == JackTransportRolling)
  281. eng->transport_cmd = TransportCommandPlay;
  282. /* silently ignore anything else */
  283. }
  284. if (info->valid & JackTransportPosition)
  285. eng->pending_time.frame = info->frame;
  286. else
  287. eng->pending_time.frame = eng->current_time.frame;
  288. eng->pending_time.valid = (info->valid & JackTransportBBT);
  289. if (info->valid & JackTransportBBT) {
  290. eng->pending_time.bar = info->bar;
  291. eng->pending_time.beat = info->beat;
  292. eng->pending_time.tick = info->tick;
  293. eng->pending_time.bar_start_tick = info->bar_start_tick;
  294. eng->pending_time.beats_per_bar = info->beats_per_bar;
  295. eng->pending_time.beat_type = info->beat_type;
  296. eng->pending_time.ticks_per_beat = info->ticks_per_beat;
  297. eng->pending_time.beats_per_minute = info->beats_per_minute;
  298. }
  299. }
  300. #endif /* OLD_TRANSPORT */