Browse Source

Make nonlib smaller by removing files that were only for sequencer, timeline and mixer

tags/v1.2.1
Nils 5 years ago
parent
commit
596db80257
27 changed files with 3 additions and 5272 deletions
  1. +0
    -59
      nonlib/Block_Timer.H
  2. +0
    -338
      nonlib/JACK/Client.C
  3. +0
    -130
      nonlib/JACK/Client.H
  4. +0
    -456
      nonlib/JACK/Port.C
  5. +0
    -115
      nonlib/JACK/Port.H
  6. +0
    -17
      nonlib/JACK/makefile.inc
  7. +0
    -308
      nonlib/Log_Entry.C
  8. +0
    -104
      nonlib/Log_Entry.H
  9. +0
    -906
      nonlib/Loggable.C
  10. +0
    -280
      nonlib/Loggable.H
  11. +0
    -164
      nonlib/MIDI/event.C
  12. +0
    -100
      nonlib/MIDI/event.H
  13. +0
    -721
      nonlib/MIDI/event_list.C
  14. +0
    -94
      nonlib/MIDI/event_list.H
  15. +0
    -221
      nonlib/MIDI/midievent.C
  16. +0
    -237
      nonlib/MIDI/midievent.H
  17. +0
    -28
      nonlib/MIDI/types.h
  18. +0
    -81
      nonlib/Mutex.H
  19. +0
    -298
      nonlib/NSM/Client.C
  20. +0
    -109
      nonlib/NSM/Client.H
  21. +0
    -270
      nonlib/dsp.C
  22. +0
    -88
      nonlib/dsp.h
  23. +0
    -91
      nonlib/string_util.C
  24. +0
    -21
      nonlib/string_util.h
  25. +0
    -25
      nonlib/types.h
  26. +2
    -11
      nonlib/wscript
  27. +1
    -0
      session-manager/src/nsmd.cpp

+ 0
- 59
nonlib/Block_Timer.H View File

@@ -1,59 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2010 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 <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

class Block_Timer
{

unsigned long long ts;
const char *prefix;

unsigned long long tv_to_ts ( timeval *tv )
{
return tv->tv_sec * 1e6 + tv->tv_usec;
}

public:

Block_Timer ( const char *prefix )
{
this->prefix = prefix;

timeval tv;

gettimeofday( &tv, NULL );

ts = tv_to_ts( &tv );
}

~Block_Timer ( )
{
timeval tv;

gettimeofday( &tv, NULL );

fprintf( stderr, "[%Lfms] %s\n", ((long double)tv_to_ts( &tv ) - ts ) / 1000, prefix );
}
};

+ 0
- 338
nonlib/JACK/Client.C View File

@@ -1,338 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "Client.H"
#include "Port.H"

#include <algorithm>


#include "debug.h"

#ifdef __SSE2_MATH__
#include <xmmintrin.h>
#endif

namespace JACK
{

// nframes_t Client::_sample_rate = 0;

Client::Client ( )
{
_active = false;
_freewheeling = false;
_zombified = false;
_client = NULL;
_xruns = 0;
}

Client::~Client ( )
{
close();
}

/** Tell JACK to stop calling process callback. This MUST be called in
* an inheriting class' destructor */
void
Client::deactivate ( )
{
if ( _active )
jack_deactivate( _client );

_active = false;
}

/*******************/
/* Static Wrappers */
/*******************/

int
Client::process ( nframes_t nframes, void *arg )
{
Client *c = (Client*)arg;
if ( ! c->_frozen.trylock() )
return 0;
int r = c->process(nframes);

c->_frozen.unlock();

return r;
}

int
Client::sync ( jack_transport_state_t state, jack_position_t *pos, void *arg )
{
return ((Client*)arg)->sync( state, pos );
}

int
Client::xrun ( void *arg )
{
++((Client*)arg)->_xruns;
return ((Client*)arg)->xrun();
}

void
Client::timebase ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg )
{
((Client*)arg)->timebase( state, nframes, pos, new_pos );
}

void
Client::freewheel ( int starting, void *arg )
{
((Client*)arg)->_freewheeling = starting;
((Client*)arg)->freewheel( starting );
}

int
Client::buffer_size ( nframes_t nframes, void *arg )
{
return ((Client*)arg)->buffer_size( nframes );
}

void
Client::thread_init ( void *arg )
{
#ifdef __SSE2_MATH__
/* set FTZ and DAZ flags */
_mm_setcsr(_mm_getcsr() | 0x8040);
#endif

((Client*)arg)->thread_init();
}

void
Client::latency ( jack_latency_callback_mode_t mode, void *arg )
{
((Client*)arg)->latency( mode );
}

void
Client::shutdown ( void *arg )
{
((Client*)arg)->_zombified = true;
((Client*)arg)->shutdown();
}

void
Client::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg )
{
Client *c = (Client*)arg;
if (! c->_frozen.trylock() )
return;

((Client*)arg)->port_connect( a, b, connect );
c->_frozen.unlock();
}

int
Client::sample_rate_changed ( nframes_t srate, void *arg )
{
// ((Client*)arg)->_sample_rate = srate;
return ((Client*)arg)->sample_rate_changed( srate );
}

void
Client::activate ( void )
{
jack_activate( _client );
_active = true;
}

/** Connect to JACK using client name /client_name/. Return a static
* pointer to actual name as reported by JACK */
const char *
Client::init ( const char *client_name, unsigned int opts )
{
if (( _client = jack_client_open ( client_name, (jack_options_t)0, NULL )) == 0 )
return NULL;

#define set_callback( name ) jack_set_ ## name ## _callback( _client, &Client:: name , this )

set_callback( thread_init );
set_callback( process );
set_callback( xrun );
set_callback( freewheel );
set_callback( buffer_size );
set_callback( port_connect );

jack_set_sample_rate_callback( _client, &Client::sample_rate_changed, this );
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
set_callback( latency );
#endif

/* FIXME: should we wait to register this until after the project
has been loaded (and we have disk threads running)? */
if ( opts & SLOW_SYNC )
set_callback( sync );

if ( opts & TIMEBASE_MASTER )
jack_set_timebase_callback( _client, 0, &Client::timebase, this );

jack_on_shutdown( _client, &Client::shutdown, this );

activate();

// _sample_rate = frame_rate();

return jack_get_client_name( _client );
}

/* THREAD: RT */
/** enter or leave freehweeling mode */
void
Client::freewheeling ( bool yes )
{
if ( jack_set_freewheel( _client, yes ) )
;
// WARNING( "Unkown error while setting freewheeling mode" );
}
const char *
Client::jack_name ( void ) const
{
return jack_get_client_name( _client );
}

void
Client::port_added ( Port *p )
{
std::list < JACK::Port * >::iterator i = std::find( _active_ports.begin(), _active_ports.end(), p );

if ( i != _active_ports.end() )
return;

_active_ports.push_back( p );
}

void
Client::port_removed ( Port *p )
{
_active_ports.remove( p );
}


void
Client::freeze_ports ( void )
{
for ( std::list < JACK::Port * >::iterator i = _active_ports.begin();
i != _active_ports.end();
++i )
{
(*i)->freeze();
}
}

void
Client::thaw_ports ( void )
{
/* Sort ports for the sake of clients (e.g. patchage), for
* whom the order of creation may matter (for display) */

_active_ports.sort();

for ( std::list < JACK::Port * >::iterator i = _active_ports.begin();
i != _active_ports.end();
++i )
{
(*i)->thaw();
}
}

void
Client::close ( void )
{
deactivate();
if ( _client )
{
DMESSAGE( "Closing JACK client" );
jack_client_close( _client );
}

_client = NULL;
}

const char *
Client::name ( const char *s )
{
/* Because the JACK API does not provide a mechanism for renaming
* clients, we have to save connections, destroy our client,
* create a client with the new name, and restore our
* connections. Lovely. */


freeze_ports();

jack_deactivate( _client );
jack_client_close( _client );

_client = NULL;

_frozen.lock();

s = init( s );

thaw_ports();
_frozen.unlock();

return s;
}

void
Client::recompute_latencies ( void )
{
jack_recompute_total_latencies( _client );
}

void
Client::transport_stop ( )
{
jack_transport_stop( _client );
}

void
Client::transport_start ( )
{
jack_transport_start( _client );
}

void
Client::transport_locate ( nframes_t frame )
{
jack_transport_locate( _client, frame );
}

jack_transport_state_t
Client::transport_query ( jack_position_t *pos )
{
return jack_transport_query( _client, pos );
}
}

+ 0
- 130
nonlib/JACK/Client.H View File

@@ -1,130 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 <jack/jack.h>
#include <jack/midiport.h>
#ifdef HAVE_JACK_METADATA
# include <jack/metadata.h>
#endif
#include <Mutex.H>

typedef jack_nframes_t nframes_t;
typedef jack_default_audio_sample_t sample_t;

#include <list>

namespace JACK
{
class Port;
class Client
{
std::list <JACK::Port*> _active_ports;

Mutex _frozen;

jack_client_t *_client;

// nframes_t _sample_rate;
volatile int _xruns;
volatile bool _freewheeling;
volatile bool _zombified;
volatile bool _active;

static int sample_rate_changed ( nframes_t srate, void *arg );
virtual int sample_rate_changed ( nframes_t srate ) { return 0; }
static void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg );
virtual void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect ) { }
static void shutdown ( void *arg );
virtual void shutdown ( void ) = 0;
static int process ( nframes_t nframes, void *arg );
virtual int process ( nframes_t nframes ) = 0;
static int sync ( jack_transport_state_t state, jack_position_t *pos, void *arg );
virtual int sync ( jack_transport_state_t, jack_position_t * ) { return 1; }
static int xrun ( void *arg );
virtual int xrun ( void ) = 0;
static void timebase ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *arg );
virtual void timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *, int ) { }
static void freewheel ( int yes, void *arg );
virtual void freewheel ( bool yes ) = 0;
static int buffer_size ( nframes_t nframes, void *arg );
virtual int buffer_size ( nframes_t nframes ) = 0;
static void thread_init ( void *arg );
virtual void thread_init ( void ) = 0;

static void latency ( jack_latency_callback_mode_t mode, void *arg );
virtual void latency ( jack_latency_callback_mode_t mode ) { }
Client ( const Client &rhs );
Client & operator = ( const Client &rhs );

void freeze_ports ( void );
void thaw_ports ( void );

protected:
bool active ( void ) const { return _active; }
void deactivate ( void );
void activate ( void );

private:

friend class Port;
friend class Transport;

public:

enum options { DEFAULT = 0,
SLOW_SYNC = 1 << 0,
TIMEBASE_MASTER = 1 << 1 };

jack_client_t * jack_client ( void ) const { return _client; }

void port_added ( JACK::Port * p );
void port_removed ( JACK::Port *p );

Client ( );
virtual ~Client ( );

const char * init ( const char *client_name, unsigned int opts = 0 );
const char * name ( const char * );

const char *jack_name ( void ) const;

void close ( void );
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 jack_get_sample_rate( _client ); }
int xruns ( void ) const { return _xruns; };
bool freewheeling ( void ) const { return _freewheeling; }
void freewheeling ( bool yes );
bool zombified ( void ) const { return _zombified; }
float cpu_load ( void ) const { return jack_cpu_load( _client ); }

void transport_stop ( void );
void transport_start ( void );
void transport_locate ( nframes_t frame );
jack_transport_state_t transport_query ( jack_position_t *pos );
void recompute_latencies ( void );

static int maximum_name_length ( void ) { return jack_client_name_size(); }
};
}

+ 0
- 456
nonlib/JACK/Port.C View File

@@ -1,456 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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. */
/*******************************************************************************/

/* Wrapper for a JACK audio port */

#include "Port.H"

#include <string.h>
#include <stdio.h> // sprintf
#include <errno.h>

#include <assert.h>
#include "debug.h"

namespace JACK
{

/* static char *name_for_port ( Port::direction_e dir, const char *base, int n, const char *type ); */

int
Port::max_name ( void )
{
return jack_port_name_size() - jack_client_name_size() - 6;
}
Port::Port ( const Port &rhs )
{
_connections = NULL;
_terminal = rhs._terminal;
// _connections = rhs._connections;
_client = rhs._client;
_port = rhs._port;
_direction = rhs._direction;
_type = rhs._type;
_name = NULL;
_name = strdup( rhs._name );
_trackname = NULL;
if ( rhs._trackname )
_trackname = strdup( rhs._trackname );
_client->port_added( this );
}

/* nframes is the number of frames to buffer */
Port::Port ( JACK::Client *client, jack_port_t *port )
{
_terminal = 0;
_connections = NULL;
_client = client;
_port = port;
_name = strdup( jack_port_name( port ) );
_trackname = NULL;
_direction = ( jack_port_flags( _port ) & JackPortIsOutput ) ? Output : Input;
const char *type = jack_port_type( _port );

_type = Audio;
if ( strstr( type, "MIDI") )
_type = MIDI;
else if ( strstr( type, "CV)") )
_type = CV;

_client->port_added( this );

}

Port::Port ( JACK::Client *client, const char *trackname, const char *name, direction_e dir, type_e type )
{
_port = 0;
_terminal = 0;
_name = NULL;
_trackname = NULL;
_connections = NULL;
_client = client;
_direction = dir;
_type = type;
_trackname = NULL;

if ( trackname )
_trackname = strdup( trackname );

_name = strdup( name );

_client->port_added( this );
}

/* Port::Port ( JACK::Client *client, direction_e dir, type_e type, const char *base, int n, const char *subtype ) */
/* { */
/* _port = 0; */
/* _terminal = 0; */
/* _name = NULL; */
/* _connections = NULL; */
/* _client = client; */

/* _name = name_for_port( dir, base, n, subtype ); */
/* _direction = dir; */
/* _type = type; */

/* _client->port_added( this ); */
/* } */

/* Port::Port ( JACK::Client *client, direction_e dir, type_e type, int n, const char *subtype ) */
/* { */
/* _port = 0; */
/* _terminal = 0; */
/* _name = NULL; */
/* _connections = NULL; */
/* _client = client; */

/* _name = name_for_port( dir, NULL, n, subtype ); */
/* _direction = dir; */
/* _type = type; */

/* _client->port_added( this ); */
/* } */

Port::~Port ( )
{
_client->port_removed( this );
if ( _name )
{
free( _name );
_name = NULL;
}
if ( _trackname )
{
free( _trackname );
_trackname = NULL;
}

}

/* sort input before output and then by alpha */
bool
Port::operator < ( const Port & rhs ) const
{
if ( type() == rhs.type() )
return strcmp( name(), rhs.name() );
else
return direction() == Port::Input;
}


/* static char * */
/* name_for_port ( Port::direction_e dir, const char *base, int n, const char *type ) */
/* { */
/* char *pname; */

/* const char *dir_s = dir == Port::Output ? "out" : "in"; */

/* if ( type ) */
/* asprintf( &pname, "%s-%s%s%s-%d", type, base ? base : "", base ? "/" : "", dir_s, n + 1 ); */
/* else */
/* asprintf( &pname, "%s%s%s-%d", base ? base : "", base ? "/" : "", dir_s, n + 1 ); */

/* return pname; */
/* } */

bool
Port::activate ( void )
{
/* assert( !_port ); */

int flags = 0;
if ( _direction == Output )
flags |= JackPortIsOutput;
else
flags |= JackPortIsInput;

if ( _terminal )
flags |= JackPortIsTerminal;

char jackname[max_name()];

snprintf( jackname, sizeof(jackname), "%s%s%s", _trackname ? _trackname : "", _trackname ? "/" : "", _name );

DMESSAGE( "Activating port name %s", jackname );
_port = jack_port_register( _client->jack_client(), jackname,
( _type == Audio ) || ( _type == CV ) ? JACK_DEFAULT_AUDIO_TYPE : JACK_DEFAULT_MIDI_TYPE,
flags,
0 );

#ifdef HAVE_JACK_METADATA
if ( _type == CV )
{
jack_uuid_t uuid = jack_port_uuid( _port );
jack_set_property( _client->jack_client(), uuid, "http://jackaudio.org/metadata/signal-type", "CV", "text/plain" );
}
#endif

DMESSAGE( "Port = %p", _port );

if ( ! _port )
return false;

_client->port_added( this );
return true;
}

/** returns the sum of latency of all ports between this one and a
terminal port. */
nframes_t
Port::total_latency ( void ) const
{
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
jack_latency_range_t range;

jack_port_get_latency_range( _port, _direction == Input ? JackPlaybackLatency : JackCaptureLatency, &range );

return range.max;
#else
return jack_port_get_total_latency( _client->jack_client() , _port );
#endif
}

/** returns the number of frames of latency assigned to this port */
void
Port::get_latency ( direction_e dir, nframes_t *min, nframes_t *max ) const
{
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
jack_latency_range_t range;

jack_port_get_latency_range( _port, dir == Output ? JackPlaybackLatency : JackCaptureLatency, &range );

*min = range.min;
*max = range.max;
#else
*min = *max = jack_port_get_latency( _port );
#endif

}

/** inform JACK that port has /frames/ frames of latency */
void
Port::set_latency ( direction_e dir, nframes_t min, nframes_t max )
{
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
jack_latency_range_t range;
// DMESSAGE( "Setting port latency!" );

range.max = max;
range.min = min;

jack_port_set_latency_range( _port, dir == Output ? JackPlaybackLatency : JackCaptureLatency, &range );
#else
jack_port_set_latency( _port, max );
#endif
}

void
Port::shutdown ( void )
{
deactivate();

_client->port_removed( this );
}

void
Port::deactivate ( void )
{
if ( _port )
{
#ifdef HAVE_JACK_METADATA
if ( _type == CV )
{
jack_uuid_t uuid = jack_port_uuid(_port);
jack_remove_property(_client->jack_client(), uuid, "http://jackaudio.org/metadata/signal-type");
}
#endif
jack_port_unregister( _client->jack_client(), _port );
}

_port = 0;
}


void
Port::name ( const char *name )
{
if ( _name )
free( _name );

_name = strdup( name );
}

void
Port::trackname ( const char *trackname )
{
if ( _trackname )
free( _trackname );

_trackname = NULL;

if ( trackname )
_trackname = strdup( trackname );
}

bool
Port::rename ( void )
{
char jackname[max_name()];

snprintf( jackname, sizeof(jackname), "%s%s%s", _trackname ? _trackname : "", _trackname ? "/" : "", _name );

if ( _port )
return 0 == jack_port_set_name( _port, jackname );
else
return false;
}

void
Port::write ( sample_t *buf, nframes_t nframes )
{
memcpy( buffer( nframes ), buf, nframes * sizeof( sample_t ) );
}

void
Port::read ( sample_t *buf, nframes_t nframes )
{
memcpy( buf, buffer( nframes ), nframes * sizeof( sample_t ) );
}

void *
Port::buffer ( nframes_t nframes )
{
return jack_port_get_buffer( _port, nframes );
}

void
Port::silence ( nframes_t nframes )
{
memset( buffer( nframes ), 0, nframes * sizeof( sample_t ) );
}

/** Return a malloc()'d null terminated array of strings
* representing all ports to which this port is connected. */
const char **
Port::connections ( void )
{
ASSERT( _port, "Attempt to get connections of null port" );

return jack_port_get_connections( _port );
}

/** Restore the connections returned by connections() */
bool
Port::connections ( const char **port_names )
{
if ( ! port_names )
return true;

for ( const char **port_name = port_names; *port_name; ++port_name )
{
printf( "Attempting to reconnect to %s\n", *port_name );
connect( *port_name );
}

return true;
}

int
Port::connect ( const char *to )
{
const char *name = jack_port_name( _port );

/* jack complains when you attempt to connect an already connected port... */
if ( connected_to( to ) )
return 0;
if ( _direction == Output )
{
DMESSAGE("Connecting jack port %s to %s", name, to );

return jack_connect( _client->jack_client(), name, to );
}
else
{
DMESSAGE("Connecting jack port %s to %s", to, name );

return jack_connect( _client->jack_client(), to, name );
}
}


int
Port::disconnect ( const char *from )
{
const char *name = jack_port_name( _port );

if ( _direction == Output )
{
DMESSAGE("Disconnecting jack port %s from %s", name, from );
return jack_disconnect( _client->jack_client(), name, from );
}
else
{
DMESSAGE("Disconnecting jack port %s from %s", from, name );
return jack_disconnect( _client->jack_client(), from, name );
}
}

bool
Port::connected_to ( const char *to )
{
return jack_port_connected_to( _port, to );
}

void
Port::freeze ( void )
{
if ( _connections )
free( _connections );

// DMESSAGE( "Freezing port %s", _name );

_connections = connections();

// deactivate();
}

void
Port::thaw ( void )
{
// DMESSAGE( "Thawing port %s", _name );

activate();
if ( _connections )
{
connections( _connections );
free( _connections );

_connections = NULL;
}
}
}

+ 0
- 115
nonlib/JACK/Port.H View File

@@ -1,115 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 <jack/jack.h>
#include "Client.H"
#include <stdlib.h>

namespace JACK
{
class Port
{
jack_port_t *_port;
char *_trackname;
char *_name;
JACK::Client *_client;

/* FIXME: reference count? */

/* /\* not permitted *\/ */
/* Port ( const Port &rhs ); */
/* Port & operator= ( const Port &rhs ); */

public:

bool operator < ( const Port & rhs ) const;

enum direction_e { Output, Input };
enum type_e { Audio, MIDI, CV };

static int max_name ( void );

Port ( JACK::Client *client, jack_port_t *port );
/* Port ( JACK::Client *client, const char *name, direction_e dir, type_e type ); */
Port ( JACK::Client *client, const char *trackname, const char *name, direction_e dir, type_e type );
/* Port ( JACK::Client *client, direction_e dir, type_e type, const char *base, int n, const char *subtype=0 ); */
/* Port ( JACK::Client *client, direction_e dir, type_e type, int n, const char *subtype=0 ); */

// Port ( );
~Port ( );

Port ( const Port & rhs );

bool valid ( void ) const { return _port; }
bool connected ( void ) const { return jack_port_connected( _port ); }
direction_e direction ( void ) const { return _direction; }
type_e type ( void ) const { return _type; }
const char * name ( void ) const { return _name; }
const char * trackname ( void ) const { return _trackname; }
void name ( const char *name );
void trackname ( const char *trackname );
bool rename ( void );
const char * jack_name ( void ) const { return jack_port_name( _port ); }
// bool name ( const char *base, int n, const char *type=0 );

nframes_t total_latency ( void ) const;

void get_latency ( direction_e dir, nframes_t *min, nframes_t *max ) const;

/* it's only valid to call this in a latency callback! */
void set_latency ( direction_e dir, nframes_t min, nframes_t max );

void terminal ( bool b ) { _terminal = b; }
bool activate ( void );
void shutdown ( void );
void write ( sample_t *buf, nframes_t nframes );
void read ( sample_t *buf, nframes_t nframes );
void *buffer ( nframes_t nframes );
void silence ( nframes_t nframes );

int connect ( const char *to );
int disconnect ( const char *from );
bool connected_to ( const char *to );
/* */
const char ** connections ( void );
bool connections ( const char **port_names );
void freeze ( void );
void thaw ( void );
JACK::Client * client ( void ) const { return _client; }
void client ( JACK::Client *c ) { _client = c; }

private:

friend class Client;

direction_e _direction;
type_e _type;
bool _terminal;

void deactivate ( void );
/* bool activate ( const char *name, direction_e dir ); */

const char **_connections;

};

}

+ 0
- 17
nonlib/JACK/makefile.inc View File

@@ -1,17 +0,0 @@
# -*- mode: makefile; -*-

nonlib_SRCS := $(wildcard JACK/*.C LASH/*.C)

nonlib_SRCS:=$(sort $(nonlib_SRCS))
nonlib_OBJS:=$(nonlib_SRCS:.C=.o)

all: nonlib/libnonlib.a

nonlib/libnonlib.a: $(nonlib_OBJS)
@ ar rcs $@ $(nonlib_OBJS)

.PHONEY: nonlib
nonlib: nonlib/libnonlib.a

nonlib_clean:
rm -f $(nonlib_OBJS) nonlib/libnonlib.a

+ 0
- 308
nonlib/Log_Entry.C View File

@@ -1,308 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "Log_Entry.H"

// #include "const.h"
#include "debug.h"

Log_Entry::Log_Entry ( )
{
_sa = (char**)malloc( sizeof( char * ) );
*_sa = NULL;
_i = 0;
}

Log_Entry::Log_Entry ( char **sa )
{
_sa = sa;
_i = 0;

if ( _sa )
while ( _sa[ _i ] ) ++_i;

}

Log_Entry::Log_Entry ( const char *s )
{
_i = 0;
_sa = s ? parse_alist( s ) : NULL;

if ( _sa )
while ( _sa[ _i ] ) ++_i;
}

Log_Entry::~Log_Entry ( )
{
if ( ! _sa )
return;

for ( _i = 0; _sa[ _i ]; ++_i )
{
free( _sa[ _i ] );
}

free( _sa );
}


/** remove escapes from string /s/ in-place */
static void
unescape ( char *s )
{
char *r = s;
for ( ; *s; s++, r++ )
{
if ( '\\' == *s )
{
switch ( *(++s) )
{
case 'n':
*r = '\n';
break;
case '"':
*r = '"';
break;
default:
break;
}
}
else
*r = *s;
}

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

free( r );

return r2;
}

/** sigh. parse a string of ":name value :name value" pairs into an
* array of strings, one per pair */
// FIXME: doesn't handle the case of :name ":foo bar", nested quotes
// or other things it should.
char **
Log_Entry::parse_alist( const char *s )
{

// FIXME: bogus over allocation...

int tl = strlen( s );
char **r = (char**)malloc( sizeof( char* ) * tl );

bool quote = false;
bool value = false;
const char *c = NULL;
int i = 0;
for ( ; ; s++ )
{
switch ( *s )
{
case '\0':
case ' ':
if ( ! quote && c )
{
if ( ! value )
{
value = true;
break;
}

int l = s - c;

char *pair = (char*)malloc( l + 1 );

/* remove trailing space */
if ( c[ l - 1 ] == ' ' )
--l;

strncpy( pair, c, l );

pair[ l ] = '\0';

r[ i++ ] = pair;

/* split */

strtok( pair, " " );

/* remove quotes */
char *v = pair + strlen( pair ) + 1;

unescape( v );

if ( *v == '"' )
{
// v++;
if ( v[ strlen( v ) - 1 ] != '"' )
WARNING( "invalid quoting in log entry!" );
else
{
v[ strlen( v ) - 1 ] = '\0';
memmove( v, v + 1, strlen( v ) + 1 );
}
}

c = NULL;
}
break;
case ':': /* this is a key */
if ( ! quote && ! c )
{
c = s;
value = false;
}
break;
case '"':
quote = !quote;
break;
case '\\':
s++;
break;
}

if ( *s == '\0' )
break;

}

r[ i ] = NULL;

return r;
}

/** compare elements of dumps s1 and s2, removing those elements
of dst which are not changed from src */
bool
Log_Entry::diff ( Log_Entry *e1, Log_Entry *e2 )
{

if ( ! e1 )
return true;

char **sa1 = e1->_sa;
char **sa2 = e2->_sa;

if ( ! sa1 )
return true;

int w = 0;
for ( int i = 0; sa1[ i ]; ++i )
{
const char *v1 = sa1[ i ] + strlen( sa1[ i ] ) + 1;
const char *v2 = sa2[ i ] + strlen( sa2[ i ] ) + 1;

if ( ! strcmp( sa1[ i ], sa2[ i ] ) && ! strcmp( v1, v2 ) )
{
free( sa2[ i ] );
free( sa1[ i ] );
}
else
{
sa2[ w ] = sa2[ i ];
sa1[ w ] = sa1[ i ];

w++;
}
}

sa1[ w ] = NULL;
sa2[ w ] = NULL;

e1->_i = w;
e2->_i = w;

return w == 0 ? false : true;
}

void
Log_Entry::grow ( )
{
_sa = (char**)realloc( _sa, sizeof( char * ) * (_i + 2) );
_sa[ _i + 1 ] = NULL;
}

int
Log_Entry::size ( void ) const
{
return _i;
}

void
Log_Entry::get ( int n, const char **name, const char **value ) const
{
*name = _sa[ n ];
*value = *name + strlen( *name ) + 1;
}


void
Log_Entry::remove ( const char *name )
{
for ( int i = 0; i < _i; i++ )
{
if ( !strcmp( _sa[ i ], name ) )
{
free( _sa[i] );
_sa[i] = NULL;
}
}
}

char **
Log_Entry::sa ( void )
{
return _sa;

/* char **sa = _sa; */

/* // _sa = NULL; */

/* return sa; */
/* } */

}

+ 0
- 104
nonlib/Log_Entry.H View File

@@ -1,104 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "Loggable.H"

#include "types.h"

class Log_Entry
{
// vector <Pair> _sa;
char **_sa;
int _i;

/* not permitted */
Log_Entry ( const Log_Entry &rhs );
Log_Entry & operator= ( const Log_Entry &rhs );

static char ** parse_alist ( const char *s );
static bool log_diff ( char **sa1, char **sa2 );

public:

Log_Entry ( );
Log_Entry ( char **sa );
Log_Entry ( const char *s );
~Log_Entry ( );

/****************/
/* Construction */
/****************/

void grow ( );

#define ADD( type, format, exp ) \
void add ( const char *name, type v ) \
{ \
grow(); \
(void)asprintf( &_sa[ _i ], "%s " format, name, (exp) ); \
strtok( _sa[ _i++ ], " " ); \
}

void add_raw ( const char *name, const char *v )
{
grow();
(void)asprintf( &_sa[ _i ], "%s %s", name, v );
strtok( _sa[ _i++ ], " " );
}

/***************/
/* Examination */
/***************/

static bool diff ( Log_Entry *e1, Log_Entry *e2 );

int size ( void ) const;

void get ( int n, const char **name, const char **value ) const;
char **sa ( void );

char *print ( void ) const;

/* #define ADD ( type, format, exp ) \ */
/* void add ( const char *name, type v ) \ */
/* { \ */
/* char pat[ 256 ]; \ */
/* Pair p; \ */
/* p.name = strdup( name ); \ */
/* snprintf( pat, sizeof( pat ), format, exp ); \ */
/* p.value = strdup( pat ); \ */
/* _sa.push( p ); \ */
/* } \ */


void remove ( const char *s );

ADD( int, "%d", v );
ADD( nframes_t, "%lu", (unsigned long)v );
ADD( unsigned long, "%lu", v );
ADD( const char *, "\"%s\"", v ? Loggable::escape( v ) : "" );
ADD( Loggable * , "0x%X", v ? v->id() : 0 );
ADD( float, "%f", v );
ADD( double, "%f", v );

#undef ADD

};

+ 0
- 906
nonlib/Loggable.C View File

@@ -1,906 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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. */
/*******************************************************************************/

/* This class handles all journaling. All journaled objects must
inherit from Loggable as well as define a few special methods (via
macros), get and set methods, and have contructors and destructors
that call log_create() and log_destroy() in the appropriate
order. Any action that might affect multiple loggable objects
*must* be braced by calls to Loggable::block_start() and
Loggable::block_end() in order for Undo to work properly. */

#include "Loggable.H"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "file.h"

// #include "const.h"
#include "debug.h"

#include "Mutex.H"

#include <algorithm>
using std::min;
using std::max;


#ifndef NDEBUG
bool Loggable::_snapshotting = false;
int Loggable::_snapshot_count = 0;
#endif

bool Loggable::_readonly = false;
FILE *Loggable::_fp;
unsigned int Loggable::_log_id = 0;
int Loggable::_level = 0;
int Loggable::_dirty = 0;
off_t Loggable::_undo_offset = 0;

std::map <unsigned int, Loggable::log_pair > Loggable::_loggables;

std::map <std::string, create_func*> Loggable::_class_map;
std::queue <char *> Loggable::_transaction;

progress_func *Loggable::_progress_callback = NULL;
void *Loggable::_progress_callback_arg = NULL;

snapshot_func *Loggable::_snapshot_callback = NULL;
void *Loggable::_snapshot_callback_arg = NULL;

dirty_func *Loggable::_dirty_callback = NULL;
void *Loggable::_dirty_callback_arg = NULL;


static Mutex _lock;

Loggable::~Loggable ( )
{
Locker lock( _lock );;
_loggables[ _id ].loggable = NULL;
}


void
Loggable::block_start ( void )
{
Locker lock( _lock );;
++Loggable::_level;
}

void
Loggable::block_end ( void )
{
Locker lock( _lock );;

--Loggable::_level;

ASSERT( Loggable::_level >= 0, "Programming error" );

if ( Loggable::_level == 0 )
flush();
}

Loggable *
Loggable::find ( unsigned int id )
{
if ( _relative_id )
id += _relative_id;

return _loggables[ id ].loggable;
}

/** Open the journal /filename/ and replay it, bringing the end state back into RAM */
bool
Loggable::open ( const char *filename )
{
FILE *fp;

Loggable::_fp = NULL;

if ( ! ( fp = fopen( filename, "a+" ) ) )
{
WARNING( "Could not open log file for writing!" );
if ( ! ( fp = fopen( filename, "r" ) ) )
{
WARNING( "Could not open log file for reading!" );
return false;
}
else
{
_readonly = true;
}
}
_readonly = false;

load_unjournaled_state();

if ( newer( "snapshot", filename ) )
{
MESSAGE( "Loading snapshot" );

FILE *fp = fopen( "snapshot", "r" );

replay( fp );

fclose( fp );
}
else
{
MESSAGE( "Replaying journal" );

replay( fp );
}

fseek( fp, 0, SEEK_END );
_undo_offset = ftell( fp );

Loggable::_fp = fp;

return true;
}

bool
Loggable::load_unjournaled_state ( void )
{
FILE *fp;

fp = fopen( "unjournaled", "r" );

if ( ! fp )
{
DWARNING( "Could not open unjournaled state file for reading" );
return false;
}

unsigned int id;
char *buf;

while ( fscanf( fp, "%X set %m[^\n]\n", &id, &buf ) == 2 )
{
_loggables[ id ].unjournaled_state = new Log_Entry( buf );
free(buf);
}

fclose( fp );

return true;
}

#include <sys/stat.h>
#include <unistd.h>

/** replay journal or snapshot */
bool
Loggable::replay ( const char *file )
{
if ( FILE *fp = fopen( file, "r" ) )
{
bool r = replay( fp );

fclose( fp );

return r;
}
else
return false;
}

/** replay journal or snapshot */
bool
Loggable::replay ( FILE *fp )
{
char *buf = NULL;

struct stat st;
fstat( fileno( fp ), &st );

off_t total = st.st_size;
off_t current = 0;

if ( _progress_callback )
_progress_callback( 0, _progress_callback_arg );

while ( fscanf( fp, "%m[^\n]\n", &buf ) == 1 )
{
if ( ! ( ! strcmp( buf, "{" ) || ! strcmp( buf, "}" ) ) )
{
if ( *buf == '\t' )
do_this( buf + 1, false );
else
do_this( buf, false );
}

free(buf);

current = ftell( fp );

if ( _progress_callback )
_progress_callback( current * 100 / total, _progress_callback_arg );
}

if ( _progress_callback )
_progress_callback( 0, _progress_callback_arg );

clear_dirty();

return true;
}

/** close journal and delete all loggable objects, returing the systemt to a blank slate */
bool
Loggable::close ( void )
{
DMESSAGE( "closing journal and destroying all journaled objects" );

if ( _fp )
{
fclose( _fp );
_fp = NULL;
}

if ( ! snapshot( "snapshot" ) )
WARNING( "Failed to create snapshot" );

if ( ! save_unjournaled_state() )
WARNING( "Failed to save unjournaled state" );

for ( std::map <unsigned int, Loggable::log_pair >::iterator i = _loggables.begin();
i != _loggables.end(); ++i )
{
if ( i->second.loggable )
delete i->second.loggable;
if ( i->second.unjournaled_state )
delete i->second.unjournaled_state;
}

_loggables.clear();

return true;
}


/** save out unjournaled state for all loggables */
bool
Loggable::save_unjournaled_state ( void )
{
FILE *fp;

fp = fopen( "unjournaled", "w" );

if ( ! fp )
{
DWARNING( "Could not open unjournaled state file for writing!" );
return false;
}

for ( std::map <unsigned int, Loggable::log_pair >::iterator i = _loggables.begin();
i != _loggables.end(); ++i )
{
/* get the latest state */
if ( i->second.loggable )
i->second.loggable->record_unjournaled();

if ( i->second.unjournaled_state )
{
char *s = i->second.unjournaled_state->print();

fprintf( fp, "0x%X set %s\n", i->first, s );

free( s );
}
}

fclose( fp );

return true;
}

/** must be called after construction in create() methods */
void
Loggable::update_id ( unsigned int id )
{
/* make sure we're the last one */
ASSERT( _id == _log_id, "%u != %u", _id, _log_id );
assert( _loggables[ _id ].loggable == this );

_loggables[ _id ].loggable = NULL;

_log_id = max( _log_id, id );

/* return this id number to the system */
// --_log_id;

_id = id;

if ( _loggables[ _id ].loggable )
FATAL( "Attempt to create object with an ID (0x%X) that already exists. The existing object is of type \"%s\", the new one is \"%s\". Corrupt journal?", _id, _loggables[ _id ].loggable->class_name(), class_name() );

_loggables[ _id ].loggable = this;
}

/** return a pointer to a static copy of /s/ with all special characters escaped */
const char *
Loggable::escape ( const char *s )
{
static char r[512];

size_t i = 0;
for ( ; *s && i < sizeof( r ); ++i, ++s )
{
if ( '\n' == *s )
{
r[ i++ ] = '\\';
r[ i ] = 'n';
}
else if ( '"' == *s )
{
r[ i++ ] = '\\';
r[ i ] = '"';
}
else
r[ i ] = *s;
}

r[ i ] = '\0';

return r;
}

unsigned int Loggable::_relative_id = 0;

/* calls to do_this() between invocation of this method and
* end_relative_id_mode() will have all their IDs made relative to the
* highest available ID at this time of this call. Non-Mixer uses
* this to allow importing of module chains */
void
Loggable::begin_relative_id_mode ( void )
{
_relative_id = ++_log_id;
}

void
Loggable::end_relative_id_mode ( void )
{
_relative_id = 0;
}


/** 'do' a message like "Audio_Region 0xF1 set :r 123" */
bool
Loggable::do_this ( const char *s, bool reverse )
{
unsigned int id = 0;

char classname[40];
char command[40];
char *arguments = NULL;

int found = sscanf( s, "%s %X %s ", classname, &id, command );

if ( 3 != found )
FATAL( "Invalid journal entry format \"%s\"", s );

const char *create, *destroy;

if ( reverse )
{
// sscanf( s, "%s %*X %s %*[^\n<]<< %m[^\n]", classname, command, &arguments );
sscanf( s, "%s %*X %s%*[^\n<]<< %m[^\n]", classname, command, &arguments );
create = "destroy";
destroy = "create";

DMESSAGE( "undoing \"%s\"", s );
}
else
{
sscanf( s, "%s %*X %s %m[^\n<]", classname, command, &arguments );
create = "create";
destroy = "destroy";
}

if ( ! strcmp( command, destroy ) )
{
Loggable *l = find( id );

/* deleting eg. a track, which contains a list of other
widgets, causes destroy messages to be emitted for all those
widgets, but when replaying the journal the destroy message
causes the children to be deleted also... This is a temporary
hack. Would it be better to queue up objects for deletion
(when?) */
if ( l )
delete l;
}
else if ( ! strcmp( command, "set" ) )
{
// printf( "got set command (%s).\n", arguments );

Loggable *l = find( id );

ASSERT( l, "Unable to find object 0x%X referenced by command \"%s\"", id, s );

Log_Entry e( arguments );

l->log_start();
l->set( e );
l->log_end();
}
else if ( ! strcmp( command, create ) )
{
Log_Entry e( arguments );

ASSERT( _class_map[ std::string( classname ) ], "Journal contains an object of class \"%s\", but I don't know how to create such objects.", classname );

{
if ( _relative_id )
id += _relative_id;

/* create */
Loggable *l = _class_map[ std::string( classname ) ]( e, id );
l->log_create();

/* we're now creating a loggable. Apply any unjournaled
* state it may have had in the past under this log ID */

Log_Entry *e = _loggables[ id ].unjournaled_state;

if ( e )
l->set( *e );
}

}

if ( arguments )
free( arguments );

return true;
}

/** Reverse the last journal transaction */
void
Loggable::undo ( void )
{
if ( ! _fp || /* journal not open */
1 == _undo_offset ) /* nothing left to undo */
return;

char *buf;

block_start();

long here = ftell( _fp );

fseek( _fp, _undo_offset, SEEK_SET );

if ( ( buf = backwards_afgets( _fp ) ) )
{
if ( ! strcmp( buf, "}\n" ) )
{
free( buf );
DMESSAGE( "undoing block" );
for ( ;; )
{
if ( ( buf = backwards_afgets( _fp ) ) )
{
char *s = buf;
if ( *s != '\t' )
{
DMESSAGE( "done with block", s );

break;
}
else
++s;
do_this( s, true );

free( buf );
}
}
}
else
{
do_this( buf, true );

free( buf );
}
}

off_t uo = ftell( _fp );

ASSERT( _undo_offset <= here, "WTF?" );
block_end();

_undo_offset = uo;
}

/** write a snapshot of the current state of all loggable objects to
* file handle /fp/ */
bool
Loggable::snapshot ( FILE *fp )
{
FILE *ofp = _fp;

if ( ! Loggable::_snapshot_callback )
{
DWARNING( "No snapshot callback defined" );
return false;
}

if ( ! ( _fp = fp ) )
{
_fp = ofp;
return false;
}

#ifndef NDEBUG
_snapshotting = true;

_snapshot_count++;
#endif

block_start();

Loggable::_snapshot_callback( _snapshot_callback_arg );

block_end();

#ifndef NDEBUG
_snapshotting = false;
#endif

_fp = ofp;

clear_dirty();

return true;
}

/** write a snapshot of the current state of all loggable objects to
* file /name/ */
bool
Loggable::snapshot ( const char *name )
{
FILE *fp;

char *tmpname;

asprintf( &tmpname, ".#%s", name );

if ( ! ( fp = fopen( tmpname, "w" ) ))
return false;

bool r = snapshot( fp );

fclose( fp );

rename( tmpname, name );

free(tmpname);

return r;
}

/** Replace the journal with a snapshot of the current state */
void
Loggable::compact ( void )
{
fseek( _fp, 0, SEEK_SET );
ftruncate( fileno( _fp ), 0 );

if ( ! snapshot( _fp ) )
FATAL( "Could not write snapshot!" );

fseek( _fp, 0, SEEK_END );
}

#include <stdarg.h>

/** Writes (part of) a line to the journal. Each separate line will be
* stored separately in _transaction until transaction is closed.
*/
void
Loggable::log ( const char *fmt, ... )
{
Locker lock( _lock );

static char * buf = NULL;
static size_t i = 0;
static size_t buf_size = 0;

if ( ! _fp )
return;

if ( NULL == buf )
{
buf_size = 1024;
buf = (char*)malloc( buf_size );
}

va_list args;

if ( fmt )
{
va_start( args, fmt );

for ( ;; )
{
size_t l = vsnprintf( buf + i, buf_size - i, fmt, args );

if ( l >= buf_size - i )
{
buf = (char*)realloc( buf, buf_size += (l + 1) + buf_size );
}
else
{
i += l;
break;
}
}

va_end( args );
}

if ( '\n' == buf[i-1] )
{
_transaction.push( strdup( buf ) );
i = 0;
}
}

/** End the current transaction and commit it to the journal */
void
Loggable::flush ( void )
{
if ( ! _fp )
{
// printf( "error: no log file open!\n" );

while ( ! _transaction.empty() )
{
free( _transaction.front() );
_transaction.pop();
}

return;
}

int n = _transaction.size();

if ( n > 1 )
fprintf( _fp, "{\n" );

while ( ! _transaction.empty() )
{
char *s = _transaction.front();

_transaction.pop();

if ( n > 1 )
fprintf( _fp, "\t" );

fprintf( _fp, "%s", s );

free( s );
}

if ( n > 1 )
fprintf( _fp, "}\n" );

if ( n )
/* something done, reset undo index */
_undo_offset = ftell( _fp );

fflush( _fp );
}

/** Print bidirectional journal entry */
void
Loggable::log_print( const Log_Entry *o, const Log_Entry *n ) const
{
if ( ! _fp )
return;

if ( n )
for ( int i = 0; i < n->size(); ++i )
{
const char *s, *v;

n->get( i, &s, &v );

log( "%s %s%s", s, v, n->size() == i + 1 ? "" : " " );
}

if ( o && o->size() )
{
if ( n ) log( " << " );

for ( int i = 0; i < o->size(); ++i )
{
const char *s, *v;

o->get( i, &s, &v );

log( "%s %s%s", s, v, o->size() == i + 1 ? "" : " " );
}
}

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. */
void
Loggable::log_start ( void )
{
Locker lock( _lock );;

if ( ! _old_state )
{
_old_state = new Log_Entry;

get( *_old_state );
}
++_nest;
}

/** Log any change to the object's state since log_start(). */
void
Loggable::log_end ( void )
{
Locker lock( _lock );;

ASSERT( _old_state, "Programming error: log_end() called before log_start()" );

if ( --_nest > 0 )
return;

Log_Entry *new_state;

new_state = new Log_Entry;

get( *new_state );

if ( Log_Entry::diff( _old_state, new_state ) )
{
log( "%s 0x%X set ", class_name(), _id );

log_print( _old_state, new_state );

set_dirty();
}

delete new_state;
delete _old_state;

_old_state = NULL;

if ( Loggable::_level == 0 )
Loggable::flush();
}

/** Log object creation. *Must* be called at the end of all public
* constructors for leaf classes */

void
Loggable::log_create ( void ) const
{
Locker lock( _lock );;

set_dirty();

if ( ! _fp )
/* replaying, don't bother */
return;

#ifndef NDEBUG
if ( _snapshotting && _snapshot_count != _num_snapshot )
{
_num_snapshot_creates = 1;
_num_snapshot = _snapshot_count;
}
else if ( _snapshotting && _snapshot_count == _num_snapshot )
{
_num_snapshot_creates++;

ASSERT( _num_snapshot_creates < 2, "Attempt to log creation of same object twice in one snapshot! %s", class_name() );
}
else
{
_num_log_creates++;
ASSERT( _num_log_creates < 2, "Attempt to log creation of same object twice in the journal! %s", class_name() );
}
#endif

log( "%s 0x%X create ", class_name(), _id );

Log_Entry e;

get( e );

if ( e.size() )
log_print( NULL, &e );
else
log( "\n" );

if ( Loggable::_level == 0 )
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[ _id ].unjournaled_state;

if ( *le )
{
delete *le;
*le = NULL;
}

if ( e->size() )
*le = e;
else
delete e;
}

/** Log object destruction. *Must* be called at the beginning of the
* destructors of leaf classes */
void
Loggable::log_destroy ( void ) const
{
Locker lock( _lock );;

set_dirty();

if ( ! _fp )
/* tearing down... don't bother */
return;

/* the unjournaled state may have changed: make a note of it. */
record_unjournaled();

log( "%s 0x%X destroy << ", class_name(), _id );

Log_Entry e;

get( e );

log_print( NULL, &e );

if ( Loggable::_level == 0 )
Loggable::flush();
}

+ 0
- 280
nonlib/Loggable.H View File

@@ -1,280 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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. */
/*******************************************************************************/


/* Master class for journaling. */

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <map>
#include <string>
#include <queue>

// #include "types.h"

typedef void (progress_func)( int, void * );
typedef void (snapshot_func)( void * );
typedef void (dirty_func)( int, void * );

class Log_Entry;
class Loggable;
typedef Loggable *(create_func)(Log_Entry &, unsigned int id);

#define LOG_REGISTER_CREATE( class ) \
Loggable::register_create( #class, & class ::create )

#define LOG_NAME_FUNC( class ) \
virtual const char *class_name ( void ) const { return #class ; }

#define LOG_CREATE_FUNC( class ) \
static Loggable * \
create ( Log_Entry &e, unsigned int id ) \
{ \
class *r = new class; \
r->update_id( id ); \
r->set( e ); \
return (Loggable *)r; \
} \
LOG_NAME_FUNC( class )


#define LOG_NOT_LOGGABLE_FUNC( class ) \
virtual const char *class_name ( void ) const { return #class ; }

class Logger;
class Loggable
{
struct log_pair {
Loggable * loggable;
Log_Entry * unjournaled_state;
};

static bool _readonly;
static FILE *_fp;
static unsigned int _log_id;
static int _level;

static off_t _undo_offset;

static std::map <unsigned int, Loggable::log_pair > _loggables;

static std::map <std::string, create_func*> _class_map;

static std::queue <char *> _transaction;

static progress_func *_progress_callback;
static void *_progress_callback_arg;

static snapshot_func *_snapshot_callback;
static void *_snapshot_callback_arg;

static dirty_func *_dirty_callback;
static void *_dirty_callback_arg;

private:

static unsigned int _relative_id;

#ifndef NDEBUG
static bool _snapshotting;
static int _snapshot_count;

mutable int _num_log_creates;
mutable int _num_snapshot;
mutable int _num_snapshot_creates;
#endif

unsigned int _id;

Log_Entry *_old_state;

int _nest;

static int _dirty; /* count of changes */

static void ensure_size ( size_t n );

void log_print ( const Log_Entry *o, const Log_Entry *n ) const;
static void log ( const char *fmt, ... );

static void flush ( void );


void init ( bool loggable=true )
{
// _new_state
#ifndef NDEBUG
_num_log_creates = 0;
_num_snapshot = 0;
_num_snapshot_creates = 0;
#endif
_old_state = NULL;
_nest = 0;

if ( loggable )
{
_id = ++_log_id;

_loggables[ _id ].loggable = this;
}
else
_id = 0;

}

/* not implemented */
const Loggable & operator= ( const Loggable &rhs );

void record_unjournaled ( void ) const;
static bool load_unjournaled_state ( void );

static bool replay ( FILE *fp );

static void signal_dirty ( int v ) { if ( _dirty_callback ) _dirty_callback( v, _dirty_callback_arg ); }
static void set_dirty ( void ) { signal_dirty( ++_dirty ); }
static void clear_dirty ( void ) { signal_dirty( _dirty = 0 ); }

public:
static bool readonly ( void ) { return _readonly; }

static bool replay ( const char *name );

static bool snapshot( FILE * fp );
static bool snapshot( const char *name );

static void snapshot_callback ( snapshot_func *p, void *arg ) { _snapshot_callback = p; _snapshot_callback_arg = arg; }
static void progress_callback ( progress_func *p, void *arg ) { _progress_callback = p; _progress_callback_arg = arg;}
static void dirty_callback ( dirty_func *p, void *arg ) { _dirty_callback = p; _dirty_callback_arg = arg;}

static const char *escape ( const char *s );

unsigned int id ( void ) const { return _id; }

static bool save_unjournaled_state ( void );
static bool open ( const char *filename );
static bool close ( void );
static void undo ( void );

static void compact ( void );

static void block_start ( void );
static void block_end ( void );

static Loggable * find ( unsigned int id );

Loggable ( bool loggable=true )
{
init( loggable );
}

void update_id ( unsigned int id );

virtual ~Loggable ( );

static
void
register_create ( const char *name, create_func *func )
{
_class_map[ std::string( name ) ] = func;
}

/* log messages for journal */
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 const char *class_name ( void ) const = 0;

virtual void log_children ( void ) const { return; }

static void begin_relative_id_mode ( void );
static void end_relative_id_mode ( void );

static bool do_this ( const char *s, bool reverse );

static int dirty ( void ) { return _dirty; }

void log_create ( void ) const;

protected:

void log_start ( void );
void log_end ( void );

void log_destroy ( void ) const;

/* leaf subclasses *must* call log_create() at the end of their copy contructors */
Loggable ( const Loggable & )
{
init( true );
}

public:

friend class Logger;
};


class Logger
{

Loggable *_this;
Logger ( ) {}

/* not permitted */
Logger ( const Logger &rhs );
const Logger & operator= ( const Logger &rhs );

public:

Logger ( Loggable *l ) : _this( l )
{
_this->log_start();

}

~Logger ( )
{
_this->log_end();
}

void hold ( void )
{
_this->_nest++;
}

void release ( void )
{
_this->_nest--;
assert( _this->_nest );
}
};

#include "Log_Entry.H"

+ 0
- 164
nonlib/MIDI/event.C View File

@@ -1,164 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2007-2008 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 "event.H"
#include <stdio.h>
#include <string.h>

namespace MIDI
{
void
event::_init ( void )
{
_link = _next = _prev = NULL;
_selected = 0;
}

event::event ( void )
{
_init();
}

event::~event ( void )
{
_link = _next = _prev = NULL;
}

/* copy constructor */
event::event ( const event &e ) : midievent( e )
{
_link = _next = _prev = NULL;
_selected = e._selected;
}

event::event ( const midievent &e ) : midievent( e )
{
_init();
}


void
event::link ( event *event )
{
if ( event == NULL )
{
if ( _link )
{
_link->_link = NULL;
_link = NULL;
}
return;
}

_link = event;
_link->_link = this;
}

event *
event::link ( void ) const
{
return _link;
}

bool
event::linked ( void ) const
{
return _link != NULL;
}

void
event::select ( void )
{
_selected = 1;

if ( _link )
_link->_selected = 1;
}

void
event::deselect ( void )
{
_selected = 0;

if ( _link )
_link->_selected = 0;
}

bool
event::selected ( int n ) const
{
return _selected == n;
}

bool
event::selected ( void ) const
{
return _selected == 1;
}

/* override this so we can update linked event */
void
event::note ( char note )
{
midievent::note( note );

if ( _link )
_link->midievent::note( note );
}

/* stupid C++ makes us override the all polymorphic functions... */
unsigned char
event::note ( void ) const
{
return midievent::note();
}

tick_t
event::note_duration ( void ) const
{
return _link ? _link->timestamp() - timestamp() : 0;
}

void
event::note_duration ( tick_t l )
{
if ( _link )
_link->timestamp( timestamp() + l );
}

void
event::get_note_properties ( note_properties *p ) const
{
p->start = timestamp();
p->duration = note_duration();
p->velocity = note_velocity();
p->note = note();
p->selected = selected();
}

void
event::set_note_properties ( const note_properties *p )
{
timestamp( p->start );
note_duration( p->duration );
note_velocity( p->velocity );
note( p->note );
selected( p->selected );
}
}

+ 0
- 100
nonlib/MIDI/event.H View File

@@ -1,100 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2007-2008 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. */
/*******************************************************************************/

/* Higher level event interface than midievent, supporting
doublely-linked list, marking, selection, and linking of note
on/off pairs. */

#pragma once

#include "midievent.H"

namespace MIDI
{
class event_list;

class event;
class note_properties {
public:
tick_t start;
tick_t duration;
int note;
int velocity;
bool selected;
};

class event : public midievent
{


protected:

/* these are only to be used by event_list class! */
event *_next;
event *_prev;

private:

event *_link; /* other event in pair */

byte_t _selected;

void _init ( void );

public:

event();
~event();
event ( const event &e );
event ( const midievent &e );

event * next ( void ) const;
event * prev ( void ) const;

void link ( event *event );
event * link ( void ) const;
bool linked ( void ) const;
void select ( void );
void deselect ( void );
bool selected ( int n ) const;
bool selected ( void ) const;
virtual void note ( char note );
virtual unsigned char note ( void ) const;
tick_t note_duration ( void ) const;
void note_duration ( tick_t l );

void get_note_properties ( note_properties *e ) const;
void set_note_properties ( const note_properties *e );

friend class event_list;

};

inline event *
event::next ( void ) const
{
return _next;
}

inline event *
event::prev ( void ) const
{
return _prev;
}
}

+ 0
- 721
nonlib/MIDI/event_list.C View File

@@ -1,721 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "debug.h"
#include "event_list.H"

/* The operations we perform on event lists are clumsy with STL lists
and iterators so we have a custom doubly-linked list implementation
here for complete control */

namespace MIDI
{
#define RFOR_ALL( it ) for ( event *next, * it = _tail; it && ((next = it ->_prev), true) ; it = next )
#define FOR_ALL( it ) for ( event *next, * it = _head; it && ((next = it ->_next), true) ; it = next )
// #define FOR_ALL( e ) for ( event * e = _head; e; e = e ->_next )
#define FOR_SELECTED( e ) FOR_ALL( e ) if ( e ->selected() )
#define RFOR_SELECTED( e ) RFOR_ALL( e ) if ( e ->selected() )


event_list::event_list ( void )
{
_head = NULL;
_tail = NULL;
_size = 0;
}

event_list::~event_list ( void )
{
clear();
}

/* copy constructor */
event_list::event_list ( const event_list &el )
{
_copy( &el );
}

event_list &
event_list::operator= ( const event_list &rhs )
{
if ( this != &rhs )
{
clear();

_copy( &rhs );
}

return *this;
}

event_list &
event_list::operator= ( const list <midievent> &rhs )
{
clear();

for ( list <midievent>::const_iterator me = rhs.begin(); me != rhs.end(); me++ )
{
event *e = new event( *me );

_insert( NULL, e );
}

relink();

return *this;
}

/** allow indexing */
event *
event_list::operator[] ( unsigned int index )
{
unsigned int i = 0;
for ( event *e = _head; e; (e = e->_next), ++i )
if ( i == index )
return e;

// all else fails.
return _tail;
}

void
event_list::_copy ( const event_list *el )
{
if ( ! el->_head )
{
_head = _tail = NULL;
_size = 0;
return;
}

_head = new event( *(el->_head) );
_head->_prev = NULL;

event *p = _head;

for ( event *e = el->_head->_next; e; e = e->_next )
{
event *n = new event( *e );

n->_next = NULL;
p->_next = n;
n->_prev = p;

p = n;
}

_tail = p;

_size = el->_size;

relink();
}

/** insert event /n/ before event /o/ */
void
event_list::_insert ( event *o, event *n )
{
++_size;

if ( ! o )
{
n->_next = NULL;
n->_prev = _tail;

if ( _tail )
_tail->_next = n;

_tail = n;
if ( ! _head )
_head = n;
return;
}

event *t = o->_prev;

o->_prev = n;
n->_next = o;
n->_prev = t;

if ( ! t )
_head = n;
else
t->_next = n;
}

void
event_list::unlink ( event *e )
{
if ( e->_next )
e->_next->_prev = e->_prev;
else
_tail = e->_prev;

if ( e->_prev )
e->_prev->_next = e->_next;
else
_head = e->_next;

--_size;
}


void
event_list::clear ( void )
{
for ( event *e = _head; e ; )
{
event *n = e->_next;
delete e;
e = n;
}

_head = NULL;
_tail = NULL;
_size = 0;
}

void
event_list::mix ( event *ne )
{
FOR_ALL( e )
if ( *e == *ne )
{
/* already have an event like this, drop it */

if ( ne->linked() )
delete ne->link();

delete ne;

return;
}

insert( ne );
if ( ne->linked() )
insert( ne->link() );

}

/** remove elements from list /el/ to this list */
void
event_list::merge ( event_list *el )
{
event *n;
for ( event *e = el->_head; e; e = n )
{
n = e->_next;

el->unlink( e );

insert( e );
}
}

/** unlink event e */
void
event_list::remove ( event *e )
{
unlink( e );
delete e;
}

/** sorted insert /e/ */
void
event_list::insert ( event *e )
{
/* find the place to insert */
RFOR_ALL( i )
if ( *e >= *i )
{
_insert( i->_next, e );
return;
}

_insert( _head, e );
}

/** just append event without sorting */
void
event_list::append ( event *e )
{
_insert( NULL, e );
}

event *
event_list::first ( void ) const
{
return _head;
}

event *
event_list::last ( void ) const
{
return _tail;
}


/*************/
/* Selection */
/*************/

/** select all events from /start/ to /end/ inclusive */
void
event_list::select ( tick_t start, tick_t end )
{
FOR_ALL( e )
{
tick_t ts = e->timestamp();

/* don't count note offs exactly on start */
if ( ts == start && e->is_note_off() )
continue;

if ( ts >= start && ts < end )
e->select();
}
}

/** select note evenets from /start/ to /end/ within range /hi/ through /lo/ */
void
event_list::select ( tick_t start, tick_t end, int hi, int lo )
{
FOR_ALL( e )
{
tick_t ts = e->timestamp();

/* don't count note offs exactly on start */
if ( ! e->is_note_on() )
continue;

if ( ts >= start && ts < end &&
e->note() <= hi && e->note() >= lo )
e->select();
}
}

/** select ALL events */
void
event_list::select_all ( void )
{
FOR_ALL( e )
e->select();
}

void
event_list::select_none ( void )
{
FOR_ALL( e )
e->deselect();
}

void
event_list::invert_selection ( void )
{
FOR_ALL( e )
if ( ! e->is_note_off() )
{
if ( e->selected() )
e->deselect();
else
e->select();
}
}

/** remove all selected events */
void
event_list::remove_selected ( void )
{
FOR_SELECTED( e )
{
remove( e );
}
}


/** copy selected events into event list /el/ */
void
event_list::copy_selected ( event_list *el ) const
{
event *fi = first();

if ( ! fi )
return;

tick_t offset = fi->timestamp();

FOR_SELECTED( e )
{
event *nel = 0;

if ( e->linked() )
nel = new event(*e->link());
event *ne = new event(*e);
ne->timestamp( ne->timestamp() - offset );

if ( nel )
{
nel->link( ne );
ne->link( nel );
nel->timestamp( nel->timestamp() - offset );
}

el->mix(ne);
}
}

/** add events from list /el/ */
void
event_list::paste ( tick_t offset, const event_list *el )
{
event *n;
for ( event *e = el->_head; e; e = n )
{
n = e->_next;

event *ne = new event(*e);
ne->link( NULL );
ne->timestamp( ne->timestamp() + offset );

insert( ne );
}

relink();
}

/** transpose selected notes (ignoring other event types) by /n/ tones
* (may span octaves) */
void
event_list::transpose_selected ( int n )
{
FOR_SELECTED( e )
{
if ( e->is_note_on() )
e->note( e->note() + n );
}

}

/** change all notes of value /from/ to /to/ */
void
event_list::rewrite_selected ( int from, int to )
{
FOR_SELECTED( e )
{
if ( e->is_note_on() && e->note() == from )
e->note( to );
}
}


/** set velocity of selected notes to /v/ */
void
event_list::selected_velocity ( int v )
{
FOR_SELECTED( e )
{
if ( e->is_note_on() )
e->note_velocity( v );
}
}


/** get timestamp of earliest selected event */
tick_t
event_list::selection_min ( void ) const
{
FOR_SELECTED( e )
return e->timestamp();

return 0;
}

tick_t
event_list::selection_max ( void ) const
{
RFOR_SELECTED( e )
return e->timestamp();

return 0;
}

/** move selected events by offset /o/ */
void
event_list::nudge_selected ( long o )
{
if ( o < 0 )
if ( selection_min() < (tick_t)( 0 - o ) )
return;

if ( o < 0 )
{
FOR_SELECTED( e )
move( e, o );
}
else
{
RFOR_SELECTED( e )
move( e, o );
}
}

/** move block of selected events to tick /tick/ */
void
event_list::move_selected ( tick_t tick )
{
/* if ( o < 0 ) */
/* if ( selection_min() < (tick_t)( 0 - o ) ) */
/* return; */

tick_t min = selection_min();
tick_t offset = tick - min;
nudge_selected( offset );

/* FOR_SELECTED( e ) */
/* { */
/* e->timestamp( e->timestamp() + offset ); */
/* sort( e ); */
/* move( e, o ); */
/* } */

}

void
event_list::push_selection ( void )
{
FOR_ALL( e )
if ( e->_selected )
++e->_selected;
}

void
event_list::pop_selection ( void )
{
FOR_ALL( e )
if ( e->_selected )
--e->_selected;
}


/** verify that all note ons are linked to note offs */
bool
event_list::verify ( void ) const
{
FOR_ALL( e )
if ( e->is_note_on() && ! e->linked() )
return false;

return true;
}

/** link /e/ (a note on) with the next corresponding note off */
void
event_list::link ( event *on )
{
if ( ! on->is_note_on() )
return;

for ( event *off = on->_next; off; off = off->_next )
{
if ( off->linked() )
continue;

if ( off->is_note_off() &&
off->channel() == on->channel() &&
off->note() == on->note() )
{
on->link( off );
return;
}
}

WARNING( "no corresponding note_off found for note on, repairing" );

event *off = new event( *on );

off->opcode( event::NOTE_OFF );

on->link( off );

insert( off );
}

/** insert /l/ ticks of time at /start/ */
void
event_list::insert_time ( tick_t start, tick_t l )
{
FOR_ALL( e )
{
tick_t ts = e->timestamp();

if ( e->is_note_off() )
continue;

if ( ts >= start )
{
if ( e->is_note_on() )
{
/* only notes ENTIRELY WITHIN the range will be moved */
e->timestamp( ts + l );
e->link()->timestamp( e->link()->timestamp() + l );
}
else
e->timestamp( e->timestamp() + l );
}
}

sort();
}

/** delete events in range and close the gap */
void
event_list::delete_time ( tick_t start, tick_t end )
{
tick_t l = end - start;

push_selection();

select( start, end );

remove_selected();

pop_selection();

/* cut out the slack */
FOR_ALL( e )
{
tick_t ts = e->timestamp();

if ( ts >= end )
e->timestamp( ts - l );
}
}

/** link all note ons to subsequent note offs */
void
event_list::relink ( void )
{
/* clear links */
FOR_ALL( e )
e->link( NULL );

/* link */
FOR_ALL( on )
link( on );

if ( ! verify() )
FATAL( "event list failed verification" );
}

/** resort event /e/ */
void
event_list::sort ( event *e )
{
unlink( e );

insert( e );
}

/** resort entire list */
void
event_list::sort ( void )
{
event_list *temp = new event_list( );

_head = temp->_head;
_tail = temp->_tail;

FOR_ALL( n )
temp->insert( n );

temp->_head = NULL;

delete temp;

relink();
}

/** move event /e/ by /o/ ticks */
void
event_list::move ( event *e, long o )
{
e->timestamp( e->timestamp() + o );

sort( e );
}

bool
event_list::empty ( void ) const
{
return _head == NULL;
}

size_t
event_list::size ( void ) const
{
return _size;
}

void
event_list::_hi_lo ( bool sel, int *hi, int *lo ) const
{
*hi = 0;
*lo = 127;

FOR_ALL( e )
{
if ( sel && ! e->selected() )
continue;

if ( ! e->is_note_on() )
continue;

int n = e->note();

if ( n > *hi )
*hi = n;

if ( n < *lo )
*lo = n;
}
}

/** set /hi/ and /lo/ to the lowest and highest pitched note events in
* this list, respectively */
void
event_list::hi_lo_note ( int *hi, int *lo ) const
{
_hi_lo( false, hi, lo );
}

void
event_list::selected_hi_lo_note ( int *hi, int *lo ) const
{
_hi_lo( true, hi, lo );
}
}

+ 0
- 94
nonlib/MIDI/event_list.H View File

@@ -1,94 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "event.H"
#include <list>

namespace MIDI {
using std::list;

class midievent;

class event_list {

event * _head;
event * _tail;

size_t _size;

void _insert ( event *o, event *n );
void _copy ( const event_list *el );
void _hi_lo ( bool sel, int *hi, int *lo ) const;

public:

event_list ( void );
~event_list ( void );
event_list ( const event_list &el );

void clear ( void );
void merge ( event_list *el );
void unlink ( event *e );
void remove ( event *e );
void insert ( event *e );
event * first ( void ) const;
event * last ( void ) const;
void select ( tick_t start, tick_t end );
void select ( tick_t start, tick_t end, int hi, int lo );

void select_all ( void );
void select_none ( void );
void invert_selection ( void );
void copy_selected ( event_list *el ) const;
void paste ( tick_t offset, const event_list *el );

void remove_selected ( void );
void transpose_selected ( int n );
tick_t selection_min ( void ) const;
tick_t selection_max ( void ) const;
void move_selected ( tick_t tick );
void nudge_selected ( long o );
void push_selection ( void );
void pop_selection ( void );
void selected_velocity ( int v );
bool verify ( void ) const;
void link ( event *on );
void insert_time ( tick_t start, tick_t l );
void delete_time ( tick_t start, tick_t end );
void relink ( void );
void sort ( event *e );
void sort ( void );
void move ( event *e, long o );
bool empty ( void ) const;
size_t size ( void ) const;
void append ( event *e );
void mix ( event *ne );
void hi_lo_note ( int *hi, int *lo ) const;
void rewrite_selected ( int from, int to );
void selected_hi_lo_note ( int *hi, int *lo ) const;

event_list & operator= ( const event_list &rhs );
event_list & operator= ( const list <midievent> &rhs );
event *operator[] ( unsigned int index );

// friend class event;
};
}

+ 0
- 221
nonlib/MIDI/midievent.C View File

@@ -1,221 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "midievent.H"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "debug.h"

namespace MIDI
{
static const char *opcode_names[] =
{
"Note Off",
"Note On",
"Aftertouch",
"Control Change",
"Program Change",
"Channel Pressure",
"Pitch Wheel"
};

midievent::midievent ( void )
{
_sysex = NULL;
_timestamp = 0;
_data.status = NOTE_OFF;
_data.msb = _data.lsb = 0;
}

midievent::~midievent ( void )
{
if ( _sysex )
delete _sysex;

_sysex = NULL;
}

int
midievent::pitch ( void ) const
{
return ((_data.msb << 7) | _data.lsb) - 0x2000;
}

void
midievent::pitch ( int n )
{
n += 0x2000;

_data.lsb = n & 0x7F;
_data.msb = (n >> 7) & 0x7F;
}

void
midievent::data ( byte_t D1, byte_t D2 )
{
_data.lsb = D1 & 0x7F;
_data.msb = D2 & 0x7F;
}

void
midievent::data ( byte_t *D1, byte_t *D2 ) const
{
*D1 = _data.lsb;
*D2 = _data.msb;
}

void
midievent::raw ( byte_t *p, int l) const
{
memcpy( p, &_data, l );
}

int
midievent::size ( void ) const
{
return midievent::event_size( opcode() );
}

void
midievent::note_velocity ( int vel )
{
_data.msb = vel & 0x7F;
}

unsigned char
midievent::note ( void ) const
{
return _data.lsb;
}

void
midievent::note ( char note )
{
_data.lsb = note & 0x7F;
}

unsigned char
midievent::note_velocity ( void ) const
{
return _data.msb;
}

bool
midievent::is_same_note ( midievent * e ) const
{
return channel() == e->channel() && note() == e->note();
}

/** get name from opcode */
const char *
midievent::name ( void ) const
{
return opcode_names[ (opcode() >> 4) - 8 ];
}

/** get opcode from name */
int
midievent::name ( const char *name ) const
{
for ( unsigned int i = elementsof( opcode_names ); i--; )
if ( ! strcmp( name, opcode_names[ i ] ) )
return (i + 8) << 4;

return -1;
}

/** print event in hexadecimal */
void
midievent::print ( void ) const
{
printf( "[%06f] %02X %02X %02X\n",
_timestamp,
_data.status,
_data.lsb,
_data.msb );
}

/** print event in english/decimal */
void
midievent::pretty_print ( void ) const
{
printf(
"[%06f] %-15s c: %2d d1: %3d d2: %3d\n",
_timestamp,
name(),
channel(),
_data.lsb,
_data.msb );
}


/*********/
/* Sysex */
/*********/

midievent::sysex::sysex ( void )
{
_data = NULL;
_size = 0;
_alloc = 0;
}

midievent::sysex::~sysex ( void )
{
if ( _data )
free( _data );

_data = NULL;
}

/** add bytes to sysex message */
void
midievent::sysex::append ( byte_t *data, size_t size )
{
if ( _size + size > _alloc )
_data = (byte_t *)realloc( _data, _alloc += 256 );

memcpy( data + _size, data, size );

_size += size;
}

/** return SysEx data */
const byte_t *
midievent::sysex::data ( void ) const
{
return _data;
}

long
midievent::sysex::size ( void ) const
{
return _size;
}


bool
midievent::operator== ( const midievent &rhs ) const
{
return _timestamp == rhs._timestamp &&
! bcmp( (void*)&_data, (void*)&rhs._data, size() );
}
}

+ 0
- 237
nonlib/MIDI/midievent.H View File

@@ -1,237 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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. */
/*******************************************************************************/

/* this class represents a single raw MIDI event plus a timestamp */

#pragma once

#include "types.h"
#include <stdlib.h>

namespace MIDI
{
class midievent
{

public:

class sysex {
size_t _size, _alloc;
byte_t *_data;

public:

sysex ( void );
~sysex ( void );

void append ( byte_t *data, size_t size );
const byte_t * data ( void ) const;
long size ( void ) const;

};

private:

sysex *_sysex;

tick_t _timestamp; /* in ticks */
struct {
byte_t status, /* full status byte */
lsb, /* data 1 */
msb; /* data 2 */
} _data;

public:

static inline int
event_size ( byte_t op )
{
switch ( op )
{
case NOTE_ON: case NOTE_OFF: case AFTERTOUCH:
case CONTROL_CHANGE: case PITCH_WHEEL:
return 3;
case PROGRAM_CHANGE: case CHANNEL_PRESSURE:
return 2;
default:
return 1;
}
};

/* define MIDI status bytes */
enum {
STATUS_BIT = 0x80,
NOTE_OFF = 0x80,
NOTE_ON = 0x90,
AFTERTOUCH = 0xA0,
CONTROL_CHANGE = 0xB0,
PROGRAM_CHANGE = 0xC0,
CHANNEL_PRESSURE = 0xD0,
PITCH_WHEEL = 0xE0,
CLEAR_CHAN_MASK = 0xF0,
MIDI_CLOCK = 0xF8,
SYSEX = 0xF0,
SYSEX_END = 0xF7,
META = 0xFF
};

midievent ( void );
virtual ~midievent ( void );

tick_t timestamp ( void ) const;
void timestamp ( tick_t time );
void status ( byte_t status );
byte_t status ( void ) const;
void channel ( byte_t channel );
byte_t channel ( void ) const;
byte_t opcode ( void ) const;
void opcode ( byte_t o );
void lsb ( byte_t n );
void msb ( byte_t n );
int lsb ( void ) const;
int msb ( void ) const;
int pitch ( void ) const;
void pitch ( int n );
void data ( byte_t D1, byte_t D2 );
void data ( byte_t *D1, byte_t *D2 ) const;
void raw ( byte_t *p, int l) const;
int size ( void ) const;
void note_velocity ( int vel );
bool is_note_on ( void ) const;
bool is_note_off ( void ) const;
virtual unsigned char note ( void ) const;
virtual void note ( char note );
unsigned char note_velocity ( void ) const;
bool is_same_note ( midievent * e ) const;
const char * name ( void ) const;
int name ( const char *name ) const;
void print ( void ) const;
void pretty_print ( void ) const;

bool operator< ( const midievent &rhs ) const;
bool operator>= ( const midievent &rhs ) const;

bool operator== ( const midievent &rhs ) const;

};


/**********************/
/* Inlined accessors */
/**********************/


inline tick_t
midievent::timestamp ( void ) const
{
return _timestamp;
}

inline void
midievent::timestamp ( tick_t time )
{
_timestamp = time;
}

inline void
midievent::status ( byte_t status )
{
_data.status = status;
}

inline byte_t
midievent::status ( void ) const
{
return _data.status;
}

inline void
midievent::channel ( byte_t channel )
{
_data.status = (_data.status & 0xF0) | (channel & 0x0F);
}

inline byte_t
midievent::channel ( void ) const
{
return _data.status & 0x0F;
}

inline byte_t
midievent::opcode ( void ) const
{
return _data.status & 0xF0;
}


inline void
midievent::opcode ( byte_t opcode )
{
_data.status = (_data.status & 0x0F) | (opcode & 0xF0);
}

inline void
midievent::lsb ( byte_t n )
{
_data.lsb = n & 0x7F;
}

inline void
midievent::msb ( byte_t n )
{
_data.msb = n & 0x7F;
}

inline int
midievent::lsb ( void ) const
{
return _data.lsb;
}

inline int
midievent::msb ( void ) const
{
return _data.msb;
}

inline bool
midievent::is_note_on ( void ) const
{
return (opcode() == NOTE_ON);
}

inline bool
midievent::is_note_off ( void ) const
{
return (opcode() == NOTE_OFF);
}

inline bool
midievent::operator< ( const midievent &rhs ) const
{
return _timestamp < rhs._timestamp;
}

inline bool
midievent::operator>= ( const midievent &rhs ) const
{
return _timestamp >= rhs._timestamp;
}

}

+ 0
- 28
nonlib/MIDI/types.h View File

@@ -1,28 +0,0 @@


/*******************************************************************************/
/* Copyright (C) 2007,2008 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

typedef unsigned char byte_t;
typedef double tick_t;
typedef unsigned int uint;

#define elementsof(x) (sizeof((x)) / sizeof((x)[0]))


+ 0
- 81
nonlib/Mutex.H View File

@@ -1,81 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 <pthread.h>

const pthread_mutex_t _mutex_initializer = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

class Mutex
{

pthread_mutex_t _lock;

public:

Mutex ( )
{
// pthread_mutex_init( &_lock, NULL );
_lock = _mutex_initializer;
}

virtual ~Mutex ( )
{
pthread_mutex_destroy( &_lock );
}

void
lock ( void )
{
pthread_mutex_lock( &_lock );
}

void
unlock ( void )
{
pthread_mutex_unlock( &_lock );
}

bool
trylock ( void )
{
return pthread_mutex_trylock( &_lock ) == 0;
}

};


class Locker
{

Mutex &_lock;

public:

Locker ( Mutex & lock ) : _lock( lock )
{
_lock.lock();
}

~Locker ( )
{
_lock.unlock();
}
};

+ 0
- 298
nonlib/NSM/Client.C View File

@@ -1,298 +0,0 @@

/*******************************************************************************/
/* 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 "../debug.h"
#include "Client.H"
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

#pragma GCC diagnostic ignored "-Wunused-parameter"

namespace NSM
{

/************************/
/* OSC Message Handlers */
/************************/

#undef OSC_REPLY
#undef OSC_REPLY_ERR

#define OSC_REPLY( value ) lo_send_from( ((NSM::Client*)user_data)->nsm_addr, ((NSM::Client*)user_data)->_server, LO_TT_IMMEDIATE, "/reply", "ss", path, value )

#define OSC_REPLY_ERR( errcode, value ) lo_send_from( ((NSM::Client*)user_data)->nsm_addr, ((NSM::Client*)user_data)->_server, LO_TT_IMMEDIATE, "/error", "sis", path, errcode, value )

Client::Client ( )
{
nsm_addr = 0;
nsm_client_id = 0;
_session_manager_name = 0;
nsm_is_active = false;
_server = 0;
_st = 0;
}

Client::~Client ( )
{
if ( _st )
stop();
if ( _st )
lo_server_thread_free( _st );
else
lo_server_free ( _server );
}

void
Client::announce ( const char *application_name, const char *capabilities, const char *process_name )
{
MESSAGE( "Announcing to NSM" );

lo_address to = lo_address_new_from_url( nsm_url );

if ( ! to )
{
MESSAGE( "Bad address" );
return;
}

int pid = (int)getpid();

lo_send_from( to, _server, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
application_name,
capabilities,
process_name,
1, /* api_major_version */
0, /* api_minor_version */
pid );

lo_address_free( to );
}

void
Client::progress ( float p )
{
if ( nsm_is_active )
{
lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/progress", "f", p );
}
}

void
Client::is_dirty ( void )
{
if ( nsm_is_active )
{
lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/is_dirty", "" );
}
}

void
Client::is_clean ( void )
{
if ( nsm_is_active )
{
lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/is_clean", "" );
}
}

void
Client::message ( int priority, const char *msg )
{
if ( nsm_is_active )
{
lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/client/message", "is", priority, msg );
}
}

void
Client::broadcast ( lo_message msg )
{
if ( nsm_is_active )
{
lo_send_message_from( nsm_addr, _server, "/nsm/server/broadcast", msg );
}
}

void
Client::check ( int timeout )
{
if ( lo_server_wait( _server, timeout ) )
while ( lo_server_recv_noblock( _server, 0 ) ) {}
}

void
Client::start ( )
{
lo_server_thread_start( _st );
}

void
Client::stop ( )
{
lo_server_thread_stop( _st );
}

int
Client::init ( const char *nsm_url )
{
this->nsm_url = nsm_url;

lo_address addr = lo_address_new_from_url( nsm_url );
int proto = lo_address_get_protocol( addr );
lo_address_free( addr );

_server = lo_server_new_with_proto( NULL, proto, NULL );

if ( ! _server )
return -1;

lo_server_add_method( _server, "/error", "sis", &Client::osc_error, this );
lo_server_add_method( _server, "/reply", "ssss", &Client::osc_announce_reply, this );
lo_server_add_method( _server, "/nsm/client/open", "sss", &Client::osc_open, this );
lo_server_add_method( _server, "/nsm/client/save", "", &Client::osc_save, this );
lo_server_add_method( _server, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this );
lo_server_add_method( _server, NULL, NULL, &Client::osc_broadcast, this );

return 0;
}

int
Client::init_thread ( const char *nsm_url )
{
this->nsm_url = nsm_url;

lo_address addr = lo_address_new_from_url( nsm_url );
int proto = lo_address_get_protocol( addr );
lo_address_free( addr );
_st = lo_server_thread_new_with_proto( NULL, proto, NULL );
_server = lo_server_thread_get_server( _st );
if ( ! _server || ! _st )
return -1;

lo_server_thread_add_method( _st, "/error", "sis", &Client::osc_error, this );
lo_server_thread_add_method( _st, "/reply", "ssss", &Client::osc_announce_reply, this );
lo_server_thread_add_method( _st, "/nsm/client/open", "sss", &Client::osc_open, this );
lo_server_thread_add_method( _st, "/nsm/client/save", "", &Client::osc_save, this );
lo_server_thread_add_method( _st, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this );
lo_server_thread_add_method( _st, NULL, NULL, &Client::osc_broadcast, this );
return 0;
}

/************************/
/* OSC Message Handlers */
/************************/

int
Client::osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
return ((NSM::Client*)user_data)->command_broadcast( path, msg );
}

int
Client::osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
char *out_msg = NULL;
int r = ((NSM::Client*)user_data)->command_save(&out_msg);

if ( r )
OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
else
OSC_REPLY( "OK" );

if ( out_msg )
free( out_msg );

return 0;
}

int
Client::osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
char *out_msg = NULL;

NSM::Client *nsm = (NSM::Client*)user_data;
nsm->nsm_client_id = strdup( &argv[2]->s );

int r = ((NSM::Client*)user_data)->command_open( &argv[0]->s, &argv[1]->s, &argv[2]->s, &out_msg);
if ( r )
OSC_REPLY_ERR( r, ( out_msg ? out_msg : "") );
else
OSC_REPLY( "OK" );

if ( out_msg )
free( out_msg );

return 0;
}

int
Client::osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
NSM::Client *nsm = (NSM::Client*)user_data;

nsm->command_session_is_loaded();

return 0;
}

int
Client::osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
return -1;
NSM::Client *nsm = (NSM::Client*)user_data;


WARNING( "Failed to register with NSM: %s", &argv[2]->s );
nsm->nsm_is_active = false;
nsm->command_active( nsm->nsm_is_active );

return 0;
}

