Mixer: Implement de-zippering for controls of all built-in modules.

pull/116/head
Jonathan Moore Liles 2013-06-15 17:51:50 -07:00
parent 3e932c9930
commit 72a1e2a5cf
19 changed files with 249 additions and 33 deletions

View File

@ -50,6 +50,8 @@ AUX_Module::AUX_Module ( ) : JACK_Module ( false )
color( FL_DARK1 );
copy_label( "Aux" );
smoothing.sample_rate( sample_rate() );
}
AUX_Module::~AUX_Module ( )
@ -97,17 +99,39 @@ AUX_Module::number ( int n )
copy_label( s );
}
void
AUX_Module::handle_sample_rate_change ( nframes_t n )
{
smoothing.sample_rate( n );
}
void
AUX_Module::process ( nframes_t nframes )
{
if ( !bypass() )
{
float g = DB_CO( control_input[0].control_value() );
float gt = DB_CO( control_input[0].control_value() );
for ( unsigned int i = 0; i < audio_input.size(); ++i )
if ( !smoothing.target_reached( gt ) )
{
if ( audio_input[i].connected() )
buffer_copy_and_apply_gain( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), nframes, g );
sample_t gainbuf[nframes];
smoothing.apply( gainbuf, nframes, gt );
for ( unsigned int i = 0; i < audio_input.size(); ++i )
{
if ( audio_input[i].connected() )
buffer_copy_and_apply_gain_buffer( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), gainbuf, nframes );
}
}
else
{
for ( unsigned int i = 0; i < audio_input.size(); ++i )
{
if ( audio_input[i].connected() )
buffer_copy_and_apply_gain( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), nframes, gt );
}
}
}
else

View File

@ -20,11 +20,14 @@
#pragma once
#include "JACK_Module.H"
#include "dsp.h"
class AUX_Module : public JACK_Module
{
int _number;
Value_Smoothing_Filter smoothing;
protected:
virtual void get ( Log_Entry &e ) const;
@ -44,6 +47,8 @@ public:
virtual ~AUX_Module ( );
LOG_CREATE_FUNC( AUX_Module );
virtual void handle_sample_rate_change ( nframes_t n );
protected:

View File

@ -250,13 +250,12 @@ Chain::initialize_with_default ( void )
m->is_default( true );
m->chain( this );
m->configure_outputs( 1 );
m->initialize();
add( m );
}
{ Module *m = new Gain_Module();
m->is_default( true );
m->initialize();
m->chain(this);
add( m );
}
@ -268,7 +267,6 @@ Chain::initialize_with_default ( void )
{ JACK_Module *m = new JACK_Module();
m->is_default( true );
m->chain( this );
m->initialize();
add( m );
}
}
@ -462,7 +460,10 @@ Chain::name ( const char *name )
engine()->buffer_size_callback( &Chain::buffer_size, this );
engine()->port_connect_callback( &Chain::port_connect, this );
engine()->sample_rate_changed_callback( &Chain::sample_rate_change, this );
Module::set_sample_rate( engine()->sample_rate() );
const char *jack_name = engine()->init( ename );
if ( ! jack_name )
@ -580,6 +581,7 @@ Chain::insert ( Module *m, Module *n )
n->ncontrol_inputs(),
n->ncontrol_outputs() );
n->initialize();
return true;
err:
@ -829,6 +831,26 @@ Chain::buffer_size ( nframes_t nframes )
}
}
int
Chain::sample_rate_change ( nframes_t nframes, void *v )
{
((Chain*)v)->sample_rate_change( nframes );
}
int
Chain::sample_rate_change ( nframes_t nframes )
{
Module::set_sample_rate ( nframes );
for ( int i = 0; i < modules(); ++i )
{
Module *m = module(i);
m->handle_sample_rate_change( nframes );
}
return 0;
}
void
Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *v )
{

View File

@ -74,6 +74,8 @@ private:
static void buffer_size ( nframes_t nframes, void *v );
void buffer_size ( nframes_t nframes );
static int sample_rate_change ( nframes_t nframes, void *v );
int sample_rate_change ( nframes_t nframes );
static void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *v );

View File

@ -20,7 +20,7 @@
#include "Engine.H"
#include "../Mixer.H" // for process()
// #include "../Mixer.H" // for process()
/* This is the home of the JACK process callback */
@ -37,6 +37,7 @@ Engine::Engine ( void (*process_callback)(nframes_t nframes, void *), void *user
_buffer_size_callback = 0;
_buffers_dropped = 0;
_port_connect_callback = 0;
_sample_rate_changed_callback = 0;
}
Engine::~Engine ( )
@ -53,6 +54,13 @@ Engine::buffer_size_callback ( void ( *buffer_size_callback ) ( nframes_t, void
_buffer_size_callback_user_data = user_data;
}
void
Engine::sample_rate_changed_callback ( int ( *sample_rate_changed_callback ) ( nframes_t, void * ), void *user_data )
{
_sample_rate_changed_callback = sample_rate_changed_callback;
_sample_rate_changed_callback_user_data = user_data;
}
void
Engine::port_connect_callback ( void ( *port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg), void *user_data )
{
@ -132,6 +140,14 @@ Engine::process ( nframes_t nframes )
return 0;
}
int
Engine::sample_rate_changed ( nframes_t srate )
{
if ( _sample_rate_changed_callback )
return _sample_rate_changed_callback( srate, _sample_rate_changed_callback_user_data );
return 0;
}
/* TRHEAD: RT */
void

View File

@ -40,9 +40,13 @@ class Engine : public JACK::Client, public Mutex
void ( * _buffer_size_callback ) ( nframes_t, void * );
void *_buffer_size_callback_user_data;
int ( * _sample_rate_changed_callback ) ( nframes_t, void * );
void *_sample_rate_changed_callback_user_data;
void ( * _port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void * );
void *_port_connect_callback_user_data;
int sample_rate_changed ( nframes_t srate );
void shutdown ( void );
int process ( nframes_t nframes );
int xrun ( void );
@ -67,5 +71,6 @@ public:
int dropped ( void ) const { return _buffers_dropped; }
void buffer_size_callback ( void ( *buffer_size_callback ) ( nframes_t, void * ), void *user_data );
void sample_rate_changed_callback ( int ( *sample_rate_changed_callback ) ( nframes_t, void * ), void *user_data );
void port_connect_callback ( void ( *port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg), void *user_data );
};

View File

@ -45,6 +45,8 @@ Gain_Module::Gain_Module ( )
end();
log_create();
smoothing.sample_rate( sample_rate() );
}
Gain_Module::~Gain_Module ( )
@ -71,6 +73,12 @@ Gain_Module::configure_inputs ( int n )
return true;
}
void
Gain_Module::handle_sample_rate_change ( nframes_t n )
{
smoothing.sample_rate( n );
}
/**********/
@ -80,13 +88,30 @@ Gain_Module::configure_inputs ( int n )
void
Gain_Module::process ( nframes_t nframes )
{
float g = DB_CO( control_input[0].control_value() );
const float gt = DB_CO( control_input[0].control_value() );
for ( int i = audio_input.size(); i--; )
if ( !smoothing.target_reached( gt ) )
{
if ( audio_input[i].connected() && audio_output[i].connected() )
sample_t gainbuf[nframes];
smoothing.apply( gainbuf, nframes, gt );
for ( int i = audio_input.size(); i--; )
{
buffer_apply_gain( (sample_t*)audio_input[i].buffer(), nframes, g );
if ( audio_input[i].connected() && audio_output[i].connected() )
{
sample_t *out = (sample_t*)audio_input[i].buffer();
buffer_apply_gain_buffer( out, gainbuf, nframes );
}
}
}
else
for ( int i = audio_input.size(); i--; )
{
if ( audio_input[i].connected() && audio_output[i].connected() )
{
buffer_apply_gain( (sample_t*)audio_input[i].buffer(), nframes, gt );
}
}
}

View File

