2 /*******************************************************************************/
3 /* Copyright (C) 2008 Jonathan Moore Liles */
5 /* This program is free software; you can redistribute it and/or modify it */
6 /* under the terms of the GNU General Public License as published by the */
7 /* Free Software Foundation; either version 2 of the License, or (at your */
8 /* option) any later version. */
10 /* This program is distributed in the hope that it will be useful, but WITHOUT */
11 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
12 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
15 /* You should have received a copy of the GNU General Public License along */
16 /* with This program; see the file COPYING. If not,write to the Free Software */
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /*******************************************************************************/
21 // #include "Audio_Sequence.H"
25 #include "Engine.H" // for locking.
27 #include "Disk_Stream.H"
41 /* A Disk_Stream uses a separate I/O thread to stream a track's
42 regions from disk into a ringbuffer to be processed by the RT
43 thread (or vice-versa). The I/O thread syncronizes access with the
44 user thread via the Timeline mutex. The size of the buffer (in
45 seconds) must be set before any Disk_Stream objects are created;
46 that is, at startup time. The default is 5 seconds, which may or
47 may not be excessive depending on various external factors. */
49 float Disk_Stream::seconds_to_buffer = 2.0f;
50 /* this is really only a rough estimate. The actual amount of data
51 read depends on many factors. Overlapping regions, for example, will
52 require more data to be read from disk, as will varying channel
54 size_t Disk_Stream::disk_io_kbytes = 256;
58 Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, int channels ) : _track( track )
66 _frame_rate = frame_rate;
68 _resize_buffers( nframes, channels );
70 sem_init( &_blocks, 0, _total_blocks );
73 Disk_Stream::~Disk_Stream ( )
75 /* it isn't safe to do all this with the RT thread running */
82 sem_destroy( &_blocks );
84 for ( int i = channels(); i--; )
85 jack_ringbuffer_free( _rb[ i ] );
92 /** flush buffers and reset. Must only be called from the RT thread. */
94 Disk_Stream::base_flush ( bool is_output )
99 for ( int i = _rb.size(); i--; )
100 jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );
102 /* sem_destroy( &_blocks ); */
104 /* if ( is_output ) */
105 /* sem_init( &_blocks, 0, _total_blocks ); */
107 /* sem_init( &_blocks, 0, 0 ); */
112 sem_getvalue( &_blocks, &n );
114 n = _total_blocks - n;
117 sem_post( &_blocks );
121 sem_destroy( &_blocks );
123 sem_init( &_blocks, 0, 0 );
129 /** signal thread to terminate, then detach it */
131 Disk_Stream::detach ( void )
140 /** stop the IO thread. */
142 Disk_Stream::shutdown ( void )
144 if ( _thread.running() )
148 /* try to wake the thread so it'll see that it's time to die */
157 sem_destroy( &_blocks );
159 sem_init( &_blocks, 0, 0 );
164 Disk_Stream::track ( void ) const
170 Disk_Stream::sequence ( void ) const
172 return (Audio_Sequence*)_track->sequence();
175 /** start Disk_Stream thread */
177 Disk_Stream::run ( void )
179 ASSERT( ! _thread.running(), "Thread is already running" );
181 if ( ! _thread.clone( &Disk_Stream::disk_thread, this ) )
182 FATAL( "Could not create IO thread!" );
186 Disk_Stream::_resize_buffers ( nframes_t nframes, int channels )
188 for ( int i = _rb.size(); i--; )
189 jack_ringbuffer_free( _rb[ i ] );
195 _total_blocks = _frame_rate * seconds_to_buffer / nframes;
197 size_t bufsize = _total_blocks * nframes * sizeof( sample_t );
199 if ( disk_io_kbytes )
200 _disk_io_blocks = ( bufsize * channels ) / ( disk_io_kbytes * 1024 );
204 for ( int i = channels; i--; )
205 _rb.push_back( jack_ringbuffer_create( bufsize ) );
208 /* THREAD: RT (non-RT) */
209 /* to be called when the JACK buffer size changes. */
211 Disk_Stream::resize_buffers ( nframes_t nframes )
213 if ( nframes != _nframes )
215 DMESSAGE( "resizing buffers" );
217 const bool was_running = _thread.running();
224 _resize_buffers( nframes, channels() );
234 Disk_Stream::disk_thread ( void *arg )
236 ((Disk_Stream*)arg)->disk_thread();
242 Disk_Stream::buffer_percent ( void )
246 sem_getvalue( &_blocks, &n );
248 return 100 - (n * 100 / _total_blocks);