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.

345 lines
9.8KB

  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 "Disk_Stream.H"
  19. #include "Track_Header.H"
  20. #include "Audio_Track.H"
  21. #include "Port.H"
  22. #include "Engine.H" // for locking.
  23. #include "dsp.h"
  24. /**********/
  25. /* Engine */
  26. /**********/
  27. /* A Disk_Stream uses a separate I/O thread to stream a track's
  28. regions from disk into a ringbuffer to be processed by the RT
  29. thread (or vice-versa). The I/O thread syncronizes access with the
  30. user thread via the Timeline mutex. The size of the buffer (in
  31. seconds) must be set before any Disk_Stream objects are created;
  32. that is, at startup time. The default is 5 seconds, which may or
  33. may not be excessive depending on various external factors. */
  34. /* FIXME: handle termination of IO thread in destructor */
  35. /* FIXME: deal with (jack) buffer size changes */
  36. /* FIXME: needs error handling everywhere! */
  37. /* TODO: handle capture too. For this to work with some kind of
  38. * punch-in/out system, I believe we'll have to always keep at least
  39. * one buffer's worth of input. We would need this anyway in order to
  40. * pass input through to output (software monitoring). What about
  41. * looped recording? */
  42. /* TODO: latency compensation? Does this really apply to us? (we're
  43. * not hosting plugins here) */
  44. /* TODO: read/write data from/to disk in larger chunks to avoid
  45. * excessive seeking. 256k is supposedly the sweetspot. */
  46. float Disk_Stream::seconds_to_buffer = 5.0f;
  47. // size_t Disk_Stream::disk_block_frames = 2048;
  48. Disk_Stream::Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th )
  49. {
  50. _frame = 0;
  51. _thread = 0;
  52. _terminate = false;
  53. _pending_seek = -1;
  54. printf( "nframes %lu\n", nframes );
  55. _total_blocks = frame_rate * seconds_to_buffer / nframes;
  56. _nframes = nframes;
  57. size_t bufsize = _total_blocks * nframes * sizeof( sample_t );
  58. /* const int blocks = 64; */
  59. /* const size_t bufsize = (blocks * (nframes * sizeof( sample_t ))) + sizeof( sample_t ); */
  60. for ( int i = channels; i--; )
  61. _rb.push_back( jack_ringbuffer_create( bufsize ) );
  62. sem_init( &_blocks, 0, _total_blocks );
  63. run();
  64. }
  65. Disk_Stream::~Disk_Stream ( )
  66. {
  67. /* stop the IO thread */
  68. _terminate = true;
  69. pthread_join( _thread, NULL );
  70. /* it isn't safe to do all this with the RT thread running */
  71. engine->lock();
  72. _th = NULL;
  73. sem_destroy( &_blocks );
  74. for ( int i = channels(); i--; )
  75. jack_ringbuffer_free( _rb[ i ] );
  76. engine->unlock();
  77. }
  78. Audio_Track *
  79. Disk_Stream::track ( void )
  80. {
  81. return (Audio_Track*)_th->track();
  82. }
  83. /** start Disk_Stream thread */
  84. void
  85. Disk_Stream::run ( void )
  86. {
  87. if ( pthread_create( &_thread, NULL, &Disk_Stream::io_thread, this ) != 0 )
  88. /* error */;
  89. }
  90. /* to be called when the JACK buffer size changes. */
  91. void
  92. Disk_Stream::resize ( nframes_t nframes )
  93. {
  94. if ( nframes != _nframes )
  95. /* FIXME: to something here! */;
  96. }
  97. bool
  98. Disk_Stream::seek_pending ( void )
  99. {
  100. return _pending_seek != (nframes_t)-1;
  101. }
  102. /* THREAD: RT */
  103. /** request that the IO thread perform a seek and rebuffer. This is
  104. called for each Disk_Stream whenever the RT thread determines that
  105. the transport has jumped to a new position. This is called *before*
  106. process. */
  107. void
  108. Disk_Stream::seek ( nframes_t frame )
  109. {
  110. printf( "requesting seek\n" );
  111. if ( seek_pending() )
  112. printf( "seek error, attempt to seek while seek is pending\n" );
  113. _pending_seek = frame;
  114. /* flush buffers */
  115. for ( int i = channels(); i--; )
  116. jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );
  117. /* dirty hack... reset the semaphore. Should we just call sem_init
  118. * again instead? */
  119. /* sem_init( &_blocks, 0, _total_blocks ); */
  120. int n;
  121. sem_getvalue( &_blocks, &n );
  122. n = _total_blocks - n;
  123. while ( n-- )
  124. sem_post( &_blocks );
  125. }
  126. /* void */
  127. /* DIsk_Stream::shutdown ( void ) */
  128. /* { */
  129. /* pthread_join( &_thread, NULL ); */
  130. /* } */
  131. /* static wrapper */
  132. void *
  133. Disk_Stream::io_thread ( void *arg )
  134. {
  135. ((Disk_Stream*)arg)->io_thread();
  136. return NULL;
  137. }
  138. /* THREAD: IO */
  139. /** read /nframes/ from the attached track into /buf/ */
  140. void
  141. Disk_Stream::read_block ( sample_t *buf, nframes_t nframes )
  142. {
  143. memset( buf, 0, nframes * sizeof( sample_t ) * channels() );
  144. /* stupid chicken/egg */
  145. if ( ! timeline )
  146. return;
  147. // printf( "IO: attempting to read block @ %lu\n", _frame );
  148. if ( ! track() )
  149. {
  150. // _frame += _nframes;
  151. return;
  152. }
  153. timeline->rdlock();
  154. if ( track()->play( buf, _frame, nframes, channels() ) )
  155. _frame += nframes;
  156. else
  157. /* error */;
  158. timeline->unlock();
  159. }
  160. int
  161. Disk_Stream::output_buffer_percent ( void )
  162. {
  163. int n;
  164. sem_getvalue( &_blocks, &n );
  165. return 100 - (n * 100 / _total_blocks);
  166. }
  167. /* THREAD: IO */
  168. void
  169. Disk_Stream::io_thread ( void )
  170. {
  171. printf( "IO thread running...\n" );
  172. /* buffer to hold the interleaved data returned by the track reader */
  173. sample_t *buf = new sample_t[ _nframes * channels() ];
  174. const size_t block_size = _nframes * sizeof( sample_t );
  175. while ( wait_for_block() )
  176. {
  177. // printf( "IO: RT thread is ready for more data...\n" );
  178. // printf( "IO: disk buffer is %3d%% full\r", output_buffer_percent() );
  179. // lock(); // for seeking
  180. if ( seek_pending() )
  181. {
  182. printf( "performing seek\n" );
  183. _frame = _pending_seek;
  184. _pending_seek = -1;
  185. /* finish flushing the buffer */
  186. /* for ( int i = channels(); i-- ) */
  187. /* jack_ringbuffer_write_advance( _rb[ i ], jack_ringbuffer_write_space( _rb[ i ] ) ); */
  188. }
  189. /* FIXME: should we not read from disk in larger-than-JACK-buffer blocks? */
  190. read_block( buf, _nframes );
  191. // unlock(); // for seeking
  192. /* deinterleave the buffer and stuff it into the per-channel ringbuffers */
  193. for ( int i = channels(); i--; )
  194. {
  195. while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size )
  196. {
  197. printf( "IO: disk buffer overrun!\n" );
  198. /* FIXME: is this *really* the right thing to do? */
  199. usleep( 2000 );
  200. }
  201. /* deinterleave direcectly into the ringbuffer to avoid
  202. * unnecessary copying */
  203. jack_ringbuffer_data_t rbd[2];
  204. jack_ringbuffer_get_write_vector( _rb[ i ], rbd );
  205. if ( rbd[ 0 ].len >= _nframes )
  206. /* it'll all fit in one go */
  207. buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), _nframes );
  208. else if ( rbd[ 1 ].len )
  209. {
  210. /* there's enough space in the ringbuffer, but it's not contiguous */
  211. /* do the first half */
  212. const nframes_t f = rbd[ 1 ].len / sizeof( sample_t );
  213. buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f );
  214. assert( rbd[ 1 ].len >= (_nframes - f) * sizeof( sample_t ) );
  215. /* do the second half */
  216. buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), _nframes - f );
  217. }
  218. else
  219. printf( "programming error: expected more space in ringbuffer\n" );
  220. /* buffer_deinterleave_one_channel( (sample_t*)rbd.buf, buf, i, channels(), _nframes ); */
  221. /* jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); */
  222. jack_ringbuffer_write_advance( _rb[ i ], _nframes * sizeof( sample_t ) );
  223. }
  224. }
  225. printf( "IO thread terminating.\n" );
  226. delete[] buf;
  227. }
  228. /* THREAD: RT */
  229. /** take a single block from the ringbuffers and send it out the
  230. * attached track's ports */
  231. nframes_t
  232. Disk_Stream::process ( nframes_t nframes )
  233. {
  234. const size_t block_size = nframes * sizeof( sample_t );
  235. // printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );
  236. for ( int i = channels(); i--; )
  237. {
  238. void *buf = _th->output[ i ].buffer( nframes );
  239. if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
  240. {
  241. printf( "RT: buffer underrun (disk can't keep up).\n" );
  242. memset( buf, 0, block_size );
  243. /* FIXME: we need to resync somehow */
  244. }
  245. /* /\* testing. *\/ */
  246. /* FILE *fp = fopen( "testing.au", "a" ); */
  247. /* fwrite( buf, block_size, 1, fp ); */
  248. /* fclose( fp ); */
  249. }
  250. block_processed();
  251. /* FIXME: bogus */
  252. return nframes;
  253. }