From b3a9d0be1d5b49bbb806bfd0346983054e7c4f05 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Sun, 1 Sep 2013 21:37:28 -0700 Subject: [PATCH] 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. --- mixer/src/Module.H | 4 +- mixer/src/Module_Parameter_Editor.C | 7 + mixer/src/Module_Parameter_Editor.H | 1 + mixer/src/Spatializer_Module.C | 238 +++++++++++++++++++++++----- mixer/src/Spatializer_Module.H | 5 +- 5 files changed, 210 insertions(+), 45 deletions(-) diff --git a/mixer/src/Module.H b/mixer/src/Module.H index 3feec3e..96ea4b4 100644 --- a/mixer/src/Module.H +++ b/mixer/src/Module.H @@ -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: diff --git a/mixer/src/Module_Parameter_Editor.C b/mixer/src/Module_Parameter_Editor.C index 5c3498e..79dff3d 100644 --- a/mixer/src/Module_Parameter_Editor.C +++ b/mixer/src/Module_Parameter_Editor.C @@ -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 ) { diff --git a/mixer/src/Module_Parameter_Editor.H b/mixer/src/Module_Parameter_Editor.H index cc447ed..08c0027 100644 --- a/mixer/src/Module_Parameter_Editor.H +++ b/mixer/src/Module_Parameter_Editor.H @@ -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 ); diff --git a/mixer/src/Spatializer_Module.C b/mixer/src/Spatializer_Module.C index 3013515..1545ec9 100644 --- a/mixer/src/Spatializer_Module.C +++ b/mixer/src/Spatializer_Module.C @@ -21,11 +21,9 @@ #include #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 @@ -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(); diff --git a/mixer/src/Spatializer_Module.H b/mixer/src/Spatializer_Module.H index 737eebf..45a4699 100644 --- a/mixer/src/Spatializer_Module.H +++ b/mixer/src/Spatializer_Module.H @@ -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 _lowpass; std::vector _highpass; std::vector _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: