Mixer/Spatializer_Module:

Remove distance related frequency effects.
Add control to disable delay effects.
Add angle control with frequency and reflection effects.
Add advanced options for controlling early and late reverb send amounts.
pull/116/head
Jonathan Moore Liles 2013-09-01 21:37:28 -07:00
parent e927781ee0
commit b3a9d0be1d
5 changed files with 210 additions and 45 deletions

View File

@ -48,8 +48,6 @@ class Module : public Fl_Group, public Loggable {
bool _is_default;
// nframes_t _latency;
Module_Parameter_Editor *_editor;
static nframes_t _sample_rate;
static Module *_copied_module_empty;
static char *_copied_module_settings;
@ -68,6 +66,8 @@ class Module : public Fl_Group, public Loggable {
protected:
Module_Parameter_Editor *_editor;
volatile bool _bypass;
public:

View File

@ -469,6 +469,13 @@ Module_Parameter_Editor::handle_control_changed ( Module::Port *p )
}
}
void
Module_Parameter_Editor::reload ( void )
{
make_controls();
redraw();
}
void
Module_Parameter_Editor::set_value (int i, float value )
{

View File

@ -90,6 +90,7 @@ class Module_Parameter_Editor : public Fl_Double_Window
public:
void reload ( void );
void handle_control_changed ( Module::Port *p );
Module_Parameter_Editor ( Module *module );

View File

@ -21,11 +21,9 @@
#include <FL/Fl_Box.H>
#include "Spatializer_Module.H"
#include "dsp.h"
#include "Module_Parameter_Editor.H"
static const float max_distance = 15.0f;
static const float HIGHPASS_FREQ = 200.0f;
//static const float LOWPASS_FREQ = 70000.0f;
static const float LOWPASS_FREQ = 22000.0f;
#include <math.h>
@ -381,6 +379,7 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
is_default( false );
_panner = 0;
_early_panner = 0;
{
Port p( this, Port::INPUT, Port::CONTROL, "Azimuth" );
@ -423,7 +422,6 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Highpass (Hz)" );
@ -432,7 +430,8 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
p.hints.minimum = 0.0f;
p.hints.maximum = 600.0f;
p.hints.default_value = 0.0f;
p.hints.visible = false;
p.connect_to( new float );
p.control_value( p.hints.default_value );
@ -446,6 +445,73 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
p.hints.minimum = -90.0f;
p.hints.maximum = 90.0f;
p.hints.default_value = 90.0f;
p.connect_to( new float );
p.control_value( p.hints.default_value );
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Angle" );
p.hints.type = Port::Hints::LINEAR;
p.hints.ranged = true;
p.hints.minimum = -180.0f;
p.hints.maximum = +180.0f;
p.hints.default_value = 0.0f;
p.connect_to( new float );
p.control_value( p.hints.default_value );
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Advanced Options" );
p.hints.type = Port::Hints::BOOLEAN;
p.hints.ranged = true;
p.hints.minimum = 0.0f;
p.hints.maximum = 1.0f;
p.hints.default_value = 0.0f;
p.connect_to( new float );
p.control_value( p.hints.default_value );
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Speed of Sound" );
p.hints.type = Port::Hints::BOOLEAN;
p.hints.ranged = true;
p.hints.minimum = 0.0f;
p.hints.maximum = 1.0f;
p.hints.default_value = 1.0f;
p.hints.visible = false;
p.connect_to( new float );
p.control_value( p.hints.default_value );
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Late Gain (dB)" );
p.hints.type = Port::Hints::LOGARITHMIC;
p.hints.ranged = true;
p.hints.minimum = -70.0f;
p.hints.maximum = 6.0f;
p.hints.default_value = 0.0f;
p.hints.visible = false;
p.connect_to( new float );
p.control_value( p.hints.default_value );
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Early Gain (dB)" );
p.hints.type = Port::Hints::LOGARITHMIC;
p.hints.ranged = true;
p.hints.minimum = -70.0f;
p.hints.maximum = 6.0f;
p.hints.default_value = 0.0f;
p.hints.visible = false;
p.connect_to( new float );
p.control_value( p.hints.default_value );
@ -456,6 +522,7 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
log_create();
_panner = new ambisonic_panner();
_early_panner = new ambisonic_panner();
labelsize(9);
@ -465,6 +532,8 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
align(FL_ALIGN_LEFT|FL_ALIGN_TOP|FL_ALIGN_INSIDE);
gain_smoothing.sample_rate( sample_rate() );
late_gain_smoothing.sample_rate( sample_rate() );
early_gain_smoothing.sample_rate( sample_rate() );
delay_smoothing.cutoff( 0.5f );
delay_smoothing.sample_rate( sample_rate() );
}
@ -472,12 +541,10 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
Spatializer_Module::~Spatializer_Module ( )
{
configure_inputs(0);
delete _early_panner;
delete _panner;
delete (float*)control_input[0].buffer();
delete (float*)control_input[1].buffer();
delete (float*)control_input[2].buffer();
delete (float*)control_input[3].buffer();
delete (float*)control_input[4].buffer();
for ( unsigned int i = 0; i < control_input.size(); i++ )
delete (float*)control_input[i].buffer();
}
@ -488,6 +555,8 @@ Spatializer_Module::handle_sample_rate_change ( nframes_t n )
{
gain_smoothing.sample_rate( n );
delay_smoothing.sample_rate( n );
early_gain_smoothing.sample_rate( n );
late_gain_smoothing.sample_rate( n );
for ( unsigned int i = 0; i < audio_input.size(); i++ )
{
@ -533,10 +602,17 @@ Spatializer_Module::process ( nframes_t nframes )
float radius = control_input[2].control_value();
float highpass_freq = control_input[3].control_value();
float width = control_input[4].control_value();
float angle = control_input[5].control_value();
// bool more_options = control_input[6].control_value();
bool speed_of_sound = control_input[7].control_value() > 0.5f;
float late_gain = DB_CO( control_input[8].control_value() );
float early_gain = DB_CO( control_input[9].control_value() );
control_input[3].hints.visible = highpass_freq != 0.0f;
float delay_seconds = 0.0f;
if ( radius > 1.0f )
if ( speed_of_sound && radius > 1.0f )
delay_seconds = ( radius - 1.0f ) / 340.29f;
/* direct sound follows inverse square law */
@ -548,12 +624,12 @@ Spatializer_Module::process ( nframes_t nframes )
float gain = 1.0f / radius;
float cutoff_frequency = gain * LOWPASS_FREQ;
/* float cutoff_frequency = gain * LOWPASS_FREQ; */
sample_t gainbuf[nframes];
sample_t delaybuf[nframes];
bool use_gainbuf = gain_smoothing.apply( gainbuf, nframes, gain );
bool use_gainbuf = false;
bool use_delaybuf = delay_smoothing.apply( delaybuf, nframes, delay_seconds );
for ( unsigned int i = 0; i < audio_input.size(); i++ )
@ -562,23 +638,101 @@ Spatializer_Module::process ( nframes_t nframes )
/* frequency effects */
_highpass[i]->run_highpass( buf, highpass_freq, nframes );
_lowpass[i]->run_lowpass( buf, cutoff_frequency, nframes );
/* send to late reverb */
if ( i == 0 )
buffer_copy( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), buf, nframes );
else
buffer_mix( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), buf, nframes );
/* /\* FIXME: use smoothed value... *\/ */
/* buffer_apply_gain( (sample_t*)jack_output[0].buffer(nframes), nframes, 1.0f / sqrt(D) ); */
if ( use_delaybuf )
_delay[i]->run( buf, delaybuf, 0, nframes );
else
_delay[i]->run( buf, 0, delay_seconds, nframes );
}
{
use_gainbuf = late_gain_smoothing.apply( gainbuf, nframes, late_gain );
/* gain effects */
if ( use_gainbuf )
buffer_apply_gain_buffer( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), gainbuf, nframes );
else
buffer_apply_gain( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), nframes, late_gain );
}
float early_angle = azimuth - angle;
if ( early_angle > 180.0f )
early_angle = -180 - ( early_angle - 180 );
else if ( early_angle < -180.0f )
early_angle = 180 - ( early_angle + 180 );
/* send to early reverb */
if ( audio_input.size() == 1 )
{
_early_panner->run_mono( (sample_t*)audio_input[0].buffer(),
(sample_t*)aux_audio_output[1].jack_port()->buffer(nframes),
(sample_t*)aux_audio_output[2].jack_port()->buffer(nframes),
(sample_t*)aux_audio_output[3].jack_port()->buffer(nframes),
(sample_t*)aux_audio_output[4].jack_port()->buffer(nframes),
azimuth + angle,
elevation,
nframes );
}
else
{
_early_panner->run_stereo( (sample_t*)audio_input[0].buffer(),
(sample_t*)audio_input[1].buffer(),
(sample_t*)aux_audio_output[1].jack_port()->buffer(nframes),
(sample_t*)aux_audio_output[2].jack_port()->buffer(nframes),
(sample_t*)aux_audio_output[3].jack_port()->buffer(nframes),
(sample_t*)aux_audio_output[4].jack_port()->buffer(nframes),
azimuth + angle,
elevation,
width,
nframes );
}
{
use_gainbuf = early_gain_smoothing.apply( gainbuf, nframes, early_gain );
for ( int i = 1; i < 5; i++ )
{
/* gain effects */
if ( use_gainbuf )
buffer_apply_gain_buffer( (sample_t*)aux_audio_output[i].jack_port()->buffer(nframes), gainbuf, nframes );
else
buffer_apply_gain( (sample_t*)aux_audio_output[i].jack_port()->buffer(nframes), nframes, early_gain );
}
}
float corrected_angle = fabs( angle ) - (fabs( width ) * 0.5f);
if ( corrected_angle < 0.0f )
corrected_angle = 0.0f;
float cutoff_frequency = ( 1.0f / ( 1.0f + corrected_angle ) ) * 300000.0f;
use_gainbuf = gain_smoothing.apply( gainbuf, nframes, gain );
for ( unsigned int i = 0; i < audio_input.size(); i++ )
{
/* gain effects */
if ( use_gainbuf )
buffer_apply_gain_buffer( (sample_t*)audio_input[i].buffer(), gainbuf, nframes );
else
buffer_apply_gain( (sample_t*)audio_input[i].buffer(), nframes, gain );
/* frequency effects */
_lowpass[i]->run_lowpass( (sample_t*)audio_input[i].buffer(), cutoff_frequency, nframes );
/* delay effects */
if ( speed_of_sound )
{
if ( use_delaybuf )
_delay[i]->run( (sample_t*)audio_input[i].buffer(), delaybuf, 0, nframes );
else
_delay[i]->run( (sample_t*)audio_input[i].buffer(), 0, delay_seconds, nframes );
}
}
/* now do direct outputs */
if ( audio_input.size() == 1 )
{
_panner->run_mono( (sample_t*)audio_input[0].buffer(),
@ -603,25 +757,24 @@ Spatializer_Module::process ( nframes_t nframes )
width,
nframes );
}
/* send to early reverb */
for ( int i = 4; i--; )
buffer_copy( (sample_t*)aux_audio_output[1 + i].jack_port()->buffer(nframes),
(sample_t*)audio_output[0 + i].buffer(),
nframes );
}
}
/* gain effects */
if ( use_gainbuf )
{
for ( int i = 4; i--; )
buffer_apply_gain_buffer( (sample_t*)audio_output[i].buffer(), gainbuf, nframes );
}
else
{
for ( int i = 4; i--; )
buffer_apply_gain( (sample_t*)audio_output[i].buffer(), nframes, gain );
}
}
void
Spatializer_Module::handle_control_changed ( Port *p )
{
if ( p == &control_input[6] )
{
bool v = p->control_value();
control_input[7].hints.visible = v;
control_input[8].hints.visible = v;
control_input[9].hints.visible = v;
DMESSAGE( "reloading" );
if ( _editor )
_editor->reload();
}
}
bool
@ -673,9 +826,10 @@ Spatializer_Module::configure_inputs ( int n )
}
}
control_input[4].hints.visible = audio_input.size() == 2;
// control_input[4].hints.visible = audio_input.size() == 2;
control_input[4].hints.default_value = audio_input.size() == 2 ? 90.0f : 0.0f;
if ( n == 0 )
{
remove_aux_audio_outputs();

View File

@ -30,12 +30,15 @@ class Spatializer_Module : public JACK_Module
{
Value_Smoothing_Filter gain_smoothing;
Value_Smoothing_Filter delay_smoothing;
Value_Smoothing_Filter late_gain_smoothing;
Value_Smoothing_Filter early_gain_smoothing;
std::vector<filter*> _lowpass;
std::vector<filter*> _highpass;
std::vector<delay*> _delay;
ambisonic_panner *_panner;
ambisonic_panner *_early_panner;
public:
@ -53,7 +56,7 @@ public:
MODULE_CLONE_FUNC(Spatializer_Module);
virtual void handle_sample_rate_change ( nframes_t n );
virtual void handle_control_changed ( Port *p );
virtual void draw ( void );
protected: