Audacity 3.2.0
LadspaInstance.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 LadspaInstance.cpp
6
7 Dominic Mazzoni
8
9 Paul Licameli split from LadspaEffect.cpp
10
11*//*******************************************************************/
12
13#include "LadspaInstance.h" // This class's header file
14#include "ConfigInterface.h"
15#include "AudacityException.h"
16
17static const wchar_t *OptionsKey = L"Options";
18static const wchar_t *UseLatencyKey = L"UseLatency";
19
21{
22 bool result{};
24 OptionsKey, UseLatencyKey, result, true /* default value */);
25 return result;
26}
27
29 const EffectDefinitionInterface &effect, bool value)
30{
31 return SetConfig(
33}
34
35
37
38auto LadspaEffectOutputs::Clone() const -> std::unique_ptr<EffectOutputs>
39{
40 return std::make_unique<LadspaEffectOutputs>(*this);
41}
42
44{
45 // Don't really need to modify src
46 const auto &srcValues = static_cast<LadspaEffectOutputs&>(src).controls;
47 auto &dstValues = controls;
48 assert(srcValues.size() == dstValues.size());
49 copy(srcValues.begin(), srcValues.end(), dstValues.data());
50}
51
52namespace {
53std::pair<float, float>
55{
56 // Find lower and upper bound values for ths hint
57 const auto multiplier =
59 return { hint.LowerBound * multiplier, hint.UpperBound * multiplier };
60}
62 const LADSPA_PortRangeHint &hint, float val, float lower, float upper)
63{
64 if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) && val < lower)
65 val = lower;
66 if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) && val > upper)
67 val = upper;
68 return val;
69}
71 const LADSPA_PortRangeHint &hint, double sampleRate)
72{
73 // See comments in library header ladspa.h about interpretation of macros
74 const auto bounds = InputControlPortBounds(hint, sampleRate);
75
76 // Function to find low, middle, or high default values
77 const auto combine = [bounds,
79 ](float lowWeight, float highWeight){
80 auto [lower, upper] = bounds;
81 return logarithmic
82 ? exp(log(lower) * lowWeight + log(upper) * highWeight)
83 : lower * lowWeight + upper * highWeight;
84 };
85
86 auto [lower, upper] = bounds;
87 auto val = 1.0f;
88 // Four bits of the descriptor describe mutually exclusive cases
91 default:
92 break;
94 val = lower; break;
96 val = combine(0.75, 0.25); break;
98 val = combine(0.5, 0.5); break;
100 val = combine(0.25, 0.75); break;
102 val = upper; break;
104 val = 0.0f; break;
106 val = 1.0f; break;
108 val = 100.0f; break;
110 val = 440.0f; break;
111 }
112
113 return ClampInputControlValue(hint, val, lower, upper);
114}
115}
116
118 const LADSPA_Descriptor *pData,
119 const ArrayOf<unsigned long> &inputPorts,
120 const ArrayOf<unsigned long> &outputPorts,
121 unsigned audioIns, unsigned audioOuts, int latencyPort
122) : PerTrackEffect::Instance{ processor }
123 , mData{ pData }, mInputPorts{ inputPorts }, mOutputPorts{ outputPorts }
124 , mAudioIns{ audioIns }, mAudioOuts{ audioOuts }
125 , mLatencyPort{ latencyPort }
126 , mUseLatency{ LoadUseLatency(processor) }
127{
128
129}
130
132 const EffectSettings &settings, double) const -> SampleCount
133{
134 auto &controls = GetSettings(settings).controls;
135 if (mUseLatency && mLatencyPort >= 0)
136 return controls[mLatencyPort];
137 return 0;
138}
139
142{
143 /* Instantiate the plugin */
144 if (!mReady) {
145 auto &ladspaSettings = GetSettings(settings);
146 // Destructive effect processing doesn't need output ports
147 mMaster = InitInstance(sampleRate, ladspaSettings, nullptr);
148 if (!mMaster)
149 return false;
150 mReady = true;
151 }
152 return true;
153}
154
156{
157return GuardedCall<bool>([&]{
158 if (mReady) {
159 mReady = false;
161 mMaster = nullptr;
162 }
163
164 return true;
165});
166}
167
169 const float *const *inBlock, float *const *outBlock, size_t blockLen)
170{
171 for (unsigned i = 0; i < mAudioIns; ++i)
173 const_cast<float*>(inBlock[i]));
174
175 for (unsigned i = 0; i < mAudioOuts; ++i)
176 mData->connect_port(mMaster, mOutputPorts[i], outBlock[i]);
177
178 mData->run(mMaster, blockLen);
179 return blockLen;
180}
181
183{
184 return true;
185}
186
188 EffectSettings &settings, EffectOutputs *pOutputs, unsigned, float sampleRate)
189{
190 auto &ladspaSettings = GetSettings(settings);
191 // Connect to outputs only if this is the first processor for the track.
192 // (What's right when a mono effect is on a stereo channel? Unclear, but
193 // this definitely causes connection with the first channel.)
194 auto pLadspaOutputs = mSlaves.empty()
195 ? static_cast<LadspaEffectOutputs *>(pOutputs) : nullptr;
196 auto slave = InitInstance(sampleRate, ladspaSettings, pLadspaOutputs);
197 if (!slave)
198 return false;
199 mSlaves.push_back(slave);
200 return true;
201}
202
204{
205 return mAudioOuts;
206}
207
209{
210 return mAudioIns;
211}
212
214{
215return GuardedCall<bool>([&]{
216 for (size_t i = 0, cnt = mSlaves.size(); i < cnt; ++i)
217 FreeInstance(mSlaves[i]);
218 mSlaves.clear();
219
220 return true;
221});
222}
223
225{
226 if (auto fn = mData->deactivate)
227 for (auto &slave : mSlaves)
228 fn(slave);
229 return true;
230}
231
233{
234 if (auto fn = mData->activate)
235 for (auto &slave : mSlaves)
236 fn(slave);
237 return true;
238}
239
241{
242 return true;
243}
244
246 const float *const *inbuf, float *const *outbuf, size_t numSamples)
247{
248 if (group >= mSlaves.size())
249 return 0;
250
251 for (unsigned i = 0; i < mAudioIns; ++i)
253 const_cast<float*>(inbuf[i]));
254
255 for (unsigned i = 0; i < mAudioOuts; ++i)
257 mSlaves[group], mOutputPorts[i], outbuf[i]);
258
259 mData->run(mSlaves[group], numSamples);
260
261 return numSamples;
262}
263
265{
266 return true;
267}
268
271 LadspaEffectOutputs *pOutputs) const
272{
273 /* Instantiate the plugin */
275 if (!handle)
276 return nullptr;
277
278 auto &controls = settings.controls;
279 for (unsigned long p = 0; p < mData->PortCount; ++p) {
281 if (LADSPA_IS_PORT_CONTROL(d)) {
283 mData->connect_port(handle, p, &controls[p]);
284 else {
285 static LADSPA_Data sink;
286 mData->connect_port(handle, p,
287 pOutputs ? &pOutputs->controls[p] : &sink);
288 }
289 }
290 }
291 if (mData->activate)
292 mData->activate(handle);
293
294 return handle;
295}
296
298{
299 if (mData->deactivate)
300 {
301 mData->deactivate(handle);
302 }
303
304 mData->cleanup(handle);
305}
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
ChannelName
LV2EffectSettings & GetSettings(EffectSettings &settings)
Definition: LV2Ports.h:215
static const wchar_t * UseLatencyKey
static const wchar_t * OptionsKey
static Settings & settings()
Definition: TrackInfo.cpp:69
static const auto fn
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
uint64_t SampleCount
Hold values to send to effect output meters.
Base class for many of the effects in Audacity.
#define LADSPA_HINT_DEFAULT_100
Definition: ladspa.h:303
#define LADSPA_IS_HINT_BOUNDED_BELOW(x)
Definition: ladspa.h:310
#define LADSPA_HINT_DEFAULT_MAXIMUM
Definition: ladspa.h:290
#define LADSPA_HINT_DEFAULT_440
Definition: ladspa.h:308
#define LADSPA_HINT_DEFAULT_LOW
Definition: ladspa.h:272
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x)
Definition: ladspa.h:311
#define LADSPA_HINT_DEFAULT_0
Definition: ladspa.h:295
#define LADSPA_IS_HINT_LOGARITHMIC(x)
Definition: ladspa.h:314
#define LADSPA_HINT_DEFAULT_HIGH
Definition: ladspa.h:286
#define LADSPA_HINT_DEFAULT_MASK
Definition: ladspa.h:258
#define LADSPA_HINT_DEFAULT_MIDDLE
Definition: ladspa.h:279
int LADSPA_PortDescriptor
Definition: ladspa.h:152
#define LADSPA_HINT_DEFAULT_1
Definition: ladspa.h:300
float LADSPA_Data
Definition: ladspa.h:84
#define LADSPA_HINT_DEFAULT_MINIMUM
Definition: ladspa.h:265
#define LADSPA_IS_PORT_INPUT(x)
Definition: ladspa.h:168
void * LADSPA_Handle
Definition: ladspa.h:363
#define LADSPA_IS_PORT_CONTROL(x)
Definition: ladspa.h:170
#define LADSPA_HINT_DEFAULT_NONE
Definition: ladspa.h:261
#define LADSPA_IS_HINT_SAMPLE_RATE(x)
Definition: ladspa.h:313
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
float ClampInputControlValue(const LADSPA_PortRangeHint &hint, float val, float lower, float upper)
float InputControlPortDefaultValue(const LADSPA_PortRangeHint &hint, double sampleRate)
std::pair< float, float > InputControlPortBounds(const LADSPA_PortRangeHint &hint, double sampleRate)
void copy(const T *src, T *dst, int32_t n)
Definition: VectorOps.h:40
STL namespace.
_LADSPA_Descriptor is a structure that provides the API to a LADSPA (Linux Audio Plugin Architecture)...
Definition: ladspa.h:373
LADSPA_Handle(* instantiate)(const struct _LADSPA_Descriptor *Descriptor, unsigned long SampleRate)
Definition: ladspa.h:437
void(* deactivate)(LADSPA_Handle Instance)
Definition: ladspa.h:549
void(* cleanup)(LADSPA_Handle Instance)
Definition: ladspa.h:558
void(* run)(LADSPA_Handle Instance, unsigned long SampleCount)
Definition: ladspa.h:505
void(* activate)(LADSPA_Handle Instance)
Definition: ladspa.h:489
void(* connect_port)(LADSPA_Handle Instance, unsigned long Port, LADSPA_Data *DataLocation)
Definition: ladspa.h:466
const LADSPA_PortDescriptor * PortDescriptors
Definition: ladspa.h:410
unsigned long PortCount
Definition: ladspa.h:406
_LADSPA_PortRangeHint is a structure that gives parameter validation information for a LADSPA (Linux ...
Definition: ladspa.h:337
LADSPA_PortRangeHintDescriptor HintDescriptor
Definition: ladspa.h:340
LADSPA_Data LowerBound
Definition: ladspa.h:345
LADSPA_Data UpperBound
Definition: ladspa.h:350
Externalized state of a plug-in.
Carry output control port information back to main thread.
~LadspaEffectOutputs() override
void Assign(EffectOutputs &&src) override
Update one Outputs object from another.
std::vector< float > controls
std::unique_ptr< EffectOutputs > Clone() const override
bool ProcessInitialize(EffectSettings &settings, double sampleRate, ChannelNames chanMap) override
static LadspaEffectSettings & GetSettings(EffectSettings &settings)
Assume settings originated from MakeSettings() and copies thereof.
bool RealtimeSuspend() override
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
bool ProcessFinalize() noexcept override
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
bool RealtimeFinalize(EffectSettings &settings) noexcept override
LadspaInstance(const PerTrackEffect &processor, const LADSPA_Descriptor *pData, const ArrayOf< unsigned long > &inputPorts, const ArrayOf< unsigned long > &outputPorts, unsigned audioIns, unsigned audioOuts, int latencyPort)
size_t RealtimeProcess(size_t group, EffectSettings &settings, const float *const *inBuf, float *const *outBuf, size_t numSamples) override
const unsigned mAudioIns
const ArrayOf< unsigned long > & mInputPorts
LADSPA_Handle InitInstance(float sampleRate, LadspaEffectSettings &settings, LadspaEffectOutputs *pOutputs) const
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
void FreeInstance(LADSPA_Handle handle) const
const unsigned mAudioOuts
std::vector< LADSPA_Handle > mSlaves
const LADSPA_Descriptor *const mData
bool RealtimeAddProcessor(EffectSettings &settings, EffectOutputs *pOutputs, unsigned numChannels, float sampleRate) override
bool RealtimeProcessEnd(EffectSettings &settings) noexcept override
settings can be updated to let a dialog change appearance at idle
const ArrayOf< unsigned long > & mOutputPorts
bool RealtimeInitialize(EffectSettings &settings, double sampleRate) override
static bool LoadUseLatency(const EffectDefinitionInterface &effect)
Get the preference for using latency.
LADSPA_Handle mMaster
static bool SaveUseLatency(const EffectDefinitionInterface &effect, bool value)
Set the preference for using latency.
bool RealtimeProcessStart(MessagePackage &package) override
settings are possibly changed, since last call, by an asynchronous dialog
bool RealtimeResume() override
SampleCount GetLatency(const EffectSettings &settings, double sampleRate) const override