int
Client::osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
{
if ( strcmp( &argv[0]->s, "/nsm/server/announce" ) )
return -1;
NSM::Client *nsm = (NSM::Client*)user_data;

MESSAGE( "Successfully registered. NSM says: %s", &argv[1]->s );
nsm->nsm_is_active = true;
nsm->_session_manager_name = strdup( &argv[2]->s );
nsm->nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ));
nsm->command_active( nsm->nsm_is_active );

return 0;
}
};

+ 0
- 109
nonlib/NSM/Client.H View File

@@ -1,109 +0,0 @@

/*******************************************************************************/
/* 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 <lo/lo.h>

namespace NSM
{

class Client
{

private:

const char *nsm_url;

lo_server _server;
lo_server_thread _st;
lo_address nsm_addr;

bool nsm_is_active;
char *nsm_client_id;
char *_session_manager_name;

public:

enum
{
ERR_OK = 0,
ERR_GENERAL = -1,
ERR_INCOMPATIBLE_API = -2,
ERR_BLACKLISTED = -3,
ERR_LAUNCH_FAILED = -4,
ERR_NO_SUCH_FILE = -5,
ERR_NO_SESSION_OPEN = -6,
ERR_UNSAVED_CHANGES = -7,
ERR_NOT_NOW = -8
};

Client ( );
virtual ~Client ( );

bool is_active ( void ) { return nsm_is_active; }

const char *session_manager_name ( void ) { return _session_manager_name; }

/* Client->Server methods */
void is_dirty ( void );
void is_clean ( void );
void progress ( float f );
void message( int priority, const char *msg );
void announce ( const char *appliction_name, const char *capabilities, const char *process_name );

