|
|
@@ -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 ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
{ |
|
|
|
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); |
|
|
|
|
|
|
|
/* /\* FIXME: use smoothed value... *\/ */ |
|
|
|
/* buffer_apply_gain( (sample_t*)jack_output[0].buffer(nframes), nframes, 1.0f / sqrt(D) ); */ |
|
|
|
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 ); |
|
|
|
|
|
|
|
if ( use_delaybuf ) |
|
|
|
_delay[i]->run( buf, delaybuf, 0, nframes ); |
|
|
|
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 |
|
|
|
_delay[i]->run( buf, 0, delay_seconds, nframes ); |
|
|
|
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(); |
|
|
|