Update Convolver/LuaConvolver
authorRobin Gareus <robin@gareus.org>
Mon, 24 Dec 2018 01:29:24 +0000 (02:29 +0100)
committerRobin Gareus <robin@gareus.org>
Mon, 24 Dec 2018 01:29:24 +0000 (02:29 +0100)
* Add API to allow per-channnel gain and delay
* Fix channel-mapping for stereo IRs w/o true-stereo

libs/ardour/ardour/convolver.h
libs/ardour/convolver.cc
libs/ardour/luabindings.cc
scripts/_convolv.lua

index 9d858a1e630e7c32f63428fe2730bbc0493ef939..a5b52cd32dda8d6ea96571ed98fcddbb04e1911e 100644 (file)
@@ -37,7 +37,38 @@ public:
                Stereo,       ///< 2 in, 2 out, stereo IR  L -> L, R -> R || 4 chan IR  L -> L, L -> R, R -> R, R -> L
        };
 
-       Convolver (Session&, std::string const&, IRChannelConfig irc = Mono, uint32_t pre_delay = 0);
+       struct IRSettings {
+               IRSettings () {
+                       gain  = 1.0;
+                       pre_delay = 0.0;
+                       channel_gain[0] = channel_gain[1] = channel_gain[2] = channel_gain[3] = 1.0;
+                       channel_delay[0] = channel_delay[1] = channel_delay[2] = channel_delay[3] = 0;
+               };
+
+               float    gain;
+               uint32_t pre_delay;
+               float    channel_gain[4];
+               uint32_t channel_delay[4];
+
+               /* convenient array accessors for Lua bindings */
+               float get_channel_gain (unsigned i) const {
+                       if (i < 4) { return channel_gain[i]; }
+                       return 0;
+               }
+               void set_channel_gain (unsigned i, float g) {
+                       if (i < 4) { channel_gain[i] = g; }
+               }
+               uint32_t get_channel_delay (unsigned i) const {
+                       if (i < 4) { return channel_delay[i]; }
+                       return 0;
+               }
+               void set_channel_delay (unsigned i, uint32_t d) {
+                       if (i < 4) { channel_delay[i] = d; }
+               }
+       };
+
+
+       Convolver (Session&, std::string const&, IRChannelConfig irc = Mono, IRSettings irs = IRSettings ());
 
        void run (float*, uint32_t);
        void run_stereo (float* L, float* R, uint32_t);
@@ -55,7 +86,7 @@ private:
        ArdourZita::Convproc _convproc;
 
        IRChannelConfig _irc;
-       uint32_t _initial_delay;
+       IRSettings      _ir_settings;
 
        uint32_t _n_samples;
        uint32_t _max_size;
index d0caa8e669ab16983802aacf248d7dff3b854ada..4cd14672deb2c9e8741f4a26cc7cbf84d610ece5 100644 (file)
@@ -36,10 +36,14 @@ using namespace ArdourZita;
 
 using ARDOUR::Session;
 
-Convolver::Convolver (Session& session, std::string const& path, IRChannelConfig irc, uint32_t pre_delay)
+Convolver::Convolver (
+               Session& session,
+               std::string const& path,
+               IRChannelConfig irc,
+               IRSettings irs)
        : SessionHandleRef (session)
        , _irc (irc)
-       , _initial_delay (pre_delay)
+       , _ir_settings (irs)
        , _n_samples (0)
        , _max_size (0)
        , _offset (0)
@@ -131,6 +135,10 @@ Convolver::reconfigure ()
        uint32_t n_imp = n_inputs() * n_outputs ();
        uint32_t n_chn = _readables.size();
 
+#ifndef NDEBUG
+       printf ("Convolver::reconfigure Nin %d Nout %d Nimp %d Nchn %d\n", n_inputs (), n_outputs (), n_imp, n_chn);
+#endif
+
        if (_irc == Stereo && n_chn == 3) {
                /* ignore 3rd channel */
                n_chn = 2;
@@ -140,12 +148,14 @@ Convolver::reconfigure ()
                n_imp = 2;
        }
 