void broadcast ( lo_message msg );

/* init without threading */
int init ( const char *nsm_url );
/* init with threading */
int init_thread ( const char *nsm_url );
/* call this periodically to check for new messages */
void check ( int timeout = 0 );

/* or call these to start and stop a thread (must do your own locking in handler!) */
void start ( void );
void stop ( void );

protected:

/* Server->Client methods */
virtual int command_open ( const char *name, const char *display_name, const char *client_id, char **out_msg ) = 0;
virtual int command_save ( char **out_msg ) = 0;

virtual void command_active ( bool ) { }

virtual void command_session_is_loaded ( void ) { }

/* invoked when an unrecognized message is received. Should return 0 if you handled it, -1 otherwise. */
virtual int command_broadcast ( const char *, lo_message ) { return -1; }

private:

/* osc handlers */
static int osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data );
static int osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data );
static int osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data );
static int osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data );
static int osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data );
static int osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data );

};
};

+ 0
- 270
nonlib/dsp.C View File

@@ -1,270 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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. */
/*******************************************************************************/

/* General DSP related functions. */

#include "dsp.h"
#include "string.h" // for memset.
#include <stdlib.h>

static const int ALIGNMENT = 16;

#ifdef HAS_BUILTIN_ASSUME_ALIGNED
#define assume_aligned(x) __builtin_assume_aligned(x,ALIGNMENT)
#else
#define assume_aligned(x) (x)
#endif

sample_t *
buffer_alloc ( nframes_t size )
{
void *p;
posix_memalign( &p, ALIGNMENT, size * sizeof( sample_t ) );

return (sample_t*)p;
}

void
buffer_apply_gain ( sample_t * __restrict__ buf, nframes_t nframes, float g )
{
sample_t * buf_ = (sample_t*) assume_aligned(buf);
if ( g == 1.0f )
return;
for ( nframes_t i = 0; i < nframes; i++ )
buf_[i] *= g;
}

void
buffer_apply_gain_unaligned ( sample_t * __restrict__ buf, nframes_t nframes, float g )
{
if ( g == 1.0f )
return;
for ( nframes_t i = 0; i < nframes; i++ )
buf[i] *= g;
}

void
buffer_apply_gain_buffer ( sample_t * __restrict__ buf, const sample_t * __restrict__ gainbuf, nframes_t nframes )
{
sample_t * buf_ = (sample_t*) assume_aligned(buf);
const sample_t * gainbuf_ = (const sample_t*) assume_aligned(gainbuf);

for ( nframes_t i = 0; i < nframes; i++ )
buf_[i] *= gainbuf_[i];
}

void
buffer_copy_and_apply_gain_buffer ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, const sample_t * __restrict__ gainbuf, nframes_t nframes )
{
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);
const sample_t * gainbuf_ = (const sample_t*) assume_aligned(gainbuf);
for ( nframes_t i = 0; i < nframes; i++ )
dst_[i] = src_[i] * gainbuf_[i];
}

void
buffer_mix ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, nframes_t nframes )
{
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);

for ( nframes_t i = 0; i < nframes; i++ )
dst_[i] += src_[i];
}

void
buffer_mix_with_gain ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, nframes_t nframes, float g )
{
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);

for ( nframes_t i = 0; i < nframes; i++ )
dst_[i] += src_[i] * g;
}

void
buffer_interleave_one_channel ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, int channel, int channels, nframes_t nframes )
{
dst += channel;

while ( nframes-- )
{
*dst = *(src++);
dst += channels;
}
}

void
buffer_interleave_one_channel_and_mix ( sample_t *__restrict__ dst, const sample_t * __restrict__ src, int channel, int channels, nframes_t nframes )
{
dst += channel;

while ( nframes-- )
{
*dst += *(src++);
dst += channels;
}
}

void
buffer_deinterleave_one_channel ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, int channel, int channels, nframes_t nframes )
{
src += channel;

while ( nframes-- )
{
*(dst++) = *src;
src += channels;
}
}

void
buffer_interleaved_mix ( sample_t *__restrict__ dst, const sample_t * __restrict__ src, int dst_channel, int src_channel, int dst_channels, int src_channels, nframes_t nframes )
{
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);

dst_ += dst_channel;
src_ += src_channel;

while ( nframes-- )
{
*dst_ += *src_;
dst_ += dst_channels;
src_ += src_channels;
}
}

