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