Update NTK.
[nondaw.git] / timeline / src / Engine / Disk_Stream.C
blob74d3a9c666f24edda77ce72d6e90c102f393928a
2 /*******************************************************************************/
3 /* Copyright (C) 2008 Jonathan Moore Liles                                     */
4 /*                                                                             */
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.                                                  */
9 /*                                                                             */
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   */
13 /* more details.                                                               */
14 /*                                                                             */
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 /*******************************************************************************/
20 #include "../Track.H"
21 // #include "Audio_Sequence.H"
22 class Audio_Sequence;
24 // #include "Port.H"
25 #include "Engine.H" // for locking.
27 #include "Disk_Stream.H"
28 #include "dsp.h"
30 #include "const.h"
31 #include "debug.h"
33 #include <unistd.h>
37 /**********/
38 /* Engine */
39 /**********/
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
53  counts.*/
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 )
60     assert( channels );
62     _frame = 0;
63     _terminate = false;
64     _pending_seek = -1;
65     _xruns = 0;
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 */
76     engine->lock();
78     shutdown();
80      _track = NULL;
82     sem_destroy( &_blocks );
84     for ( int i = channels(); i--; )
85         jack_ringbuffer_free( _rb[ i ] );
87     engine->unlock();
92 /** flush buffers and reset. Must only be called from the RT thread. */
93 void
94 Disk_Stream::base_flush ( bool is_output )
96     THREAD_ASSERT( RT );
98     /* flush buffers */
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 ); */
106 /*     else */
107 /*         sem_init( &_blocks, 0, 0 ); */
109     if ( is_output )
110     {
111         int n;
112         sem_getvalue( &_blocks, &n );
114         n = _total_blocks - n;
116         while ( n-- )
117             sem_post( &_blocks );
118     }
119     else
120     {
121         sem_destroy( &_blocks );
123         sem_init( &_blocks, 0, 0 );
124     }
129 /** signal thread to terminate, then detach it */
130 void
131 Disk_Stream::detach ( void )
133     _terminate = true;
135     block_processed();
137     _thread.detach();
140 /** stop the IO thread. */
141 void
142 Disk_Stream::shutdown ( void )
144     if ( _thread.running() )
145     {
146         _terminate = true;
147         
148         /* try to wake the thread so it'll see that it's time to die */
149         while ( _terminate )
150         {
151             usleep( 100 );
152             block_processed();
153         }
154         
155         _thread.join();
157         sem_destroy( &_blocks );
159         sem_init( &_blocks, 0, 0 );
160     }
163 Track *
164 Disk_Stream::track ( void ) const
166     return _track;
169 Audio_Sequence *
170 Disk_Stream::sequence ( void ) const
172     return (Audio_Sequence*)_track->sequence();
175 /** start Disk_Stream thread */
176 void
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!" );
185 void
186 Disk_Stream::_resize_buffers ( nframes_t nframes, int channels )
188     for ( int i = _rb.size(); i--; )
189         jack_ringbuffer_free( _rb[ i ] );
191     _rb.clear();
193     _nframes = nframes;
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 );
201     else
202         _disk_io_blocks = 1;
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. */
210 void
211 Disk_Stream::resize_buffers ( nframes_t nframes )
213     if ( nframes != _nframes )
214     {
215         DMESSAGE( "resizing buffers" );
217         const bool was_running = _thread.running();
219         if ( was_running )
220             shutdown();
222         flush();
224         _resize_buffers( nframes, channels() );
226         if ( was_running )
227             run();
228     }
232 /* static wrapper */
233 void *
234 Disk_Stream::disk_thread ( void *arg )
236     ((Disk_Stream*)arg)->disk_thread();
238     return NULL;
242 Disk_Stream::buffer_percent ( void )
244     int n;
246     sem_getvalue( &_blocks, &n );
248     return 100 - (n * 100 / _total_blocks);