@ -20,9 +20,12 @@
#pragma once
#include "Module.H"
#include "dsp.h"
class Gain_Module : public Module
{
Value_Smoothing_Filter smoothing;
public:
Gain_Module ( );
@ -38,6 +41,8 @@ public:
MODULE_CLONE_FUNC( Gain_Module );
virtual void handle_sample_rate_change ( nframes_t n );
protected:
virtual void process ( nframes_t nframes );

View File

@ -47,6 +47,7 @@
nframes_t Module::_sample_rate = 0;
Module *Module::_copied_module_empty = 0;
char *Module::_copied_module_settings = 0;

View File

@ -49,6 +49,7 @@ class Module : public Fl_Group, public Loggable {
Module_Parameter_Editor *_editor;
static nframes_t _sample_rate;
static Module *_copied_module_empty;
static char *_copied_module_settings;
@ -414,6 +415,9 @@ public:
virtual void process ( nframes_t ) = 0;
/* called whenever the module is initialized or when the sample rate is changed at runtime */
virtual void handle_sample_rate_change ( nframes_t sample_rate ) {}
/* called whenever the value of a control port is changed.
This can be used to take appropriate action from the GUI thread */
virtual void handle_control_changed ( Port * );
@ -436,6 +440,8 @@ public:
protected:
nframes_t sample_rate ( void ) const { return Module::_sample_rate; }
void draw_connections ( void );
void draw_label ( int X, int Y, int W, int H );
void draw_box ( int X, int Y, int W, int H );
@ -448,6 +454,8 @@ protected:
public:
static void set_sample_rate ( nframes_t srate ) { _sample_rate = srate; }
void command_open_parameter_editor();
virtual void command_activate ( void );
virtual void command_deactivate ( void );

View File

@ -47,6 +47,8 @@ Mono_Pan_Module::Mono_Pan_Module ( )
end();
log_create();
smoothing.sample_rate( sample_rate() );
}
Mono_Pan_Module::~Mono_Pan_Module ( )
@ -57,6 +59,12 @@ Mono_Pan_Module::~Mono_Pan_Module ( )
void
Mono_Pan_Module::handle_sample_rate_change ( nframes_t n )
{
smoothing.sample_rate( n );
}
bool
Mono_Pan_Module::configure_inputs ( int )
{
@ -72,10 +80,6 @@ Mono_Pan_Module::configure_inputs ( int )
void
Mono_Pan_Module::process ( nframes_t nframes )
{
const float g = control_input[0].control_value();
const float lg = (0.0f - g) + 1.0f;
const float rg = g + 1.0f;
if ( audio_input[0].connected() &&
audio_output[0].connected() &&
@ -87,9 +91,38 @@ Mono_Pan_Module::process ( nframes_t nframes )
}
else
{
buffer_copy_and_apply_gain( (sample_t*)audio_output[1].buffer(), (sample_t*)audio_input[0].buffer(), nframes, rg );
const float gt = (control_input[0].control_value() + 1.0f) * 0.5f;
if ( ! smoothing.target_reached( gt ) )
{
sample_t gainbuf[nframes];
buffer_apply_gain( (sample_t*)audio_output[0].buffer(), nframes, lg );
smoothing.apply( gainbuf, nframes, gt );
/* right channel */
buffer_copy_and_apply_gain_buffer( (sample_t*)audio_output[1].buffer(),
(sample_t*)audio_input[0].buffer(),
gainbuf,
nframes );
/* left channel */
for ( nframes_t i = 0; i < nframes; i++ )
gainbuf[i] = 1.0f - gainbuf[i];
buffer_apply_gain_buffer( (sample_t*)audio_output[0].buffer(), gainbuf, nframes );
}
else
{
/* right channel */
buffer_copy_and_apply_gain( (sample_t*)audio_output[1].buffer(),
(sample_t*)audio_input[0].buffer(),
nframes,
gt );
/* left channel */
buffer_apply_gain( (sample_t*)audio_output[0].buffer(), nframes, 1.0f - gt);
}
}
}
}

View File

@ -20,9 +20,12 @@
#pragma once
#include "Module.H"
#include "dsp.h"
class Mono_Pan_Module : public Module
{
Value_Smoothing_Filter smoothing;
public:
Mono_Pan_Module ( );
@ -37,6 +40,8 @@ public:
MODULE_CLONE_FUNC( Mono_Pan_Module );
virtual void handle_sample_rate_change ( nframes_t n );
protected:
virtual void process ( nframes_t nframes );

View File

@ -341,7 +341,7 @@ Plugin_Module::plugin_instances ( unsigned int n )
DMESSAGE( "Instantiating plugin..." );
if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, Engine::sample_rate() ) ) )
if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) )
{
WARNING( "Failed to instantiate plugin" );
return false;
@ -474,7 +474,7 @@ Plugin_Module::load ( unsigned long id )
p.hints.minimum = _idata->descriptor->PortRangeHints[i].LowerBound;
if ( LADSPA_IS_HINT_SAMPLE_RATE(hd) )
{
p.hints.minimum *= Engine::sample_rate();
p.hints.minimum *= sample_rate();
}
}
if ( LADSPA_IS_HINT_BOUNDED_ABOVE(hd) )
@ -483,7 +483,7 @@ Plugin_Module::load ( unsigned long id )
p.hints.maximum = _idata->descriptor->PortRangeHints[i].UpperBound;
if ( LADSPA_IS_HINT_SAMPLE_RATE(hd) )
{
p.hints.maximum *= Engine::sample_rate();
p.hints.maximum *= sample_rate();
}
}
@ -500,7 +500,7 @@ Plugin_Module::load ( unsigned long id )
Min=_idata->descriptor->PortRangeHints[Port].LowerBound;
if (LADSPA_IS_HINT_SAMPLE_RATE(HintDesc))
{
Min*=Engine::sample_rate();
Min*=sample_rate();
}
}
if (LADSPA_IS_HINT_BOUNDED_ABOVE(HintDesc))
@ -508,7 +508,7 @@ Plugin_Module::load ( unsigned long id )
Max=_idata->descriptor->PortRangeHints[Port].UpperBound;
if (LADSPA_IS_HINT_SAMPLE_RATE(HintDesc))
{
Max*=Engine::sample_rate();
Max*=sample_rate();
}
}
@ -576,7 +576,7 @@ Plugin_Module::load ( unsigned long id )
}
}
if (LADSPA_IS_HINT_SAMPLE_RATE(HintDesc)) {
Default *= Engine::sample_rate();
Default *= sample_rate();
}
if (LADSPA_IS_HINT_INTEGER(HintDesc)) {
if ( p.hints.ranged &&

View File

@ -29,7 +29,7 @@
namespace JACK
{
nframes_t Client::_sample_rate = 0;
// nframes_t Client::_sample_rate = 0;
Client::Client ( )
{
@ -114,6 +114,13 @@ namespace JACK
((Client*)arg)->port_connect( a, b, connect );
}
int
Client::sample_rate_changed ( nframes_t srate, void *arg )
{
// ((Client*)arg)->_sample_rate = srate;
return ((Client*)arg)->sample_rate_changed( srate );
}
/** Connect to JACK using client name /client_name/. Return a static
* pointer to actual name as reported by JACK */
const char *
@ -131,6 +138,8 @@ namespace JACK
set_callback( buffer_size );
set_callback( port_connect );
jack_set_sample_rate_callback( _client, &Client::sample_rate_changed, this );
/* FIXME: should we wait to register this until after the project
has been loaded (and we have disk threads running)? */
if ( opts & SLOW_SYNC )
@ -143,7 +152,7 @@ namespace JACK
jack_activate( _client );
_sample_rate = frame_rate();
// _sample_rate = frame_rate();
return jack_get_client_name( _client );
}

View File

@ -35,11 +35,13 @@ namespace JACK
jack_client_t *_client;
static nframes_t _sample_rate;
// nframes_t _sample_rate;
volatile int _xruns;
volatile bool _freewheeling;
volatile bool _zombified;
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 );
@ -93,15 +95,14 @@ namespace JACK
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 ); }
static nframes_t sample_rate ( void ) { return _sample_rate; }
// 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 );

