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.

317 lines
8.7KB

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