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.

214 lines
6.0KB

  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. // float Disk_Stream::seconds_to_buffer = 5.0f;
  23. float Disk_Stream::seconds_to_buffer = 5.0f;
  24. // size_t Disk_Stream::disk_block_frames = 2048;
  25. /* A Disk_Stream uses a separate I/O thread to stream a track's
  26. regions from disk into a ringbuffer, to be processed by the RT
  27. thread (or vice-versa). */
  28. /* FIXME: handle termination of IO thread in destructor */
  29. /* FIXME: could all of this not simply be included in the Track_Header
  30. class? */
  31. /* FIXME: deal with (jack) buffer size changes */
  32. /* FIXME: can this be made to actually handle capture? */
  33. /* FIXME: needs error handling everywhere! */
  34. Disk_Stream::Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th )
  35. {
  36. _frame = 0;
  37. _thread = 0;
  38. printf( "nframes %lu\n", nframes );
  39. const int blocks = frame_rate * seconds_to_buffer / nframes;
  40. _nframes = nframes;
  41. size_t bufsize = blocks * nframes * sizeof( sample_t );
  42. /* const int blocks = 64; */
  43. /* const size_t bufsize = (blocks * (nframes * sizeof( sample_t ))) + sizeof( sample_t ); */
  44. for ( int i = channels; i--; )
  45. _rb.push_back( jack_ringbuffer_create( bufsize ) );
  46. sem_init( &_blocks, 0, blocks );
  47. run();
  48. }
  49. Disk_Stream::~Disk_Stream ( )
  50. {
  51. _th = NULL;
  52. sem_destroy( &_blocks );
  53. for ( int i = channels(); i--; )
  54. jack_ringbuffer_free( _rb[ i ] );
  55. }
  56. Audio_Track *
  57. Disk_Stream::track ( void )
  58. {
  59. return (Audio_Track*)_th->track();
  60. }
  61. /** start Disk_Stream thread */
  62. void
  63. Disk_Stream::run ( void )
  64. {
  65. if ( pthread_create( &_thread, NULL, &Disk_Stream::io_thread, this ) != 0 )
  66. /* error */;
  67. }
  68. /* void */
  69. /* DIsk_Stream::shutdown ( void ) */
  70. /* { */
  71. /* pthread_join( &_thread, NULL ); */
  72. /* } */
  73. /* static wrapper */
  74. void *
  75. Disk_Stream::io_thread ( void *arg )
  76. {
  77. ((Disk_Stream*)arg)->io_thread();
  78. return NULL;
  79. }
  80. /* THREAD: IO */
  81. /** read a block of data from the track into /buf/ */
  82. void
  83. Disk_Stream::read_block ( sample_t *buf )
  84. {
  85. /* stupid chicken/egg */
  86. if ( ! timeline )
  87. return;
  88. // printf( "IO: attempting to read block @ %lu\n", _frame );
  89. if ( ! track() )
  90. {
  91. // _frame += _nframes;
  92. return;
  93. }
  94. timeline->rdlock();
  95. if ( track()->play( buf, _frame, _nframes, channels() ) )
  96. _frame += _nframes;
  97. else
  98. /* error */;
  99. timeline->unlock();
  100. }
  101. /* THREAD: IO */
  102. void
  103. Disk_Stream::io_thread ( void )
  104. {
  105. printf( "IO thread running...\n" );
  106. /* buffer to hold the interleaved data returned by the track reader */
  107. sample_t *buf = new sample_t[ _nframes * channels() ];
  108. /* buffer for a single channel */
  109. sample_t *cbuf = new sample_t[ _nframes ];
  110. const size_t block_size = _nframes * sizeof( sample_t );
  111. while ( wait_for_block() )
  112. {
  113. // printf( "IO: RT thread is ready for more data...\n" );
  114. read_block( buf );
  115. /* deinterleave the buffer and stuff it into the per-channel ringbuffers */
  116. for ( int i = channels(); i--; )
  117. {
  118. int k = 0;
  119. for ( unsigned int j = i; k < _nframes; j += channels() )
  120. cbuf[ k++ ] = buf[ j ];
  121. while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size )
  122. {
  123. printf( "IO: disk buffer overrun!\n" );
  124. usleep( 2000 );
  125. }
  126. jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size );
  127. }
  128. }
  129. delete[] buf;
  130. delete[] cbuf;
  131. }
  132. /* THREAD: RT */
  133. /** take a block from the ringbuffers and send it out the track's
  134. * ports */
  135. nframes_t
  136. Disk_Stream::process ( nframes_t nframes )
  137. {
  138. const size_t block_size = nframes * sizeof( sample_t );
  139. // printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );
  140. for ( int i = channels(); i--; )
  141. {
  142. void *buf = _th->output[ i ].buffer( nframes );
  143. /* FIXME: handle underrun */
  144. /* if ( jack_ringbuffer_read_space( _rb[ i ] ) < block_size ) */
  145. /* { */
  146. /* printf( "disktream (rt): buffer underrun!\n" ); */
  147. /* memset( buf, 0, block_size ); */
  148. /* } */
  149. /* else */
  150. if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
  151. {
  152. printf( "RT: buffer underrun (disk can't keep up).\n" );
  153. memset( buf, 0, block_size );
  154. }
  155. /* /\* testing. *\/ */
  156. /* FILE *fp = fopen( "testing.au", "a" ); */
  157. /* fwrite( buf, block_size, 1, fp ); */
  158. /* fclose( fp ); */
  159. }
  160. block_processed();
  161. /* FIXME: bogus */
  162. return nframes;
  163. }