View File

@ -127,3 +127,37 @@ buffer_copy_and_apply_gain ( sample_t *dst, const sample_t *src, nframes_t nfram
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 = 10.0f / (FS * T);
}
void
Value_Smoothing_Filter::apply( sample_t *dst, nframes_t nframes, float gt )
{
const float a = 0.07f;
const float b = 1 + a;
const float gm = b * gt;
float g1 = this->g1;
float g2 = this->g2;
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;
}

View File

@ -35,6 +35,27 @@ bool buffer_is_digital_black ( 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;
public:
Value_Smoothing_Filter ( )
{
g1 = g2 = 0;
}
void sample_rate ( nframes_t v );
inline bool target_reached ( float gt ) const { return gt == g2; }
void apply ( sample_t *dst, nframes_t nframes, float target );
};
// 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)

View File

@ -64,7 +64,7 @@ public:
float frames_to_milliseconds ( nframes_t frames )
{
return ( frames * 1000 ) / (float)frame_rate();
return ( frames * 1000 ) / (float)sample_rate();
}
};

View File

@ -109,7 +109,7 @@ Track::configure_outputs ( int n )
}
if ( output.size() )
playback_ds = new Playback_DS( this, engine->frame_rate(), engine->nframes(), output.size() );
playback_ds = new Playback_DS( this, engine->sample_rate(), engine->nframes(), output.size() );
/* FIXME: bogus */
return true;
@ -162,7 +162,7 @@ Track::configure_inputs ( int n )
}
if ( input.size() )
record_ds = new Record_DS( this, engine->frame_rate(), engine->nframes(), input.size() );
record_ds = new Record_DS( this, engine->sample_rate(), engine->nframes(), input.size() );
// engine->unlock();