| @@ -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 | |||
| @@ -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 ) | |||
| { | |||
| @@ -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 ); | |||
| @@ -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 ) | |||
| { | |||
| @@ -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 ); | |||
| @@ -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 ); | |||
| @@ -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 | |||
| @@ -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 ); | |||
| } | |||
| @@ -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; } | |||
| @@ -22,6 +22,8 @@ | |||
| peakfile reading/writing. | |||
| */ | |||
| /* Code for peakfile reading, resampling, generation and streaming */ | |||
| #include <sys/mman.h> | |||
| #include <sys/types.h> | |||
| #include <sys/stat.h> | |||
| @@ -39,6 +41,7 @@ | |||
| #include "assert.h" | |||
| #include "util/debug.h" | |||
| #include "util/Thread.H" | |||
| #include "util/file.h" | |||
| #include <errno.h> | |||
| @@ -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; | |||
| @@ -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 <string.h> | |||
| @@ -25,6 +27,8 @@ | |||
| #include <stdio.h> // 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 ) | |||
| { | |||
| @@ -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 <time.h> | |||
| /** very cheap UUID generator... */ | |||
| @@ -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. */ | |||
| @@ -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(); | |||
| } | |||
| @@ -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 ); | |||
| @@ -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_Widget *> Sequence::_delete_queue; | |||
| Sequence::Sequence ( Track *track ) : Fl_Widget( 0, 0, 0, 0 ), Loggable( true ) | |||
| { | |||
| init(); | |||
| @@ -59,9 +66,25 @@ Sequence::init ( void ) | |||
| // clear_visible_focus(); | |||
| } | |||
| Sequence::~Sequence ( ) | |||
| { | |||
| DMESSAGE( "destroying sequence" ); | |||
| if ( _name ) | |||
| free( _name ); | |||
| if ( _widgets.size() ) | |||
| 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 <Sequence_Widget*>::iterator i = _widgets.begin(); | |||
| i != _widgets.end(); ++i ) | |||
| { | |||
| @@ -73,25 +96,18 @@ Sequence::clear ( void ) | |||
| } | |||
| _widgets.clear(); | |||
| } | |||
| Sequence::~Sequence ( ) | |||
| { | |||
| DMESSAGE( "destroying sequence" ); | |||
| if ( _name ) | |||
| free( _name ); | |||
| if ( _widgets.size() ) | |||
| FATAL( "programming error: leaf destructor must call Sequence::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 <Sequence_Widget *>::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) | |||
| (*r)->draw_box(); | |||
| for ( list <Sequence_Widget *>::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 <Sequence_Widget *>::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 <Sequence_Widget *>::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 <Sequence_Widget *>::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,37 +242,44 @@ 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 <Sequence_Widget*>::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; | |||
| /** return the location of the next widget from frame /from/ */ | |||
| nframes_t | |||
| Sequence::prev ( nframes_t from ) const | |||
| { | |||
| for ( list <Sequence_Widget*>::const_reverse_iterator i = _widgets.rbegin(); i != _widgets.rend(); i++ ) | |||
| if ( (*i)->start() < from ) | |||
| return (*i)->start(); | |||
| fl_push_clip( x(), y(), w(), h() ); | |||
| if ( _widgets.size() ) | |||
| return _widgets.front()->start(); | |||
| else | |||
| return 0; | |||
| } | |||
| /* 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() ); | |||
| #include "FL/event_name.H" | |||
| int X, Y, W, H; | |||
| #include "Transport.H" // for locate() | |||
| 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 <Sequence_Widget *>::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) | |||
| (*r)->draw_box(); | |||
| for ( list <Sequence_Widget *>::const_iterator r = _widgets.begin(); r != _widgets.end(); ++r ) | |||
| (*r)->draw(); | |||
| fl_pop_clip(); | |||
| } | |||
| 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 <Sequence_Widget *>::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 <Sequence_Widget*>::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 <Sequence_Widget*>::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 <Sequence_Widget *>::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 <Sequence_Widget *>::const_reverse_iterator r = _widgets.rbegin(); r != _widgets.rend(); ++r ) | |||
| if ( ! ( (*r)->start() > ets || (*r)->start() + (*r)->length() < sts ) ) | |||
| (*r)->select(); | |||
| } | |||
| @@ -21,6 +21,29 @@ | |||
| #include <FL/fl_draw.H> | |||
| 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 | |||
| { | |||
| @@ -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 ); | |||
| }; | |||
| @@ -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 ) | |||
| { | |||
| } | |||
| @@ -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 ); | |||
| }; | |||
| @@ -63,6 +63,8 @@ Sequence_Widget::~Sequence_Widget ( ) | |||
| _selection.remove( this ); | |||
| } | |||
| void | |||
| Sequence_Widget::get ( Log_Entry &e ) const | |||
| { | |||
| @@ -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 { | |||
| @@ -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 ) | |||
| @@ -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 <FL/Fl_Int_Input.H> | |||
| #include <FL/Fl_Menu_Window.H> | |||
| class Time_Point_Editor : public Fl_Menu_Window | |||
| { | |||
| @@ -196,7 +193,6 @@ public: | |||
| } | |||
| }; | |||
| bool | |||
| Time_Point::edit ( time_sig *sig ) | |||
| { | |||
| @@ -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 ) | |||
| { | |||
| @@ -21,8 +21,6 @@ | |||
| #include "Transport.H" | |||
| /* #include "Port.H" */ | |||
| #include "../FL/Fl_Sometimes_Input.H" | |||
| #include <FL/fl_ask.H> | |||
| #include <FL/Fl_Color_Chooser.H> | |||
| @@ -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(); | |||
| name( name_field->value() ); | |||
| init(); | |||
| 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,49 +207,148 @@ 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(); | |||
| 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()); | |||
| } | |||
| takes = NULL; | |||
| control = NULL; | |||
| annotation = NULL; | |||
| Fl_Group::clear(); | |||
| void | |||
| Track::cb_input_field ( Fl_Widget *, void *v ) | |||
| { | |||
| ((Track*)v)->cb_input_field(); | |||
| } | |||
| log_destroy(); | |||
| void | |||
| Track::cb_button ( Fl_Widget *w, void *v ) | |||
| { | |||
| ((Track*)v)->cb_button( w ); | |||
| } | |||
| timeline->remove_track( this ); | |||
| void | |||
| Track::cb_input_field ( void ) | |||
| { | |||
| log_start(); | |||
| /* give up our ports */ | |||
| configure_inputs( 0 ); | |||
| configure_outputs( 0 ); | |||
| name( name_field->value() ); | |||
| _sequence = NULL; | |||
| log_end(); | |||
| } | |||
| if ( _name ) | |||
| free( _name ); | |||
| void | |||
| Track::cb_button ( Fl_Widget *w ) | |||
| { | |||
| Loggable::block_end(); | |||
| } | |||
| 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 ) | |||
| { | |||
| @@ -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 <FL/Fl_Menu_Button.H> | |||
| @@ -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 ) | |||
| { | |||
| @@ -97,15 +97,13 @@ private: | |||
| void update_port_names ( void ); | |||
| const char *name_for_port( Port::type_e type, int n ); | |||
| Track ( ); | |||
| void init ( void ); | |||
| Track ( ) : Fl_Group( 0, 0, 1, 1 ) | |||
| { | |||
| init(); | |||
| protected: | |||
| timeline->add_track( this ); | |||
| } | |||
| void init ( void ); | |||
| void get ( Log_Entry &e ) const; | |||
| void set ( Log_Entry &e ); | |||
| public: | |||
| @@ -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; | |||
| @@ -21,6 +21,7 @@ | |||
| #include <sys/stat.h> | |||
| #include <sys/types.h> | |||
| #include <unistd.h> | |||
| #include <stdio.h> | |||
| 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 ); | |||
| } | |||
| @@ -17,9 +17,14 @@ | |||
| /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
| /*******************************************************************************/ | |||
| #include <stdio.h> | |||
| 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 ); | |||