@@ -26,6 +26,10 @@ | |||||
#include "Audio_File.H" | #include "Audio_File.H" | ||||
#include "dsp.h" | #include "dsp.h" | ||||
#include "util/Thread.H" | |||||
/** Apply a (portion of) fade from /start/ to /end/ assuming a | /** Apply a (portion of) fade from /start/ to /end/ assuming a | ||||
* buffer size of /nframes/. /start/ and /end/ are relative to the | * buffer size of /nframes/. /start/ and /end/ are relative to the | ||||
* given buffer, and /start/ may be negative. */ | * given buffer, and /start/ may be negative. */ | ||||
@@ -63,7 +67,6 @@ Audio_Region::Fade::apply ( sample_t *buf, Audio_Region::Fade::fade_dir_e dir, l | |||||
*(buf++) *= gain( fi ); | *(buf++) *= gain( fi ); | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** read the overlapping part of /channel/ at /pos/ for /nframes/ of | /** read the overlapping part of /channel/ at /pos/ for /nframes/ of | ||||
this region into /buf/, where /pos/ is in timeline frames */ | this region into /buf/, where /pos/ is in timeline frames */ | ||||
/* this runs in the diskstream thread. */ | /* this runs in the diskstream thread. */ | ||||
@@ -78,6 +81,8 @@ Audio_Region::Fade::apply ( sample_t *buf, Audio_Region::Fade::fade_dir_e dir, l | |||||
nframes_t | nframes_t | ||||
Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const | Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const | ||||
{ | { | ||||
THREAD_ASSERT( Playback ); | |||||
const Range r = _range; | const Range r = _range; | ||||
/* do nothing if we aren't covered by this frame range */ | /* do nothing if we aren't covered by this frame range */ | ||||
@@ -193,12 +198,13 @@ Audio_Region::prepare ( void ) | |||||
log_start(); | log_start(); | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** write /nframes/ from /buf/ to source. /buf/ is interleaved and | /** write /nframes/ from /buf/ to source. /buf/ is interleaved and | ||||
must match the channel layout of the write source! */ | must match the channel layout of the write source! */ | ||||
nframes_t | nframes_t | ||||
Audio_Region::write ( nframes_t nframes ) | Audio_Region::write ( nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
_range.length += nframes; | _range.length += nframes; | ||||
/* FIXME: too much? */ | /* FIXME: too much? */ | ||||
@@ -230,12 +236,13 @@ Audio_Region::write ( nframes_t nframes ) | |||||
return nframes; | return nframes; | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** finalize region capture. Assumes that this *is* a captured region | /** finalize region capture. Assumes that this *is* a captured region | ||||
and that no other regions refer to the same source */ | and that no other regions refer to the same source */ | ||||
bool | bool | ||||
Audio_Region::finalize ( nframes_t frame ) | Audio_Region::finalize ( nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
DMESSAGE( "finalizing capture region" ); | DMESSAGE( "finalizing capture region" ); | ||||
_range.length = frame - _range.start; | _range.length = frame - _range.start; | ||||
@@ -21,6 +21,8 @@ | |||||
#include "dsp.h" | #include "dsp.h" | ||||
#include "util/Thread.H" | |||||
using namespace std; | using namespace std; | ||||
@@ -29,12 +31,13 @@ using namespace std; | |||||
/* Engine */ | /* Engine */ | ||||
/**********/ | /**********/ | ||||
/* THREAD: IO */ | |||||
/** determine region coverage and fill /buf/ with interleaved samples | /** determine region coverage and fill /buf/ with interleaved samples | ||||
* from /frame/ to /nframes/ for exactly /channels/ channels. */ | * from /frame/ to /nframes/ for exactly /channels/ channels. */ | ||||
nframes_t | nframes_t | ||||
Audio_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ) | Audio_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ) | ||||
{ | { | ||||
THREAD_ASSERT( Playback ); | |||||
sample_t *cbuf = new sample_t[ nframes ]; | sample_t *cbuf = new sample_t[ nframes ]; | ||||
memset( cbuf, 0, nframes * sizeof( sample_t ) ); | memset( cbuf, 0, nframes * sizeof( sample_t ) ); | ||||
@@ -65,10 +68,3 @@ Audio_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int ch | |||||
/* FIXME: bogus */ | /* FIXME: bogus */ | ||||
return nframes; | return nframes; | ||||
} | } | ||||
/* /\* THREAD: RT *\/ */ | |||||
/* nframes_t */ | |||||
/* Audio_Sequence::process ( nframes_t nframes ) */ | |||||
/* { */ | |||||
/* return disktream->process( nframes ); */ | |||||
/* } */ |
@@ -21,6 +21,8 @@ | |||||
#include "../Transport.H" // for ->frame | #include "../Transport.H" // for ->frame | ||||
#include "util/Thread.H" | |||||
#include <list> | #include <list> | ||||
using std::list; | using std::list; | ||||
@@ -45,12 +47,13 @@ sigmoid_interpolate ( float y1, float y2, float mu ) | |||||
/* THREAD: RT */ | |||||
/** fill buf with /nframes/ of interpolated control curve values | /** fill buf with /nframes/ of interpolated control curve values | ||||
* starting at /frame/ */ | * starting at /frame/ */ | ||||
nframes_t | nframes_t | ||||
Control_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes ) | Control_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
Control_Point *p2, *p1 = (Control_Point*)&_widgets.front(); | Control_Point *p2, *p1 = (Control_Point*)&_widgets.front(); | ||||
nframes_t n = nframes; | nframes_t n = nframes; | ||||
@@ -84,11 +87,11 @@ Control_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes ) | |||||
return nframes - n; | return nframes - n; | ||||
} | } | ||||
/* THREAD: RT */ | |||||
nframes_t | nframes_t | ||||
Control_Sequence::process ( nframes_t nframes ) | Control_Sequence::process ( nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
if ( _output->connected() ) /* don't waste CPU on disconnected ports */ | if ( _output->connected() ) /* don't waste CPU on disconnected ports */ | ||||
{ | { | ||||
void *buf = _output->buffer( nframes ); | void *buf = _output->buffer( nframes ); | ||||
@@ -58,7 +58,6 @@ Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, in | |||||
assert( channels ); | assert( channels ); | ||||
_frame = 0; | _frame = 0; | ||||
_thread = 0; | |||||
_terminate = false; | _terminate = false; | ||||
_pending_seek = -1; | _pending_seek = -1; | ||||
_xruns = 0; | _xruns = 0; | ||||
@@ -87,11 +86,11 @@ Disk_Stream::~Disk_Stream ( ) | |||||
} | } | ||||
/* THREAD: RT */ | |||||
/** flush buffers and reset. Must only be called from the RT thread. */ | /** flush buffers and reset. Must only be called from the RT thread. */ | ||||
void | void | ||||
Disk_Stream::base_flush ( bool is_output ) | Disk_Stream::base_flush ( bool is_output ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
/* flush buffers */ | /* flush buffers */ | ||||
for ( int i = _rb.size(); i--; ) | for ( int i = _rb.size(); i--; ) | ||||
@@ -132,7 +131,7 @@ Disk_Stream::detach ( void ) | |||||
block_processed(); | block_processed(); | ||||
pthread_detach( _thread ); | |||||
_thread.detach(); | |||||
} | } | ||||
/** stop the IO thread. */ | /** stop the IO thread. */ | ||||
@@ -144,8 +143,8 @@ Disk_Stream::shutdown ( void ) | |||||
/* try to wake the thread so it'll see that it's time to die */ | /* try to wake the thread so it'll see that it's time to die */ | ||||
block_processed(); | block_processed(); | ||||
if ( _thread ) | |||||
pthread_join( _thread, NULL ); | |||||
if ( _thread.running() ) | |||||
_thread.join(); | |||||
} | } | ||||
Track * | Track * | ||||
@@ -164,9 +163,9 @@ Disk_Stream::sequence ( void ) const | |||||
void | void | ||||
Disk_Stream::run ( void ) | Disk_Stream::run ( void ) | ||||
{ | { | ||||
ASSERT( ! _thread, "Thread is already running" ); | |||||
ASSERT( ! _thread.running(), "Thread is already running" ); | |||||
if ( pthread_create( &_thread, NULL, &Disk_Stream::disk_thread, this ) != 0 ) | |||||
if ( ! _thread.clone( &Disk_Stream::disk_thread, this ) ) | |||||
FATAL( "Could not create IO thread!" ); | FATAL( "Could not create IO thread!" ); | ||||
} | } | ||||
@@ -202,7 +201,7 @@ Disk_Stream::resize_buffers ( nframes_t nframes ) | |||||
{ | { | ||||
DMESSAGE( "resizing buffers" ); | DMESSAGE( "resizing buffers" ); | ||||
const bool was_running = _thread; | |||||
const bool was_running = _thread.running(); | |||||
if ( was_running ) | if ( was_running ) | ||||
shutdown(); | shutdown(); | ||||
@@ -24,11 +24,11 @@ | |||||
#include <semaphore.h> | #include <semaphore.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <pthread.h> | |||||
#include <vector> | #include <vector> | ||||
#include "types.h" | #include "types.h" | ||||
#include "util/Mutex.H" | #include "util/Mutex.H" | ||||
#include "util/Thread.H" | |||||
class Track; | class Track; | ||||
class Audio_Sequence; | class Audio_Sequence; | ||||
@@ -40,9 +40,10 @@ class Disk_Stream : public Mutex | |||||
Disk_Stream ( const Disk_Stream &rhs ); | Disk_Stream ( const Disk_Stream &rhs ); | ||||
Disk_Stream & operator = ( const Disk_Stream &rhs ); | Disk_Stream & operator = ( const Disk_Stream &rhs ); | ||||
protected: | protected: | ||||
pthread_t _thread; /* io thread */ | |||||
Thread _thread; /* io thread */ | |||||
Track *_track; /* Track we belong to */ | Track *_track; /* Track we belong to */ | ||||
@@ -28,7 +28,9 @@ | |||||
/* This is the home of the JACK process callback (does this *really* | /* This is the home of the JACK process callback (does this *really* | ||||
need to be a class?) */ | need to be a class?) */ | ||||
Engine::Engine ( ) | |||||
#include "util/Thread.H" | |||||
Engine::Engine ( ) : _thread( "RT" ) | |||||
{ | { | ||||
_freewheeling = false; | _freewheeling = false; | ||||
_client = NULL; | _client = NULL; | ||||
@@ -190,6 +192,9 @@ Engine::timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *pos, | |||||
int | int | ||||
Engine::process ( nframes_t nframes ) | Engine::process ( nframes_t nframes ) | ||||
{ | { | ||||
/* FIXME: wrong place for this */ | |||||
_thread.set( "RT" ); | |||||
transport->poll(); | transport->poll(); | ||||
if ( freewheeling() ) | if ( freewheeling() ) | ||||
@@ -237,6 +242,18 @@ Engine::freewheeling ( bool yes ) | |||||
WARNING( "Unkown error while setting freewheeling mode" ); | WARNING( "Unkown error while setting freewheeling mode" ); | ||||
} | } | ||||
void | |||||
Engine::thread_init ( void *arg ) | |||||
{ | |||||
((Engine*)arg)->thread_init(); | |||||
} | |||||
void | |||||
Engine::thread_init ( void ) | |||||
{ | |||||
_thread.set( "RT" ); | |||||
} | |||||
int | int | ||||
Engine::init ( void ) | Engine::init ( void ) | ||||
{ | { | ||||
@@ -245,6 +262,7 @@ Engine::init ( void ) | |||||
#define set_callback( name ) jack_set_ ## name ## _callback( _client, &Engine:: name , this ) | #define set_callback( name ) jack_set_ ## name ## _callback( _client, &Engine:: name , this ) | ||||
set_callback( thread_init ); | |||||
set_callback( process ); | set_callback( process ); | ||||
set_callback( xrun ); | set_callback( xrun ); | ||||
set_callback( freewheel ); | set_callback( freewheel ); | ||||
@@ -27,10 +27,15 @@ typedef jack_nframes_t nframes_t; | |||||
class Port; | class Port; | ||||
#include "Thread.H" | |||||
class Engine : public Mutex | class Engine : public Mutex | ||||
{ | { | ||||
jack_client_t *_client; | jack_client_t *_client; | ||||
Thread _thread; /* only used for thread checking */ | |||||
/* I know locking out the process callback is cheating, even | /* I know locking out the process callback is cheating, even | ||||
though we use trylock... The thing is, every other DAW does | though we use trylock... The thing is, every other DAW does | ||||
this too and you can hear it in the glitches Ardour and friends | this too and you can hear it in the glitches Ardour and friends | ||||
@@ -57,6 +62,8 @@ class Engine : public Mutex | |||||
void freewheel ( bool yes ); | void freewheel ( bool yes ); | ||||
static int buffer_size ( nframes_t nframes, void *arg ); | static int buffer_size ( nframes_t nframes, void *arg ); | ||||
int buffer_size ( nframes_t nframes ); | int buffer_size ( nframes_t nframes ); | ||||
static void thread_init ( void *arg ); | |||||
void thread_init ( void ); | |||||
Engine ( const Engine &rhs ); | Engine ( const Engine &rhs ); | ||||
Engine & operator = ( const Engine &rhs ); | Engine & operator = ( const Engine &rhs ); | ||||
@@ -38,6 +38,8 @@ | |||||
#include "assert.h" | #include "assert.h" | ||||
#include "util/debug.h" | #include "util/debug.h" | ||||
#include "util/Thread.H" | |||||
#include <errno.h> | #include <errno.h> | ||||
#include <list> | #include <list> | ||||
@@ -520,11 +522,12 @@ Peak::normalization_factor( void ) const | |||||
return s; | return s; | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/* wrapper for peak writer */ | /* wrapper for peak writer */ | ||||
void | void | ||||
Peaks::prepare_for_writing ( void ) | Peaks::prepare_for_writing ( void ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
assert( ! _peak_writer ); | assert( ! _peak_writer ); | ||||
_peak_writer = new Peaks::Streamer( _clip->name(), _clip->channels(), cache_minimum ); | _peak_writer = new Peaks::Streamer( _clip->name(), _clip->channels(), cache_minimum ); | ||||
@@ -544,10 +547,11 @@ Peaks::finish_writing ( void ) | |||||
} | } | ||||
/* THREAD: IO */ | |||||
void | void | ||||
Peaks::write ( sample_t *buf, nframes_t nframes ) | Peaks::write ( sample_t *buf, nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
_peak_writer->write( buf, nframes ); | _peak_writer->write( buf, nframes ); | ||||
} | } | ||||
@@ -31,6 +31,7 @@ | |||||
#include "dsp.h" | #include "dsp.h" | ||||
#include "util/debug.h" | #include "util/debug.h" | ||||
#include "util/Thread.H" | |||||
bool | bool | ||||
Playback_DS::seek_pending ( void ) | Playback_DS::seek_pending ( void ) | ||||
@@ -38,7 +39,6 @@ Playback_DS::seek_pending ( void ) | |||||
return _pending_seek != (nframes_t)-1; | return _pending_seek != (nframes_t)-1; | ||||
} | } | ||||
/* THREAD: RT */ | |||||
/** request that the IO thread perform a seek and rebuffer. This is | /** request that the IO thread perform a seek and rebuffer. This is | ||||
called for each Disk_Stream whenever the RT thread determines that | called for each Disk_Stream whenever the RT thread determines that | ||||
the transport has jumped to a new position. This is called *before* | the transport has jumped to a new position. This is called *before* | ||||
@@ -46,6 +46,8 @@ Playback_DS::seek_pending ( void ) | |||||
void | void | ||||
Playback_DS::seek ( nframes_t frame ) | Playback_DS::seek ( nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
DMESSAGE( "requesting seek" ); | DMESSAGE( "requesting seek" ); | ||||
if ( seek_pending() ) | if ( seek_pending() ) | ||||
@@ -56,11 +58,11 @@ Playback_DS::seek ( nframes_t frame ) | |||||
flush(); | flush(); | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** read /nframes/ from the attached track into /buf/ */ | /** read /nframes/ from the attached track into /buf/ */ | ||||
void | void | ||||
Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) | Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( Playback ); | |||||
memset( buf, 0, nframes * sizeof( sample_t ) * channels() ); | memset( buf, 0, nframes * sizeof( sample_t ) * channels() ); | ||||
@@ -88,10 +90,11 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) | |||||
#define AVOID_UNNECESSARY_COPYING 1 | #define AVOID_UNNECESSARY_COPYING 1 | ||||
/* THREAD: IO */ | |||||
void | void | ||||
Playback_DS::disk_thread ( void ) | Playback_DS::disk_thread ( void ) | ||||
{ | { | ||||
_thread.name( "Playback" ); | |||||
DMESSAGE( "playback thread running" ); | DMESSAGE( "playback thread running" ); | ||||
/* buffer to hold the interleaved data returned by the track reader */ | /* buffer to hold the interleaved data returned by the track reader */ | ||||
@@ -198,15 +201,15 @@ Playback_DS::disk_thread ( void ) | |||||
#endif | #endif | ||||
_terminate = false; | _terminate = false; | ||||
_thread = 0; | |||||
} | } | ||||
/* THREAD: RT */ | |||||
/** take a single block from the ringbuffers and send it out the | /** take a single block from the ringbuffers and send it out the | ||||
* attached track's ports */ | * attached track's ports */ | ||||
nframes_t | nframes_t | ||||
Playback_DS::process ( nframes_t nframes ) | Playback_DS::process ( nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
const size_t block_size = nframes * sizeof( sample_t ); | const size_t block_size = nframes * sizeof( sample_t ); | ||||
// printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes ); | // printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes ); | ||||
@@ -30,6 +30,7 @@ | |||||
#include "dsp.h" | #include "dsp.h" | ||||
#include "util/debug.h" | #include "util/debug.h" | ||||
#include "util/Thread.H" | |||||
const Audio_Region * | const Audio_Region * | ||||
Record_DS::capture_region ( void ) const | Record_DS::capture_region ( void ) const | ||||
@@ -40,11 +41,11 @@ Record_DS::capture_region ( void ) const | |||||
return NULL; | return NULL; | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** write /nframes/ from buf to the capture file of the attached track */ | /** write /nframes/ from buf to the capture file of the attached track */ | ||||
void | void | ||||
Record_DS::write_block ( sample_t *buf, nframes_t nframes ) | Record_DS::write_block ( sample_t *buf, nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
/* stupid chicken/egg */ | /* stupid chicken/egg */ | ||||
if ( ! ( timeline && sequence() ) ) | if ( ! ( timeline && sequence() ) ) | ||||
@@ -61,12 +62,16 @@ Record_DS::write_block ( sample_t *buf, nframes_t nframes ) | |||||
#define AVOID_UNNECESSARY_COPYING 1 | #define AVOID_UNNECESSARY_COPYING 1 | ||||
/* THREAD: IO */ | |||||
void | void | ||||
Record_DS::disk_thread ( void ) | Record_DS::disk_thread ( void ) | ||||
{ | { | ||||
_thread.name( "Capture" ); | |||||
track()->record( _capture, _frame ); | |||||
DMESSAGE( "capture thread running..." ); | DMESSAGE( "capture thread running..." ); | ||||
const nframes_t nframes = _nframes * _disk_io_blocks; | const nframes_t nframes = _nframes * _disk_io_blocks; | ||||
/* buffer to hold the interleaved data returned by the track reader */ | /* buffer to hold the interleaved data returned by the track reader */ | ||||
@@ -199,7 +204,6 @@ Record_DS::disk_thread ( void ) | |||||
delete _capture; | delete _capture; | ||||
_capture = NULL; | _capture = NULL; | ||||
_thread = 0; | |||||
_terminate = false; | _terminate = false; | ||||
DMESSAGE( "capture thread gone" ); | DMESSAGE( "capture thread gone" ); | ||||
} | } | ||||
@@ -209,6 +213,7 @@ Record_DS::disk_thread ( void ) | |||||
void | void | ||||
Record_DS::start ( nframes_t frame ) | Record_DS::start ( nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( UI ); | |||||
if ( _recording ) | if ( _recording ) | ||||
{ | { | ||||
@@ -216,15 +221,13 @@ Record_DS::start ( nframes_t frame ) | |||||
return; | return; | ||||
} | } | ||||
/* FIXME: safe to do this here? */ | |||||
flush(); | |||||
/* /\* FIXME: safe to do this here? *\/ */ | |||||
/* flush(); */ | |||||
_frame = frame; | _frame = frame; | ||||
_capture = new Track::Capture; | _capture = new Track::Capture; | ||||
track()->record( _capture, frame ); | |||||
run(); | run(); | ||||
_recording = true; | _recording = true; | ||||
@@ -235,6 +238,8 @@ Record_DS::start ( nframes_t frame ) | |||||
void | void | ||||
Record_DS::stop ( nframes_t frame ) | Record_DS::stop ( nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( UI ); | |||||
if ( ! _recording ) | if ( ! _recording ) | ||||
{ | { | ||||
WARNING( "programming error: attempt to stop recording when no recording is being made" ); | WARNING( "programming error: attempt to stop recording when no recording is being made" ); | ||||
@@ -251,11 +256,11 @@ Record_DS::stop ( nframes_t frame ) | |||||
} | } | ||||
/* THREAD: RT */ | |||||
/** read from the attached track's ports and stuff the ringbuffers */ | /** read from the attached track's ports and stuff the ringbuffers */ | ||||
nframes_t | nframes_t | ||||
Record_DS::process ( nframes_t nframes ) | Record_DS::process ( nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
if ( ! _recording ) | if ( ! _recording ) | ||||
return 0; | return 0; | ||||
@@ -25,6 +25,8 @@ | |||||
#include "Record_DS.H" | #include "Record_DS.H" | ||||
#include "Playback_DS.H" | #include "Playback_DS.H" | ||||
#include "util/Thread.H" | |||||
/** Initiate recording for all armed tracks */ | /** Initiate recording for all armed tracks */ | ||||
bool | bool | ||||
Timeline::record ( void ) | Timeline::record ( void ) | ||||
@@ -90,10 +92,11 @@ Timeline::process ( nframes_t nframes ) | |||||
return nframes; | return nframes; | ||||
} | } | ||||
/* THREAD: RT */ | |||||
void | void | ||||
Timeline::seek ( nframes_t frame ) | Timeline::seek ( nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
for ( int i = tracks->children(); i-- ; ) | for ( int i = tracks->children(); i-- ; ) | ||||
{ | { | ||||
Track *t = (Track*)tracks->child( i ); | Track *t = (Track*)tracks->child( i ); | ||||
@@ -114,10 +117,11 @@ Timeline::resize_buffers ( nframes_t nframes ) | |||||
} | } | ||||
} | } | ||||
/* THREAD: RT */ | |||||
int | int | ||||
Timeline::seek_pending ( void ) | Timeline::seek_pending ( void ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
int r = 0; | int r = 0; | ||||
for ( int i = tracks->children(); i-- ; ) | for ( int i = tracks->children(); i-- ; ) | ||||
@@ -148,10 +148,11 @@ Track::configure_inputs ( int n ) | |||||
return true; | return true; | ||||
} | } | ||||
/* THREAD: RT */ | |||||
nframes_t | nframes_t | ||||
Track::process ( nframes_t nframes ) | Track::process ( nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
if ( ! transport->rolling ) | if ( ! transport->rolling ) | ||||
{ | { | ||||
for ( int i = output.size(); i--; ) | for ( int i = output.size(); i--; ) | ||||
@@ -175,10 +176,11 @@ Track::process ( nframes_t nframes ) | |||||
return 0; | return 0; | ||||
} | } | ||||
/* THREAD: RT */ | |||||
void | void | ||||
Track::seek ( nframes_t frame ) | Track::seek ( nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( RT ); | |||||
if ( playback_ds ) | if ( playback_ds ) | ||||
return playback_ds->seek( frame ); | return playback_ds->seek( frame ); | ||||
} | } | ||||
@@ -207,13 +209,12 @@ uuid ( void ) | |||||
return (unsigned long long) t; | return (unsigned long long) t; | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** create capture region and prepare to record */ | /** create capture region and prepare to record */ | ||||
void | void | ||||
Track::record ( Capture *c, nframes_t frame ) | |||||
Track::record ( Capture *c, nframes_t frame ) | |||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
char pat[256]; | char pat[256]; | ||||
snprintf( pat, sizeof( pat ), "%s-%llu", name(), uuid() ); | snprintf( pat, sizeof( pat ), "%s-%llu", name(), uuid() ); | ||||
@@ -231,11 +232,12 @@ Track::record ( Capture *c, nframes_t frame ) | |||||
c->region->prepare(); | c->region->prepare(); | ||||
} | } | ||||
/* THREAD: IO */ | |||||
/** write a block to the (already opened) capture file */ | /** write a block to the (already opened) capture file */ | ||||
void | void | ||||
Track::write ( Capture *c, sample_t *buf, nframes_t nframes ) | Track::write ( Capture *c, sample_t *buf, nframes_t nframes ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
nframes_t l = c->audio_file->write( buf, nframes ); | nframes_t l = c->audio_file->write( buf, nframes ); | ||||
c->region->write( l ); | c->region->write( l ); | ||||
@@ -243,10 +245,11 @@ Track::write ( Capture *c, sample_t *buf, nframes_t nframes ) | |||||
#include <stdio.h> | #include <stdio.h> | ||||
/* THREAD: IO */ | |||||
void | void | ||||
Track::finalize ( Capture *c, nframes_t frame ) | Track::finalize ( Capture *c, nframes_t frame ) | ||||
{ | { | ||||
THREAD_ASSERT( Capture ); | |||||
c->region->finalize( frame ); | c->region->finalize( frame ); | ||||
DMESSAGE( "finalizing audio file" ); | DMESSAGE( "finalizing audio file" ); | ||||
c->audio_file->finalize(); | c->audio_file->finalize(); | ||||
@@ -47,6 +47,8 @@ | |||||
#include "Transport.H" | #include "Transport.H" | ||||
#include "Engine/Engine.H" | #include "Engine/Engine.H" | ||||
#include "util/Thread.H" | |||||
Engine *engine; | Engine *engine; | ||||
Timeline *timeline; | Timeline *timeline; | ||||
Transport *transport; | Transport *transport; | ||||
@@ -85,6 +87,10 @@ ensure_dirs ( void ) | |||||
int | int | ||||
main ( int argc, char **argv ) | main ( int argc, char **argv ) | ||||
{ | { | ||||
Thread::init(); | |||||
Thread thread( "UI" ); | |||||
thread.set(); | |||||
fl_register_images(); | fl_register_images(); | ||||
@@ -4,7 +4,7 @@ Timeline_VERSION := 0.5.0 | |||||
Timeline_SRCS := $(wildcard Timeline/*.C Timeline/*.fl Timeline/Engine/*.C) | Timeline_SRCS := $(wildcard Timeline/*.C Timeline/*.fl Timeline/Engine/*.C) | ||||
Timeline_SRCS += util/debug.C | |||||
Timeline_SRCS += util/debug.C util/Thread.C | |||||
Timeline_SRCS:=$(Timeline_SRCS:.fl=.C) | Timeline_SRCS:=$(Timeline_SRCS:.fl=.C) | ||||
Timeline_SRCS:=$(sort $(Timeline_SRCS)) | Timeline_SRCS:=$(sort $(Timeline_SRCS)) | ||||
@@ -0,0 +1,118 @@ | |||||
/*******************************************************************************/ | |||||
/* Copyright (C) 2008 Jonathan Moore Liles */ | |||||
/* */ | |||||
/* This program is free software; you can redistribute it and/or modify it */ | |||||
/* under the terms of the GNU General Public License as published by the */ | |||||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||||
/* option) any later version. */ | |||||
/* */ | |||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||||
/* more details. */ | |||||
/* */ | |||||
/* You should have received a copy of the GNU General Public License along */ | |||||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||||
/*******************************************************************************/ | |||||
#include "Thread.H" | |||||
#include <assert.h> | |||||
#include <string.h> | |||||
pthread_key_t Thread::_current = 0; | |||||
Thread::Thread ( ) | |||||
{ | |||||
_thread = 0; | |||||
_name = 0; | |||||
} | |||||
Thread::Thread ( const char *name ) | |||||
{ | |||||
_thread = 0; | |||||
_name = name; | |||||
} | |||||
void | |||||
Thread::init ( void ) | |||||
{ | |||||
pthread_key_create( &_current, NULL ); | |||||
} | |||||
bool | |||||
Thread::is ( const char *name ) | |||||
{ | |||||
return ! strcmp( Thread::current()->name(), name ); | |||||
} | |||||
/** to be used by existing threads (that won't call clone()) */ | |||||
void | |||||
Thread::set ( const char *name ) | |||||
{ | |||||
_thread = pthread_self(); | |||||
_name = name; | |||||
pthread_setspecific( _current, (void*)this ); | |||||
} | |||||
Thread * | |||||
Thread::current ( void ) | |||||
{ | |||||
return (Thread*)pthread_getspecific( _current ); | |||||
} | |||||
struct thread_data | |||||
{ | |||||
void *(*entry_point)(void *); | |||||
void *arg; | |||||
void *t; | |||||
}; | |||||
void * | |||||
Thread::run_thread ( void *arg ) | |||||
{ | |||||
thread_data td = *(thread_data *)arg; | |||||
delete (thread_data*)arg; | |||||
pthread_setspecific( _current, td.t ); | |||||
return td.entry_point( td.arg ); | |||||
} | |||||
bool | |||||
Thread::clone ( void *(*entry_point)(void *), void *arg ) | |||||
{ | |||||
assert( ! _thread ); | |||||
thread_data *td = new thread_data; | |||||
td->entry_point = entry_point; | |||||
td->arg = arg; | |||||
td->t = this; | |||||
if ( pthread_create( &_thread, NULL, run_thread, td ) != 0 ) | |||||
return false; | |||||
return true; | |||||
} | |||||
void | |||||
Thread::detach ( void ) | |||||
{ | |||||
pthread_detach( _thread ); | |||||
_thread = 0; | |||||
} | |||||
void | |||||
Thread::join ( void ) | |||||
{ | |||||
pthread_join( _thread, NULL ); | |||||
_thread = 0; | |||||
} |
@@ -0,0 +1,58 @@ | |||||
/*******************************************************************************/ | |||||
/* Copyright (C) 2008 Jonathan Moore Liles */ | |||||
/* */ | |||||
/* This program is free software; you can redistribute it and/or modify it */ | |||||
/* under the terms of the GNU General Public License as published by the */ | |||||
/* Free Software Foundation; either version 2 of the License, or (at your */ | |||||
/* option) any later version. */ | |||||
/* */ | |||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */ | |||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ | |||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ | |||||
/* more details. */ | |||||
/* */ | |||||
/* You should have received a copy of the GNU General Public License along */ | |||||
/* with This program; see the file COPYING. If not,write to the Free Software */ | |||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||||
/*******************************************************************************/ | |||||
#pragma once | |||||
/* simple wrapper for pthreads with thread role checking */ | |||||
#include <pthread.h> | |||||
#include "debug.h" | |||||
#define THREAD_ASSERT( n ) ASSERT( Thread::is( #n ), "Function called from wrong thread! (is %s, should be %s)", Thread::current()->name(), #n ) | |||||
class Thread | |||||
{ | |||||
static pthread_key_t _current; | |||||
pthread_t _thread; | |||||
const char * _name; | |||||
static void * run_thread ( void *arg ); | |||||
public: | |||||
static bool is ( const char *name ); | |||||
static void init ( void ); | |||||
static Thread *current ( void ); | |||||
Thread ( ); | |||||
Thread ( const char *name ); | |||||
const char *name ( void ) const { return _name; } | |||||
void name ( const char *name ) { _name = name; } | |||||
bool running ( void ) const { return _thread; } | |||||
void set ( const char *name ); | |||||
void set ( void ) { set( _name ); } | |||||
bool clone ( void *(*entry_point)(void *), void *arg ); | |||||
void detach ( void ); | |||||
void join ( void ); | |||||
}; |