Non reinvents the DAW. Powerful enough to form a complete studio, fast and light enough to run on low-end hardware like the eeePC or Raspberry Pi, and so reliable that it can be used live https://non.tuxfamily.org/
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.

268 lines
7.1KB

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