JACK example clients
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.

158 lines
4.8KB

  1. /*
  2. * intime.c -- JACK internal timebase master example client.
  3. *
  4. * To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'.
  5. */
  6. /* Copyright (C) 2003 Jack O'Quin.
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <jack/jack.h>
  25. /* Time and tempo variables, global to the entire transport timeline.
  26. * There is no attempt to keep a true tempo map. The default time
  27. * signature is "march time": 4/4, 120bpm
  28. */
  29. float time_beats_per_bar = 4.0;
  30. float time_beat_type = 4.0;
  31. double time_ticks_per_beat = 1920.0;
  32. double time_beats_per_minute = 120.0;
  33. /* BBT timebase callback.
  34. *
  35. * Runs in the process thread. Realtime, must not wait.
  36. */
  37. void
  38. timebbt (jack_transport_state_t state, jack_nframes_t nframes,
  39. jack_position_t *pos, int new_pos, void *arg)
  40. {
  41. double min; /* minutes since frame 0 */
  42. long abs_tick; /* ticks since frame 0 */
  43. long abs_beat; /* beats since frame 0 */
  44. if (new_pos) {
  45. pos->valid = JackPositionBBT;
  46. pos->beats_per_bar = time_beats_per_bar;
  47. pos->beat_type = time_beat_type;
  48. pos->ticks_per_beat = time_ticks_per_beat;
  49. pos->beats_per_minute = time_beats_per_minute;
  50. /* Compute BBT info from frame number. This is
  51. * relatively simple here, but would become complex if
  52. * we supported tempo or time signature changes at
  53. * specific locations in the transport timeline. I
  54. * make no claims for the numerical accuracy or
  55. * efficiency of these calculations. */
  56. min = pos->frame / ((double) pos->frame_rate * 60.0);
  57. abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat;
  58. abs_beat = abs_tick / pos->ticks_per_beat;
  59. pos->bar = abs_beat / pos->beats_per_bar;
  60. pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1;
  61. pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat);
  62. pos->bar_start_tick = pos->bar * pos->beats_per_bar *
  63. pos->ticks_per_beat;
  64. pos->bar++; /* adjust start to bar 1 */
  65. /* some debug code... */
  66. fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3"
  67. PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n",
  68. pos->frame, pos->bar, pos->beat, pos->tick);
  69. } else {
  70. /* Compute BBT info based on previous period. */
  71. pos->tick += (nframes * pos->ticks_per_beat *
  72. pos->beats_per_minute / (pos->frame_rate * 60));
  73. while (pos->tick >= pos->ticks_per_beat) {
  74. pos->tick -= pos->ticks_per_beat;
  75. if (++pos->beat > pos->beats_per_bar) {
  76. pos->beat = 1;
  77. ++pos->bar;
  78. pos->bar_start_tick += (pos->beats_per_bar *
  79. pos->ticks_per_beat);
  80. }
  81. }
  82. }
  83. }
  84. /* experimental timecode callback
  85. *
  86. * Fill in extended timecode fields using the trivial assumption that
  87. * we are running at nominal speed, hence with no drift.
  88. *
  89. * It would probably be faster to compute frame_time without the
  90. * conditional expression. But, this demonstrates the invariant:
  91. * next_time[i] == frame_time[i+1], unless a reposition occurs.
  92. *
  93. * Runs in the process thread. Realtime, must not wait.
  94. */
  95. void
  96. timecode (jack_transport_state_t state, jack_nframes_t nframes,
  97. jack_position_t *pos, int new_pos, void *arg)
  98. {
  99. /* nominal transport speed */
  100. double seconds_per_frame = 1.0 / (double) pos->frame_rate;
  101. pos->valid = JackPositionTimecode;
  102. pos->frame_time = (new_pos?
  103. pos->frame * seconds_per_frame:
  104. pos->next_time);
  105. pos->next_time = (pos->frame + nframes) * seconds_per_frame;
  106. }
  107. /* after internal client loaded */
  108. int
  109. jack_initialize (jack_client_t *client, const char *load_init)
  110. {
  111. JackTimebaseCallback callback = timebbt;
  112. int rc = sscanf(load_init, " %f/%f, %lf bpm ", &time_beats_per_bar,
  113. &time_beat_type, &time_beats_per_minute);
  114. if (rc > 0) {
  115. fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n",
  116. time_beats_per_bar, time_beat_type,
  117. time_beats_per_minute);
  118. } else {
  119. int len = strlen(load_init);
  120. if ((len > 0) && (strncmp(load_init, "timecode", len) == 0))
  121. callback = timecode;
  122. }
  123. if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) {
  124. fprintf (stderr, "Unable to take over timebase.\n");
  125. return 1; /* terminate */
  126. }
  127. fprintf (stderr, "Internal timebase master defined.\n");
  128. jack_activate (client);
  129. return 0; /* success */
  130. }
  131. /* before unloading */
  132. void
  133. jack_finish (void *arg)
  134. {
  135. fprintf (stderr, "Internal timebase client exiting.\n");
  136. }