Timeline: Implement new cursor system.

This adds new cursor rulers for edit, punch and playback.  P1/P2 are now known as the
Edit Cursor. Multiple Punch Cursors may be defined. The playback cursor affects Home and End
controls. New options are available for looping over the playback cursor (even while recording)
and automatically creating new takes at start of recording (or loop).

The new cursor objects bump the project file version. Older versions of non-daw will be
unable to load new/edited projects.
pull/3/head
Jonathan Moore Liles 2012-10-23 22:44:19 -07:00
parent bcfa3953b1
commit 2f06f509d7
22 changed files with 1123 additions and 145 deletions

View File

@ -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;
}

View File

@ -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 );

View File

@ -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 );

140
timeline/src/Cursor_Point.C Normal file
View File

@ -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 );
}

View File

@ -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 );
};

View File

@ -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 <FL/Fl_Tooltip.H>
#include <FL/fl_ask.H>
#include <FL/fl_draw.H>
#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;
}

View File

@ -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 );
}
};

View File

@ -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;
}
}

View File

@ -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 );
};

View File

@ -26,6 +26,7 @@
#include "Playback_DS.H"
#include "Thread.H"
#include "../Cursor_Sequence.H"
#include <unistd.h>
@ -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();

View File

@ -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 )

View File

@ -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 <Sequence_Widget*>::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 <Sequence_Widget*>::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;
}

View File

@ -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; }

View File

@ -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 );

View File

@ -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 ) );
}

View File

@ -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 );

View File

@ -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 )
{

View File

@ -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
}
}
}
}

View File

@ -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 <unistd.h>
#include <nsm.h>
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() );
p2 = t;
range_end( t );
redraw();
}
else if ( ! strcmp( picked, "P1 to playhead" ) )
else if ( ! strcmp( picked, "Edit start to playhead" ) )
{
p1 = transport->frame;
range_start( transport->frame );
redraw();
}
else if ( ! strcmp( picked, "P2 to playhead" ) )
else if ( ! strcmp( picked, "Edit end to playhead" ) )
{
p2 = transport->frame;
range_end( transport->frame );
redraw();
}
else if ( ! strcmp( picked, "Punch from edit" ) )
{
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, "Playback from edit" ) )
{
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<Fl_Menu_Item*>(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() );
}
void
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 ( !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 )
{
for ( std::list<Sequence_Widget*>::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
{
if ( p1 != p2 )
{
draw_cursor( p1, FL_BLUE, draw_full_arrow_symbol );
draw_cursor( p2, FL_GREEN, draw_full_arrow_symbol );
}
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 );

View File

@ -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 );

View File

@ -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();
}

View File

@ -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 );