Update DSP::Convolution
Expose zita-convolver bindings, to allow for custom NxM convolution matrices, and dedicated FIR processors.
This commit is contained in:
parent
bfebe43a02
commit
00fcf6719c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2018-2020 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -23,21 +23,117 @@
|
||||
#include "zita-convolver/zita-convolver.h"
|
||||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
|
||||
#include "ardour/buffer_set.h"
|
||||
#include "ardour/chan_mapping.h"
|
||||
#include "ardour/readable.h"
|
||||
|
||||
namespace ARDOUR { namespace DSP {
|
||||
|
||||
class LIBARDOUR_API Convolver : public SessionHandleRef {
|
||||
class LIBARDOUR_API Convolution : public SessionHandleRef
|
||||
{
|
||||
public:
|
||||
Convolution (Session&, uint32_t n_in, uint32_t n_out);
|
||||
virtual ~Convolution () {}
|
||||
|
||||
bool add_impdata (
|
||||
uint32_t c_in,
|
||||
uint32_t c_out,
|
||||
boost::shared_ptr<Readable> r,
|
||||
float gain = 1.0,
|
||||
uint32_t pre_delay = 0,
|
||||
sampleoffset_t offset = 0,
|
||||
samplecnt_t length = 0,
|
||||
uint32_t channel = 0);
|
||||
|
||||
bool ready () const;
|
||||
uint32_t latency () const { return _n_samples; }
|
||||
uint32_t n_inputs () const { return _n_inputs; }
|
||||
uint32_t n_outputs () const { return _n_outputs; }
|
||||
|
||||
void restart ();
|
||||
void run (BufferSet&, ChanMapping const&, ChanMapping const&, pframes_t, samplecnt_t);
|
||||
|
||||
protected:
|
||||
ArdourZita::Convproc _convproc;
|
||||
|
||||
uint32_t _n_samples;
|
||||
uint32_t _max_size;
|
||||
uint32_t _offset;
|
||||
bool _configured;
|
||||
|
||||
private:
|
||||
class ImpData : public Readable
|
||||
{
|
||||
public:
|
||||
ImpData (uint32_t ci, uint32_t co, boost::shared_ptr<Readable> r, float g, float d, sampleoffset_t s = 0, samplecnt_t l = 0, uint32_t c = 0)
|
||||
: c_in (ci)
|
||||
, c_out (co)
|
||||
, gain (g)
|
||||
, delay (d)
|
||||
, _readable (r)
|
||||
, _offset (s)
|
||||
, _length (l)
|
||||
, _channel (c)
|
||||
{}
|
||||
|
||||
uint32_t c_in;
|
||||
uint32_t c_out;
|
||||
float gain;
|
||||
uint32_t delay;
|
||||
|
||||
samplecnt_t read (Sample* s, samplepos_t pos, samplecnt_t cnt, int c = -1) const {
|
||||
return _readable->read (s, pos + _offset, cnt, _channel);
|
||||
}
|
||||
|
||||
samplecnt_t readable_length () const {
|
||||
samplecnt_t rl = _readable->readable_length ();
|
||||
if (rl < _offset) {
|
||||
return 0;
|
||||
} else if (_length > 0) {
|
||||
return std::min (rl - _offset, _length);
|
||||
} else {
|
||||
return rl - _offset;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t n_channels () const {
|
||||
return _readable->n_channels ();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<Readable> _readable;
|
||||
|
||||
sampleoffset_t _offset;
|
||||
samplecnt_t _length;
|
||||
uint32_t _channel;
|
||||
};
|
||||
|
||||
std::vector<ImpData> _impdata;
|
||||
uint32_t _n_inputs;
|
||||
uint32_t _n_outputs;
|
||||
};
|
||||
|
||||
class LIBARDOUR_API Convolver : public Convolution
|
||||
{
|
||||
public:
|
||||
enum IRChannelConfig {
|
||||
Mono, ///< 1 in, 1 out; 1ch IR
|
||||
MonoToStereo, ///< 1 in, 2 out, stereo IR M -> L, M -> R
|
||||
Stereo, ///< 2 in, 2 out, stereo IR L -> L, R -> R || 4 chan IR L -> L, L -> R, R -> R, R -> L
|
||||
};
|
||||
|
||||
static uint32_t ircc_in (IRChannelConfig irc) {
|
||||
return irc < Stereo ? 1 : 2;
|
||||
}
|
||||
|
||||
static uint32_t ircc_out (IRChannelConfig irc) {
|
||||
return irc == Mono ? 1 : 2;
|
||||
}
|
||||
|
||||
struct IRSettings {
|
||||
IRSettings () {
|
||||
IRSettings ()
|
||||
{
|
||||
gain = 1.0;
|
||||
pre_delay = 0.0;
|
||||
channel_gain[0] = channel_gain[1] = channel_gain[2] = channel_gain[3] = 1.0;
|
||||
@ -66,31 +162,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Convolver (Session&, std::string const&, IRChannelConfig irc = Mono, IRSettings irs = IRSettings ());
|
||||
|
||||
void run (float*, uint32_t);
|
||||
void run_mono (float*, uint32_t);
|
||||
void run_stereo (float* L, float* R, uint32_t);
|
||||
|
||||
uint32_t latency () const { return _n_samples; }
|
||||
|
||||
uint32_t n_inputs () const { return _irc < Stereo ? 1 : 2; }
|
||||
uint32_t n_outputs () const { return _irc == Mono ? 1 : 2; }
|
||||
|
||||
bool ready () const;
|
||||
|
||||
private:
|
||||
void reconfigure ();
|
||||
std::vector<boost::shared_ptr<Readable> > _readables;
|
||||
ArdourZita::Convproc _convproc;
|
||||
|
||||
IRChannelConfig _irc;
|
||||
IRSettings _ir_settings;
|
||||
|
||||
uint32_t _n_samples;
|
||||
uint32_t _max_size;
|
||||
uint32_t _offset;
|
||||
bool _configured;
|
||||
};
|
||||
|
||||
} } /* namespace */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2018-2020 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -21,13 +21,15 @@
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/pthread_utils.h"
|
||||
|
||||
#include "ardour/audio_buffer.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/audiofilesource.h"
|
||||
#include "ardour/convolver.h"
|
||||
#include "ardour/dsp_filter.h"
|
||||
#include "ardour/readable.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/srcfilesource.h"
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/srcfilesource.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
@ -35,149 +37,104 @@ using namespace ARDOUR::DSP;
|
||||
using namespace ArdourZita;
|
||||
|
||||
using ARDOUR::Session;
|
||||
|
||||
Convolver::Convolver (
|
||||
Session& session,
|
||||
std::string const& path,
|
||||
IRChannelConfig irc,
|
||||
IRSettings irs)
|
||||
Convolution::Convolution (Session& session, uint32_t n_in, uint32_t n_out)
|
||||
: SessionHandleRef (session)
|
||||
, _irc (irc)
|
||||
, _ir_settings (irs)
|
||||
, _n_samples (0)
|
||||
, _max_size (0)
|
||||
, _offset (0)
|
||||
, _configured (false)
|
||||
, _n_inputs (n_in)
|
||||
, _n_outputs (n_out)
|
||||
{
|
||||
_readables = Readable::load (_session, path);
|
||||
|
||||
if (_readables.empty ()) {
|
||||
PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg;
|
||||
throw failed_constructor ();
|
||||
AudioEngine::instance ()->BufferSizeChanged.connect_same_thread (*this, boost::bind (&Convolution::restart, this));
|
||||
}
|
||||
|
||||
if (_readables[0]->readable_length () > 0x1000000 /*2^24*/) {
|
||||
PBD::error << string_compose(_("Convolver: IR \"%1\" file too long."), path) << endmsg;
|
||||
throw failed_constructor ();
|
||||
bool
|
||||
Convolution::add_impdata (
|
||||
uint32_t c_in,
|
||||
uint32_t c_out,
|
||||
boost::shared_ptr<Readable> readable,
|
||||
float gain,
|
||||
uint32_t pre_delay,
|
||||
sampleoffset_t offset,
|
||||
samplecnt_t length,
|
||||
uint32_t channel)
|
||||
{
|
||||
if (_configured || c_in >= _n_inputs || c_out >= _n_outputs) {
|
||||
return false;
|
||||
}
|
||||
if (!readable || readable->readable_length () <= offset || readable->n_channels () <= channel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioEngine::instance ()->BufferSizeChanged.connect_same_thread (*this, boost::bind (&Convolver::reconfigure, this));
|
||||
_impdata.push_back (ImpData (c_in, c_out, readable, gain, pre_delay, offset, length));
|
||||
return true;
|
||||
}
|
||||
|
||||
reconfigure ();
|
||||
bool
|
||||
Convolution::ready () const
|
||||
{
|
||||
return _configured && _convproc.state () == Convproc::ST_PROC;
|
||||
}
|
||||
|
||||
void
|
||||
Convolver::reconfigure ()
|
||||
Convolution::restart ()
|
||||
{
|
||||
_convproc.stop_process ();
|
||||
_convproc.cleanup ();
|
||||
_convproc.set_options (0);
|
||||
|
||||
assert (!_readables.empty ());
|
||||
|
||||
_offset = 0;
|
||||
_max_size = 0;
|
||||
_n_samples = _session.get_block_size ();
|
||||
_max_size = _readables[0]->readable_length ();
|
||||
|
||||
for (std::vector<ImpData>::const_iterator i = _impdata.begin (); i != _impdata.end (); ++i) {
|
||||
_max_size = std::max (_max_size, (uint32_t)i->readable_length ());
|
||||
}
|
||||
|
||||
uint32_t power_of_two;
|
||||
for (power_of_two = 1; 1U << power_of_two < _n_samples; ++power_of_two) ;
|
||||
_n_samples = 1 << power_of_two;
|
||||
|
||||
int n_part = std::min ((uint32_t)Convproc::MAXPART, 4 * _n_samples);
|
||||
|
||||
int rv = _convproc.configure (
|
||||
/*in*/ n_inputs (),
|
||||
/*out*/ n_outputs (),
|
||||
/*in*/ _n_inputs,
|
||||
/*out*/ _n_outputs,
|
||||
/*max-convolution length */ _max_size,
|
||||
/*quantum, nominal-buffersize*/ _n_samples,
|
||||
/*Convproc::MINPART*/ _n_samples,
|
||||
/*Convproc::MAXPART*/ n_part,
|
||||
/*density*/ 0);
|
||||
|
||||
/* map channels
|
||||
* - Mono:
|
||||
* always use first only
|
||||
* - MonoToStereo:
|
||||
* mono-file: use 1st for M -> L, M -> R
|
||||
* else: use first two channels
|
||||
* - Stereo
|
||||
* mono-file: use 1st for both L -> L, R -> R, no x-over
|
||||
* stereo-file: L -> L, R -> R -- no L/R, R/L x-over
|
||||
* 3chan-file: ignore 3rd channel, use as stereo-file.
|
||||
* 4chan file: L -> L, L -> R, R -> R, R -> L
|
||||
*/
|
||||
|
||||
uint32_t n_imp = n_inputs () * n_outputs ();
|
||||
uint32_t n_chn = _readables.size ();
|
||||
|
||||
if (_irc == Stereo && n_chn == 3) {
|
||||
/* ignore 3rd channel */
|
||||
n_chn = 2;
|
||||
}
|
||||
if (_irc == Stereo && n_chn <= 2) {
|
||||
/* ignore x-over */
|
||||
n_imp = 2;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
printf ("Convolver::reconfigure Nin=%d Nout=%d Nimp=%d Nchn=%d\n", n_inputs (), n_outputs (), n_imp, n_chn);
|
||||
#endif
|
||||
|
||||
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 == 2 && _irc == Stereo) {
|
||||
/* (imp, in, out)
|
||||
* Stereo (2, 2, 2) 1: L -> L, 2: R -> R
|
||||
*/
|
||||
io_i = c % n_inputs ();
|
||||
} else {
|
||||
/* (imp, in, out)
|
||||
* Mono (1, 1, 1) 1: M -> M
|
||||
* MonoToStereo (2, 1, 2) 1: M -> L, 2: M -> R
|
||||
* Stereo (4, 2, 2) 1: L -> L, 2: L -> R, 3: R -> L, 4: R -> R
|
||||
*/
|
||||
io_i = (c / n_outputs ()) % n_inputs ();
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
/*density 0 = auto, i/o dependent */ 0);
|
||||
|
||||
for (std::vector<ImpData>::const_iterator i = _impdata.begin (); i != _impdata.end (); ++i) {
|
||||
uint32_t pos = 0;
|
||||
|
||||
const float ir_gain = i->gain;
|
||||
const uint32_t ir_delay = i->delay;
|
||||
const uint32_t ir_len = i->readable_length ();
|
||||
|
||||
while (true) {
|
||||
float ir[8192];
|
||||
|
||||
samplecnt_t to_read = std::min ((uint32_t)8192, _max_size - pos);
|
||||
samplecnt_t ns = r->read (ir, pos, to_read, 0);
|
||||
samplecnt_t to_read = std::min ((uint32_t)8192, ir_len - pos);
|
||||
samplecnt_t ns = i->read (ir, pos, to_read);
|
||||
|
||||
if (ns == 0) {
|
||||
assert (pos == _max_size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (chan_gain != 1.f) {
|
||||
if (ir_gain != 1.f) {
|
||||
for (samplecnt_t i = 0; i < ns; ++i) {
|
||||
ir[i] *= chan_gain;
|
||||
ir[i] *= ir_gain;
|
||||
}
|
||||
}
|
||||
|
||||
rv = _convproc.impdata_create (
|
||||
/*i/o map */ io_i, io_o,
|
||||
/*i/o map */ i->c_in, i->c_out,
|
||||
/*stride, de-interleave */ 1,
|
||||
ir,
|
||||
chan_delay + pos, chan_delay + pos + ns);
|
||||
ir_delay + pos, ir_delay + pos + ns);
|
||||
|
||||
if (rv != 0) {
|
||||
break;
|
||||
@ -211,14 +168,142 @@ Convolver::reconfigure ()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Convolver::ready () const
|
||||
void
|
||||
Convolution::run (BufferSet& bufs, ChanMapping const& in_map, ChanMapping const& out_map, pframes_t n_samples, samplecnt_t offset)
|
||||
{
|
||||
return _configured && _convproc.state () == Convproc::ST_PROC;
|
||||
if (!ready ()) {
|
||||
process_map (&bufs, in_map, out_map, n_samples, offset, DataType::AUDIO);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t done = 0;
|
||||
uint32_t remain = n_samples;
|
||||
|
||||
while (remain > 0) {
|
||||
uint32_t ns = std::min (remain, _n_samples - _offset);
|
||||
|
||||
for (uint32_t c = 0; c < _n_inputs; ++c) {
|
||||
bool valid;
|
||||
const uint32_t idx = in_map.get (DataType::AUDIO, c, &valid);
|
||||
if (!valid) {
|
||||
::memset (&_convproc.inpdata (c)[_offset], 0, sizeof (float) * ns);
|
||||
} else {
|
||||
AudioBuffer const& ab (bufs.get_audio (idx));
|
||||
memcpy (&_convproc.inpdata (c)[_offset], ab.data (done + offset), sizeof (float) * ns);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t c = 0; c < _n_outputs; ++c) {
|
||||
bool valid;
|
||||
const uint32_t idx = out_map.get (DataType::AUDIO, c, &valid);
|
||||
if (valid) {
|
||||
AudioBuffer& ab (bufs.get_audio (idx));
|
||||
memcpy (ab.data (done + offset), &_convproc.outdata (c)[_offset], sizeof (float) * ns);
|
||||
}
|
||||
}
|
||||
|
||||
_offset += ns;
|
||||
done += ns;
|
||||
remain -= ns;
|
||||
|
||||
if (_offset == _n_samples) {
|
||||
_convproc.process (/*sync, freewheeling*/ true);
|
||||
_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
Convolver::Convolver (
|
||||
Session& session,
|
||||
std::string const& path,
|
||||
IRChannelConfig irc,
|
||||
IRSettings irs)
|
||||
: Convolution (session, ircc_in (irc), ircc_out (irc))
|
||||
, _irc (irc)
|
||||
, _ir_settings (irs)
|
||||
{
|
||||
std::vector<boost::shared_ptr<Readable> > readables = Readable::load (_session, path);
|
||||
|
||||
if (readables.empty ()) {
|
||||
PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg;
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
if (readables[0]->readable_length () > 0x1000000 /*2^24*/) {
|
||||
PBD::error << string_compose (_("Convolver: IR \"%1\" file too long."), path) << endmsg;
|
||||
throw failed_constructor ();
|
||||
}
|
||||
|
||||
/* map channels
|
||||
* - Mono:
|
||||
* always use first only
|
||||
* - MonoToStereo:
|
||||
* mono-file: use 1st for M -> L, M -> R
|
||||
* else: use first two channels
|
||||
* - Stereo
|
||||
* mono-file: use 1st for both L -> L, R -> R, no x-over
|
||||
* stereo-file: L -> L, R -> R -- no L/R, R/L x-over
|
||||
* 3chan-file: ignore 3rd channel, use as stereo-file.
|
||||
* 4chan file: L -> L, L -> R, R -> R, R -> L
|
||||
*/
|
||||
|
||||
uint32_t n_imp = n_inputs () * n_outputs ();
|
||||
uint32_t n_chn = readables.size ();
|
||||
|
||||
if (_irc == Stereo && n_chn == 3) {
|
||||
/* ignore 3rd channel */
|
||||
n_chn = 2;
|
||||
}
|
||||
if (_irc == Stereo && n_chn <= 2) {
|
||||
/* ignore x-over */
|
||||
n_imp = 2;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
printf ("Convolver: Nin=%d Nout=%d Nimp=%d Nchn=%d\n", n_inputs (), n_outputs (), n_imp, n_chn);
|
||||
#endif
|
||||
|
||||
assert (n_imp <= 4);
|
||||
|
||||
for (uint32_t c = 0; c < n_imp; ++c) {
|
||||
int ir_c = c % n_chn;
|
||||
int io_o = c % n_outputs ();
|
||||
int io_i;
|
||||
|
||||
if (n_imp == 2 && _irc == Stereo) {
|
||||
/* (imp, in, out)
|
||||
* Stereo (2, 2, 2) 1: L -> L, 2: R -> R
|
||||
*/
|
||||
io_i = c % n_inputs ();
|
||||
} else {
|
||||
/* (imp, in, out)
|
||||
* Mono (1, 1, 1) 1: M -> M
|
||||
* MonoToStereo (2, 1, 2) 1: M -> L, 2: M -> R
|
||||
* Stereo (4, 2, 2) 1: L -> L, 2: L -> R, 3: R -> L, 4: R -> R
|
||||
*/
|
||||
io_i = (c / n_outputs ()) % n_inputs ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Readable> r = readables[ir_c];
|
||||
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
|
||||
|
||||
add_impdata (io_i, io_o, r, chan_gain, chan_delay);
|
||||
}
|
||||
|
||||
Convolution::restart ();
|
||||
}
|
||||
|
||||
void
|
||||
Convolver::run (float* buf, uint32_t n_samples)
|
||||
Convolver::run_mono (float* buf, uint32_t n_samples)
|
||||
{
|
||||
assert (_convproc.state () == Convproc::ST_PROC);
|
||||
assert (_irc == Mono);
|
||||
|
@ -2545,6 +2545,17 @@ LuaBindings::common (lua_State* L)
|
||||
.addRefFunction ("read", &ARDOUR::LTCReader::read)
|
||||
.endClass ()
|
||||
|
||||
.beginClass <DSP::Convolution> ("Convolution")
|
||||
.addConstructor <void (*) (Session&, uint32_t, uint32_t)> ()
|
||||
.addFunction ("add_impdata", &ARDOUR::DSP::Convolution::add_impdata)
|
||||
.addFunction ("run", &ARDOUR::DSP::Convolution::run)
|
||||
.addFunction ("restart", &ARDOUR::DSP::Convolution::restart)
|
||||
.addFunction ("ready", &ARDOUR::DSP::Convolution::ready)
|
||||
.addFunction ("latency", &ARDOUR::DSP::Convolution::latency)
|
||||
.addFunction ("n_inputs", &ARDOUR::DSP::Convolution::n_inputs)
|
||||
.addFunction ("n_outputs", &ARDOUR::DSP::Convolution::n_outputs)
|
||||
.endClass ()
|
||||
|
||||
.beginClass <DSP::Convolver::IRSettings> ("IRSettings")
|
||||
.addVoidConstructor ()
|
||||
.addData ("gain", &DSP::Convolver::IRSettings::gain)
|
||||
@ -2555,14 +2566,10 @@ LuaBindings::common (lua_State* L)
|
||||
.addFunction ("set_channel_delay", &ARDOUR::DSP::Convolver::IRSettings::set_channel_delay)
|
||||
.endClass ()
|
||||
|
||||
.beginClass <DSP::Convolver> ("Convolver")
|
||||
.deriveClass <DSP::Convolver, DSP::Convolution> ("Convolver")
|
||||
.addConstructor <void (*) (Session&, std::string const&, DSP::Convolver::IRChannelConfig, DSP::Convolver::IRSettings)> ()
|
||||
.addFunction ("run", &ARDOUR::DSP::Convolver::run)
|
||||
.addFunction ("run_mono", &ARDOUR::DSP::Convolver::run_mono)
|
||||
.addFunction ("run_stereo", &ARDOUR::DSP::Convolver::run_stereo)
|
||||
.addFunction ("latency", &ARDOUR::DSP::Convolver::latency)
|
||||
.addFunction ("n_inputs", &ARDOUR::DSP::Convolver::n_inputs)
|
||||
.addFunction ("n_outputs", &ARDOUR::DSP::Convolver::n_outputs)
|
||||
.addFunction ("ready", &ARDOUR::DSP::Convolver::ready)
|
||||
.endClass ()
|
||||
|
||||
/* DSP enums */
|
||||
|
Loading…
Reference in New Issue
Block a user