+       assert (n_imp <= 4);
+
        for (uint32_t c = 0; c < n_imp && rv == 0; ++c) {
                int ir_c = c % n_chn;
                int io_o = c % n_outputs();
                int io_i;
 
-               if (n_imp > n_chn && _irc == Stereo) {
+               if (n_imp == 2 && _irc == Stereo) {
                        /*           (imp, in, out)
                         * Stereo       (2, 2, 2)    1: L -> L, 2: R -> R
                         */
@@ -159,14 +169,18 @@ Convolver::reconfigure ()
                        io_i = (c / n_outputs()) % n_inputs();
                }
 
-#ifndef NDEBUG
-               printf ("Convolver map: IR-chn %d: in %d -> out %d\n", ir_c + 1, io_i + 1, io_o + 1);
-#endif
 
-               boost::shared_ptr<Readable> r = _readables[ir_c % n_chn];
+               boost::shared_ptr<Readable> r = _readables[ir_c];
                assert (r->readable_length () == _max_size);
                assert (r->n_channels () == 1);
 
+               const float    chan_gain  = _ir_settings.gain * _ir_settings.channel_gain[c];
+               const uint32_t chan_delay = _ir_settings.pre_delay + _ir_settings.channel_delay[c];
+
+#ifndef NDEBUG
+               printf ("Convolver map: IR-chn %d: in %d -> out %d (gain: %.1fdB delay; %d)\n", ir_c + 1, io_i + 1, io_o + 1, 20.f * log10f(chan_gain), chan_delay);
+#endif
+
                uint32_t pos = 0;
                while (true) {
                        float ir[8192];
@@ -178,11 +192,17 @@ Convolver::reconfigure ()
                                break;
                        }
 
+                       if (chan_gain != 1.f) {
+                               for (samplecnt_t i = 0; i < ns; ++i) {
+                                       ir[i] *= chan_gain;
+                               }
+                       }
+
                        rv = _convproc.impdata_create (
                                        /*i/o map */ io_i, io_o,
                                        /*stride, de-interleave */1,
                                        ir,
-                                       _initial_delay + pos, _initial_delay + pos + ns);
+                                       chan_delay + pos, chan_delay + pos + ns);
 
                        if (rv != 0) {
                                break;
@@ -193,7 +213,7 @@ Convolver::reconfigure ()
                        if (pos == _max_size) {
                                break;
                        }
-               };
+               }
        }
 
        if (rv == 0) {
index 9fb807e5debddb9e648133e96a3481a5176d10fb..f3eac8529ff9349472e43084233e283d2d7854cd 100644 (file)
@@ -2412,8 +2412,18 @@ LuaBindings::common (lua_State* L)
                .addRefFunction ("read", &ARDOUR::LTCReader::read)
                .endClass ()
 
+               .beginClass <DSP::Convolver::IRSettings> ("IRSettings")
+               .addVoidConstructor ()
+               .addData ("gain", &DSP::Convolver::IRSettings::gain)
+               .addData ("pre_delay", &DSP::Convolver::IRSettings::pre_delay)
+               .addFunction ("get_channel_gain", &ARDOUR::DSP::Convolver::IRSettings::get_channel_gain)
+               .addFunction ("set_channel_gain", &ARDOUR::DSP::Convolver::IRSettings::set_channel_gain)
+               .addFunction ("get_channel_delay", &ARDOUR::DSP::Convolver::IRSettings::get_channel_delay)
+               .addFunction ("set_channel_delay", &ARDOUR::DSP::Convolver::IRSettings::set_channel_delay)
+               .endClass ()
+
                .beginClass <DSP::Convolver> ("Convolver")
-               .addConstructor <void (*) (Session&, std::string const&, DSP::Convolver::IRChannelConfig, uint32_t)> ()
+               .addConstructor <void (*) (Session&, std::string const&, DSP::Convolver::IRChannelConfig, DSP::Convolver::IRSettings)> ()
                .addFunction ("run", &ARDOUR::DSP::Convolver::run)
                .addFunction ("run_stereo", &ARDOUR::DSP::Convolver::run_stereo)
                .addFunction ("latency", &ARDOUR::DSP::Convolver::latency)
index b2f6b477ab9928566b526f3bfc351e72b19704a6..b8d82627fb8eebb60a820608cffd6d352a562bcb 100644 (file)
@@ -26,7 +26,9 @@ function dsp_configure (ins, outs)
                mode = ARDOUR.DSP.IRChannelConfig.Stereo
        end
 
-       conv = ARDOUR.DSP.Convolver (Session, ir_file, mode, 0)
+       local irs = ARDOUR.DSP.IRSettings()
+       irs.gain = 0.5
+       conv = ARDOUR.DSP.Convolver (Session, ir_file, mode, irs)
        collectgarbage ()
 end