diff --git a/Makefile b/Makefile index a62df60..c4f539c 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,10 @@ TAGS: $(SRCS) etags $(SRCS) .deps: .config $(SRCS) +ifneq ($(CALCULATING),yes) @ echo -n Calculating dependencies... - @ makedepend -f- -- $(CXXFLAGS) $(INCLUDES) -- $(SRCS) > .deps 2>/dev/null && echo $(DONE) + @ makedepend -f- -- $(CXXFLAGS) $(INCLUDES) -- $(SRCS) 2>/dev/null > .deps && echo $(DONE) +endif clean_deps: @ rm -f .deps diff --git a/Timeline/Audio_Region.C b/Timeline/Audio_Region.C index 17ab6bf..81b6cca 100644 --- a/Timeline/Audio_Region.C +++ b/Timeline/Audio_Region.C @@ -57,6 +57,7 @@ static Fl_Color fl_invert_color ( Fl_Color c ) return fl_rgb_color( 255 - r, 255 - g, 255 - b ); } + void Audio_Region::get ( Log_Entry &e ) const @@ -154,7 +155,6 @@ Audio_Region::Audio_Region ( Audio_File *c ) log_create(); } - /* used when DND importing */ Audio_Region::Audio_Region ( Audio_File *c, Sequence *t, nframes_t o ) { @@ -189,12 +189,13 @@ Audio_Region::Audio_Region ( Audio_File *c, Sequence *t, nframes_t o ) log_create(); } -const char * -Audio_Region::source_name ( void ) const +Audio_Region::~Audio_Region ( ) { - return _clip->name(); + log_destroy(); } + + void Audio_Region::menu_cb ( Fl_Widget *w, void *v ) { @@ -309,123 +310,6 @@ Audio_Region::menu ( void ) return m; } -int -Audio_Region::handle ( int m ) -{ - static int ox, oy; - - static bool copied = false; - static nframes_t os; - - int X = Fl::event_x(); - int Y = Fl::event_y(); - - Logger _log( this ); - - switch ( m ) - { - case FL_FOCUS: - case FL_UNFOCUS: - return 1; - case FL_KEYBOARD: - return menu().test_shortcut() != 0; - case FL_ENTER: - return Sequence_Region::handle( m ); - case FL_LEAVE: - return Sequence_Region::handle( m ); - case FL_PUSH: - { - /* splitting */ - if ( test_press( FL_BUTTON2 | FL_SHIFT ) ) - { - /* split */ - if ( ! copied ) - { - Loggable::block_start(); - - Audio_Region *copy = new Audio_Region( *this ); - - trim( RIGHT, X ); - copy->trim( LEFT, X ); - - sequence()->add( copy ); - - log_end(); - - Loggable::block_end(); - } - - return 0; - } - else - { - ox = x() - X; - oy = y() - Y; - /* for panning */ - os = _r->offset; - - if ( test_press( FL_BUTTON2 | FL_CTRL ) ) - { - normalize(); - /* FIXME: wrong place for this? */ - sequence()->handle_widget_change( start(), length() ); - redraw(); - return 1; - } - else if ( test_press( FL_BUTTON3 ) ) - { - /* context menu */ - menu_popup( &menu() ); - - return 1; - } - else - return Sequence_Region::handle( m ); - } - - break; - } - case FL_RELEASE: - { - Sequence_Region::handle( m ); - - copied = false; - - return 1; - } - case FL_DRAG: - if ( ! _drag ) - { - begin_drag( Drag( x() - X, y() - Y, x_to_offset( X ) ) ); - _log.hold(); - } - - if ( test_press( FL_BUTTON1 | FL_SHIFT | FL_CTRL ) ) - { - /* panning */ - int d = (ox + X) - x(); - long td = timeline->x_to_ts( d ); - - if ( td > 0 && os < (nframes_t)td ) - _r->offset = 0; - else - _r->offset = os - td; - - redraw(); - return 1; - } - - return Sequence_Region::handle( m ); - - default: - return Sequence_Region::handle( m ); - break; - } - - return 0; -} - - /** Draws the curve for a single fade. /X/ and /W/ repersent the portion of the region covered by this draw, which may or may not cover the fade in question. */ @@ -705,7 +589,137 @@ Audio_Region::draw ( void ) } +int +Audio_Region::handle ( int m ) +{ + static int ox, oy; + static bool copied = false; + static nframes_t os; + + int X = Fl::event_x(); + int Y = Fl::event_y(); + + Logger _log( this ); + + switch ( m ) + { + case FL_FOCUS: + case FL_UNFOCUS: + return 1; + case FL_KEYBOARD: + return menu().test_shortcut() != 0; + case FL_ENTER: + return Sequence_Region::handle( m ); + case FL_LEAVE: + return Sequence_Region::handle( m ); + case FL_PUSH: + { + /* splitting */ + if ( test_press( FL_BUTTON2 | FL_SHIFT ) ) + { + /* split */ + if ( ! copied ) + { + Loggable::block_start(); + + Audio_Region *copy = new Audio_Region( *this ); + + trim( RIGHT, X ); + copy->trim( LEFT, X ); + + sequence()->add( copy ); + + log_end(); + + Loggable::block_end(); + } + + return 0; + } + else + { + ox = x() - X; + oy = y() - Y; + /* for panning */ + os = _r->offset; + + if ( test_press( FL_BUTTON2 | FL_CTRL ) ) + { + normalize(); + /* FIXME: wrong place for this? */ + sequence()->handle_widget_change( start(), length() ); + redraw(); + return 1; + } + else if ( test_press( FL_BUTTON3 ) ) + { + /* context menu */ + menu_popup( &menu() ); + + return 1; + } + else + return Sequence_Region::handle( m ); + } + + break; + } + case FL_RELEASE: + { + Sequence_Region::handle( m ); + + copied = false; + + return 1; + } + case FL_DRAG: + if ( ! _drag ) + { + begin_drag( Drag( x() - X, y() - Y, x_to_offset( X ) ) ); + _log.hold(); + } + + if ( test_press( FL_BUTTON1 | FL_SHIFT | FL_CTRL ) ) + { + /* panning */ + int d = (ox + X) - x(); + long td = timeline->x_to_ts( d ); + + if ( td > 0 && os < (nframes_t)td ) + _r->offset = 0; + else + _r->offset = os - td; + + redraw(); + return 1; + } + + return Sequence_Region::handle( m ); + + default: + return Sequence_Region::handle( m ); + break; + } + + return 0; +} + + + +/**********/ +/* Public */ +/**********/ + +/** return the name of the audio source this region represents */ +const char * +Audio_Region::source_name ( void ) const +{ + return _clip->name(); +} + +/** set the amplitude scaling for this region from the normalization + * factor for the range of samples represented by this region */ void Audio_Region::normalize ( void ) { diff --git a/Timeline/Audio_Region.H b/Timeline/Audio_Region.H index c9d4acc..8f5390d 100644 --- a/Timeline/Audio_Region.H +++ b/Timeline/Audio_Region.H @@ -111,13 +111,24 @@ private: static void menu_cb ( Fl_Widget *w, void *v ); void menu_cb ( const Fl_Menu_ *m ); + void draw_fade ( const Fade &fade, Fade::fade_dir_e dir, bool filled, int X, int W ); + protected: virtual void get ( Log_Entry &e ) const; virtual void set ( Log_Entry &e ); + int handle ( int m ); + void draw_box( void ); + void draw ( void ); + void resize ( void ); + public: + LOG_CREATE_FUNC( Audio_Region ); + + SEQUENCE_WIDGET_CLONE_FUNC( Audio_Region ); + static Fl_Boxtype _box; static Fl_Color _selection_color; Fl_Color selection_color ( void ) const { return _selection_color; } @@ -132,37 +143,18 @@ public: bool current ( void ) const { return this == belowmouse(); } -public: - const char * source_name ( void ) const; - LOG_CREATE_FUNC( Audio_Region ); - - SEQUENCE_WIDGET_CLONE_FUNC( Audio_Region ); - - ~Audio_Region ( ) - { - log_destroy(); - } - - Fl_Boxtype box ( void ) const { return Audio_Region::_box; } - Fl_Align align ( void ) const { return (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_BOTTOM /*| FL_ALIGN_CLIP*/ | FL_ALIGN_INSIDE); } - Audio_Region ( const Audio_Region & rhs ); Audio_Region ( Audio_File *c ); Audio_Region ( Audio_File *c, Sequence *t, nframes_t o ); + ~Audio_Region ( ); - void draw_fade ( const Fade &fade, Fade::fade_dir_e dir, bool filled, int X, int W ); - - - int handle ( int m ); - void draw_box( void ); - void draw ( void ); - void resize ( void ); + Fl_Boxtype box ( void ) const { return Audio_Region::_box; } + Fl_Align align ( void ) const { return (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_BOTTOM /*| FL_ALIGN_CLIP*/ | FL_ALIGN_INSIDE); } void normalize ( void ); - /* Engine */ nframes_t read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const; nframes_t write ( nframes_t nframes ); diff --git a/Timeline/Audio_Sequence.C b/Timeline/Audio_Sequence.C index 378c594..eecda1b 100644 --- a/Timeline/Audio_Sequence.C +++ b/Timeline/Audio_Sequence.C @@ -61,7 +61,9 @@ Audio_Sequence::~Audio_Sequence ( ) Loggable::block_end(); } + +/** return a pointer to the current capture region for this sequence */ const Audio_Region * Audio_Sequence::capture_region ( void ) const { @@ -129,7 +131,6 @@ deurlify ( char *url ) *w = NULL; } - void Audio_Sequence::handle_widget_change ( nframes_t start, nframes_t length ) { diff --git a/Timeline/Audio_Sequence.H b/Timeline/Audio_Sequence.H index ff11f3c..410ee9a 100644 --- a/Timeline/Audio_Sequence.H +++ b/Timeline/Audio_Sequence.H @@ -41,16 +41,17 @@ protected: void handle_widget_change ( nframes_t start, nframes_t length ); + void draw ( void ); + int handle ( int m ); + public: LOG_CREATE_FUNC( Audio_Sequence ); - Fl_Cursor cursor ( void ) const { return FL_CURSOR_DEFAULT; } - - Audio_Sequence ( Track *track ); ~Audio_Sequence ( ); + Fl_Cursor cursor ( void ) const { return FL_CURSOR_DEFAULT; } Sequence * clone_empty ( void ) { @@ -59,13 +60,6 @@ public: return t; } -// const char *class_name ( void ) { return "Audio_Sequence"; } - - void draw ( void ); - int handle ( int m ); - void dump ( void ); - void remove_selected ( void ); - const Audio_Region *capture_region ( void ) const; nframes_t play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ); diff --git a/Timeline/Control_Sequence.H b/Timeline/Control_Sequence.H index 53e10c1..52786cc 100644 --- a/Timeline/Control_Sequence.H +++ b/Timeline/Control_Sequence.H @@ -28,7 +28,6 @@ class Control_Sequence : public Sequence { - /* not permitted */ Control_Sequence ( const Control_Sequence &rhs ); Control_Sequence & operator = ( const Control_Sequence &rhs ); @@ -47,6 +46,7 @@ private: void init ( void ); + void draw_curve ( bool flip, bool filled ); protected: @@ -59,9 +59,9 @@ protected: init(); } -private: - void draw_curve ( bool flip, bool filled ); + void draw ( void ); + int handle ( int m ); public: @@ -76,12 +76,6 @@ public: Fl_Cursor cursor ( void ) const { return FL_CURSOR_CROSS; } -// const char *class_name ( void ) { return "Control_Sequence"; } - - void draw ( void ); - int handle ( int m ); - - /* Engine */ void output ( Port *p ) { _output = p; } nframes_t play ( sample_t *buf, nframes_t frame, nframes_t nframes ); diff --git a/Timeline/Engine/Disk_Stream.C b/Timeline/Engine/Disk_Stream.C index f84f688..8823a16 100644 --- a/Timeline/Engine/Disk_Stream.C +++ b/Timeline/Engine/Disk_Stream.C @@ -17,7 +17,6 @@ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ - #include "../Track.H" // #include "Audio_Sequence.H" class Audio_Sequence; @@ -28,6 +27,8 @@ class Audio_Sequence; #include "Disk_Stream.H" #include "dsp.h" + + /**********/ /* Engine */ /**********/ @@ -40,12 +41,6 @@ class Audio_Sequence; that is, at startup time. The default is 5 seconds, which may or may not be excessive depending on various external factors. */ -/* FIXME: deal with (jack) buffer size changes */ -/* FIXME: needs error handling everywhere! */ -/* TODO: read/write data from/to disk in larger chunks to avoid - * excessive seeking. 256k is supposedly the sweetspot. */ - -//float Disk_Stream::seconds_to_buffer = 5.0f; float Disk_Stream::seconds_to_buffer = 2.0f; /* this is really only a rough estimate. The actual amount of data read depends on many factors. Overlapping regions, for example, will @@ -53,6 +48,8 @@ float Disk_Stream::seconds_to_buffer = 2.0f; counts.*/ size_t Disk_Stream::disk_io_kbytes = 256; + + Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, int channels ) : _track( track ) { assert( channels ); @@ -85,6 +82,7 @@ Disk_Stream::~Disk_Stream ( ) engine->unlock(); } + /** flush buffers and reset. Must only be called from the RT thread. */ void diff --git a/Timeline/Engine/Engine.C b/Timeline/Engine/Engine.C index ae2149c..9567a37 100644 --- a/Timeline/Engine/Engine.C +++ b/Timeline/Engine/Engine.C @@ -30,6 +30,8 @@ #include "util/Thread.H" + + Engine::Engine ( ) : _thread( "RT" ) { _freewheeling = false; @@ -39,6 +41,8 @@ Engine::Engine ( ) : _thread( "RT" ) _xruns = 0; } + + /*******************/ /* Static Wrappers */ /*******************/ @@ -79,15 +83,24 @@ Engine::buffer_size ( nframes_t nframes, void *arg ) return ((Engine*)arg)->buffer_size( nframes ); } - +void +Engine::thread_init ( void *arg ) +{ + ((Engine*)arg)->thread_init(); +} void -Engine::request_locate ( nframes_t frame ) +Engine::shutdown ( void *arg ) { - if ( timeline ) - timeline->seek( frame ); + ((Engine*)arg)->shutdown(); } + + +/*************/ +/* Callbacks */ +/*************/ + /* THREAD: RT */ /** This is the jack xrun callback */ int @@ -114,7 +127,6 @@ Engine::freewheel ( bool starting ) int Engine::buffer_size ( nframes_t nframes ) { - /* TODO: inform all disktreams the the buffer size has changed */ timeline->resize_buffers( nframes ); return 0; @@ -166,7 +178,6 @@ Engine::sync ( jack_transport_state_t state, jack_position_t *pos ) return 0; } - /* THREAD: RT */ void Engine::timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *pos, int ) @@ -189,7 +200,6 @@ Engine::timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *pos, } - /* THREAD: RT */ int Engine::process ( nframes_t nframes ) @@ -235,7 +245,7 @@ Engine::process ( nframes_t nframes ) return 0; } - +/* THREAD: RT */ /** enter or leave freehweeling mode */ void Engine::freewheeling ( bool yes ) @@ -244,31 +254,22 @@ Engine::freewheeling ( bool yes ) WARNING( "Unkown error while setting freewheeling mode" ); } -void -Engine::thread_init ( void *arg ) -{ - ((Engine*)arg)->thread_init(); -} - +/* TRHEAD: RT */ void Engine::thread_init ( void ) { _thread.set( "RT" ); } - -void -Engine::shutdown ( void *arg ) -{ - ((Engine*)arg)->shutdown(); -} - +/* THREAD: RT */ void Engine::shutdown ( void ) { _zombified = true; } + +/** Connect to JACK */ int Engine::init ( void ) { @@ -300,3 +301,10 @@ Engine::init ( void ) /* we don't need to create any ports until tracks are created */ return 1; } + +void +Engine::request_locate ( nframes_t frame ) +{ + if ( timeline ) + timeline->seek( frame ); +} diff --git a/Timeline/Engine/Engine.H b/Timeline/Engine/Engine.H index 1bfae37..aba86a2 100644 --- a/Timeline/Engine/Engine.H +++ b/Timeline/Engine/Engine.H @@ -35,23 +35,12 @@ class Engine : public Mutex Thread _thread; /* only used for thread checking */ - - /* I know locking out the process callback is cheating, even - though we use trylock... The thing is, every other DAW does - this too and you can hear it in the glitches Ardour and friends - produce when reconfiguring I/O... Working out a message queue - system would obviously be better, but a DAW isn't a performance - instrument anyway, so I think these drop-outs are a reasonable - compromise. Obviously, this lock should never be held during - blocking operations. */ - int _buffers_dropped; /* buffers dropped because of locking */ nframes_t _sample_rate; volatile int _xruns; volatile bool _freewheeling; volatile bool _zombified; - static void shutdown ( void *arg ); void shutdown ( void ); static int process ( nframes_t nframes, void *arg ); @@ -72,6 +61,8 @@ class Engine : public Mutex Engine ( const Engine &rhs ); Engine & operator = ( const Engine &rhs ); + void request_locate ( nframes_t frame ); + private: friend class Port; @@ -85,8 +76,6 @@ public: int init ( void ); - void request_locate ( nframes_t frame ); - nframes_t nframes ( void ) const { return jack_get_buffer_size( _client ); } float frame_rate ( void ) const { return jack_get_sample_rate( _client ); } nframes_t sample_rate ( void ) const { return _sample_rate; } diff --git a/Timeline/Engine/Peaks.C b/Timeline/Engine/Peaks.C index 9afce47..b244207 100644 --- a/Timeline/Engine/Peaks.C +++ b/Timeline/Engine/Peaks.C @@ -22,6 +22,8 @@ peakfile reading/writing. */ +/* Code for peakfile reading, resampling, generation and streaming */ + #include #include #include @@ -39,6 +41,7 @@ #include "assert.h" #include "util/debug.h" #include "util/Thread.H" +#include "util/file.h" #include @@ -47,6 +50,7 @@ using std::min; using std::max; + /* whether to cache peaks at multiple resolutions on disk to * drastically improve performance */ @@ -56,7 +60,6 @@ const int Peaks::cache_minimum = 256; /* minimum chunksize to build pea const int Peaks::cache_levels = 8; /* number of sampling levels in peak cache */ const int Peaks::cache_step = 1; /* powers of two between each level. 4 == 256, 2048, 16384, ... */ - Peaks::peakbuffer Peaks::_peakbuf; @@ -72,17 +75,6 @@ peakname ( const char *filename ) return (const char*)&file; } -/** update the modification time of file referred to by /fd/ */ -static void -touch ( int fd ) -{ - struct stat st; - - fstat( fd, &st ); - - fchmod( fd, st.st_mode ); -} - Peaks::Peaks ( Audio_File *c ) @@ -97,6 +89,8 @@ Peaks::~Peaks ( ) delete _peak_writer; } + + /** Prepare a buffer of peaks from /s/ to /e/ for reading. Must be * called before any calls to operator[] */ int @@ -389,7 +383,6 @@ Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, nframes_t chu return _peakfile.read_peaks( peaks, s, npeaks, chunksize ); } - int Peaks::read_source_peaks ( Peak *peaks, int npeaks, nframes_t chunksize ) const { @@ -472,27 +465,9 @@ Peaks::read_peaks ( nframes_t s, int npeaks, nframes_t chunksize ) const bool Peaks::current ( void ) const { - int sfd, pfd; - - if ( ( sfd = ::open( _clip->name(), O_RDONLY ) ) < 0 ) - return true; - - if ( ( pfd = ::open( peakname( _clip->name() ), O_RDONLY ) ) < 0 ) - return false; - - struct stat sst, pst; - - fstat( sfd, &sst ); - fstat( pfd, &pst ); - - close( sfd ); - close( pfd ); - - return sst.st_mtime <= pst.st_mtime; + return ! newer( _clip->name(), peakname( _clip->name() ) ); } - - bool Peaks::make_peaks ( void ) const { @@ -817,7 +792,6 @@ Peaks::Builder::make_peaks ( void ) return true; } - Peaks::Builder::Builder ( const Peaks *peaks ) : _peaks( peaks ) { fp = NULL; diff --git a/Timeline/Engine/Port.C b/Timeline/Engine/Port.C index 1111ac3..fe85f59 100644 --- a/Timeline/Engine/Port.C +++ b/Timeline/Engine/Port.C @@ -17,6 +17,8 @@ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ +/* Wrapper for a JACK audio port */ + #include "Port.H" #include @@ -25,6 +27,8 @@ #include // sprintf +static const char *name_for_port ( Port::type_e dir, const char *base, int n, const char *type ); + /* nframes is the number of frames to buffer */ @@ -39,6 +43,22 @@ Port::Port ( const char *name, type_e dir ) activate( name, dir ); } +Port::Port ( type_e dir, const char *base, int n, const char *type ) +{ + const char *name = name_for_port( dir, base, n, type ); + + activate( name, dir ); +} + +Port::~Port ( ) +{ +/* if ( _port ) */ +/* jack_port_unregister( engine->client(), _port ); */ + +} + + + static const char * name_for_port ( Port::type_e dir, const char *base, int n, const char *type ) { @@ -54,27 +74,6 @@ name_for_port ( Port::type_e dir, const char *base, int n, const char *type ) return pname; } -Port::Port ( type_e dir, const char *base, int n, const char *type ) -{ - const char *name = name_for_port( dir, base, n, type ); - - activate( name, dir ); -} - -/* Port::Port ( ) */ -/* { */ -/* _name = NULL; */ -/* _port = NULL; */ -/* } */ - -Port::~Port ( ) -{ - -/* if ( _port ) */ -/* jack_port_unregister( engine->client(), _port ); */ - -} - void Port::activate ( const char *name, type_e dir ) { diff --git a/Timeline/Engine/Track.C b/Timeline/Engine/Track.C index 32f6482..bf3e0d0 100644 --- a/Timeline/Engine/Track.C +++ b/Timeline/Engine/Track.C @@ -25,6 +25,8 @@ #include "Record_DS.H" #include "Engine.H" + + /**********/ /* Engine */ /**********/ @@ -195,9 +197,6 @@ Track::resize_buffers ( nframes_t nframes ) playback_ds->resize_buffers( nframes ); } -/* #include "Audio_Region.H" */ - - #include /** very cheap UUID generator... */ diff --git a/Timeline/Loggable.C b/Timeline/Loggable.C index 3ddb607..1a867ac 100644 --- a/Timeline/Loggable.C +++ b/Timeline/Loggable.C @@ -305,44 +305,6 @@ Loggable::do_this ( const char *s, bool reverse ) return true; } - -static int -backwards_fgetc ( FILE *fp ) -{ - int c; - - if ( fseek( fp, -1, SEEK_CUR ) != 0 ) - return -1; - - c = fgetc( fp ); - - fseek( fp, -1, SEEK_CUR ); - - return c; -} - -static char * -backwards_fgets ( char *s, int size, FILE *fp ) -{ - if ( fseek( fp, -1, SEEK_CUR ) != 0 ) - return NULL; - - int c; - while ( ( c = backwards_fgetc( fp ) ) >= 0 ) - if ( '\n' == c ) - break; - - long here = ftell( fp ); - - fseek( fp, 1, SEEK_CUR ); - - char *r = fgets( s, size, fp ); - - fseek( fp, here, SEEK_SET ); - - return r; -} - /** Reverse the last journal transaction */ void Loggable::undo ( void ) @@ -386,6 +348,9 @@ Loggable::undo ( void ) _undo_offset = uo; } +/** Make all loggable ids consecutive. This invalidates any existing + * journal or snapshot, so you *must* write out a new one after + * performing this operation*/ void Loggable::compact_ids ( void ) { @@ -406,9 +371,8 @@ Loggable::compact_ids ( void ) _log_id = id; } -/* FIXME: we need a version of this that is fully const, right? */ -/** write a snapshot of the state of all loggable objects, sufficient - * for later reconstruction, to /fp/ */ +/** write a snapshot of the current state of all loggable objects to + * file handle /fp/ */ bool Loggable::snapshot ( FILE *fp ) { @@ -437,6 +401,8 @@ Loggable::snapshot ( FILE *fp ) return true; } +/** write a snapshot of the current state of all loggable objects to + * file /name/ */ bool Loggable::snapshot ( const char *name ) { @@ -575,7 +541,6 @@ Loggable::log_print( const Log_Entry *o, const Log_Entry *n ) const log( "\n" ); } - /** Remember current object state for later comparison. *Must* be * called before any user action that might change one of the object's * journaled properties. */ diff --git a/Timeline/Project.C b/Timeline/Project.C index d874266..59fe67e 100644 --- a/Timeline/Project.C +++ b/Timeline/Project.C @@ -56,6 +56,10 @@ int Project::_lockfd = 0; +/***********/ +/* Private */ +/***********/ + void Project::set_name ( const char *name ) { @@ -75,27 +79,6 @@ Project::set_name ( const char *name ) *s = ' '; } -bool -Project::close ( void ) -{ - if ( ! open() ) - return true; - - tle->save_timeline_settings(); - - Loggable::close(); - - write_info(); - - _is_open = false; - - *Project::_name = '\0'; - - release_lock( &_lockfd, ".lock" ); - - return true; -} - bool Project::write_info ( void ) { @@ -139,7 +122,33 @@ Project::read_info ( void ) return true; } -/** ensure a project is valid before opening it... */ +/**********/ +/* Public */ +/**********/ + +/** Close the project (reclaiming all memory) */ +bool +Project::close ( void ) +{ + if ( ! open() ) + return true; + + tle->save_timeline_settings(); + + Loggable::close(); + + write_info(); + + _is_open = false; + + *Project::_name = '\0'; + + release_lock( &_lockfd, ".lock" ); + + return true; +} + +/** Ensure a project is valid before opening it... */ bool Project::validate ( const char *name ) { @@ -169,7 +178,8 @@ Project::validate ( const char *name ) return r; } -/** try to open project /name/. Returns 0 if sucsessful, an error code otherwise */ +/** Try to open project /name/. Returns 0 if sucsessful, an error code + * otherwise */ int Project::open ( const char *name ) { @@ -207,6 +217,8 @@ Project::open ( const char *name ) return 0; } +/** Create a new project /name/ from existing template + * /template_name/ */ bool Project::create ( const char *name, const char *template_name ) { @@ -251,3 +263,10 @@ Project::create ( const char *name, const char *template_name ) return false; } } + +/** Replace the journal with a snapshot of the current state */ +void +Project::compact ( void ) +{ + Loggable::compact(); +} diff --git a/Timeline/Project.H b/Timeline/Project.H index 2c9f2a4..6d81fc2 100644 --- a/Timeline/Project.H +++ b/Timeline/Project.H @@ -28,6 +28,10 @@ class Project static char _name[256]; static char _path[512]; + static bool write_info ( void ); + static bool read_info ( void ); + static void set_name ( const char *name ); + public: enum @@ -37,10 +41,8 @@ public: E_PERM = -3, }; - static bool write_info ( void ); - static bool read_info ( void ); static const char *name ( void ) { return Project::_name; } - static void set_name ( const char *name ); + static void compact ( void ); static bool close ( void ); static bool validate ( const char *name ); static int open ( const char *name ); diff --git a/Timeline/Sequence.C b/Timeline/Sequence.C index fd2edc9..ffc0884 100644 --- a/Timeline/Sequence.C +++ b/Timeline/Sequence.C @@ -17,7 +17,6 @@ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ - #include "Sequence.H" #include "Timeline.H" @@ -25,12 +24,20 @@ #include "Track.H" +#include "FL/event_name.H" + +#include "Transport.H" // for locate() + #include "../FL/Boxtypes.H" using namespace std; + + queue Sequence::_delete_queue; + + Sequence::Sequence ( Track *track ) : Fl_Widget( 0, 0, 0, 0 ), Loggable( true ) { init(); @@ -59,22 +66,6 @@ Sequence::init ( void ) // clear_visible_focus(); } -void -Sequence::clear ( void ) -{ - for ( std::list ::iterator i = _widgets.begin(); - i != _widgets.end(); ++i ) - { - Sequence_Widget *w = *i; - - *i = NULL; - - delete w; - } - - _widgets.clear(); -} - Sequence::~Sequence ( ) { DMESSAGE( "destroying sequence" ); @@ -86,12 +77,37 @@ Sequence::~Sequence ( ) FATAL( "programming error: leaf destructor must call Sequence::clear()!" ); } + + +/** remove all widgets from this sequence */ +void +Sequence::clear ( void ) +{ + Loggable::block_start(); + + for ( std::list ::iterator i = _widgets.begin(); + i != _widgets.end(); ++i ) + { + Sequence_Widget *w = *i; + + *i = NULL; + + delete w; + } + + _widgets.clear(); + + Loggable::block_end(); +} + +/** given screen pixel coordinate X, return an absolute frame offset into this sequence */ nframes_t Sequence::x_to_offset ( int X ) { return timeline->xoffset + timeline->x_to_ts( X - x() ); } +/** sort the widgets in this sequence by position */ void Sequence::sort ( void ) { @@ -112,95 +128,12 @@ Sequence::overlaps ( Sequence_Widget *r ) return NULL; } -void -Sequence::draw ( void ) -{ - - if ( ! fl_not_clipped( x(), y(), w(), h() ) ) - return; - - fl_push_clip( x(), y(), w(), h() ); - - /* draw the box with the ends cut off. */ - draw_box( box(), x() - Fl::box_dx( box() ) - 1, y(), w() + Fl::box_dw( box() ) + 2, h(), color() ); - - int X, Y, W, H; - - fl_clip_box( x(), y(), w(), h(), X, Y, W, H ); - -/* if ( Sequence_Widget::pushed() && Sequence_Widget::pushed()->sequence() == this ) */ -/* { */ -/* /\* make sure the Sequence_Widget::pushed widget is above all others *\/ */ -/* remove( Sequence_Widget::pushed() ); */ -/* add( Sequence_Widget::pushed() ); */ -/* } */ - -// printf( "track::draw %d,%d %dx%d\n", X,Y,W,H ); - - timeline->draw_measure_lines( X, Y, W, H, color() ); - - for ( list ::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) - (*r)->draw_box(); - - - for ( list ::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) - (*r)->draw(); - - fl_pop_clip(); - -} - -void -Sequence::remove ( Sequence_Widget *r ) -{ - timeline->wrlock(); - - _widgets.remove( r ); - - timeline->unlock(); - - handle_widget_change( r->start(), r->length() ); -} - - -void -Sequence::remove_selected ( void ) -{ - Loggable::block_start(); - - for ( list ::iterator r = _widgets.begin(); r != _widgets.end(); ) - if ( (*r)->selected() ) - { - Sequence_Widget *t = *r; - _widgets.erase( r++ ); - delete t; - } - else - ++r; - - Loggable::block_end(); -} - - void Sequence::handle_widget_change ( nframes_t start, nframes_t length ) { // timeline->update_length( start + length ); } -/** calculate the length of this sequence by looking at the end of the - * least widget it contains */ -nframes_t -Sequence::length ( void ) const -{ - nframes_t l = 0; - - for ( list ::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) - l = max( l, (*r)->start() + (*r)->length() ); - - return l; -} - Sequence_Widget * Sequence::widget_at ( nframes_t ts, int Y ) { @@ -212,6 +145,8 @@ Sequence::widget_at ( nframes_t ts, int Y ) return NULL; } +/** return a pointer to the widget under the current mouse event, or + * NULL if no widget intersects the event coordinates */ Sequence_Widget * Sequence::event_widget ( void ) { @@ -219,17 +154,6 @@ Sequence::event_widget ( void ) return widget_at( ets, Fl::event_y() ); } -void -Sequence::select_range ( int X, int W ) -{ - nframes_t sts = x_to_offset( X ); - nframes_t ets = sts + timeline->x_to_ts( W ); - - for ( list ::const_reverse_iterator r = _widgets.rbegin(); r != _widgets.rend(); ++r ) - if ( ! ( (*r)->start() > ets || (*r)->start() + (*r)->length() < sts ) ) - (*r)->select(); -} - void Sequence::add ( Sequence_Widget *r ) { @@ -254,13 +178,25 @@ Sequence::add ( Sequence_Widget *r ) handle_widget_change( r->start(), r->length() ); } +void +Sequence::remove ( Sequence_Widget *r ) +{ + timeline->wrlock(); + + _widgets.remove( r ); + + timeline->unlock(); + + handle_widget_change( r->start(), r->length() ); +} + static nframes_t abs_diff ( nframes_t n1, nframes_t n2 ) { return n1 > n2 ? n1 - n2 : n2 - n1; } -/* snap /r/ to nearest edge */ +/** snap widget /r/ to nearest edge */ void Sequence::snap ( Sequence_Widget *r ) { @@ -306,38 +242,45 @@ Sequence::snap ( Sequence_Widget *r ) r->start( f ); } -/** return the location of the next widget from frame /from/ */ -nframes_t -Sequence::next ( nframes_t from ) const + +void +Sequence::draw ( void ) { - for ( list ::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ ) - if ( (*i)->start() > from ) - return (*i)->start(); - if ( _widgets.size() ) - return _widgets.back()->start(); - else - return 0; + if ( ! fl_not_clipped( x(), y(), w(), h() ) ) + return; + + fl_push_clip( x(), y(), w(), h() ); + + /* draw the box with the ends cut off. */ + draw_box( box(), x() - Fl::box_dx( box() ) - 1, y(), w() + Fl::box_dw( box() ) + 2, h(), color() ); + + int X, Y, W, H; + + fl_clip_box( x(), y(), w(), h(), X, Y, W, H ); + +/* if ( Sequence_Widget::pushed() && Sequence_Widget::pushed()->sequence() == this ) */ +/* { */ +/* /\* make sure the Sequence_Widget::pushed widget is above all others *\/ */ +/* remove( Sequence_Widget::pushed() ); */ +/* add( Sequence_Widget::pushed() ); */ +/* } */ + +// printf( "track::draw %d,%d %dx%d\n", X,Y,W,H ); + + timeline->draw_measure_lines( X, Y, W, H, color() ); + + for ( list ::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) + (*r)->draw_box(); + + + for ( list ::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) + (*r)->draw(); + + fl_pop_clip(); + } -/** return the location of the next widget from frame /from/ */ -nframes_t -Sequence::prev ( nframes_t from ) const -{ - for ( list ::const_reverse_iterator i = _widgets.rbegin(); i != _widgets.rend(); i++ ) - if ( (*i)->start() < from ) - return (*i)->start(); - - if ( _widgets.size() ) - return _widgets.front()->start(); - else - return 0; -} - -#include "FL/event_name.H" - -#include "Transport.H" // for locate() - int Sequence::handle ( int m ) { @@ -509,3 +452,85 @@ Sequence::handle ( int m ) } } } + + + +/**********/ +/* Public */ +/**********/ + +/** calculate the length of this sequence by looking at the end of the + * least widget it contains */ + +/** return the length in frames of this sequence calculated from the + * right edge of the rightmost widget */ +nframes_t +Sequence::length ( void ) const +{ + nframes_t l = 0; + + for ( list ::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) + l = max( l, (*r)->start() + (*r)->length() ); + + return l; +} + +/** return the location of the next widget from frame /from/ */ +nframes_t +Sequence::next ( nframes_t from ) const +{ + for ( list ::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ ) + if ( (*i)->start() > from ) + return (*i)->start(); + + if ( _widgets.size() ) + return _widgets.back()->start(); + else + return 0; +} + +/** return the location of the next widget from frame /from/ */ +nframes_t +Sequence::prev ( nframes_t from ) const +{ + for ( list ::const_reverse_iterator i = _widgets.rbegin(); i != _widgets.rend(); i++ ) + if ( (*i)->start() < from ) + return (*i)->start(); + + if ( _widgets.size() ) + return _widgets.front()->start(); + else + return 0; +} + +/** delete all selected widgets in this sequence */ +void +Sequence::remove_selected ( void ) +{ + Loggable::block_start(); + + for ( list ::iterator r = _widgets.begin(); r != _widgets.end(); ) + if ( (*r)->selected() ) + { + Sequence_Widget *t = *r; + _widgets.erase( r++ ); + delete t; + } + else + ++r; + + Loggable::block_end(); +} + +/** select all widgets intersecting with the range defined by the + * pixel coordinates X through W */ +void +Sequence::select_range ( int X, int W ) +{ + nframes_t sts = x_to_offset( X ); + nframes_t ets = sts + timeline->x_to_ts( W ); + + for ( list ::const_reverse_iterator r = _widgets.rbegin(); r != _widgets.rend(); ++r ) + if ( ! ( (*r)->start() > ets || (*r)->start() + (*r)->length() < sts ) ) + (*r)->select(); +} diff --git a/Timeline/Sequence_Point.C b/Timeline/Sequence_Point.C index dd3746a..272e40e 100644 --- a/Timeline/Sequence_Point.C +++ b/Timeline/Sequence_Point.C @@ -21,6 +21,29 @@ #include + + +Sequence_Point::Sequence_Point ( const Sequence_Point &rhs ) : Sequence_Widget( rhs ) +{ + if ( _label ) + _label = strdup( rhs._label ); +} + +Sequence_Point::Sequence_Point ( ) +{ + _label = NULL; + + color( FL_CYAN ); +} + +Sequence_Point::~Sequence_Point ( ) +{ + if ( _label ) + free( _label ); +} + + + void Sequence_Point::get ( Log_Entry &e ) const { diff --git a/Timeline/Sequence_Point.H b/Timeline/Sequence_Point.H index 16e9589..bd3b628 100644 --- a/Timeline/Sequence_Point.H +++ b/Timeline/Sequence_Point.H @@ -33,11 +33,13 @@ protected: void get ( Log_Entry &e ) const; void set ( Log_Entry &e ); - Sequence_Point ( const Sequence_Point &rhs ) : Sequence_Widget( rhs ) - { - if ( _label ) - _label = strdup( rhs._label ); - } + + virtual void draw_box ( void ); + virtual void draw ( void ); + + Sequence_Point ( const Sequence_Point &rhs ); + Sequence_Point ( ); + ~Sequence_Point ( ); public: @@ -68,21 +70,4 @@ public: nframes_t length ( void ) const { return timeline->x_to_ts( abs_w() ); } - Sequence_Point ( ) - { - _label = NULL; - - color( FL_CYAN ); - } - - - virtual ~Sequence_Point ( ) - { - if ( _label ) - free( _label ); - } - - virtual void draw_box ( void ); - virtual void draw ( void ); - }; diff --git a/Timeline/Sequence_Region.C b/Timeline/Sequence_Region.C index dc41353..5e7f86e 100644 --- a/Timeline/Sequence_Region.C +++ b/Timeline/Sequence_Region.C @@ -20,6 +20,23 @@ #include "Sequence_Region.H" #include "Track.H" + + +Sequence_Region::Sequence_Region ( ) +{ + color( FL_CYAN ); +} + +Sequence_Region::Sequence_Region ( const Sequence_Region &rhs ) : Sequence_Widget( rhs ) +{ +} + +Sequence_Region::~Sequence_Region ( ) +{ +} + + + void Sequence_Region::get ( Log_Entry &e ) const { @@ -29,7 +46,6 @@ Sequence_Region::get ( Log_Entry &e ) const Sequence_Widget::get( e ); } - void Sequence_Region::set ( Log_Entry &e ) { @@ -49,18 +65,6 @@ Sequence_Region::set ( Log_Entry &e ) Sequence_Widget::set( e ); } - -void -Sequence_Region::draw_box ( void ) -{ - fl_draw_box( box(), line_x(), y(), abs_w(), h(), box_color() ); -} - -void -Sequence_Region::draw ( void ) -{ -} - void Sequence_Region::trim ( enum trim_e t, int X ) { @@ -232,3 +236,14 @@ Sequence_Region::handle ( int m ) return 0; } + +void +Sequence_Region::draw_box ( void ) +{ + fl_draw_box( box(), line_x(), y(), abs_w(), h(), box_color() ); +} + +void +Sequence_Region::draw ( void ) +{ +} diff --git a/Timeline/Sequence_Region.H b/Timeline/Sequence_Region.H index d5a49ac..10d144a 100644 --- a/Timeline/Sequence_Region.H +++ b/Timeline/Sequence_Region.H @@ -33,20 +33,13 @@ protected: virtual void get ( Log_Entry &e ) const; virtual void set ( Log_Entry &e ); - Sequence_Region ( ) - { - color( FL_CYAN ); - } + Sequence_Region ( ); + Sequence_Region ( const Sequence_Region &rhs ); + virtual ~Sequence_Region ( ); - virtual ~Sequence_Region ( ) - { - - } - - Sequence_Region ( const Sequence_Region &rhs ) : Sequence_Widget( rhs ) - { - - } + virtual int handle ( int m ); + virtual void draw_box( void ); + virtual void draw ( void ); public: @@ -55,8 +48,4 @@ public: enum trim_e { NO, LEFT, RIGHT }; void trim ( enum trim_e t, int X ); - virtual int handle ( int m ); - virtual void draw_box( void ); - virtual void draw ( void ); - }; diff --git a/Timeline/Sequence_Widget.C b/Timeline/Sequence_Widget.C index 6d78fe8..0f11fa5 100644 --- a/Timeline/Sequence_Widget.C +++ b/Timeline/Sequence_Widget.C @@ -63,6 +63,8 @@ Sequence_Widget::~Sequence_Widget ( ) _selection.remove( this ); } + + void Sequence_Widget::get ( Log_Entry &e ) const { diff --git a/Timeline/TLE.fl b/Timeline/TLE.fl index c8dd412..27b2e44 100644 --- a/Timeline/TLE.fl +++ b/Timeline/TLE.fl @@ -230,7 +230,7 @@ if ( r < 0 ) if ( n != 2 ) return; -Loggable::compact();} +Project::compact();} selected xywh {20 20 40 25} } Submenu {} { @@ -868,7 +868,7 @@ while ( _window->shown() ) Function {make_window()} {open } { Fl_Window _window { - label {New Project} open selected + label {New Project} open xywh {615 414 550 195} type Double modal xclass Non_DAW visible } { Fl_File_Input _name { diff --git a/Timeline/Tempo_Point.C b/Timeline/Tempo_Point.C index 6581404..3a80fff 100644 --- a/Timeline/Tempo_Point.C +++ b/Timeline/Tempo_Point.C @@ -23,6 +23,32 @@ +Tempo_Point::Tempo_Point ( ) +{ + timeline->tempo_track->add( this ); +} + +Tempo_Point::Tempo_Point ( nframes_t when, float bpm ) +{ + _tempo = bpm; + + _make_label(); + + timeline->tempo_track->add( this ); + + start( when ); + + log_create(); +} + +Tempo_Point::~Tempo_Point ( ) +{ + timeline->tempo_track->remove( this ); + log_destroy(); +} + + + void Tempo_Point::get ( Log_Entry &e ) const { @@ -58,33 +84,6 @@ Tempo_Point::set ( Log_Entry &e ) } -Tempo_Point::Tempo_Point ( ) -{ - timeline->tempo_track->add( this ); -} - -Tempo_Point::Tempo_Point ( nframes_t when, float bpm ) -{ - _tempo = bpm; - - _make_label(); - - timeline->tempo_track->add( this ); - - start( when ); - - log_create(); -} - - - -Tempo_Point::~Tempo_Point ( ) -{ - timeline->tempo_track->remove( this ); - log_destroy(); -} - - int Tempo_Point::handle ( int m ) diff --git a/Timeline/Time_Point.C b/Timeline/Time_Point.C index 6ab475d..1dd243d 100644 --- a/Timeline/Time_Point.C +++ b/Timeline/Time_Point.C @@ -23,6 +23,39 @@ +Time_Point::Time_Point ( ) : _time( 4, 4 ) +{ + timeline->time_track->add( this ); +} + +Time_Point::Time_Point ( nframes_t when, int bpb, int note ) : _time( bpb, note ) +{ + _make_label(); + + timeline->time_track->add( this ); + + start( when ); + + log_create(); +} + +Time_Point::Time_Point ( const Time_Point &rhs ) : Sequence_Point( rhs ) +{ + _time = rhs._time; + + log_create(); + +} + +Time_Point::~Time_Point ( ) +{ + timeline->time_track->remove( this ); + + log_destroy(); +} + + + void Time_Point::get ( Log_Entry &e ) const { @@ -60,39 +93,6 @@ Time_Point::set ( Log_Entry &e ) _make_label(); } - -Time_Point::Time_Point ( ) : _time( 4, 4 ) -{ - timeline->time_track->add( this ); -} - -Time_Point::Time_Point ( nframes_t when, int bpb, int note ) : _time( bpb, note ) -{ - _make_label(); - - timeline->time_track->add( this ); - - start( when ); - - log_create(); -} - -Time_Point::Time_Point ( const Time_Point &rhs ) : Sequence_Point( rhs ) -{ - _time = rhs._time; - - log_create(); - -} - -Time_Point::~Time_Point ( ) -{ - timeline->time_track->remove( this ); - - log_destroy(); -} - - int Time_Point::handle ( int m ) { @@ -113,12 +113,9 @@ Time_Point::handle ( int m ) return Sequence_Point::handle( m ); } - - #include #include - class Time_Point_Editor : public Fl_Menu_Window { @@ -196,7 +193,6 @@ public: } }; - bool Time_Point::edit ( time_sig *sig ) { diff --git a/Timeline/Timeline.C b/Timeline/Timeline.C index a52a0dc..3999bb6 100644 --- a/Timeline/Timeline.C +++ b/Timeline/Timeline.C @@ -106,6 +106,7 @@ Timeline::adjust_vscroll ( void ) vscroll->value( _yposition, h() - rulers->h() - hscroll->h(), 0, pack_visible_height( tracks ) ); } +/** recalculate the size of horizontal scrolling area and inform scrollbar */ void Timeline::adjust_hscroll ( void ) { @@ -157,6 +158,7 @@ Timeline::menu_cb ( Fl_Widget *w, void *v ) ((Timeline*)v)->menu_cb( (Fl_Menu_*)w ); } +/** ensure that p1 is less than p2 */ void Timeline::fix_range ( void ) { @@ -466,24 +468,6 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : Fl_Overlay_Wi } - - -/* float */ -/* Timeline::beats_per_minute ( nframes_t when ) const */ -/* { */ - -/* /\* return tempo_track->beats_per_minute( when ); *\/ */ - -/* } */ - -/* int */ -/* Timeline::beats_per_bar ( nframes_t when ) const */ -/* { */ -/* time_sig t = time_track->time( when ); */ - -/* return t.beats_per_bar; */ -/* } */ - void Timeline::beats_per_minute ( nframes_t when, float bpm ) { @@ -496,7 +480,6 @@ Timeline::time ( nframes_t when, int bpb, int note_type ) time_track->add( new Time_Point( when, bpb, note_type ) ); } - /************/ /* Snapping */ /************/ @@ -590,7 +573,6 @@ Timeline::next_line ( nframes_t *frame, bool bar ) const } } - /** Set the value pointed to by /frame/ to the frame number of the of the nearest measure line to *less than* /when/. Returns true if the new value of *frame is valid, false otherwise. */ @@ -612,17 +594,17 @@ Timeline::prev_line ( nframes_t *frame, bool bar ) const } } - - +/** given screen pixel coordinate /x/ return frame offset into + * timeline, taking into account the current scroll position, widget + * layout, etc. */ nframes_t Timeline::x_to_offset ( int x ) const { return x_to_ts( max( 0, x - Track::width() ) ) + xoffset; } - /** draws a single measure line */ static void draw_measure_cb ( nframes_t frame, const BBT &bbt, void *arg ) @@ -647,6 +629,7 @@ draw_measure_cb ( nframes_t frame, const BBT &bbt, void *arg ) /* FIXME: wrong place for this */ const float ticks_per_beat = 1920.0; +/** re-render the unified tempomap based on the current contents of the Time and Tempo sequences */ void Timeline::update_tempomap ( void ) { @@ -664,6 +647,7 @@ Timeline::update_tempomap ( void ) _tempomap.sort( Sequence_Widget::sort_func ); } +/** return a stucture containing the BBT info which applies at /frame/ */ position_info Timeline::solve_tempomap ( nframes_t frame ) const { @@ -782,6 +766,7 @@ done: return pos; } +/** maybe draw appropriate measure lines in rectangle defined by X, Y, W, and H, using color /color/ as a base */ void Timeline::draw_measure_lines ( int X, int Y, int W, int H, Fl_Color color ) { @@ -804,36 +789,6 @@ Timeline::draw_measure_lines ( int X, int Y, int W, int H, Fl_Color color ) } -/* /\** just like draw mesure lines except that it also draws the BBT values. *\/ */ -/* void */ -/* Timeline::draw_measure_BBT ( int X, int Y, int W, int H, Fl_Color color ) */ -/* { */ -/* // render_tempomap( X, Y, W, H, color, true ); */ -/* } */ - -void -Timeline::xposition ( int X ) -{ -// _old_xposition = xoffset; - -/* /\* FIXME: shouldn't have to do this... *\/ */ -/* X = min( X, ts_to_x( length() ) - tracks->w() - Track::width() ); */ - - xoffset = x_to_ts( X ); - - damage( FL_DAMAGE_SCROLL ); -} - -void -Timeline::yposition ( int Y ) -{ -// _old_yposition = _yposition; - - _yposition = Y; - - damage( FL_DAMAGE_SCROLL ); -} - void Timeline::draw_clip ( void * v, int X, int Y, int W, int H ) { @@ -855,6 +810,7 @@ Timeline::draw_clip ( void * v, int X, int Y, int W, int H ) fl_pop_clip(); } +/** handle resize event */ void Timeline::resize ( int X, int Y, int W, int H ) { @@ -868,6 +824,7 @@ Timeline::resize ( int X, int Y, int W, int H ) vscroll->size( vscroll->w(), H - 18 ); } +/** draw ancillary cursors (not necessarily in the overlay plane) */ void Timeline::draw_cursors ( void ) const { @@ -960,7 +917,7 @@ done: } - +/** draw a single cursor line at /frame/ with color /color/ using symbol routine /symbol/ for the cap */ void Timeline::draw_cursor ( nframes_t frame, Fl_Color color, void (*symbol)(Fl_Color) ) const { @@ -1031,8 +988,7 @@ Timeline::redraw_playhead ( void ) } } - -/** called so many times a second to redraw the playhead etc. */ +/** called so many times a second to redraw the playhead etc. */ void Timeline::update_cb ( void *arg ) { @@ -1043,6 +999,7 @@ Timeline::update_cb ( void *arg ) tl->redraw_playhead(); } +/** draw cursors in overlay plane */ void Timeline::draw_overlay ( void ) { @@ -1075,9 +1032,7 @@ Timeline::draw_overlay ( void ) } -// #include "Sequence_Widget.H" - -/** select all widgets in inside rectangle /r/ */ +/** select sequence widgets within rectangle /r/ */ void Timeline::select ( const Rectangle &r ) { @@ -1092,19 +1047,20 @@ Timeline::select ( const Rectangle &r ) } } +/** delete all selected sequence widgets */ void Timeline::delete_selected ( void ) { Sequence_Widget::delete_selected(); } +/** clear the selection of seqeunce widgets */ void Timeline::select_none ( void ) { Sequence_Widget::select_none(); } - /** An unfortunate necessity for implementing our own DND aside from * the (bogus) native FLTK system */ Track * @@ -1137,19 +1093,6 @@ Timeline::handle_scroll ( int m ) return 0; } -nframes_t -Timeline::length ( void ) const -{ - nframes_t l = 0; - - for ( int i = tracks->children(); i--; ) - l = max( l, ((Track*)tracks->child( i ))->sequence()->length() ); - -// adjust_hscroll(); - - return l; -} - int Timeline::handle ( int m ) { @@ -1293,13 +1236,82 @@ Timeline::handle ( int m ) } } +/** retrun a pointer to the track named /name/, or NULL if no track is named /name/ */ +Track * +Timeline::track_by_name ( const char *name ) +{ + for ( int i = tracks->children(); i-- ; ) + { + Track *t = (Track*)tracks->child( i ); + if ( ! strcmp( name, t->name() ) ) + return t; + } + + return NULL; +} + +/** return a malloc'd string representing a unique name for a new track */ +char * +Timeline::get_unique_track_name ( const char *name ) +{ + char pat[256]; + + strcpy( pat, name ); + + for ( int i = 1; track_by_name( pat ); ++i ) + snprintf( pat, sizeof( pat ), "%s.%d", name, i ); + + return strdup( pat ); +} + +/**********/ +/* Public */ +/**********/ + +/** return the current length of the timeline, which is arrived at by + * calculating the end frame of the rightmost audio region on an + * active audio sequence. Control_Points, etc. do not factor into this + * calcaulation. */ +nframes_t +Timeline::length ( void ) const +{ + nframes_t l = 0; + + for ( int i = tracks->children(); i--; ) + l = max( l, ((Track*)tracks->child( i ))->sequence()->length() ); + +// adjust_hscroll(); + + return l; +} + +/** set horizontal scroll postion to absolute pixel coordinate /X/ */ +void +Timeline::xposition ( int X ) +{ + xoffset = x_to_ts( X ); + + damage( FL_DAMAGE_SCROLL ); +} + +/** set vertical scroll position to absolute pixel coordinate /Y/ */ +void +Timeline::yposition ( int Y ) +{ + _yposition = Y; + + damage( FL_DAMAGE_SCROLL ); +} + +/** zoom in by one zoom step */ void Timeline::zoom_in ( void ) { hscroll->zoom_in(); } +/** zoom out by one zoom step */ void Timeline::zoom_out ( void ) { @@ -1322,6 +1334,7 @@ Timeline::zoom ( float secs ) redraw(); } +/** fit the zoom to the current length of the timeline (subject to nearest power of two) */ void Timeline::zoom_fit ( void ) { @@ -1329,33 +1342,7 @@ Timeline::zoom_fit ( void ) zoom( length() / (float)sample_rate() ); } -Track * -Timeline::track_by_name ( const char *name ) -{ - for ( int i = tracks->children(); i-- ; ) - { - Track *t = (Track*)tracks->child( i ); - - if ( ! strcmp( name, t->name() ) ) - return t; - } - - return NULL; -} - -char * -Timeline::get_unique_track_name ( const char *name ) -{ - char pat[256]; - - strcpy( pat, name ); - - for ( int i = 1; track_by_name( pat ); ++i ) - snprintf( pat, sizeof( pat ), "%s.%d", name, i ); - - return strdup( pat ); -} - +/** add /track/ to the timeline */ void Timeline::add_track ( Track *track ) { @@ -1372,6 +1359,7 @@ Timeline::add_track ( Track *track ) } +/** remove /track/ from the timeline */ void Timeline::remove_track ( Track *track ) { diff --git a/Timeline/Track.C b/Timeline/Track.C index 7dff29a..c1ff26d 100644 --- a/Timeline/Track.C +++ b/Timeline/Track.C @@ -21,8 +21,6 @@ #include "Transport.H" -/* #include "Port.H" */ - #include "../FL/Fl_Sometimes_Input.H" #include #include @@ -41,76 +39,54 @@ const char *Track::capture_format = "Wav 24"; -void -Track::cb_input_field ( Fl_Widget *, void *v ) +Track::Track ( const char *L, int channels ) : + Fl_Group ( 0, 0, 0, 0, 0 ) { - ((Track*)v)->cb_input_field(); -} + init(); -void -Track::cb_button ( Fl_Widget *w, void *v ) -{ - ((Track*)v)->cb_button( w ); + if ( L ) + name( L ); + + color( (Fl_Color)rand() ); + + configure_inputs( channels ); + configure_outputs( channels ); + + log_create(); } -void -Track::cb_input_field ( void ) +Track::Track ( ) : Fl_Group( 0, 0, 1, 1 ) { - log_start(); + init(); - name( name_field->value() ); - - log_end(); + timeline->add_track( this ); } -void -Track::cb_button ( Fl_Widget *w ) +Track::~Track ( ) { + Loggable::block_start(); - if ( w == record_button ) - { + takes = NULL; + control = NULL; + annotation = NULL; - } - if ( w == mute_button ) - { + Fl_Group::clear(); - } - if ( w == solo_button ) - { - if ( solo_button->value() ) - ++_soloing; - else - --_soloing; - } - else - if ( w == take_menu ) - { - int v = take_menu->value(); + log_destroy(); - switch ( v ) - { - case 0: /* show all takes */ - show_all_takes( take_menu->menu()[ v ].value() ); - return; - case 1: /* new */ - sequence( (Audio_Sequence*)sequence()->clone_empty() ); - return; - } + timeline->remove_track( this ); - const char *s = take_menu->menu()[ v ].text; + /* give up our ports */ + configure_inputs( 0 ); + configure_outputs( 0 ); - for ( int i = takes->children(); i--; ) - { - Audio_Sequence *t = (Audio_Sequence*)takes->child( i ); - if ( ! strcmp( s, t->name() ) ) - { - sequence( t ); - redraw(); - break; - } - } - } + _sequence = NULL; + + if ( _name ) + free( _name ); + + Loggable::block_end(); } void @@ -231,50 +207,149 @@ Track::init ( void ) } + -Track::Track ( const char *L, int channels ) : - Fl_Group ( 0, 0, 0, 0, 0 ) +void +Track::set ( Log_Entry &e ) { - init(); + for ( int i = 0; i < e.size(); ++i ) + { + const char *s, *v; - if ( L ) - name( L ); + e.get( i, &s, &v ); - color( (Fl_Color)rand() ); + if ( ! strcmp( s, ":height" ) ) + { + size( atoi( v ) ); - configure_inputs( channels ); - configure_outputs( channels ); +// Fl_Widget::size( w(), height() ); + resize(); + } + else if ( ! strcmp( s, ":selected" ) ) + _selected = atoi( v ); +// else if ( ! strcmp( s, ":armed" + else if ( ! strcmp( s, ":name" ) ) + name( v ); + else if ( ! strcmp( s, ":inputs" ) ) + configure_inputs( atoi( v ) ); + else if ( ! strcmp( s, ":outputs" ) ) + configure_outputs( atoi( v ) ); + else if ( ! strcmp( s, ":color" ) ) + { + color( (Fl_Color)atoll( v ) ); + redraw(); + } + else if ( ! strcmp( s, ":sequence" ) ) + { + int i; + sscanf( v, "%X", &i ); - log_create(); + if ( i ) + { + Audio_Sequence *t = (Audio_Sequence*)Loggable::find( i ); + + /* FIXME: our track might not have been + * defined yet... what should we do about this + * chicken/egg problem? */ + if ( t ) + { +// assert( t ); + + sequence( t ); + } + + } + + } + + } } -Track::~Track ( ) + +void +Track::get ( Log_Entry &e ) const { - Loggable::block_start(); - - takes = NULL; - control = NULL; - annotation = NULL; - - Fl_Group::clear(); - - log_destroy(); - - timeline->remove_track( this ); - - /* give up our ports */ - configure_inputs( 0 ); - configure_outputs( 0 ); - - _sequence = NULL; - - if ( _name ) - free( _name ); - - Loggable::block_end(); + e.add( ":name", _name ); + e.add( ":sequence", sequence() ); + e.add( ":selected", _selected ); + e.add( ":height", size() ); + e.add( ":inputs", input.size() ); + e.add( ":outputs", output.size() ); + e.add( ":color", (unsigned long)color()); } +void +Track::cb_input_field ( Fl_Widget *, void *v ) +{ + ((Track*)v)->cb_input_field(); +} + +void +Track::cb_button ( Fl_Widget *w, void *v ) +{ + ((Track*)v)->cb_button( w ); +} + +void +Track::cb_input_field ( void ) +{ + log_start(); + + name( name_field->value() ); + + log_end(); +} + +void +Track::cb_button ( Fl_Widget *w ) +{ + + if ( w == record_button ) + { + + } + if ( w == mute_button ) + { + + } + if ( w == solo_button ) + { + if ( solo_button->value() ) + ++_soloing; + else + --_soloing; + } + else + if ( w == take_menu ) + { + int v = take_menu->value(); + + switch ( v ) + { + case 0: /* show all takes */ + show_all_takes( take_menu->menu()[ v ].value() ); + return; + case 1: /* new */ + sequence( (Audio_Sequence*)sequence()->clone_empty() ); + return; + } + + const char *s = take_menu->menu()[ v ].text; + + for ( int i = takes->children(); i--; ) + { + Audio_Sequence *t = (Audio_Sequence*)takes->child( i ); + if ( ! strcmp( s, t->name() ) ) + { + sequence( t ); + redraw(); + break; + } + } + } +} + static int pack_visible( Fl_Pack *p ) { int v = 0; @@ -342,7 +417,6 @@ Track::size ( int v ) resize(); } - void Track::add ( Audio_Sequence * t ) { @@ -471,22 +545,6 @@ Track::select ( int X, int Y, int W, int H, } } -void -Track::draw ( void ) -{ - if ( _selected ) - { - Fl_Color c = color(); - - color( FL_RED ); - - Fl_Group::draw(); - - color( c ); - } - else - Fl_Group::draw(); -} #include @@ -601,6 +659,23 @@ Track::menu ( void ) const #include "FL/event_name.H" #include "FL/test_press.H" +void +Track::draw ( void ) +{ + if ( _selected ) + { + Fl_Color c = color(); + + color( FL_RED ); + + Fl_Group::draw(); + + color( c ); + } + else + Fl_Group::draw(); +} + int Track::handle ( int m ) { diff --git a/Timeline/Track.H b/Timeline/Track.H index 33165cc..bd52f9e 100644 --- a/Timeline/Track.H +++ b/Timeline/Track.H @@ -97,16 +97,14 @@ private: void update_port_names ( void ); const char *name_for_port( Port::type_e type, int n ); - - Track ( ) : Fl_Group( 0, 0, 1, 1 ) - { - init(); - - timeline->add_track( this ); - } - + Track ( ); void init ( void ); +protected: + + void get ( Log_Entry &e ) const; + void set ( Log_Entry &e ); + public: Fl_Input *name_field; @@ -128,76 +126,6 @@ public: Playback_DS *playback_ds; Record_DS *record_ds; -// const char *class_name ( void ) { return "Track"; } - - void - set ( Log_Entry &e ) - { - for ( int i = 0; i < e.size(); ++i ) - { - const char *s, *v; - - e.get( i, &s, &v ); - - if ( ! strcmp( s, ":height" ) ) - { - size( atoi( v ) ); - -// Fl_Widget::size( w(), height() ); - resize(); - } - else if ( ! strcmp( s, ":selected" ) ) - _selected = atoi( v ); -// else if ( ! strcmp( s, ":armed" - else if ( ! strcmp( s, ":name" ) ) - name( v ); - else if ( ! strcmp( s, ":inputs" ) ) - configure_inputs( atoi( v ) ); - else if ( ! strcmp( s, ":outputs" ) ) - configure_outputs( atoi( v ) ); - else if ( ! strcmp( s, ":color" ) ) - { - color( (Fl_Color)atoll( v ) ); - redraw(); - } - else if ( ! strcmp( s, ":sequence" ) ) - { - int i; - sscanf( v, "%X", &i ); - - if ( i ) - { - Audio_Sequence *t = (Audio_Sequence*)Loggable::find( i ); - - /* FIXME: our track might not have been - * defined yet... what should we do about this - * chicken/egg problem? */ - if ( t ) - { -// assert( t ); - - sequence( t ); - } - - } - - } - - } - } - - - virtual void get ( Log_Entry &e ) const - { - e.add( ":name", _name ); - e.add( ":sequence", sequence() ); - e.add( ":selected", _selected ); - e.add( ":height", size() ); - e.add( ":inputs", input.size() ); - e.add( ":outputs", output.size() ); - e.add( ":color", (unsigned long)color()); - } - /* for loggable */ LOG_CREATE_FUNC( Track ); @@ -270,7 +198,6 @@ public: void draw ( void ); int handle ( int m ); - /* Engine */ const Audio_Region *capture_region ( void ) const; diff --git a/util/file.C b/util/file.C index e201cf1..b7a6195 100644 --- a/util/file.C +++ b/util/file.C @@ -21,6 +21,7 @@ #include #include #include +#include unsigned long mtime ( const char *file ) @@ -86,3 +87,52 @@ release_lock ( int *lockfd, const char *filename ) *lockfd = 0; } + +int +backwards_fgetc ( FILE *fp ) +{ + int c; + + if ( fseek( fp, -1, SEEK_CUR ) != 0 ) + return -1; + + c = fgetc( fp ); + + fseek( fp, -1, SEEK_CUR ); + + return c; +} + +char * +backwards_fgets ( char *s, int size, FILE *fp ) +{ + if ( fseek( fp, -1, SEEK_CUR ) != 0 ) + return NULL; + + int c; + while ( ( c = backwards_fgetc( fp ) ) >= 0 ) + if ( '\n' == c ) + break; + + long here = ftell( fp ); + + fseek( fp, 1, SEEK_CUR ); + + char *r = fgets( s, size, fp ); + + fseek( fp, here, SEEK_SET ); + + return r; +} + + +/** update the modification time of file referred to by /fd/ */ +void +touch ( int fd ) +{ + struct stat st; + + fstat( fd, &st ); + + fchmod( fd, st.st_mode ); +} diff --git a/util/file.h b/util/file.h index d0411c0..12210e3 100644 --- a/util/file.h +++ b/util/file.h @@ -17,9 +17,14 @@ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ +#include + unsigned long mtime ( const char *file ); bool newer ( const char *file1, const char *file2 ); unsigned long size ( const char *file ); int exists ( const char *name ); bool acquire_lock ( int *lockfd, const char *filename ); void release_lock ( int *lockfd, const char *filename ); +int backwards_fgetc ( FILE *fp ); +char * backwards_fgets ( char *s, int size, FILE *fp ); +void touch ( int fd );