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.

286 lines
7.4KB

  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 "Engine.H"
  19. #include "../Transport.H"
  20. #include "../Timeline.H" // for process()
  21. #include "../Sequence_Widget.H" // for BBT and position info.
  22. #define APP_NAME "Non-DAW" // FIXME: wrong place for this!
  23. /* This is the home of the JACK process callback (does this *really*
  24. need to be a class?) */
  25. #include "util/Thread.H"
  26. Engine::Engine ( ) : _thread( "RT" )
  27. {
  28. _freewheeling = false;
  29. _client = NULL;
  30. _buffers_dropped = 0;
  31. _xruns = 0;
  32. }
  33. /*******************/
  34. /* Static Wrappers */
  35. /*******************/
  36. int
  37. Engine::process ( nframes_t nframes, void *arg )
  38. {
  39. return ((Engine*)arg)->process( nframes );
  40. }
  41. int
  42. Engine::sync ( jack_transport_state_t state, jack_position_t *pos, void *arg )
  43. {
  44. return ((Engine*)arg)->sync( state, pos );
  45. }
  46. int
  47. Engine::xrun ( void *arg )
  48. {
  49. return ((Engine*)arg)->xrun();
  50. }
  51. void
  52. Engine::timebase ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg )
  53. {
  54. ((Engine*)arg)->timebase( state, nframes, pos, new_pos );
  55. }
  56. void
  57. Engine::freewheel ( int starting, void *arg )
  58. {
  59. ((Engine*)arg)->freewheel( starting );
  60. }
  61. int
  62. Engine::buffer_size ( nframes_t nframes, void *arg )
  63. {
  64. return ((Engine*)arg)->buffer_size( nframes );
  65. }
  66. void
  67. Engine::request_locate ( nframes_t frame )
  68. {
  69. if ( timeline )
  70. timeline->seek( frame );
  71. }
  72. /* THREAD: RT */
  73. /** This is the jack xrun callback */
  74. int
  75. Engine::xrun ( void )
  76. {
  77. ++_xruns;
  78. return 0;
  79. }
  80. /* THREAD: RT */
  81. void
  82. Engine::freewheel ( bool starting )
  83. {
  84. _freewheeling = starting;
  85. if ( starting )
  86. DMESSAGE( "entering freewheeling mode" );
  87. else
  88. DMESSAGE( "leaving freewheeling mode" );
  89. }
  90. /* THREAD: RT (non-RT) */
  91. int
  92. Engine::buffer_size ( nframes_t nframes )
  93. {
  94. /* TODO: inform all disktreams the the buffer size has changed */
  95. timeline->resize_buffers( nframes );
  96. return 0;
  97. }
  98. /* THREAD: RT */
  99. /** This is the jack slow-sync callback. */
  100. int
  101. Engine::sync ( jack_transport_state_t state, jack_position_t *pos )
  102. {
  103. static bool seeking = false;
  104. switch ( state )
  105. {
  106. case JackTransportStopped: /* new position requested */
  107. /* JACK docs lie. This is only called when the transport
  108. is *really* stopped, not when starting a slow-sync
  109. cycle */
  110. transport->frame = pos->frame;
  111. return 1;
  112. case JackTransportStarting: /* this means JACK is polling slow-sync clients */
  113. {
  114. if ( ! seeking )
  115. {
  116. request_locate( pos->frame );
  117. seeking = true;
  118. }
  119. int r = true;
  120. if ( timeline )
  121. r = timeline->seek_pending();
  122. if ( ! r )
  123. seeking = false;
  124. return ! seeking;
  125. }
  126. case JackTransportRolling: /* JACK's timeout has expired */
  127. /* FIXME: what's the right thing to do here? */
  128. // request_locate( pos->frame );
  129. return 1;
  130. // return transport->frame == pos->frame;
  131. break;
  132. default:
  133. printf( "unknown transport state.\n" );
  134. }
  135. return 0;
  136. }
  137. /* THREAD: RT */
  138. void
  139. Engine::timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *pos, int )
  140. {
  141. position_info pi = timeline->solve_tempomap( pos->frame );
  142. pos->valid = JackPositionBBT;
  143. pos->beats_per_bar = pi.beats_per_bar;
  144. pos->beat_type = pi.beat_type;
  145. pos->beats_per_minute = pi.tempo;
  146. pos->bar = pi.bbt.bar + 1;
  147. pos->beat = pi.bbt.beat + 1;
  148. pos->tick = pi.bbt.tick;
  149. pos->ticks_per_beat = 1920.0; /* FIXME: wrong place for this */
  150. /* FIXME: fill this in */
  151. pos->bar_start_tick = 0;
  152. }
  153. /* THREAD: RT */
  154. int
  155. Engine::process ( nframes_t nframes )
  156. {
  157. /* FIXME: wrong place for this */
  158. _thread.set( "RT" );
  159. transport->poll();
  160. if ( freewheeling() )
  161. {
  162. /* freewheeling mode/export. We're actually running
  163. non-RT. Assume that everything is quiescent, locking is
  164. unecessary and do I/O synchronously */
  165. if ( timeline )
  166. timeline->process( nframes );
  167. /* because we're going faster than realtime. */
  168. timeline->wait_for_buffers();
  169. }
  170. else
  171. {
  172. if ( ! trylock() )
  173. {
  174. /* the data structures we need to access here (tracks and
  175. * their ports, but not track contents) may be in an
  176. * inconsistent state at the moment. Just punt and drop this
  177. * buffer. */
  178. ++_buffers_dropped;
  179. return 0;
  180. }
  181. /* handle chicken/egg problem */
  182. if ( timeline )
  183. /* this will initiate the process() call graph for the various
  184. * number and types of tracks, which will in turn send data out
  185. * the appropriate ports. */
  186. timeline->process( nframes );
  187. unlock();
  188. }
  189. return 0;
  190. }
  191. /** enter or leave freehweeling mode */
  192. void
  193. Engine::freewheeling ( bool yes )
  194. {
  195. if ( jack_set_freewheel( _client, yes ) )
  196. WARNING( "Unkown error while setting freewheeling mode" );
  197. }
  198. void
  199. Engine::thread_init ( void *arg )
  200. {
  201. ((Engine*)arg)->thread_init();
  202. }
  203. void
  204. Engine::thread_init ( void )
  205. {
  206. _thread.set( "RT" );
  207. }
  208. int
  209. Engine::init ( void )
  210. {
  211. if (( _client = jack_client_open ( APP_NAME, (jack_options_t)0, NULL )) == 0 )
  212. return 0;
  213. #define set_callback( name ) jack_set_ ## name ## _callback( _client, &Engine:: name , this )
  214. set_callback( thread_init );
  215. set_callback( process );
  216. set_callback( xrun );
  217. set_callback( freewheel );
  218. set_callback( buffer_size );
  219. /* FIXME: should we wait to register this until after the project
  220. has been loaded (and we have disk threads running)? */
  221. set_callback( sync );
  222. jack_set_timebase_callback( _client, 0, &Engine::timebase, this );
  223. jack_activate( _client );
  224. _sample_rate = frame_rate();
  225. timeline->_sample_rate = frame_rate();
  226. /* we don't need to create any ports until tracks are created */
  227. return 1;
  228. }