Implement storage and loading of unjournaled state for Loggable objects.
This commit is contained in:
parent
8dc6681a53
commit
15a579774c
|
@ -90,6 +90,35 @@ unescape ( char *s )
|
||||||
*r = '\0';
|
*r = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** return a dynamically allocated string representing this log entry */
|
||||||
|
char *
|
||||||
|
Log_Entry::print ( void ) const
|
||||||
|
{
|
||||||
|
/* FIXME: gross over-allocation */
|
||||||
|
char *r = (char*)malloc( 1024 );
|
||||||
|
|
||||||
|
r[0] = 0;
|
||||||
|
|
||||||
|
for ( int i = 0; i < size(); ++i )
|
||||||
|
{
|
||||||
|
const char *s, *v;
|
||||||
|
|
||||||
|
get( i, &s, &v );
|
||||||
|
|
||||||
|
/* FIXME: arbitrary limit */
|
||||||
|
char t[1024];
|
||||||
|
snprintf( t, sizeof( t ), "%s %s%s", s, v, size() == i + 1 ? "" : " " );
|
||||||
|
|
||||||
|
strcat( r, t );
|
||||||
|
}
|
||||||
|
|
||||||
|
char *r2 = (char*)malloc( strlen( r ) + 1 );
|
||||||
|
|
||||||
|
strcpy( r2, r );
|
||||||
|
|
||||||
|
return r2;
|
||||||
|
}
|
||||||
|
|
||||||
/** sigh. parse a string of ":name value :name value" pairs into an
|
/** sigh. parse a string of ":name value :name value" pairs into an
|
||||||
* array of strings, one per pair */
|
* array of strings, one per pair */
|
||||||
// FIXME: doesn't handle the case of :name ":foo bar", nested quotes
|
// FIXME: doesn't handle the case of :name ":foo bar", nested quotes
|
||||||
|
|
|
@ -67,6 +67,8 @@ public:
|
||||||
void get ( int n, const char **name, const char **value ) const;
|
void get ( int n, const char **name, const char **value ) const;
|
||||||
char **sa ( void );
|
char **sa ( void );
|
||||||
|
|
||||||
|
char *print ( void ) const;
|
||||||
|
|
||||||
/* #define ADD ( type, format, exp ) \ */
|
/* #define ADD ( type, format, exp ) \ */
|
||||||
/* void add ( const char *name, type v ) \ */
|
/* void add ( const char *name, type v ) \ */
|
||||||
/* { \ */
|
/* { \ */
|
||||||
|
|
|
@ -50,6 +50,8 @@ off_t Loggable::_undo_offset = 0;
|
||||||
|
|
||||||
size_t Loggable::_loggables_size = 0;
|
size_t Loggable::_loggables_size = 0;
|
||||||
Loggable ** Loggable::_loggables;
|
Loggable ** Loggable::_loggables;
|
||||||
|
std::map <unsigned int, Log_Entry *> Loggable::_loggables_unjournaled;
|
||||||
|
|
||||||
std::map <std::string, create_func*> Loggable::_class_map;
|
std::map <std::string, create_func*> Loggable::_class_map;
|
||||||
std::queue <char *> Loggable::_transaction;
|
std::queue <char *> Loggable::_transaction;
|
||||||
|
|
||||||
|
@ -59,6 +61,14 @@ void *Loggable::_progress_callback_arg = NULL;
|
||||||
snapshot_func *Loggable::_snapshot_callback = NULL;
|
snapshot_func *Loggable::_snapshot_callback = NULL;
|
||||||
void *Loggable::_snapshot_callback_arg = NULL;
|
void *Loggable::_snapshot_callback_arg = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loggable::~Loggable ( )
|
||||||
|
{
|
||||||
|
_loggables[ _id - 1 ] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** ensure that _loggables array is big enough for /n/ elements */
|
/** ensure that _loggables array is big enough for /n/ elements */
|
||||||
|
@ -121,6 +131,8 @@ Loggable::open ( const char *filename )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
load_unjournaled_state();
|
||||||
|
|
||||||
if ( newer( "snapshot", filename ) )
|
if ( newer( "snapshot", filename ) )
|
||||||
{
|
{
|
||||||
MESSAGE( "Loading snapshot" );
|
MESSAGE( "Loading snapshot" );
|
||||||
|
@ -146,6 +158,33 @@ Loggable::open ( const char *filename )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Loggable::load_unjournaled_state ( void )
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen( "unjournaled", "r" );
|
||||||
|
|
||||||
|
if ( ! fp )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned int id;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
|
while ( fscanf( fp, "%X set %[^\n]\n", &id, buf ) == 2 )
|
||||||
|
{
|
||||||
|
Log_Entry *e = new Log_Entry( buf );
|
||||||
|
|
||||||
|
_loggables_unjournaled[ id - 1 ] = e;
|
||||||
|
|
||||||
|
Loggable *l = Loggable::find( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -214,11 +253,45 @@ Loggable::close ( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save_unjournaled_state();
|
||||||
|
|
||||||
_log_id = 0;
|
_log_id = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** save out unjournaled state for all loggables */
|
||||||
|
bool
|
||||||
|
Loggable::save_unjournaled_state ( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* FIXME: check for errors */
|
||||||
|
FILE *fp = fopen( "unjournaled", "w" );
|
||||||
|
|
||||||
|
/* write out the unjournaled state of all currently active
|
||||||
|
* loggables */
|
||||||
|
for ( int i = 0; i < _log_id - 1; ++i )
|
||||||
|
{
|
||||||
|
Log_Entry *e = _loggables_unjournaled[ i ];
|
||||||
|
|
||||||
|
if ( e )
|
||||||
|
{
|
||||||
|
char *s = e->print();
|
||||||
|
|
||||||
|
fprintf( fp, "0x%X set %s\n", i + 1, s );
|
||||||
|
|
||||||
|
free( s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write out the remembered state of inactive loggables. */
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** must be called after construction in create() methods */
|
/** must be called after construction in create() methods */
|
||||||
void
|
void
|
||||||
Loggable::update_id ( unsigned int id )
|
Loggable::update_id ( unsigned int id )
|
||||||
|
@ -338,6 +411,12 @@ Loggable::do_this ( const char *s, bool reverse )
|
||||||
/* create */
|
/* create */
|
||||||
Loggable *l = _class_map[ std::string( classname ) ]( e, id );
|
Loggable *l = _class_map[ std::string( classname ) ]( e, id );
|
||||||
l->log_create();
|
l->log_create();
|
||||||
|
|
||||||
|
/* we're now creating a loggable. Apply any unjournaled
|
||||||
|
* state it may have had in the past under this log ID */
|
||||||
|
|
||||||
|
if ( _loggables_unjournaled[ id - 1 ] )
|
||||||
|
l->set( *_loggables_unjournaled[ id - 1 ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -391,29 +470,6 @@ Loggable::undo ( void )
|
||||||
_undo_offset = uo;
|
_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 )
|
|
||||||
{
|
|
||||||
unsigned int id = 0;
|
|
||||||
for ( unsigned int i = 0; i < _log_id; ++i )
|
|
||||||
if ( _loggables[ i ] )
|
|
||||||
{
|
|
||||||
++id;
|
|
||||||
|
|
||||||
if ( _loggables[ id - 1 ] )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_loggables[ id - 1 ] = _loggables[ i ];
|
|
||||||
_loggables[ i ] = NULL;
|
|
||||||
_loggables[ id - 1 ]->_id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
_log_id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** write a snapshot of the current state of all loggable objects to
|
/** write a snapshot of the current state of all loggable objects to
|
||||||
* file handle /fp/ */
|
* file handle /fp/ */
|
||||||
bool
|
bool
|
||||||
|
@ -468,7 +524,6 @@ Loggable::compact ( void )
|
||||||
fseek( _fp, 0, SEEK_SET );
|
fseek( _fp, 0, SEEK_SET );
|
||||||
ftruncate( fileno( _fp ), 0 );
|
ftruncate( fileno( _fp ), 0 );
|
||||||
|
|
||||||
compact_ids();
|
|
||||||
if ( ! snapshot( _fp ) )
|
if ( ! snapshot( _fp ) )
|
||||||
FATAL( "Could not write snapshot!" );
|
FATAL( "Could not write snapshot!" );
|
||||||
|
|
||||||
|
@ -654,11 +709,37 @@ Loggable::log_create ( void ) const
|
||||||
Loggable::flush();
|
Loggable::flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** record this loggable's unjournaled state in memory */
|
||||||
|
void
|
||||||
|
Loggable::record_unjournaled ( void ) const
|
||||||
|
{
|
||||||
|
Log_Entry *e = new Log_Entry();
|
||||||
|
|
||||||
|
get_unjournaled( *e );
|
||||||
|
|
||||||
|
Log_Entry **le = &_loggables_unjournaled[ _id - 1 ];
|
||||||
|
|
||||||
|
if ( *le )
|
||||||
|
delete *le;
|
||||||
|
|
||||||
|
if ( e->size() )
|
||||||
|
{
|
||||||
|
*le = e;
|
||||||
|
DMESSAGE( "logging %s", (*le)->print() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* don't waste space on loggables with no unjournaled properties */
|
||||||
|
*le = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/** Log object destruction. *Must* be called at the beginning of the
|
/** Log object destruction. *Must* be called at the beginning of the
|
||||||
* destructors of leaf classes */
|
* destructors of leaf classes */
|
||||||
void
|
void
|
||||||
Loggable::log_destroy ( void ) const
|
Loggable::log_destroy ( void ) const
|
||||||
{
|
{
|
||||||
|
/* the unjournaled state may have changed: make a note of it. */
|
||||||
|
record_unjournaled();
|
||||||
|
|
||||||
if ( ! _fp )
|
if ( ! _fp )
|
||||||
/* tearing down... don't bother */
|
/* tearing down... don't bother */
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -73,6 +73,7 @@ class Loggable
|
||||||
|
|
||||||
static size_t _loggables_size;
|
static size_t _loggables_size;
|
||||||
static Loggable ** _loggables;
|
static Loggable ** _loggables;
|
||||||
|
static std::map <unsigned int, Log_Entry *> _loggables_unjournaled;
|
||||||
|
|
||||||
static std::map <std::string, create_func*> _class_map;
|
static std::map <std::string, create_func*> _class_map;
|
||||||
|
|
||||||
|
@ -94,13 +95,14 @@ private:
|
||||||
|
|
||||||
static void ensure_size ( size_t n );
|
static void ensure_size ( size_t n );
|
||||||
|
|
||||||
void log_print( const Log_Entry *o, const Log_Entry *n ) const;
|
void log_print ( const Log_Entry *o, const Log_Entry *n ) const;
|
||||||
static void log ( const char *fmt, ... );
|
static void log ( const char *fmt, ... );
|
||||||
|
|
||||||
static void flush ( void );
|
static void flush ( void );
|
||||||
|
|
||||||
static bool snapshot( FILE * fp );
|
static bool snapshot ( FILE * fp );
|
||||||
static bool snapshot( const char *name );
|
static bool snapshot ( const char *name );
|
||||||
|
static bool save_unjournaled_state ( void );
|
||||||
static bool replay ( FILE *fp );
|
static bool replay ( FILE *fp );
|
||||||
|
|
||||||
void init ( bool loggable=true )
|
void init ( bool loggable=true )
|
||||||
|
@ -125,7 +127,8 @@ private:
|
||||||
/* not implemented */
|
/* not implemented */
|
||||||
const Loggable & operator= ( const Loggable &rhs );
|
const Loggable & operator= ( const Loggable &rhs );
|
||||||
|
|
||||||
static void compact_ids ( void );
|
void record_unjournaled ( void ) const;
|
||||||
|
static bool load_unjournaled_state ( void );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -153,10 +156,7 @@ public:
|
||||||
|
|
||||||
void update_id ( unsigned int id );
|
void update_id ( unsigned int id );
|
||||||
|
|
||||||
virtual ~Loggable ( )
|
virtual ~Loggable ( );
|
||||||
{
|
|
||||||
_loggables[ _id - 1 ] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
|
@ -167,6 +167,10 @@ public:
|
||||||
|
|
||||||
/* log messages for journal */
|
/* log messages for journal */
|
||||||
virtual void get ( Log_Entry &e ) const = 0;
|
virtual void get ( Log_Entry &e ) const = 0;
|
||||||
|
virtual void get_unjournaled ( Log_Entry & ) const
|
||||||
|
{
|
||||||
|
/* implementation optional */
|
||||||
|
}
|
||||||
virtual void set ( Log_Entry &e ) = 0;
|
virtual void set ( Log_Entry &e ) = 0;
|
||||||
|
|
||||||
virtual const char *class_name ( void ) const = 0;
|
virtual const char *class_name ( void ) const = 0;
|
||||||
|
|
|
@ -176,7 +176,6 @@ Project::close ( void )
|
||||||
tle->save_timeline_settings();
|
tle->save_timeline_settings();
|
||||||
|
|
||||||
Loggable::close();
|
Loggable::close();
|
||||||
|
|
||||||
// write_info();
|
// write_info();
|
||||||
|
|
||||||
_is_open = false;
|
_is_open = false;
|
||||||
|
|
|
@ -73,21 +73,25 @@ Track::Track ( ) : Fl_Group( 0, 0, 1, 1 )
|
||||||
timeline->add_track( this );
|
timeline->add_track( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Track::~Track ( )
|
Track::~Track ( )
|
||||||
{
|
{
|
||||||
Loggable::block_start();
|
Loggable::block_start();
|
||||||
|
|
||||||
|
/* must destroy sequences first to preserve proper log order */
|
||||||
|
takes->clear();
|
||||||
|
control->clear();
|
||||||
|
annotation->clear();
|
||||||
|
delete sequence();
|
||||||
|
|
||||||
takes = NULL;
|
takes = NULL;
|
||||||
control = NULL;
|
control = NULL;
|
||||||
annotation = NULL;
|
annotation = NULL;
|
||||||
|
|
||||||
solo( false );
|
|
||||||
|
|
||||||
Fl_Group::clear();
|
|
||||||
|
|
||||||
log_destroy();
|
log_destroy();
|
||||||
|
|
||||||
|
/* ensure that soloing accounting is performed */
|
||||||
|
solo( false );
|
||||||
|
|
||||||
timeline->remove_track( this );
|
timeline->remove_track( this );
|
||||||
|
|
||||||
/* give up our ports */
|
/* give up our ports */
|
||||||
|
@ -101,6 +105,7 @@ Track::~Track ( )
|
||||||
|
|
||||||
Loggable::block_end();
|
Loggable::block_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "FL/Boxtypes.H"
|
#include "FL/Boxtypes.H"
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -258,6 +263,12 @@ Track::set ( Log_Entry &e )
|
||||||
}
|
}
|
||||||
else if ( ! strcmp( s, ":show-all-takes" ) )
|
else if ( ! strcmp( s, ":show-all-takes" ) )
|
||||||
show_all_takes( atoi( v ) );
|
show_all_takes( atoi( v ) );
|
||||||
|
else if ( ! strcmp( s, ":solo" ) )
|
||||||
|
solo( atoi( v ) );
|
||||||
|
else if ( ! strcmp( s, ":mute" ) )
|
||||||
|
mute( atoi( v ) );
|
||||||
|
else if ( ! strcmp( s, ":arm" ) )
|
||||||
|
armed( atoi( v ) );
|
||||||
else if ( ! strcmp( s, ":sequence" ) )
|
else if ( ! strcmp( s, ":sequence" ) )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -290,11 +301,19 @@ Track::get ( Log_Entry &e ) const
|
||||||
e.add( ":name", _name );
|
e.add( ":name", _name );
|
||||||
e.add( ":sequence", sequence() );
|
e.add( ":sequence", sequence() );
|
||||||
e.add( ":selected", _selected );
|
e.add( ":selected", _selected );
|
||||||
|
e.add( ":color", (unsigned long)color());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Track::get_unjournaled ( Log_Entry &e ) const
|
||||||
|
{
|
||||||
e.add( ":height", size() );
|
e.add( ":height", size() );
|
||||||
e.add( ":inputs", input.size() );
|
e.add( ":inputs", input.size() );
|
||||||
e.add( ":outputs", output.size() );
|
e.add( ":outputs", output.size() );
|
||||||
e.add( ":color", (unsigned long)color());
|
|
||||||
e.add( ":show-all-takes", _show_all_takes );
|
e.add( ":show-all-takes", _show_all_takes );
|
||||||
|
e.add( ":armed", armed() );
|
||||||
|
e.add( ":mute", mute() );
|
||||||
|
e.add( ":solo", solo() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -104,6 +104,7 @@ private:
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void get ( Log_Entry &e ) const;
|
void get ( Log_Entry &e ) const;
|
||||||
|
void get_unjournaled ( Log_Entry &e ) const;
|
||||||
void set ( Log_Entry &e );
|
void set ( Log_Entry &e );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -177,11 +178,15 @@ public:
|
||||||
|
|
||||||
const char * name ( void ) const { return _name; }
|
const char * name ( void ) const { return _name; }
|
||||||
bool mute ( void ) const { return mute_button->value(); }
|
bool mute ( void ) const { return mute_button->value(); }
|
||||||
|
void mute ( bool b ) { mute_button->value( b ); }
|
||||||
bool solo ( void ) const { return solo_button->value(); }
|
bool solo ( void ) const { return solo_button->value(); }
|
||||||
|
void solo ( bool b );
|
||||||
|
|
||||||
bool armed ( void ) const { return record_button->value(); }
|
bool armed ( void ) const { return record_button->value(); }
|
||||||
|
void armed ( bool b ) { record_button->value( b ); }
|
||||||
|
|
||||||
bool selected ( void ) const { return _selected; }
|
bool selected ( void ) const { return _selected; }
|
||||||
|
|
||||||
void solo ( bool b );
|
|
||||||
|
|
||||||
static void cb_input_field ( Fl_Widget *w, void *v );
|
static void cb_input_field ( Fl_Widget *w, void *v );
|
||||||
void cb_input_field ( void );
|
void cb_input_field ( void );
|
||||||
|
|
Loading…
Reference in New Issue