@@ -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 | |||
@@ -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: | |||
@@ -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 ) | |||
{ | |||
@@ -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 ); | |||
@@ -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 | |||
@@ -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 ); | |||
}; |
@@ -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 ); | |||
} | |||
} | |||
} |
@@ -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 ); | |||
@@ -47,6 +47,7 @@ | |||
nframes_t Module::_sample_rate = 0; | |||
Module *Module::_copied_module_empty = 0; | |||
char *Module::_copied_module_settings = 0; | |||
@@ -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 ); | |||
@@ -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); | |||
} | |||
} | |||
} | |||
} |
@@ -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 ); | |||
@@ -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 && | |||
@@ -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 ); | |||
} | |||
@@ -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 ); | |||
@@ -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; | |||
} |
@@ -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) | |||
@@ -64,7 +64,7 @@ public: | |||
float frames_to_milliseconds ( nframes_t frames ) | |||
{ | |||
return ( frames * 1000 ) / (float)frame_rate(); | |||
return ( frames * 1000 ) / (float)sample_rate(); | |||
} | |||
}; | |||
@@ -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(); | |||