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.

309 lines
8.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 "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 */
  37. float Disk_Stream::seconds_to_buffer = 1.0f;
  38. // size_t Disk_Stream::disk_block_frames = 2048;
  39. Disk_Stream::Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th )
  40. {
  41. _frame = 0;
  42. _thread = 0;
  43. _terminate = false;
  44. _pending_seek = -1;
  45. printf( "nframes %lu\n", nframes );
  46. _total_blocks = frame_rate * seconds_to_buffer / nframes;
  47. _nframes = nframes;
  48. size_t bufsize = _total_blocks * nframes * sizeof( sample_t );
  49. /* const int blocks = 64; */
  50. /* const size_t bufsize = (blocks * (nframes * sizeof( sample_t ))) + sizeof( sample_t ); */
  51. for ( int i = channels; i--; )
  52. _rb.push_back( jack_ringbuffer_create( bufsize ) );
  53. sem_init( &_blocks, 0, _total_blocks );
  54. run();
  55. }
  56. Disk_Stream::~Disk_Stream ( )
  57. {
  58. /* stop the IO thread */
  59. _terminate = true;
  60. pthread_join( _thread, NULL );
  61. /* it isn't safe to do all this with the RT thread running */
  62. engine->lock();
  63. _th = NULL;
  64. sem_destroy( &_blocks );
  65. for ( int i = channels(); i--; )
  66. jack_ringbuffer_free( _rb[ i ] );
  67. engine->unlock();
  68. }
  69. Audio_Track *
  70. Disk_Stream::track ( void )
  71. {
  72. return (Audio_Track*)_th->track();
  73. }
  74. /** start Disk_Stream thread */
  75. void
  76. Disk_Stream::run ( void )
  77. {
  78. if ( pthread_create( &_thread, NULL, &Disk_Stream::io_thread, this ) != 0 )
  79. /* error */;
  80. }
  81. /* to be called when the JACK buffer size changes. */
  82. void
  83. Disk_Stream::resize ( nframes_t nframes )
  84. {
  85. if ( nframes != _nframes )
  86. /* FIXME: to something here! */;
  87. }
  88. bool
  89. Disk_Stream::seek_pending ( void )
  90. {
  91. return _pending_seek != (nframes_t)-1;
  92. }
  93. /* THREAD: RT */
  94. /** request that the IO thread perform a seek and rebuffer. This is
  95. called for each Disk_Stream whenever the RT thread determines that
  96. the transport has jumped to a new position. This is called *before*
  97. process. */
  98. void
  99. Disk_Stream::seek ( nframes_t frame )
  100. {
  101. printf( "requesting seek\n" );
  102. if ( seek_pending() )
  103. printf( "seek error, attempt to seek while seek is pending\n" );
  104. _pending_seek = frame;
  105. /* flush buffers */
  106. for ( int i = channels(); i--; )
  107. jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );
  108. /* dirty hack... reset the semaphore. Should we just call sem_init
  109. * again instead? */
  110. /* sem_init( &_blocks, 0, _total_blocks ); */
  111. int n;
  112. sem_getvalue( &_blocks, &n );
  113. n = _total_blocks - n;
  114. while ( n-- )
  115. sem_post( &_blocks );
  116. }
  117. /* void */
  118. /* DIsk_Stream::shutdown ( void ) */
  119. /* { */
  120. /* pthread_join( &_thread, NULL ); */
  121. /* } */
  122. /* static wrapper */
  123. void *
  124. Disk_Stream::io_thread ( void *arg )
  125. {
  126. ((Disk_Stream*)arg)->io_thread();
  127. return NULL;
  128. }
  129. /* THREAD: IO */
  130. /** read /nframes/ from the attached track into /buf/ */
  131. void
  132. Disk_Stream::read_block ( sample_t *buf, nframes_t nframes )
  133. {
  134. memset( buf, 0, nframes * sizeof( sample_t ) * channels() );
  135. /* stupid chicken/egg */
  136. if ( ! timeline )
  137. return;
  138. // printf( "IO: attempting to read block @ %lu\n", _frame );
  139. if ( ! track() )
  140. {
  141. // _frame += _nframes;
  142. return;
  143. }
  144. timeline->rdlock();
  145. if ( track()->play( buf, _frame, nframes, channels() ) )
  146. _frame += nframes;
  147. else
  148. /* error */;
  149. timeline->unlock();
  150. }
  151. int
  152. Disk_Stream::output_buffer_percent ( void )
  153. {
  154. int n;
  155. sem_getvalue( &_blocks, &n );
  156. return 100 - (n * 100 / _total_blocks);
  157. }
  158. /* THREAD: IO */
  159. void
  160. Disk_Stream::io_thread ( void )
  161. {
  162. printf( "IO thread running...\n" );
  163. /* buffer to hold the interleaved data returned by the track reader */
  164. sample_t *buf = new sample_t[ _nframes * channels() ];
  165. /* buffer for a single channel */
  166. sample_t *cbuf = new sample_t[ _nframes ];
  167. const size_t block_size = _nframes * sizeof( sample_t );
  168. while ( wait_for_block() )
  169. {
  170. // printf( "IO: RT thread is ready for more data...\n" );
  171. // printf( "IO: disk buffer is %3d%% full\r", output_buffer_percent() );
  172. // lock(); // for seeking
  173. if ( seek_pending() )
  174. {
  175. printf( "performing seek\n" );
  176. _frame = _pending_seek;
  177. _pending_seek = -1;
  178. /* finish flushing the buffer */
  179. /* for ( int i = channels(); i-- ) */
  180. /* jack_ringbuffer_write_advance( _rb[ i ], jack_ringbuffer_write_space( _rb[ i ] ) ); */
  181. }
  182. /* FIXME: should we not read from disk in larger-than-JACK-buffer blocks? */
  183. read_block( buf, _nframes );
  184. // unlock(); // for seeking
  185. /* deinterleave the buffer and stuff it into the per-channel ringbuffers */
  186. for ( int i = channels(); i--; )
  187. {
  188. int k = 0;
  189. for ( unsigned int j = i; k < _nframes; j += channels() )
  190. cbuf[ k++ ] = buf[ j ];
  191. while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size )
  192. {
  193. printf( "IO: disk buffer overrun!\n" );
  194. /* FIXME: is this *really* the right thing to do? */
  195. usleep( 2000 );
  196. }
  197. jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size );
  198. }
  199. }
  200. printf( "IO thread terminating.\n" );
  201. delete[] buf;
  202. delete[] cbuf;
  203. }
  204. /* THREAD: RT */
  205. /** take a single block from the ringbuffers and send it out the
  206. * attached track's ports */
  207. nframes_t
  208. Disk_Stream::process ( nframes_t nframes )
  209. {
  210. const size_t block_size = nframes * sizeof( sample_t );
  211. // printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );
  212. for ( int i = channels(); i--; )
  213. {
  214. void *buf = _th->output[ i ].buffer( nframes );
  215. if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
  216. {
  217. printf( "RT: buffer underrun (disk can't keep up).\n" );
  218. memset( buf, 0, block_size );
  219. /* FIXME: we need to resync somehow */
  220. }
  221. /* /\* testing. *\/ */
  222. /* FILE *fp = fopen( "testing.au", "a" ); */
  223. /* fwrite( buf, block_size, 1, fp ); */
  224. /* fclose( fp ); */
  225. }
  226. block_processed();
  227. /* FIXME: bogus */
  228. return nframes;
  229. }