Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
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.

218 lines
6.3KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. #include <jack/jack.h>
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <math.h>
  22. #include "transport.H"
  23. #include "common.h"
  24. #include "const.h"
  25. extern jack_client_t *client;
  26. /* FIXME: use JackSyncCallback instead? (sync-callback) */
  27. Transport transport;
  28. static volatile bool _done;
  29. /** callback for when we're Timebase Master, mostly taken from
  30. * transport.c in Jack's example clients. */
  31. /* FIXME: there is a subtle interaction here between the tempo and
  32. * JACK's buffer size. Inflating ticks_per_beat (as jack_transport
  33. * does) diminishes the effect of this correlation, but does not
  34. * eliminate it... This is caused by the accumulation of a precision
  35. * error, and all timebase master routines I've examined appear to
  36. * suffer from this same tempo distortion (and all use the magic
  37. * number of 1920 ticks_per_beat in an attempt to reduce the magnitude
  38. * of the error. Currently, we keep this behaviour. */
  39. void
  40. Transport::timebase ( jack_transport_state_t, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void * )
  41. {
  42. if ( new_pos || ! _done )
  43. {
  44. pos->valid = JackPositionBBT;
  45. pos->beats_per_bar = transport._master_beats_per_bar;
  46. pos->ticks_per_beat = 1920.0; /* magic number means what? */
  47. pos->beat_type = transport._master_beat_type;
  48. pos->beats_per_minute = transport._master_beats_per_minute;
  49. double wallclock = (double)pos->frame / (pos->frame_rate * 60);
  50. unsigned long abs_tick = wallclock * pos->beats_per_minute * pos->ticks_per_beat;
  51. unsigned long abs_beat = abs_tick / pos->ticks_per_beat;
  52. pos->bar = abs_beat / pos->beats_per_bar;
  53. pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1;
  54. pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat);
  55. pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat;
  56. pos->bar++;
  57. _done = true;
  58. }
  59. else
  60. {
  61. pos->tick += nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60);
  62. while ( pos->tick >= pos->ticks_per_beat )
  63. {
  64. pos->tick -= pos->ticks_per_beat;
  65. if ( ++pos->beat > pos->beats_per_bar )
  66. {
  67. pos->beat = 1;
  68. ++pos->bar;
  69. pos->bar_start_tick += pos->beats_per_bar * pos->ticks_per_beat;
  70. }
  71. }
  72. }
  73. }
  74. Transport::Transport ( void )
  75. {
  76. _master_beats_per_bar = 4;
  77. _master_beat_type = 4;
  78. _master_beats_per_minute = 120;
  79. _done = false;
  80. }
  81. void
  82. Transport::poll ( void )
  83. {
  84. jack_transport_state_t ts;
  85. jack_position_t pos;
  86. ts = jack_transport_query( client, &pos );
  87. rolling = ts == JackTransportRolling;
  88. valid = pos.valid & JackPositionBBT;
  89. bar = pos.bar;
  90. beat = pos.beat;
  91. tick = pos.tick;
  92. /* bars and beats start at 1.. */
  93. pos.bar--;
  94. pos.beat--;
  95. /* FIXME: these probably shouldn't be called from the RT
  96. thread... Anyway, it happens infrequently. */
  97. if ( pos.beats_per_minute != beats_per_minute )
  98. signal_tempo_change( pos.beats_per_minute );
  99. if ( pos.beats_per_bar != beats_per_bar )
  100. signal_bpb_change( pos.beats_per_bar );
  101. if ( pos.beat_type != beat_type )
  102. signal_beat_change( pos.beat_type );
  103. ticks_per_beat = pos.ticks_per_beat;
  104. beats_per_bar = pos.beats_per_bar;
  105. beat_type = pos.beat_type;
  106. beats_per_minute = pos.beats_per_minute;
  107. frame = pos.frame;
  108. frame_rate = pos.frame_rate;
  109. /* FIXME: this only needs to be calculated if bpm or framerate changes */
  110. {
  111. const double frames_per_beat = frame_rate * 60 / beats_per_minute;
  112. frames_per_tick = frames_per_beat / (double)PPQN;
  113. ticks_per_period = nframes / frames_per_tick;
  114. }
  115. tick_t abs_tick = (pos.bar * pos.beats_per_bar + pos.beat) * pos.ticks_per_beat + pos.tick;
  116. // tick_t abs_tick = pos.bar_start_tick + (pos.beat * pos.ticks_per_beat) + pos.tick;
  117. /* scale Jack's ticks to our ticks */
  118. const double pulses_per_tick = PPQN / pos.ticks_per_beat;
  119. ticks = abs_tick * pulses_per_tick;
  120. tick = tick * pulses_per_tick;
  121. ticks_per_beat = PPQN;
  122. }
  123. void
  124. Transport::start ( void )
  125. {
  126. MESSAGE( "Starting transport" );
  127. jack_transport_start( client );
  128. }
  129. void
  130. Transport::stop ( void )
  131. {
  132. MESSAGE( "Stopping transport" );
  133. jack_transport_stop( client );
  134. }
  135. void
  136. Transport::toggle ( void )
  137. {
  138. if ( rolling )
  139. stop();
  140. else
  141. start();
  142. }
  143. void
  144. Transport::locate ( tick_t ticks )
  145. {
  146. jack_nframes_t frame = trunc( ticks * transport.frames_per_tick );
  147. MESSAGE( "Relocating transport to %lu, %lu", ticks, frame );
  148. jack_transport_locate( client, frame );
  149. }
  150. void
  151. Transport::set_beats_per_minute ( double n )
  152. {
  153. _master_beats_per_minute = n;
  154. }
  155. void
  156. Transport::set_beats_per_bar ( int n )
  157. {
  158. if ( n < 2 )
  159. return;
  160. _master_beats_per_bar = n;
  161. }
  162. void
  163. Transport::set_beat_type ( int n )
  164. {
  165. if ( n < 4 )
  166. return;
  167. _master_beat_type = n;
  168. }