Audacity 3.2.0
Reverb.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4 Audacity(R) is copyright (c) 1999-2013 Audacity Team.
5 License: GPL v2 or later. See License.txt.
6
7 Reverb.cpp
8 Rob Sykes, Vaughan Johnson
9
10******************************************************************//*******************************************************************/
16
17
18#include "Reverb.h"
19#include "LoadEffects.h"
20
21#include <wx/arrstr.h>
22#include <wx/checkbox.h>
23#include <wx/intl.h>
24#include <wx/slider.h>
25#include <wx/spinctrl.h>
26
27#include "Prefs.h"
28#include "../ShuttleGui.h"
29#include "../widgets/valnum.h"
30
31#include "Reverb_libSoX.h"
32
33
35{
39 > parameters;
40 return parameters;
41}
42
43static const struct
44{
47}
49{
50 // Room Pre Hf Tone Tone Wet Dry Stereo Wet
51 // Name Size, Delay, Reverb, Damping, Low, High, Gain, Gain, Width, Only
52 { XO("Vocal I" ), { 70, 20, 40, 99, 100, 50, -12, 0, 70, false } },
53 { XO("Vocal II"), { 50, 0, 50, 99, 50, 100, -1, -1, 70, false } },
54 { XO("Bathroom"), { 16, 8, 80, 0, 0, 100, -6, 0, 100, false } },
55 { XO("Small Room Bright"), { 30, 10, 50, 50, 50, 100, -1, -1, 100, false } },
56 { XO("Small Room Dark"), { 30, 10, 50, 50, 100, 0, -1, -1, 100, false } },
57 { XO("Medium Room"), { 75, 10, 40, 50, 100, 70, -1, -1, 70, false } },
58 { XO("Large Room"), { 85, 10, 40, 50, 100, 80, 0, -6, 90, false } },
59 { XO("Church Hall"), { 90, 32, 60, 50, 100, 50, 0, -12, 100, false } },
60 { XO("Cathedral"), { 90, 16, 90, 50, 100, 0, 0, -20, 100, false } },
61};
62
64{
66 float *dry;
67 float *wet[2];
68};
69
71{
74 {
76 }
77};
78
80{
81 unsigned mNumChans{};
82 std::unique_ptr<Reverb_priv_ex[]> mP{};
83};
84
85
86//
87// EffectReverb
88//
89
91{ XO("Reverb") };
92
94
95
98{
101 : EffectUIValidator{ effect, access }
103 {}
104 virtual ~Validator() = default;
105
106 Effect& GetEffect() const { return static_cast<Effect&>(mEffect); }
107
108 bool ValidateUI() override;
109 bool UpdateUI() override;
110
112
114
115 bool mProcessingEvent = false;
116
117#define SpinSlider(n) \
118 wxSpinCtrl *m ## n ## T; \
119 wxSlider *m ## n ## S;
120
130
131#undef SpinSlider
132
133 wxCheckBox* mWetOnlyC;
134
135
136#define SpinSliderHandlers(n) \
137 void On ## n ## Slider(wxCommandEvent & evt); \
138 void On ## n ## Text(wxCommandEvent & evt);
139
149
150#undef SpinSliderHandlers
151
152 void OnCheckbox(wxCommandEvent &evt);
153
154};
155
156
158{
159 auto& rs = mSettings;
160
161 rs.mRoomSize = mRoomSizeS->GetValue();
162 rs.mPreDelay = mPreDelayS->GetValue();
163 rs.mReverberance = mReverberanceS->GetValue();
164 rs.mHfDamping = mHfDampingS->GetValue();
165 rs.mToneLow = mToneLowS->GetValue();
166 rs.mToneHigh = mToneHighS->GetValue();
167 rs.mWetGain = mWetGainS->GetValue();
168 rs.mDryGain = mDryGainS->GetValue();
169 rs.mStereoWidth = mStereoWidthS->GetValue();
170 rs.mWetOnly = mWetOnlyC->GetValue();
171
173 (
174 [this](EffectSettings& settings)
175 {
176 // pass back the modified settings to the MessageBuffer
177
179 }
180 );
181
182 return true;
183}
184
185
189{
190 explicit Instance(const PerTrackEffect& effect)
191 : PerTrackEffect::Instance{ effect }
192 {}
193
194 bool ProcessInitialize(EffectSettings &settings, double sampleRate,
195 sampleCount totalLen, ChannelNames chanMap) override;
196
198 const float* const* inBlock, float* const* outBlock, size_t blockLen) override;
199
200 bool ProcessFinalize(void) override; // not every effect needs this
201
202 // Realtime section
203
205 {
206 SetBlockSize(512);
207 mSlaves.clear();
208 return true;
209 }
210
212 unsigned numChannels, float sampleRate) override
213 {
214 EffectReverbState slave;
215
216 // The notion of ChannelNames is unavailable here,
217 // so we'll have to force the stereo init, if this is the case
218 //
219 InstanceInit(settings, sampleRate,
220 slave, /*ChannelNames=*/nullptr, /*forceStereo=*/(numChannels == 2));
221
222 mSlaves.push_back( std::move(slave) );
223 return true;
224 }
225
226 bool RealtimeFinalize(EffectSettings& settings) noexcept override
227 {
228 mSlaves.clear();
229 return true;
230 }
231
233 const float* const* inbuf, float* const* outbuf, size_t numSamples) override
234 {
235 if (group >= mSlaves.size())
236 return 0;
237 return InstanceProcess(settings, mSlaves[group], inbuf, outbuf, numSamples);
238 }
239
240 bool InstanceInit(EffectSettings& settings, double sampleRate,
241 EffectReverbState& data, ChannelNames chanMap, bool forceStereo);
242
244 const float* const* inBlock, float* const* outBlock, size_t blockLen);
245
247 std::vector<EffectReverbState> mSlaves;
248};
249
250
251
252std::shared_ptr<EffectInstance>
254{
255 return std::make_shared<Instance>(*this);
256}
257
258
260{
262}
263
265{
266}
267
268// ComponentInterface implementation
269
271{
272 return Symbol;
273}
274
276{
277 return XO("Adds ambience or a \"hall effect\"");
278}
279
281{
282 return L"Reverb";
283}
284
285// EffectDefinitionInterface implementation
286
288{
289 return EffectTypeProcess;
290}
291
293{
294 return 2;
295}
296
298{
299 return 2;
300}
301
302static size_t BLOCK = 16384;
303
305 double sampleRate, sampleCount, ChannelNames chanMap)
306{
307 return InstanceInit(settings,
308 sampleRate, mMaster, chanMap, /* forceStereo = */ false);
309}
310
311
313 double sampleRate, EffectReverbState& state,
314 ChannelNames chanMap, bool forceStereo)
315{
316 auto& rs = GetSettings(settings);
317
318 bool isStereo = false;
319 state.mNumChans = 1;
320 if ( (chanMap && chanMap[0] != ChannelNameEOL && chanMap[1] == ChannelNameFrontRight)
321 || forceStereo )
322 {
323 isStereo = true;
324 state.mNumChans = 2;
325 }
326
327 state.mP = std::make_unique<Reverb_priv_ex[]>(state.mNumChans);
328
329 for (unsigned int i = 0; i < state.mNumChans; i++)
330 {
331 reverb_create(&state.mP[i].reverb,
332 sampleRate,
333 rs.mWetGain,
334 rs.mRoomSize,
335 rs.mReverberance,
336 rs.mHfDamping,
337 rs.mPreDelay,
338 rs.mStereoWidth * (isStereo ? 1 : 0),
339 rs.mToneLow,
340 rs.mToneHigh,
341 BLOCK,
342 state.mP[i].wet);
343 }
344
345 return true;
346}
347
349{
350 return true;
351}
352
354 const float* const* inBlock, float* const* outBlock, size_t blockLen)
355{
356 return InstanceProcess(settings, mMaster, inBlock, outBlock, blockLen);
357}
358
360 const float* const* inBlock, float* const* outBlock, size_t blockLen)
361{
362 auto& rs = GetSettings(settings);
363
364 const float *ichans[2] = {NULL, NULL};
365 float *ochans[2] = {NULL, NULL};
366
367 for (unsigned int c = 0; c < state.mNumChans; c++)
368 {
369 ichans[c] = inBlock[c];
370 ochans[c] = outBlock[c];
371 }
372
373 float const dryMult = rs.mWetOnly ? 0 : dB_to_linear(rs.mDryGain);
374
375 auto remaining = blockLen;
376
377 while (remaining)
378 {
379 auto len = std::min(remaining, decltype(remaining)(BLOCK));
380 for (unsigned int c = 0; c < state.mNumChans; c++)
381 {
382 // Write the input samples to the reverb fifo. Returned value is the address of the
383 // fifo buffer which contains a copy of the input samples.
384 state.mP[c].dry = (float *) fifo_write(&state.mP[c].reverb.input_fifo, len, ichans[c]);
385 reverb_process(&state.mP[c].reverb, len);
386 }
387
388 if (state.mNumChans == 2)
389 {
390 for (decltype(len) i = 0; i < len; i++)
391 {
392 for (int w = 0; w < 2; w++)
393 {
394 ochans[w][i] = dryMult *
395 state.mP[w].dry[i] +
396 0.5 *
397 (state.mP[0].wet[w][i] + state.mP[1].wet[w][i]);
398 }
399 }
400 }
401 else
402 {
403 for (decltype(len) i = 0; i < len; i++)
404 {
405 ochans[0][i] = dryMult *
406 state.mP[0].dry[i] +
407 state.mP[0].wet[0][i];
408 }
409 }
410
411 remaining -= len;
412
413 for (unsigned int c = 0; c < state.mNumChans; c++)
414 {
415 ichans[c] += len;
416 ochans[c] += len;
417 }
418 }
419
420 return blockLen;
421}
422
424{
426
427 for (size_t i = 0; i < WXSIZEOF(FactoryPresets); i++)
428 {
429 names.push_back( FactoryPresets[i].name.Translation() );
430 }
431
432 return names;
433}
434
435
437{
438 if (id < 0 || id >= (int) WXSIZEOF(FactoryPresets))
439 {
440 return false;
441 }
442
444
445 return true;
446}
447
448// Effect implementation
449std::unique_ptr<EffectUIValidator> EffectReverb::PopulateOrExchange(
451{
452 auto& settings = access.Get();
453 auto& myEffSettings = GetSettings(settings);
454
455 auto result = std::make_unique<Validator>(*this, access, myEffSettings);
456 result->PopulateOrExchange(S);
457 return result;
458}
459
460
462{
463 S.AddSpace(0, 5);
464
465 S.StartMultiColumn(3, wxEXPAND);
466 {
467 S.SetStretchyCol(2);
468
469#define SpinSlider(n, p) \
470 m ## n ## T = S.AddSpinCtrl( p, n.def, n.max, n.min); \
471 BindTo(*m ## n ## T, wxEVT_SPINCTRL, &Validator::On ## n ## Text);\
472 \
473 m ## n ## S = S.Style(wxSL_HORIZONTAL).AddSlider( {}, n.def, n.max, n.min); \
474 BindTo(*m ## n ## S, wxEVT_SLIDER, &Validator::On ## n ## Slider);
475
476 SpinSlider(RoomSize, XXO("&Room Size (%):"))
477 SpinSlider(PreDelay, XXO("&Pre-delay (ms):"))
478 SpinSlider(Reverberance, XXO("Rever&berance (%):"))
479 SpinSlider(HfDamping, XXO("Da&mping (%):"))
480 SpinSlider(ToneLow, XXO("Tone &Low (%):"))
481 SpinSlider(ToneHigh, XXO("Tone &High (%):"))
482 SpinSlider(WetGain, XXO("Wet &Gain (dB):"))
483 SpinSlider(DryGain, XXO("Dr&y Gain (dB):"))
484 SpinSlider(StereoWidth, XXO("Stereo Wid&th (%):"))
485
486#undef SpinSlider
487
488 }
489 S.EndMultiColumn();
490
491 S.StartHorizontalLay(wxCENTER, false);
492 {
493 mWetOnlyC =
494 S.AddCheckBox(XXO("Wet O&nly"), WetOnly.def);
495 BindTo(*mWetOnlyC, wxEVT_CHECKBOX, &Validator::OnCheckbox);
496 }
497 S.EndHorizontalLay();
498
499}
500
502{
503 // get the settings from the MessageBuffer and write them to our local copy
504 mSettings = GetSettings(mAccess.Get());
505
506 auto& rs = mSettings;
507
508#define SetSpinSlider(n) \
509 m ## n ## S->SetValue((int) rs.m ## n); \
510 m ## n ## T->SetValue(wxString::Format(wxT("%d"), (int) rs.m ## n));
511
521
522#undef SetSpinSlider
523
524 mWetOnlyC->SetValue((int) rs.mWetOnly);
525
526 return true;
527}
528
529
530#define SpinSliderHandlers(n) \
531 void EffectReverb::Validator::On ## n ## Slider(wxCommandEvent & evt) \
532 { \
533 if (mProcessingEvent) return; \
534 mProcessingEvent = true; \
535 m ## n ## T->SetValue(wxString::Format(wxT("%d"), evt.GetInt())); \
536 mProcessingEvent = false; \
537 ValidateUI(); \
538 } \
539 void EffectReverb::Validator::On ## n ## Text(wxCommandEvent & evt) \
540 { \
541 if (mProcessingEvent) return; \
542 mProcessingEvent = true; \
543 m ## n ## S->SetValue(std::clamp<long>(evt.GetInt(), n.min, n.max)); \
544 mProcessingEvent = false; \
545 ValidateUI(); \
546 }
547
557
558void EffectReverb::Validator::OnCheckbox(wxCommandEvent &evt)
559{
560 ValidateUI();
561}
562
563#undef SpinSliderHandlers
int min(int a, int b)
EffectType
@ EffectTypeProcess
enum ChannelName * ChannelNames
@ ChannelNameEOL
@ ChannelNameFrontRight
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
static const struct @36 FactoryPresets[]
#define SetSpinSlider(n)
static size_t BLOCK
Definition: Reverb.cpp:302
#define SpinSliderHandlers(n)
Definition: Reverb.cpp:530
EffectReverbSettings preset
Definition: Reverb.cpp:46
const TranslatableString name
Definition: Reverb.cpp:45
#define SpinSlider(n)
Definition: Reverb.cpp:117
#define dB_to_linear(x)
Definition: Reverb_libSoX.h:27
static void reverb_process(reverb_t *p, size_t length)
static void reverb_delete(reverb_t *p)
static void reverb_create(reverb_t *p, double sample_rate_Hz, double wet_gain_dB, double room_scale, double reverberance, double hf_damping, double pre_delay_ms, double stereo_depth, double tone_low, double tone_high, size_t buffer_size, float **out)
static void * fifo_write(fifo_t *f, FIFO_SIZE_T n, void const *data)
Definition: Reverb_libSoX.h:74
static TranslatableStrings names
Definition: TagsEditor.cpp:151
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
int id
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: EffectBase.cpp:218
Base class for many of the effects in Audacity.
Definition: Effect.h:29
bool ValidateUI(EffectSettings &) override
Definition: Effect.cpp:313
Performs effect computation.
Inherit to add a state variable to an EffectInstance subclass.
size_t SetBlockSize(size_t maxBlockSize) override
Interface for manipulations of an Effect's settings.
const EffectParameterMethods & Parameters() const override
Definition: Reverb.cpp:34
virtual ~EffectReverb()
Definition: Reverb.cpp:264
EffectType GetType() const override
Type determines how it behaves.
Definition: Reverb.cpp:287
static constexpr EffectParameter ToneLow
Definition: Reverb.h:106
static constexpr EffectParameter PreDelay
Definition: Reverb.h:97
static constexpr EffectParameter RoomSize
Definition: Reverb.h:94
ComponentInterfaceSymbol GetSymbol() const override
Definition: Reverb.cpp:270
static constexpr EffectParameter StereoWidth
Definition: Reverb.h:118
static const ComponentInterfaceSymbol Symbol
Definition: Reverb.h:52
static constexpr EffectParameter Reverberance
Definition: Reverb.h:100
static constexpr EffectParameter WetGain
Definition: Reverb.h:112
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
Definition: Reverb.cpp:297
static constexpr EffectParameter HfDamping
Definition: Reverb.h:103
static constexpr EffectParameter ToneHigh
Definition: Reverb.h:109
static constexpr EffectParameter WetOnly
Definition: Reverb.h:121
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
Definition: Reverb.cpp:292
TranslatableString GetDescription() const override
Definition: Reverb.cpp:275
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: Reverb.cpp:280
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Add controls to effect panel; always succeeds.
Definition: Reverb.cpp:449
static constexpr EffectParameter DryGain
Definition: Reverb.h:115
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
Definition: Reverb.cpp:253
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
Definition: Reverb.cpp:423
bool LoadFactoryPreset(int id, EffectSettings &settings) const override
Change settings to the preset whose name is GetFactoryPresets()[id]
Definition: Reverb.cpp:436
void ModifySettings(Function &&function)
Do a correct read-modify-write of settings.
virtual const EffectSettings & Get()=0
EffectUIClientInterface is an abstract base class to populate a UI and validate UI values....
Interface for transferring values from a panel of effect controls.
EffectSettingsAccess & mAccess
EffectUIClientInterface & mEffect
static EffectReverbSettings & GetSettings(EffectSettings &settings)
Assume settings originated from MakeSettings() and copies thereof.
Definition: Effect.h:296
Base class for many of the effects in Audacity.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
BuiltinEffectsModule::Registration< EffectReverb > reg
Definition: Reverb.cpp:93
const Type def
Default value.
Definition: Shuttle.h:29
size_t RealtimeProcess(size_t group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
Definition: Reverb.cpp:232
bool InstanceInit(EffectSettings &settings, double sampleRate, EffectReverbState &data, ChannelNames chanMap, bool forceStereo)
Definition: Reverb.cpp:312
EffectReverbState mMaster
Definition: Reverb.cpp:246
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
Definition: Reverb.cpp:353
size_t InstanceProcess(EffectSettings &settings, EffectReverbState &data, const float *const *inBlock, float *const *outBlock, size_t blockLen)
Definition: Reverb.cpp:359
bool ProcessInitialize(EffectSettings &settings, double sampleRate, sampleCount totalLen, ChannelNames chanMap) override
Definition: Reverb.cpp:304
std::vector< EffectReverbState > mSlaves
Definition: Reverb.cpp:247
bool RealtimeAddProcessor(EffectSettings &settings, unsigned numChannels, float sampleRate) override
Definition: Reverb.cpp:211
Instance(const PerTrackEffect &effect)
Definition: Reverb.cpp:190
bool RealtimeInitialize(EffectSettings &settings, double) override
Definition: Reverb.cpp:204
bool ProcessFinalize(void) override
Definition: Reverb.cpp:348
bool RealtimeFinalize(EffectSettings &settings) noexcept override
Definition: Reverb.cpp:226
SpinSliderHandlers(RoomSize) SpinSliderHandlers(PreDelay) SpinSliderHandlers(Reverberance) SpinSliderHandlers(HfDamping) SpinSliderHandlers(ToneLow) SpinSliderHandlers(ToneHigh) SpinSliderHandlers(WetGain) SpinSliderHandlers(DryGain) SpinSliderHandlers(StereoWidth) void OnCheckbox(wxCommandEvent &evt)
void PopulateOrExchange(ShuttleGui &S)
Definition: Reverb.cpp:461
EffectReverbSettings mSettings
Definition: Reverb.cpp:113
virtual ~Validator()=default
bool ValidateUI() override
Get settings data from the panel; may make error dialogs and return false.
Definition: Reverb.cpp:157
Effect & GetEffect() const
Definition: Reverb.cpp:106
Validator(EffectUIClientInterface &effect, EffectSettingsAccess &access, const EffectReverbSettings &settings)
Definition: Reverb.cpp:99
SpinSlider(RoomSize) SpinSlider(PreDelay) SpinSlider(Reverberance) SpinSlider(HfDamping) SpinSlider(ToneLow) SpinSlider(ToneHigh) SpinSlider(WetGain) SpinSlider(DryGain) SpinSlider(StereoWidth) wxCheckBox *mWetOnlyC
bool UpdateUI() override
Update appearance of the panel for changes in settings.
Definition: Reverb.cpp:501
double mRoomSize
Definition: Reverb.h:34
std::unique_ptr< Reverb_priv_ex[]> mP
Definition: Reverb.cpp:82
unsigned mNumChans
Definition: Reverb.cpp:81
Externalized state of a plug-in.
float * wet[2]
Definition: Reverb.cpp:67
reverb_t reverb
Definition: Reverb.cpp:65
float * dry
Definition: Reverb.cpp:66