diff --git a/timeline/src/Annotation_Point.H b/timeline/src/Annotation_Point.H index c7f29db..028732b 100644 --- a/timeline/src/Annotation_Point.H +++ b/timeline/src/Annotation_Point.H @@ -30,7 +30,7 @@ class Annotation_Point : public Sequence_Point protected: -// const char *class_name ( void ) { return "Annotation_Point"; } +// const char *class_label ( void ) { return "Annotation_Point"; } virtual void get ( Log_Entry &e ) const { @@ -51,7 +51,7 @@ protected: e.get( i, &s, &v ); if ( ! strcmp( s, ":label" ) ) - name( v ); + label( v ); } // timeline->redraw(); @@ -67,13 +67,13 @@ public: LOG_CREATE_FUNC( Annotation_Point ); SEQUENCE_WIDGET_CLONE_FUNC( Annotation_Point ); - Annotation_Point ( Sequence *sequence, nframes_t when, const char *name ) + Annotation_Point ( Sequence *sequence, nframes_t when, const char *label ) { _sequence = sequence; _r->start = when; - _label = strdup( name ); + _label = strdup( label ); log_create(); } @@ -96,10 +96,10 @@ public: if ( m == FL_PUSH && Fl::test_shortcut( FL_BUTTON3 ) && ! Fl::event_shift() ) { - const char *s = fl_input( "New name for mark:", name() ); + const char *s = fl_input( "New label for mark:", label() ); if ( s ) - name( s ); + label( s ); return 0; } diff --git a/timeline/src/Annotation_Region.C b/timeline/src/Annotation_Region.C index c80a4b9..73df324 100644 --- a/timeline/src/Annotation_Region.C +++ b/timeline/src/Annotation_Region.C @@ -45,13 +45,13 @@ Annotation_Region::set ( Log_Entry &e ) e.get( i, &s, &v ); if ( ! strcmp( s, ":label" ) ) - name( v ); + label( v ); } // timeline->redraw(); } -Annotation_Region::Annotation_Region ( Sequence *sequence, nframes_t when, const char *name ) +Annotation_Region::Annotation_Region ( Sequence *sequence, nframes_t when, const char *label ) { _sequence = sequence; @@ -60,7 +60,7 @@ Annotation_Region::Annotation_Region ( Sequence *sequence, nframes_t when, const /* FIXME: hack */ _r->length = 400; - _label = strdup( name ); + _label = strdup( label ); log_create(); } @@ -103,10 +103,10 @@ Annotation_Region::handle ( int m ) { if ( test_press( FL_BUTTON3 ) ) { - char *s = fl_text_edit( "Annotation text:", "&Save", name() ); + char *s = fl_text_edit( "Annotation text:", "&Save", label() ); if ( s ) - name( s ); + label( s ); free( s ); diff --git a/timeline/src/Annotation_Region.H b/timeline/src/Annotation_Region.H index cefb6d2..9d56da7 100644 --- a/timeline/src/Annotation_Region.H +++ b/timeline/src/Annotation_Region.H @@ -30,19 +30,6 @@ class Annotation_Region : public Sequence_Region /* not permitted */ Annotation_Region & operator = ( const Annotation_Region &rhs ); - char *_label; - -public: - - const char *name ( void ) const { return _label; } - void name ( const char *s ) - { - if ( _label ) - free( _label ); - _label = strdup( s ); - redraw(); - } - protected: virtual void get ( Log_Entry &e ) const; @@ -50,7 +37,6 @@ protected: Annotation_Region ( ) { - _label = NULL; } Annotation_Region ( const Annotation_Region &rhs ); diff --git a/timeline/src/Cursor_Point.C b/timeline/src/Cursor_Point.C new file mode 100644 index 0000000..771f896 --- /dev/null +++ b/timeline/src/Cursor_Point.C @@ -0,0 +1,140 @@ + +/*******************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ +/* more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with This program; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + + +#include "Cursor_Point.H" +#include "Cursor_Sequence.H" +#include "Timeline.H" // for timeline->time_track + +Cursor_Point::Cursor_Point ( ) +{ +// timeline->->add( this ); + _label = NULL; + _type = NULL; +} + +Cursor_Point::Cursor_Point ( nframes_t when, const char *type, const char *label ) +{ +// _make_label(); + + _label = NULL; + _type = NULL; + + this->label( label ); + this->type( type ); + + timeline->add_cursor( this ); + + start( when ); + + log_create(); +} + +Cursor_Point::Cursor_Point ( const Cursor_Point &rhs ) : Sequence_Point( rhs ) +{ + label( rhs.label() ); + type( rhs.type() ); + + log_create(); +} + +Cursor_Point::~Cursor_Point ( ) +{ +// sequence()->remove( this ); + + log_destroy(); + + label(NULL); + type(NULL); +} + + + +void +Cursor_Point::get ( Log_Entry &e ) const +{ +// Sequence_Point::get( e ); + + e.add( ":start", start() ); + e.add( ":label", label() ); + e.add( ":type", type() ); +} + +void +Cursor_Point::set ( Log_Entry &e ) +{ + + Sequence_Point::set( e ); + + for ( int i = 0; i < e.size(); ++i ) + { + const char *s, *v; + + e.get( i, &s, &v ); + + if ( ! strcmp( s, ":label" ) ) + label( v ); + else if ( ! strcmp( s, ":type" )) + { + type( v ); + + timeline->add_cursor( this ); + } + +/* /\* FIXME: we need to add this to the time track on creation!!! *\/ */ +/* timeline->time_track->add( this ); */ + + } + + sequence()->handle_widget_change( start(), length() ); + +// _make_label(); +} + + + +void +Cursor_Point::log_children ( void ) const +{ + log_create(); +} + + +int +Cursor_Point::handle ( int m ) +{ + Logger log( this ); + + /* if ( m == FL_PUSH && Fl::event_button3() && ! ( Fl::event_state() & ( FL_ALT | FL_CTRL | FL_SHIFT ) ) ) */ + /* { */ + + /* time_sig t = _time; */ + + /* edit( &t ); */ + + /* time( t.beats_per_bar, t.beat_type ); */ + + /* return 0; */ + + /* } */ + + return Sequence_Point::handle( m ); +} + + diff --git a/timeline/src/Cursor_Point.H b/timeline/src/Cursor_Point.H new file mode 100644 index 0000000..7f2c342 --- /dev/null +++ b/timeline/src/Cursor_Point.H @@ -0,0 +1,65 @@ + +/*******************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ +/* more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with This program; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +#pragma once + +#include "Sequence_Point.H" + + +class Cursor_Point : public Sequence_Point +{ + char *_type; + +protected: + +// const char *class_name ( void ) { return "Time_Point"; } + + virtual void get ( Log_Entry &e ) const; + void set ( Log_Entry &e ); + void log_children ( void ) const; + + Cursor_Point ( ); + +public: + + LOG_CREATE_FUNC( Cursor_Point ); + SEQUENCE_WIDGET_CLONE_FUNC( Cursor_Point ); + +// static bool edit ( time_sig *sig ); + + Cursor_Point ( nframes_t when, const char *type, const char *label ); + Cursor_Point ( const Cursor_Point &rhs ); + + ~Cursor_Point ( ); + + const char * type ( void ) const { return _type; } + void type ( const char *v ) + { + if ( _type ) + free( _type ); + + _type = NULL; + + if ( v ) + _type = strdup( v ); + } + + int handle ( int m ); + +}; diff --git a/timeline/src/Cursor_Region.C b/timeline/src/Cursor_Region.C new file mode 100644 index 0000000..3fcbcd1 --- /dev/null +++ b/timeline/src/Cursor_Region.C @@ -0,0 +1,154 @@ + +/*******************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ +/* more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with This program; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +#include +#include +#include + +#include "Cursor_Region.H" +#include "Cursor_Sequence.H" +#include "Timeline.H" + +Fl_Color Cursor_Region::box_color ( void ) const +{ + return ((Cursor_Sequence*)sequence())->cursor_color(); +} + + +void Cursor_Region::box_color ( Fl_Color c ) +{ + ((Cursor_Sequence*)sequence())->cursor_color( c ); +} + + + +void +Cursor_Region::get ( Log_Entry &e ) const +{ +// Sequence_Region::get( e ); + e.add( ":start", start() ); + e.add( ":length", length() ); + e.add( ":label", label() ); + e.add( ":type", type() ); +} + +void +Cursor_Region::set ( Log_Entry &e ) +{ + Sequence_Region::set( e ); + + for ( int i = 0; i < e.size(); ++i ) + { + const char *s, *v; + + e.get( i, &s, &v ); + + if ( ! strcmp( s, ":label" ) ) + label( v ); + if ( ! strcmp( s, ":type" ) ) + { + type( v ); + timeline->add_cursor( this ); + } + } + +// timeline->redraw(); +} + +Cursor_Region::Cursor_Region ( nframes_t when, nframes_t length, const char *type, const char *label ) +{ + _label = NULL; + _type = NULL; + + this->label( label ); + this->type( type ); + + timeline->add_cursor( this ); + + start( when ); + + this->length( length ); + + log_create(); +} + +Cursor_Region::Cursor_Region ( const Cursor_Region &rhs ) : Sequence_Region( rhs ) +{ + _label = strdup( rhs._label ); + _type = strdup( rhs._type ); + + log_create(); +} + + +Cursor_Region::~Cursor_Region ( ) +{ +// timeline->cursor_track->remove( this ); + + log_destroy(); + + label(NULL); + type(NULL); +} + +void +Cursor_Region::draw_box ( void ) +{ + Sequence_Region::draw_box(); +} + +void +Cursor_Region::draw ( void ) +{ + draw_label( _label, (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_TOP | FL_ALIGN_CLIP ) ); +} + +#include "FL/Fl_Text_Edit_Window.H" +#include "FL/test_press.H" + +int +Cursor_Region::handle ( int m ) +{ + Logger _log( this ); + + if ( m == FL_PUSH ) + { + if ( test_press( FL_BUTTON3 ) ) + { + char *s = fl_text_edit( "Cursor text:", "&Save", label() ); + + if ( s ) + label( s ); + + free( s ); + + return 0; + } + } + + int r = Sequence_Region::handle( m ); + + if ( m == FL_RELEASE ) + { + sequence()->sort(); + timeline->redraw(); + } + + return r; +} diff --git a/timeline/src/Cursor_Region.H b/timeline/src/Cursor_Region.H new file mode 100644 index 0000000..3290867 --- /dev/null +++ b/timeline/src/Cursor_Region.H @@ -0,0 +1,74 @@ + +/*******************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ +/* more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with This program; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +#pragma once + +#include "Sequence_Region.H" +#include "Cursor_Sequence.H" + +class Cursor_Region : public Sequence_Region +{ + /* not permitted */ + Cursor_Region & operator = ( const Cursor_Region &rhs ); + + char *_type; + +protected: + + virtual void get ( Log_Entry &e ) const; + virtual void set ( Log_Entry &e ); + + Cursor_Region ( ) + { + _label = NULL; + _type = NULL; + } + + Cursor_Region ( const Cursor_Region &rhs ); + +public: + + virtual Fl_Color box_color ( void ) const; + virtual void box_color ( Fl_Color c ); + + /* for loggable */ + LOG_CREATE_FUNC( Cursor_Region ); + SEQUENCE_WIDGET_CLONE_FUNC( Cursor_Region ); + + Cursor_Region ( nframes_t when, nframes_t length, const char *type, const char *label ); + virtual ~Cursor_Region ( ); + + void draw_box ( void ); + void draw ( void ); + int handle ( int m ); + + + const char * type ( void ) const { return _type; } + void type ( const char *v ) + { + if ( _type ) + free( _type ); + + _type = NULL; + + if ( v ) + _type = strdup( v ); + } + +}; diff --git a/timeline/src/Cursor_Sequence.C b/timeline/src/Cursor_Sequence.C new file mode 100644 index 0000000..94bdf98 --- /dev/null +++ b/timeline/src/Cursor_Sequence.C @@ -0,0 +1,62 @@ + +/*******************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ +/* more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with This program; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +#include "Cursor_Sequence.H" +#include "Cursor_Point.H" +#include "Timeline.H" + +void +Cursor_Sequence::handle_widget_change ( nframes_t start, nframes_t length ) +{ + sort(); + timeline->redraw(); +} + +Sequence_Widget * +Cursor_Sequence::active_cursor ( void ) +{ + if ( _widgets.size() ) + return _widgets.front(); + else + return 0; +} + +int +Cursor_Sequence::handle ( int m ) +{ + int r = Sequence::handle( m ); + + if ( r ) + return r; + + switch ( m ) + { + case FL_PUSH: + /* if ( Fl::event_button1() ) */ + /* { */ + /* add( new Cursor_Point( timeline->x_to_offset( Fl::event_x() ), "NONE" ) ); */ + /* timeline->redraw(); */ + /* return 0; */ + /* } */ + return 0; + default: + return 0; + + } +} diff --git a/timeline/src/Cursor_Sequence.H b/timeline/src/Cursor_Sequence.H new file mode 100644 index 0000000..472386c --- /dev/null +++ b/timeline/src/Cursor_Sequence.H @@ -0,0 +1,54 @@ + +/*******************************************************************************/ +/* Copyright (C) 2012 Jonathan Moore Liles */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but WITHOUT */ +/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ +/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ +/* more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with This program; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +#pragma once + +#include "Sequence.H" +#include "Cursor_Point.H" +#include "Cursor_Region.H" + +class Cursor_Sequence : public Sequence +{ + + Fl_Color _cursor_color; + +protected: + + /* not used */ + void get ( Log_Entry & ) const { } + void set ( Log_Entry & ) { } + +public: + + Sequence_Widget *active_cursor ( void ); + + Fl_Color cursor_color ( void ) const { return _cursor_color; } + void cursor_color ( Fl_Color c ) { _cursor_color = c; } + + Fl_Cursor cursor ( void ) const { return FL_CURSOR_DEFAULT; } + + Cursor_Sequence ( int X, int Y, int W, int H ) : Sequence ( X, Y, W, H ) + { + _cursor_color = FL_CYAN; + } + + + void handle_widget_change ( nframes_t start, nframes_t length ); + int handle ( int m ); +}; diff --git a/timeline/src/Engine/Timeline.C b/timeline/src/Engine/Timeline.C index a4320ad..7f17490 100644 --- a/timeline/src/Engine/Timeline.C +++ b/timeline/src/Engine/Timeline.C @@ -26,6 +26,7 @@ #include "Playback_DS.H" #include "Thread.H" +#include "../Cursor_Sequence.H" #include @@ -34,14 +35,48 @@ bool Timeline::record ( void ) { /* FIXME: right place for this? */ + + if ( Timeline::automatically_create_takes && + ! _created_new_takes ) + { + add_take_for_armed_tracks(); + _created_new_takes = true; + } + transport->recording = true; + deactivate(); + Loggable::block_start(); nframes_t frame = transport->frame; - if ( transport->punch_enabled() && range_start() != range_end() && frame < range_start() ) - frame = range_start(); + if ( transport->punch_enabled() ) + { + const Sequence_Widget *w = punch_cursor_track->next( frame ); + + if ( w && w->start() >= frame ) + { + frame = w->start(); + _punch_out_frame = w->start() + w->length(); + } + } + + _punch_in_frame = frame; + + punch_in( frame ); + + return true; +} + +void +Timeline::punch_in ( nframes_t frame ) +{ + if ( _punched_in ) + { + WARNING( "Programming error. Attempt to punch in twice" ); + return; + } DMESSAGE( "Going to record starting at frame %lu", (unsigned long)frame ); @@ -53,20 +88,12 @@ Timeline::record ( void ) t->record_ds->start( frame ); } - deactivate(); - - return true; + _punched_in = true; } -/** stop recording for all armed tracks */ void -Timeline::stop ( void ) +Timeline::punch_out ( nframes_t frame ) { - nframes_t frame = transport->frame; - - if ( transport->punch_enabled() && range_start() != range_end() && frame > range_end() ) - frame = range_end(); - for ( int i = tracks->children(); i-- ; ) { Track *t = (Track*)tracks->child( i ); @@ -85,6 +112,27 @@ Timeline::stop ( void ) if ( t->armed() && t->record_ds ) t->record_ds->shutdown(); } + + _punched_in = false; + _punch_in_frame = 0; + _punch_out_frame = 0; +} + +/** stop recording for all armed tracks. Does not affect transport. */ +void +Timeline::stop ( void ) +{ + nframes_t frame = transport->frame; + + if ( transport->punch_enabled() ) + { + const Sequence_Widget *w = punch_cursor_track->prev( frame ); + + if ( w && w->start() + w->length() < frame ) + frame = w->start() + w->length(); + } + + punch_out( frame ); Loggable::block_end(); diff --git a/timeline/src/Project.C b/timeline/src/Project.C index f516c99..7cd1f6f 100644 --- a/timeline/src/Project.C +++ b/timeline/src/Project.C @@ -49,7 +49,7 @@ extern Transport *transport; extern TLE *tle; -const int PROJECT_VERSION = 1; +const int PROJECT_VERSION = 2; extern char *instance_name; @@ -287,9 +287,14 @@ Project::open ( const char *name ) strncmp( created_by, APP_NAME, strlen( APP_NAME ) ) ) return E_INVALID; - if ( version != PROJECT_VERSION ) + if ( version > PROJECT_VERSION ) return E_VERSION; + if ( version < 2 ) + { + /* FIXME: Version 1->2 adds Cursor_Sequence and Cursor_Point to default project... */ + } + /* normally, engine will be NULL after a close or on an initial open, but 'new' will have already created it to get the sample rate. */ if ( ! engine ) diff --git a/timeline/src/Sequence.C b/timeline/src/Sequence.C index 40f89d6..9997187 100644 --- a/timeline/src/Sequence.C +++ b/timeline/src/Sequence.C @@ -303,12 +303,20 @@ Sequence::handle ( int m ) case FL_SHORTCUT: if ( Fl::test_shortcut( FL_CTRL + FL_Right ) ) { - transport->locate( next( transport->frame ) ); + const Sequence_Widget *w = next( transport->frame ); + + if ( w ) + transport->locate( w->start() ); + return 1; } else if ( Fl::test_shortcut( FL_CTRL + FL_Left ) ) { - transport->locate( prev( transport->frame ) ); + const Sequence_Widget *w = prev( transport->frame ); + + if ( w ) + transport->locate( w->start() ); + return 1; } else if ( Fl::test_shortcut( FL_CTRL + ' ' ) ) @@ -496,29 +504,29 @@ Sequence::handle ( int m ) } /** return the location of the next widget from frame /from/ */ - nframes_t +const Sequence_Widget * Sequence::next ( nframes_t from ) const { for ( list ::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ ) if ( (*i)->start() > from ) - return (*i)->start(); + return *i; if ( _widgets.size() ) - return _widgets.back()->start(); + return _widgets.back(); else return 0; } /** return the location of the next widget from frame /from/ */ - nframes_t +const Sequence_Widget * 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(); + return *i; if ( _widgets.size() ) - return _widgets.front()->start(); + return _widgets.front(); else return 0; } diff --git a/timeline/src/Sequence.H b/timeline/src/Sequence.H index 54e807a..4e6c0ef 100644 --- a/timeline/src/Sequence.H +++ b/timeline/src/Sequence.H @@ -96,8 +96,8 @@ public: void sort ( void ); void clear ( void ); - nframes_t next ( nframes_t from ) const; - nframes_t prev ( nframes_t from ) const; + const Sequence_Widget *next ( nframes_t from ) const; + const Sequence_Widget *prev ( nframes_t from ) const; Track *track ( void ) const { return _track; } void track ( Track *t ) { _track = t; } diff --git a/timeline/src/Sequence_Point.H b/timeline/src/Sequence_Point.H index f87a06e..715a0b9 100644 --- a/timeline/src/Sequence_Point.H +++ b/timeline/src/Sequence_Point.H @@ -28,8 +28,6 @@ class Sequence_Point : public Sequence_Widget protected: - char *_label; - void get ( Log_Entry &e ) const; void set ( Log_Entry &e ); @@ -43,8 +41,8 @@ protected: public: - const char *name ( void ) const { return _label; } - void name ( const char *s ) + const char *label ( void ) const { return _label; } + void label ( const char *s ) { if ( _label ) free( _label ); diff --git a/timeline/src/Sequence_Region.C b/timeline/src/Sequence_Region.C index 8ecd82f..8f8bc5d 100644 --- a/timeline/src/Sequence_Region.C +++ b/timeline/src/Sequence_Region.C @@ -248,6 +248,7 @@ void Sequence_Region::draw_box ( void ) { Fl_Color c = selected() ? selection_color() : box_color(); + fl_draw_box( box(), line_x(), y(), abs_w(), h(), fl_color_add_alpha( c, 127 ) ); } diff --git a/timeline/src/Sequence_Widget.C b/timeline/src/Sequence_Widget.C index b8b3722..87bb4b4 100644 --- a/timeline/src/Sequence_Widget.C +++ b/timeline/src/Sequence_Widget.C @@ -39,6 +39,7 @@ Fl_Color Sequence_Widget::_selection_color = FL_MAGENTA; Sequence_Widget::Sequence_Widget ( ) { + _label = 0; _sequence = NULL; _r = &_range; @@ -56,6 +57,9 @@ Sequence_Widget::Sequence_Widget ( const Sequence_Widget &rhs ) : Loggable( rhs { _drag = NULL; + if ( rhs._label ) + _label = strdup( rhs._label ); + _sequence = rhs._sequence; _range = rhs._range; @@ -77,6 +81,9 @@ Sequence_Widget::operator= ( const Sequence_Widget &rhs ) _box_color = rhs._box_color; _color = rhs._color; + if ( rhs._label ) + _label = strdup( rhs._label ); + return *this; } @@ -90,6 +97,8 @@ Sequence_Widget::~Sequence_Widget ( ) if ( this == _belowmouse ) _belowmouse = NULL; + label( NULL ); + _sequence->remove( this ); _selection.remove( this ); diff --git a/timeline/src/Sequence_Widget.H b/timeline/src/Sequence_Widget.H index 8da354e..dc5d511 100644 --- a/timeline/src/Sequence_Widget.H +++ b/timeline/src/Sequence_Widget.H @@ -136,6 +136,8 @@ class Sequence_Widget : public Loggable protected: + + char *_label; Sequence *_sequence; /* track this region belongs to */ @@ -208,7 +210,7 @@ public: /* use this as x() when you need to draw lines between widgets */ int line_x ( void ) const { - return _r->start < timeline->xoffset ? max( -32768, _sequence->x() - timeline->ts_to_x( timeline->xoffset - _r->start )) : min( 32767, _sequence->x() + timeline->ts_to_x( _r->start - timeline->xoffset ) ); + return _r->start < timeline->xoffset ? max( -32767, _sequence->x() - timeline->ts_to_x( timeline->xoffset - _r->start )) : min( 32767, _sequence->x() + timeline->ts_to_x( _r->start - timeline->xoffset ) ); } virtual int w ( void ) const @@ -229,8 +231,8 @@ public: Fl_Color color ( void ) const { return _color; } void color ( Fl_Color v ) { _color = v; } - Fl_Color box_color ( void ) const { return _box_color; } - void box_color ( Fl_Color v ) { _box_color = v; } + virtual Fl_Color box_color ( void ) const { return _box_color; } + virtual void box_color ( Fl_Color v ) { _box_color = v; } virtual Fl_Color selection_color ( void ) const { return _selection_color; } virtual void selection_color ( Fl_Color v ) { _selection_color = v; } @@ -242,12 +244,28 @@ public: /* void start ( nframes_t o ) { _r->start = o; } */ void start ( nframes_t where ); - void length ( nframes_t v ) { _r->length = v; } virtual nframes_t length ( void ) const { return _r->length; } void offset ( nframes_t v ) { _r->offset = v; } nframes_t offset ( void ) const { return _r->offset; } + void set_left ( nframes_t v ) { _r->set_left( v ); } + void set_right ( nframes_t v ) { _r->set_right( v ); } + + const char *label ( void ) const { return _label; } + void label ( const char *s ) + { + if ( _label ) + free( _label ); + + _label = NULL; + + if ( s ) + _label = strdup( s ); + + redraw(); + } + /** convert a screen x coord into an start into the region */ nframes_t x_to_offset ( int X ) { diff --git a/timeline/src/TLE.fl b/timeline/src/TLE.fl index 73b12f7..43e3dcb 100644 --- a/timeline/src/TLE.fl +++ b/timeline/src/TLE.fl @@ -504,6 +504,13 @@ Project::compact();} timeline->redraw();} xywh {15 15 40 25} type Toggle value 1 } + MenuItem {} { + label {&Cursor Overlay} + callback {Timeline::draw_with_cursor_overlay = menu_picked_value( o ); + +timeline->redraw();} + xywh {15 14 40 25} type Toggle value 1 + } } Submenu {} { label {&Waveform} open @@ -594,6 +601,16 @@ timeline->redraw();} callback {transport->stop_disables_record( ((Fl_Menu_*)o)->mvalue()->flags & FL_MENU_VALUE );} xywh {10 10 40 25} type Toggle value 1 } + MenuItem {} { + label {Loop Playback} + callback {timeline->loop_playback = ( ((Fl_Menu_*)o)->mvalue()->flags & FL_MENU_VALUE );} + xywh {10 10 40 25} type Toggle value 0 + } + MenuItem {} { + label {Automatically Create Takes} + callback {timeline->automatically_create_takes = ( ((Fl_Menu_*)o)->mvalue()->flags & FL_MENU_VALUE );} + xywh {10 10 40 25} type Toggle value 0 + } } } } diff --git a/timeline/src/Timeline.C b/timeline/src/Timeline.C index 085f1ed..b488c10 100644 --- a/timeline/src/Timeline.C +++ b/timeline/src/Timeline.C @@ -32,6 +32,7 @@ #include "Timeline.H" #include "Tempo_Sequence.H" #include "Time_Sequence.H" +#include "Cursor_Sequence.H" #include "Audio_Sequence.H" #include "Control_Sequence.H" #include "Scalebar.H" @@ -55,6 +56,8 @@ #include "OSC_Thread.H" #include "OSC/Endpoint.H" +#include + #include extern nsm_client_t *nsm; @@ -78,11 +81,14 @@ extern nsm_client_t *nsm; bool Timeline::draw_with_measure_lines = true; +bool Timeline::draw_with_cursor_overlay = true; Timeline::snap_e Timeline::snap_to = Bars; bool Timeline::snapping_on_hold = false; bool Timeline::snap_magnetic = true; bool Timeline::follow_playhead = true; bool Timeline::center_playhead = true; +bool Timeline::loop_playback = false; +bool Timeline::automatically_create_takes = false; const float UPDATE_FREQ = 1.0 / 18.0f; @@ -138,6 +144,72 @@ draw_full_arrow_symbol ( Fl_Color color ) +nframes_t +Timeline::range_start ( void ) const +{ + if ( edit_cursor_track->active_cursor() ) + return edit_cursor_track->active_cursor()->start(); + else + return 0; +} + +nframes_t +Timeline::range_end ( void ) const +{ + if ( edit_cursor_track->active_cursor() ) + return edit_cursor_track->active_cursor()->start() + edit_cursor_track->active_cursor()->length(); + else + return 0; +} + +void +Timeline::range_start ( nframes_t n ) +{ + if ( ! edit_cursor_track->active_cursor() ) + new Cursor_Region( 0, 0, "Edit", NULL ); + + Logger log( edit_cursor_track->active_cursor() ); + + edit_cursor_track->active_cursor()->set_left( n ); +} + +void +Timeline::range_end ( nframes_t n ) +{ + if ( ! edit_cursor_track->active_cursor() ) + new Cursor_Region( 0, 0, "Edit", NULL ); + + Logger log( edit_cursor_track->active_cursor() ); + + edit_cursor_track->active_cursor()->set_right( n ); +} + +/** return first frame of playback (might not be 0) */ +nframes_t +Timeline::playback_home ( void ) const +{ + if ( play_cursor_track->active_cursor() ) + return play_cursor_track->active_cursor()->start(); + else + return 0; +} + +/** return last frame of playback */ +nframes_t +Timeline::playback_end ( void ) const +{ + if ( play_cursor_track->active_cursor() ) + return play_cursor_track->active_cursor()->start() + play_cursor_track->active_cursor()->length(); + else + return length(); +} + +void +Timeline::reset_range ( void ) +{ + delete edit_cursor_track->active_cursor(); +} + /** callback used by Loggable class to create a snapshot of system * state. */ void @@ -145,6 +217,9 @@ Timeline::snapshot ( void ) { tempo_track->log_children(); time_track->log_children(); + edit_cursor_track->log_children(); + punch_cursor_track->log_children(); + play_cursor_track->log_children(); for ( int i = 0; i < tracks->children(); ++i ) { @@ -211,15 +286,15 @@ Timeline::menu_cb ( Fl_Widget *w, void *v ) ((Timeline*)v)->menu_cb( (Fl_Menu_*)w ); } -/** ensure that p1 is less than p2 */ +/** ensure that p1 is less than range_end() */ void Timeline::fix_range ( void ) { - if ( p1 > p2 ) + if ( range_start() > range_end() ) { - nframes_t t = p2; - p2 = p1; - p1 = t; + nframes_t t = range_end(); + range_end( range_start() ); + range_start( t ); } } @@ -227,12 +302,25 @@ Timeline::fix_range ( void ) void Timeline::range ( nframes_t start, nframes_t length ) { - p1 = start; - p2 = start + length; + range_start( start ); + range_end( start + length ); redraw(); } +/** create a new take for every armed track */ +void +Timeline::add_take_for_armed_tracks ( void ) +{ + for ( int i = tracks->children(); i-- ; ) + { + Track *t = (Track*)tracks->child( i ); + + if ( t->armed() && t->sequence()->_widgets.size() ) + t->sequence( new Audio_Sequence( t ) ); + } +} + void Timeline::menu_cb ( Fl_Menu_ *m ) { @@ -245,7 +333,7 @@ Timeline::menu_cb ( Fl_Menu_ *m ) DMESSAGE( "%s", picked ); - if ( ! strcmp( picked, "Add Audio Track" ) ) + if ( ! strcmp( picked, "Add audio track" ) ) { /* FIXME: prompt for I/O config? */ @@ -266,28 +354,28 @@ Timeline::menu_cb ( Fl_Menu_ *m ) Loggable::block_end(); } - else if ( ! strcmp( picked, "Tempo from range (beat)" ) ) + else if ( ! strcmp( picked, "Tempo from edit (beat)" ) ) { - if ( p1 != p2 ) + if ( range_start() != range_end() ) { fix_range(); - beats_per_minute( p1, sample_rate() * 60 / (float)( p2 - p1 ) ); + beats_per_minute( range_start(), sample_rate() * 60 / (float)( range_end() - range_start() ) ); - p2 = p1; + range_end( range_start() ); } } - else if ( ! strcmp( picked, "Tempo from range (bar)" ) ) + else if ( ! strcmp( picked, "Tempo from edit (bar)" ) ) { - if ( p1 != p2 ) + if ( range_start() != range_end() ) { fix_range(); - position_info pi = solve_tempomap( p1 ); + position_info pi = solve_tempomap( range_start() ); - beats_per_minute( p1, sample_rate() * 60 / (float)( ( p2 - p1 ) / pi.beats_per_bar ) ); + beats_per_minute( range_start(), sample_rate() * 60 / (float)( ( range_end() - range_start() ) / pi.beats_per_bar ) ); - p2 = p1; + range_end( range_start() ); } } else if ( ! strcmp( picked, "Playhead to mouse" ) ) @@ -299,13 +387,13 @@ Timeline::menu_cb ( Fl_Menu_ *m ) transport->locate( xoffset + x_to_ts( X ) ); } } - else if ( ! strcmp( picked, "P1 to mouse" ) ) + else if ( ! strcmp( picked, "Edit start to mouse" ) ) { int X = Fl::event_x() - Track::width(); if ( X > 0 ) { - p1 = xoffset + x_to_ts( X ); + range_start( xoffset + x_to_ts( X ) ); } fix_range(); @@ -313,13 +401,13 @@ Timeline::menu_cb ( Fl_Menu_ *m ) /* FIXME: only needs to damage the location of the old cursor! */ redraw(); } - else if ( ! strcmp( picked, "P2 to mouse" ) ) + else if ( ! strcmp( picked, "Edit end to mouse" ) ) { int X = Fl::event_x() - Track::width(); if ( X > 0 ) { - p2 = xoffset + x_to_ts( X ); + range_end( xoffset + x_to_ts( X ) ); } fix_range(); @@ -355,35 +443,72 @@ Timeline::menu_cb ( Fl_Menu_ *m ) if ( next_line( &f, true ) ) transport->locate( f ); } - else if ( ! strcmp( picked, "Swap P1 and playhead" ) ) + else if ( ! strcmp( picked, "Swap edit start and playhead" ) ) { nframes_t t = transport->frame; - transport->locate( p1 ); + transport->locate( range_start() ); - p1 = t; + range_start( t ); redraw(); } - else if ( ! strcmp( picked, "Swap P2 and playhead" ) ) + else if ( ! strcmp( picked, "Swap edit end and playhead" ) ) { nframes_t t = transport->frame; - transport->locate( p2 ); + transport->locate( range_end() ); + + range_end( t ); + + redraw(); + } + else if ( ! strcmp( picked, "Edit start to playhead" ) ) + { + range_start( transport->frame ); - p2 = t; + redraw(); + } + else if ( ! strcmp( picked, "Edit end to playhead" ) ) + { + range_end( transport->frame ); redraw(); } - else if ( ! strcmp( picked, "P1 to playhead" ) ) + else if ( ! strcmp( picked, "Punch from edit" ) ) { - p1 = transport->frame; + if ( range_start() != range_end() ) + { + Loggable::block_start(); + + Cursor_Region *o = new Cursor_Region( range_start(), range_end() - range_start(), "Punch", NULL ); + reset_range(); + + Loggable::block_end(); + } redraw(); } - else if ( ! strcmp( picked, "P2 to playhead" ) ) + else if ( ! strcmp( picked, "Playback from edit" ) ) { - p2 = transport->frame; + if ( range_start() != range_end() ) + { + Loggable::block_start(); + + if ( play_cursor_track->active_cursor() ) + { + play_cursor_track->active_cursor()->start( range_start() ); + play_cursor_track->active_cursor()->set_right( range_end() ); + } + else + { + Cursor_Region *o = new Cursor_Region( range_start(), range_end() - range_start(), "Playback", NULL ); + } + + reset_range(); + + Loggable::block_end(); + } redraw(); } @@ -412,6 +537,14 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W { Loggable::snapshot_callback( &Timeline::snapshot, this ); + edit_cursor_track = NULL; + punch_cursor_track = NULL; + play_cursor_track = NULL; + + _created_new_takes = 0; + _punched_in = 0; + _punch_in_frame = 0; + _punch_out_frame = 0; osc_thread = 0; _sample_rate = 44100; @@ -425,26 +558,28 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W X = Y = 0; #endif - p1 = p2 = 0; +// range_start( range_end( 0 ) ); menu = new Fl_Menu_Button( 0, 0, 0, 0, "Timeline" ); /* menu->add( "Add Track", 0, 0, 0 ); */ - menu->add( "Add Audio Track", 'a', 0, 0 ); - menu->add( "Tempo from range (beat)", 't', 0, 0 ); - menu->add( "Tempo from range (bar)", FL_CTRL + 't', 0, 0 ); + menu->add( "Add audio track", 'a', 0, 0 ); + menu->add( "Tempo from edit (beat)", 't', 0, 0 ); + menu->add( "Tempo from edit (bar)", FL_CTRL + 't', 0, 0 ); menu->add( "Playhead to mouse", 'p', 0, 0 ); - menu->add( "P1 to mouse", '[', 0, 0 ); - menu->add( "P2 to mouse", ']', 0, 0 ); + menu->add( "Edit start to mouse", '[', 0, 0 ); + menu->add( "Edit end to mouse", ']', 0, 0 ); menu->add( "Playhead left beat", FL_SHIFT + FL_Left, 0, 0 ); menu->add( "Playhead right beat", FL_SHIFT + FL_Right, 0, 0 ); menu->add( "Playhead left bar", FL_CTRL + FL_SHIFT + FL_Left, 0, 0 ); menu->add( "Playhead right bar", FL_CTRL + FL_SHIFT + FL_Right, 0, 0 ); - menu->add( "Swap P1 and playhead", FL_CTRL + FL_SHIFT + '[', 0, 0 ); - menu->add( "Swap P2 and playhead", FL_CTRL + FL_SHIFT + ']', 0, 0 ); - menu->add( "P1 to playhead", FL_CTRL + '[', 0, 0 ); - menu->add( "P2 to playhead", FL_CTRL + ']', 0, 0 ); + menu->add( "Swap edit start and playhead", FL_CTRL + FL_SHIFT + '[', 0, 0 ); + menu->add( "Swap edit end and playhead", FL_CTRL + FL_SHIFT + ']', 0, 0 ); + menu->add( "Edit start to playhead", FL_CTRL + '[', 0, 0 ); + menu->add( "Edit end to playhead", FL_CTRL + ']', 0, 0 ); + menu->add( "Punch from edit", FL_CTRL + FL_SHIFT + 'p', 0, 0 ); + menu->add( "Playback from edit", FL_CTRL + FL_SHIFT + 'l', 0, 0 ); menu->add( "Redraw", FL_CTRL + 'l', 0, 0 ); menu_set_callback( const_cast(menu->menu()), &Timeline::menu_cb, (void*)this ); @@ -478,10 +613,11 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W o->type( Fl_Pack::VERTICAL ); { - Tempo_Sequence *o = new Tempo_Sequence( 0, 0, 800, 24 ); + Tempo_Sequence *o = new Tempo_Sequence( 0, 0, 800, 18 ); - o->color( fl_gray_ramp( 18 ) ); + o->color( FL_GRAY ); + o->labelsize( 12 ); o->label( "Tempo" ); o->align( FL_ALIGN_LEFT ); @@ -489,16 +625,55 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W } { - Time_Sequence *o = new Time_Sequence( 0, 24, 800, 24 ); + Time_Sequence *o = new Time_Sequence( 0, 24, 800, 18 ); - o->color( fl_gray_ramp( 16 ) ); + o->color( fl_lighter( FL_GRAY ) ); + o->labelsize( 12 ); o->label( "Time" ); o->align( FL_ALIGN_LEFT ); time_track = o; } + { + Cursor_Sequence *o = new Cursor_Sequence( 0, 24, 800, 18 ); + + o->color( FL_GRAY ); + + o->labelsize( 12 ); + o->label( "Edit" ); + o->align( FL_ALIGN_LEFT ); + o->cursor_color( FL_YELLOW ); + + edit_cursor_track = o; + } + + { + Cursor_Sequence *o = new Cursor_Sequence( 0, 24, 800, 18 ); + + o->color( fl_lighter( FL_GRAY ) ); + + o->labelsize( 12 ); + o->label( "Punch" ); + o->align( FL_ALIGN_LEFT ); + o->cursor_color( FL_RED ); + + punch_cursor_track = o; + } + + { + Cursor_Sequence *o = new Cursor_Sequence( 0, 24, 800, 18 ); + + o->color( FL_GRAY ); + + o->labelsize( 12 ); + o->label( "Playback" ); + o->align( FL_ALIGN_LEFT ); + o->cursor_color( FL_GREEN ); + + play_cursor_track = o; + } /* { */ /* Annotation_Sequence *o = new Annotation_Sequence( 0, 24, 800, 24 ); */ @@ -511,8 +686,8 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W /* ruler_track = o; */ /* } */ - o->size( o->w(), o->child( 0 )->h() * o->children() ); rulers = o; + o->size( o->w(), o->child( 0 )->h() * o->children() ); o->end(); } @@ -893,6 +1068,8 @@ Timeline::draw_clip ( void * v, int X, int Y, int W, int H ) fl_push_clip( tl->tracks->x(), tl->rulers->y() + tl->rulers->h(), tl->tracks->w(), tl->h() - tl->rulers->h() - tl->hscroll->h() ); tl->draw_child( *tl->tracks ); + tl->draw_cursors(); + fl_pop_clip(); fl_pop_clip(); @@ -914,20 +1091,83 @@ Timeline::resize ( int X, int Y, int W, int H ) tracks->resize( BX, BY + rulers->h(), W - vscroll->w(), H - vscroll->h() ); } -/** draw ancillary cursors (not necessarily in the overlay plane) */ + void -Timeline::draw_cursors ( void ) const +Timeline::add_cursor ( Cursor_Region *o ) +{ + if ( !strcmp( o->type(), "Edit" ) ) + { + DMESSAGE( "Adding cursor to edit track" ); + edit_cursor_track->add( o ); + } + else if ( !strcmp( o->type(), "Punch" ) ) + { + DMESSAGE( "Adding cursor to punch track" ); + punch_cursor_track->add( o ); + } + else if ( !strcmp( o->type(), "Playback" ) ) + { + DMESSAGE( "Adding cursor to punch track" ); + play_cursor_track->add( o ); + } + +} + +void +Timeline::add_cursor ( Cursor_Point *o ) { - if ( p1 != p2 ) + if ( !strcmp( o->type(), "Edit" ) ) + edit_cursor_track->add( o ); + else if ( !strcmp( o->type(), "Punch" ) ) + punch_cursor_track->add( o ); +} + +void +Timeline::draw_cursors ( Cursor_Sequence *o ) const +{ + fl_push_clip( tracks->x() + Track::width(), rulers->y() + rulers->h(), tracks->w() - Track::width(), h() - rulers->h() - hscroll->h() ); + + if ( o && o->_widgets.size() > 0 ) { - draw_cursor( p1, FL_BLUE, draw_full_arrow_symbol ); - draw_cursor( p2, FL_GREEN, draw_full_arrow_symbol ); + for ( std::list::const_iterator i = o->_widgets.begin(); + i != o->_widgets.end(); + i++ ) + { + if ( Timeline::draw_with_cursor_overlay ) + { + fl_color( fl_color_add_alpha( (*i)->box_color(), 50 ) ); + + fl_rectf( (*i)->line_x(), tracks->y(), (*i)->abs_w(), tracks->h() ); + } + + fl_color( fl_color_add_alpha( (*i)->box_color(), 127 )); + + fl_line( (*i)->line_x(), tracks->y(), (*i)->line_x(), 9000 ); + + fl_line( (*i)->line_x() + (*i)->abs_w(), tracks->y(), (*i)->line_x() + (*i)->abs_w(), tracks->h() ); + } } + + fl_pop_clip(); +} + +/** draw ancillary cursors (not necessarily in the overlay plane) */ +void +Timeline::draw_cursors ( void ) const +{ + draw_cursors( edit_cursor_track ); + + if ( transport->punch_enabled() ) + draw_cursors( punch_cursor_track ); } + void Timeline::draw ( void ) { + +// resize_rulers(); + int X, Y, W, H; int bdx = 0; @@ -943,7 +1183,7 @@ Timeline::draw ( void ) #ifndef USE_UNOPTIMIZED_DRAWING if ( ( damage() & FL_DAMAGE_ALL ) ) #else - #warning Optimized drawing of timeline disabled. This will waste your CPU. +#warning Optimized drawing of timeline disabled. This will waste your CPU. #endif { DMESSAGE( "complete redraw" ); @@ -957,12 +1197,13 @@ Timeline::draw ( void ) fl_push_clip( tracks->x(), rulers->y() + rulers->h(), tracks->w(), hscroll->y() - (rulers->y() + rulers->h()) ); draw_child( *tracks ); + draw_cursors(); + fl_pop_clip(); draw_child( *hscroll ); draw_child( *vscroll ); - draw_cursors(); redraw_overlay(); @@ -998,13 +1239,14 @@ Timeline::draw ( void ) { fl_push_clip( tracks->x(), rulers->y() + rulers->h(), tracks->w(), h() - rulers->h() - hscroll->h() ); update_child( *tracks ); + + draw_cursors(); + fl_pop_clip(); } update_child( *hscroll ); update_child( *vscroll ); - - draw_cursors(); } done: @@ -1063,13 +1305,63 @@ Timeline::redraw_playhead ( void ) static nframes_t last_playhead = -1; static int last_playhead_x = -1; - - /* FIXME: kind of a hackish way to invoke punch stop from the UI thread... */ + /* FIXME: kind of a hackish way to invoke punch / looping stuff from the UI thread... */ if ( transport->rolling && transport->rec_enabled() && - ( ( transport->punch_enabled() && range_start() != range_end() ) && transport->frame > range_end() ) ) - transport->stop(); + transport->punch_enabled() ) + { + if ( _punched_in && + transport->frame > _punch_in_frame && + transport->frame > _punch_out_frame ) + { + punch_out( _punch_out_frame ); + } + else if ( ! _punched_in ) + { + /* we've passed one or more punch regions... punch in for the next, if available. */ + const Sequence_Widget *w = punch_cursor_track->next( transport->frame ); + + if ( w && + w->start() > transport->frame ) + { + _punch_in_frame = w->start(); + _punch_out_frame = w->start() + w->length(); + + punch_in( w->start() ); + } + } + } + + + if ( transport->rolling ) + { + if ( play_cursor_track->active_cursor() ) + { + if ( Timeline::loop_playback ) + { + if ( transport->frame > playback_end() ) + { + if ( ! seek_pending() ) + { + if ( transport->recording ) + { + stop(); + transport->locate( playback_home() ); + record(); + } + else + { + transport->locate( playback_home() ); + } + } + } + } + else + if ( transport->frame > playback_end() ) + transport->stop(); + } + } int playhead_x = ts_to_x( transport->frame ); @@ -1314,8 +1606,8 @@ Timeline::handle ( int m ) if ( range ) { - p1 = x_to_offset( _selection.x ); - p2 = x_to_offset( _selection.x + _selection.w ); + range_start( x_to_offset( _selection.x ) ); + range_end( x_to_offset( _selection.x + _selection.w ) ); redraw(); } @@ -1331,8 +1623,8 @@ Timeline::handle ( int m ) if ( range ) { - p1 = x_to_offset( _selection.x ); - p2 = x_to_offset( _selection.x + _selection.w ); + range_start( x_to_offset( _selection.x ) ); + range_end( x_to_offset( _selection.x + _selection.w ) ); redraw(); } else @@ -1608,35 +1900,35 @@ Timeline::remove_track ( Track *track ) void Timeline::command_quit ( ) { - Project::close(); + Project::close(); - command_save(); + command_save(); - while ( Fl::first_window() ) Fl::first_window()->hide(); + while ( Fl::first_window() ) Fl::first_window()->hide(); } bool Timeline::command_load ( const char *name, const char *display_name ) { - if ( ! name ) - return false; + if ( ! name ) + return false; - int r = Project::open( name ); + int r = Project::open( name ); - if ( r < 0 ) - { + if ( r < 0 ) + { const char *s = Project::errstr( r ); fl_alert( "Could not open project \"%s\":\n\n\t%s", name, s ); return false; - } + } - Project::set_name ( display_name ? display_name : name ); + Project::set_name ( display_name ? display_name : name ); - apply_track_order(); + apply_track_order(); - return true; + return true; } bool @@ -1659,7 +1951,7 @@ Timeline::command_new ( const char *name, const char *display_name ) /* tle->main_window->redraw(); */ - return b; + return b; } const char * @@ -1748,11 +2040,11 @@ Timeline::reply_to_finger ( lo_message msg ) lo_address reply = lo_address_new_from_url( &argv[0]->s ); osc->send( reply, - "/non/hello", - osc->url(), - APP_NAME, - VERSION, - instance_name ); + "/non/hello", + osc->url(), + APP_NAME, + VERSION, + instance_name ); osc->hello( &argv[0]->s ); diff --git a/timeline/src/Timeline.H b/timeline/src/Timeline.H index 6c50256..1f2c269 100644 --- a/timeline/src/Timeline.H +++ b/timeline/src/Timeline.H @@ -48,10 +48,13 @@ struct BBT; class Tempo_Sequence; class Time_Sequence; class Annotation_Sequence; +class Cursor_Sequence; class Track; class Scalebar; class Sequence; class Sequence_Widget; +class Cursor_Region; +class Cursor_Point; namespace OSC { class Endpoint; } @@ -116,7 +119,7 @@ class Timeline : public Fl_Single_Window, public RWLock int _fpp; /* frames per pixel, power of two */ - nframes_t p1, p2; /* cursors */ +// nframes_t p1, p2; /* cursors */ nframes_t _playhead; /* not permitted */ @@ -147,19 +150,34 @@ public: None }; + /* configuration values */ static bool draw_with_measure_lines; + static bool draw_with_cursor_overlay; static snap_e snap_to; static bool snapping_on_hold; static bool snap_magnetic; static bool follow_playhead; static bool center_playhead; + static bool loop_playback; + static bool automatically_create_takes; + + + Tempo_Sequence *tempo_track; Time_Sequence *time_track; Annotation_Sequence *ruler_track; + Cursor_Sequence *edit_cursor_track; + Cursor_Sequence *punch_cursor_track; + Cursor_Sequence *play_cursor_track; Fl_Menu_Button *menu; + int _punched_in; + nframes_t _punch_out_frame; + nframes_t _punch_in_frame; + bool _created_new_takes; + nframes_t xoffset; int _yposition; @@ -177,8 +195,15 @@ public: nframes_t fpp ( void ) const { return 1 << _fpp; } void range ( nframes_t start, nframes_t length ); - nframes_t range_start ( void ) const { return p1; } - nframes_t range_end ( void ) const { return p2; } + + nframes_t range_start ( void ) const; + nframes_t range_end ( void ) const; + void range_start ( nframes_t n ); + void range_end ( nframes_t n ); + void reset_range ( void ); + nframes_t playback_home ( void ) const; + nframes_t playback_end ( void ) const; + // nframes_t playhead ( void ) const { return transport->frame; } nframes_t length ( void ) const; void sample_rate ( nframes_t r ) { _sample_rate = r; } @@ -205,6 +230,7 @@ public: void xposition ( int X ); void yposition ( int Y ); void draw_cursor ( nframes_t frame, Fl_Color color, void (*symbol)(Fl_Color) ) const; + void draw_cursors ( Cursor_Sequence *o ) const; void draw_cursors ( void ) const; void draw_playhead ( void ); void redraw_playhead ( void ); @@ -249,6 +275,8 @@ public: bool record ( void ); void stop ( void ); + void punch_in ( nframes_t frame ); + void punch_out ( nframes_t frame ); void wait_for_buffers ( void ); bool seek_pending ( void ); @@ -274,8 +302,13 @@ public: void reply_to_finger ( lo_message msg ); -private: + void add_cursor ( Cursor_Region *o ); + void add_cursor ( Cursor_Point *o ); +private: + + void add_take_for_armed_tracks(); + void resize_rulers ( void ); static void snapshot ( void *v ) { ((Timeline*)v)->snapshot(); } void snapshot ( void ); diff --git a/timeline/src/Transport.C b/timeline/src/Transport.C index 7490271..ea531a5 100644 --- a/timeline/src/Transport.C +++ b/timeline/src/Transport.C @@ -84,7 +84,7 @@ Transport::Transport ( int X, int Y, int W, int H, const char *L ) o->shortcut( 'P' ); o->callback( cb_button, this ); o->when( FL_WHEN_CHANGED ); - o->color2( FL_GREEN ); + o->color2( FL_RED ); o->box( FL_UP_BOX ); end(); @@ -135,13 +135,15 @@ void Transport::cb_button ( Fl_Widget *w ) { if ( w == _home_button ) - locate( 0 ); + locate( timeline->playback_home() ); else if ( w == _end_button ) - locate( timeline->length() ); + locate( timeline->playback_end() ); else if ( w == _play_button ) toggle(); else if ( w == _record_button ) update_record_state(); + else if ( w == _punch_button ) + timeline->redraw(); } void @@ -196,8 +198,15 @@ Transport::locate ( nframes_t frame ) return; if ( ! recording ) + { // don't allow seeking while record is in progress engine->transport_locate( frame ); + + /* so there isn't a race waiting for the transport to sync */ + this->frame = frame; + } + + timeline->_created_new_takes = false; } @@ -224,6 +233,8 @@ Transport::stop ( void ) if ( _stop_disables_record ) _record_button->value( 0 ); + timeline->_created_new_takes = false; + update_record_state(); } diff --git a/timeline/src/main.C b/timeline/src/main.C index 00d4868..61457e6 100644 --- a/timeline/src/main.C +++ b/timeline/src/main.C @@ -37,6 +37,7 @@ #include "Time_Sequence.H" #include "Annotation_Sequence.H" #include "Control_Sequence.H" +#include "Cursor_Sequence.H" #include "Track.H" #include "TLE.H" @@ -184,6 +185,8 @@ main ( int argc, char **argv ) LOG_REGISTER_CREATE( Control_Sequence ); LOG_REGISTER_CREATE( Tempo_Point ); LOG_REGISTER_CREATE( Time_Point ); + LOG_REGISTER_CREATE( Cursor_Point ); + LOG_REGISTER_CREATE( Cursor_Region ); LOG_REGISTER_CREATE( Track ); signal( SIGPIPE, SIG_IGN );