void
buffer_interleaved_copy ( sample_t *__restrict__ dst, const sample_t * __restrict__ src, int dst_channel, int src_channel, int dst_channels, int src_channels, nframes_t nframes )
{
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);

dst_ += dst_channel;
src_ += src_channel;

while ( nframes-- )
{
*dst_ = *src_;
dst_ += dst_channels;
src_ += src_channels;
}
}

void
buffer_fill_with_silence ( sample_t *buf, nframes_t nframes )
{
memset( buf, 0, nframes * sizeof( sample_t ) );
}

bool
buffer_is_digital_black ( const sample_t *buf, nframes_t nframes )
{
while ( nframes-- )
{
if (! *(buf++) )
continue;

return false;
}

return true;
}

float
buffer_get_peak ( const sample_t * __restrict__ buf, nframes_t nframes )
{
const sample_t * buf_ = (const sample_t*) assume_aligned(buf);

float pmax = 0.0f;
float pmin = 0.0f;

for ( nframes_t i = 0; i < nframes; i++ )
{
pmax = buf_[i] > pmax ? buf_[i] : pmax;
pmin = buf_[i] < pmin ? buf_[i] : pmin;
}

pmax = fabsf(pmax);
pmin = fabsf(pmin);
return pmax > pmin ? pmax : pmin;
}

void
buffer_copy ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, nframes_t nframes )
{
memcpy( dst, src, nframes * sizeof( sample_t ) );
}

void
buffer_copy_and_apply_gain ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, nframes_t nframes, float gain )
{
memcpy( dst, src, nframes * sizeof( sample_t ) );
buffer_apply_gain( dst, nframes, gain );
}


void
Value_Smoothing_Filter::sample_rate ( nframes_t n )
{
const float FS = n;
const float T = 0.05f;
w = _cutoff / (FS * T);
}

bool
Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, float gt )
{
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const float a = 0.07f;
const float b = 1 + a;
const float gm = b * gt;

float g1 = this->g1;
float g2 = this->g2;

if ( target_reached(gt) )
return false;

for (nframes_t i = 0; i < nframes; i++)
{
g1 += w * (gm - g1 - a * g2);
g2 += w * (g1 - g2);
dst_[i] = g2;
}

if ( fabsf( gt - g2 ) < 0.0001f )
g2 = gt;

this->g1 = g1;
this->g2 = g2;

return true;
}

+ 0
- 88
nonlib/dsp.h View File

@@ -1,88 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 "JACK/Client.H"
#include <math.h>


sample_t *buffer_alloc ( nframes_t size );
void buffer_apply_gain ( sample_t *buf, nframes_t nframes, float g );
void buffer_apply_gain_unaligned ( sample_t *buf, nframes_t nframes, float g );
void buffer_apply_gain_buffer ( sample_t *buf, const sample_t *gainbuf, nframes_t nframes );
void buffer_copy_and_apply_gain_buffer ( sample_t *dst, const sample_t *src, const sample_t *gainbuf, nframes_t nframes );
void buffer_mix ( sample_t *dst, const sample_t *src, nframes_t nframes );
void buffer_mix_with_gain ( sample_t *dst, const sample_t *src, nframes_t nframes, float g );
void buffer_interleave_one_channel ( sample_t *dst, const sample_t *src, int channel, int channels, nframes_t nframes );
void buffer_interleave_one_channel_and_mix ( sample_t *dst, const sample_t *src, int channel, int channels, nframes_t nframes );
void buffer_deinterleave_one_channel ( sample_t *dst, const sample_t *src, int channel, int channels, nframes_t nframes );
void buffer_interleaved_mix ( sample_t *__restrict__ dst, const sample_t * __restrict__ src, int dst_channel, int src_channel, int dst_channels, int src_channels, nframes_t nframes );
void buffer_interleaved_copy ( sample_t *__restrict__ dst, const sample_t * __restrict__ src, int dst_channel, int src_channel, int dst_channels, int src_channels, nframes_t nframes );
void buffer_fill_with_silence ( sample_t *buf, nframes_t nframes );
bool buffer_is_digital_black ( const sample_t *buf, nframes_t nframes );
float buffer_get_peak ( const sample_t *buf, nframes_t nframes );
void buffer_copy ( sample_t *dst, const sample_t *src, nframes_t nframes );
void buffer_copy_and_apply_gain ( sample_t *dst, const sample_t *src, nframes_t nframes, float gain );

class Value_Smoothing_Filter
{
float w, g1, g2;
float _cutoff;

public:

Value_Smoothing_Filter ( )
{
g1 = g2 = 0;
_cutoff = 10.0f;
}

void cutoff ( float v ) { _cutoff = v; }

void sample_rate ( nframes_t v );
inline bool target_reached ( float gt ) const { return gt == g2; }
bool apply ( sample_t *dst, nframes_t nframes, float target );

};

static inline float interpolate_cubic ( const float fr, const float inm1, const float in, const float inp1, const float inp2)
{
return in + 0.5f * fr * (inp1 - inm1 +
fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 +
fr * (3.0f * (in - inp1) - inm1 + inp2)));
}

// from SWH plugins.
// Convert a value in dB's to a coefficent
#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
#define CO_DB(v) (20.0f * log10f(v))

#define DEG2RAD 0.01745329251f
#define ONEOVERSQRT2 0.70710678118f

#ifndef likely
#define likely(x) __builtin_expect(x,1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(x,0)
#endif

+ 0
- 91
nonlib/string_util.C View File

@@ -1,91 +0,0 @@

/*******************************************************************************/
/* 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 <string.h>
#include <stdio.h>

void unescape_url ( char *url )
{
char *r, *w;

r = w = url;

for ( ; *r; r++, w++ )
{
if ( *r == '%' )
{
char data[3] = { *(r + 1), *(r + 2), 0 };

int c;

sscanf( data, "%2X", &c );

*w = c;

r += 2;
}
else
*w = *r;
}

*w = 0;
}

char *escape_url ( const char *url )
{
const char *s;
char *w;

char r[1024];

s = url;

w = r;

for ( ; *s && w < r + sizeof( r ); s++, w++ )
{
switch ( *s )
{
case '<':
case '>':
case '%':
// liblo doesn't like these in method names
case '[':
case ']':
case '{':
case '}':
case '?':
case ',':
case '#':
case '*':
case ' ':
sprintf( w, "%%%2X", *s );
w += 2;
break;
default:
*w = *s;
break;
}
}

*w = 0;
return strdup( r );
}

+ 0
- 21
nonlib/string_util.h View File

@@ -1,21 +0,0 @@

/*******************************************************************************/
/* 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. */
/*******************************************************************************/

void unescape_url ( char *url );
char * escape_url ( const char *url );

+ 0
- 25
nonlib/types.h View File

@@ -1,25 +0,0 @@

/*******************************************************************************/
/* Copyright (C) 2008 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 <jack/jack.h>

typedef jack_nframes_t nframes_t;
typedef float sample_t;

+ 2
- 11
nonlib/wscript View File

@@ -7,23 +7,14 @@ def configure(conf):
pass pass


def build(bld): def build(bld):
#Thread is needed by OSC/Endpoint
#File is for nsmd lockfiles
bld.stlib( bld.stlib(
source = ''' source = '''
JACK/Client.C
JACK/Port.C
Log_Entry.C
Loggable.C
NSM/Client.C
OSC/Endpoint.C OSC/Endpoint.C
Thread.C Thread.C
debug.C debug.C
dsp.C
file.C file.C
MIDI/midievent.C
string_util.C
MIDI/event_list.C
MIDI/event.C
MIDI/midievent.C
''', ''',
includes = '.', includes = '.',
export_incdirs = [ '.', 'nonlib'], export_incdirs = [ '.', 'nonlib'],


+ 1
- 0
session-manager/src/nsmd.cpp View File

@@ -19,6 +19,7 @@


#define __MODULE__ "nsmd" #define __MODULE__ "nsmd"


//debug.C has only one function that gets used multiple times by debug.H and for logging and printing
#include "debug.h" #include "debug.h"


#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE


Loading…
Cancel
Save