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
parent
e927781ee0
commit
b3a9d0be1d
|
@ -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:
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue