Audacity 3.2.0
Compressor.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Compressor.cpp
6
7 Dominic Mazzoni
8 Martyn Shaw
9 Steve Jolly
10
11*******************************************************************//****************************************************************//*******************************************************************/
26#include "Compressor.h"
27#include "EffectEditor.h"
28#include "LoadEffects.h"
29
30#include <math.h>
31
32#include <wx/brush.h>
33#include <wx/checkbox.h>
34#include <wx/dcclient.h>
35#include <wx/slider.h>
36#include <wx/stattext.h>
37
38#include "AColor.h"
39#include "Prefs.h"
40#include "ShuttleGui.h"
41#include "Theme.h"
42#include "float_cast.h"
43#include "../widgets/LinearUpdater.h"
44#include "../widgets/Ruler.h"
45#include "../widgets/LinearDBFormat.h"
46#include "../widgets/LinearUpdater.h"
47
48#include "WaveTrack.h"
49#include "AllThemeResources.h"
50
51enum
52{
53 ID_Threshold = 10000,
58};
59
61{
63 Threshold, NoiseFloor, Ratio, // positive number > 1.0
64 AttackTime, // seconds
65 ReleaseTime, // seconds
67 > parameters;
68 return parameters;
69}
70
71//----------------------------------------------------------------------------
72// EffectCompressor
73//----------------------------------------------------------------------------
74
76{ XO("Compressor") };
77
79
80BEGIN_EVENT_TABLE(EffectCompressor, wxEvtHandler)
81 EVT_SLIDER(wxID_ANY, EffectCompressor::OnSlider)
83
85{
86 Parameters().Reset(*this);
87
88 mThreshold = 0.25;
89 mNoiseFloor = 0.01;
90 mCompression = 0.5;
91 mFollowLen = 0;
92
93 SetLinearEffectFlag(false);
94}
95
97{
98}
99
100// ComponentInterface implementation
101
103{
104 return Symbol;
105}
106
108{
109 return XO("Compresses the dynamic range of audio");
110}
111
113{
114 return L"Compressor";
115}
116
117// EffectDefinitionInterface implementation
118
120{
121 return EffectTypeProcess;
122}
123
124// Effect Implementation
125
126namespace {
127
129 /* i18n-hint: usually leave this as is as dB doesn't get translated*/
130{ return XO("%3d dB").Format(value); }
131
133{ return XO("%.2f secs").Format( value ); }
134
136{ return XO("%.1f secs").Format( value ); }
137
138TranslatableString RatioTextFormat( int sliderValue, double value )
139{
140 auto format = (sliderValue % 10 == 0)
141 /* i18n-hint: Unless your language has a different convention for ratios,
142 * like 8:1, leave as is.*/
143 ? XO("%.0f:1")
144 /* i18n-hint: Unless your language has a different convention for ratios,
145 * like 8:1, leave as is.*/
146 : XO("%.1f:1");
147 return format.Format( value );
148}
149
150TranslatableString RatioLabelFormat( int sliderValue, double value )
151{
152 auto format = (sliderValue % 10 == 0)
153 ? XO("Ratio %.0f to 1")
154 : XO("Ratio %.1f to 1");
155 return format.Format( value );
156}
157
158}
159
160std::unique_ptr<EffectEditor> EffectCompressor::PopulateOrExchange(
162 const EffectOutputs *)
163{
164 mUIParent = S.GetParent();
165 S.SetBorder(5);
166
167 S.StartHorizontalLay(wxEXPAND, true);
168 {
169 S.SetBorder(10);
170 mPanel = safenew EffectCompressorPanel(S.GetParent(), wxID_ANY,
173 mRatio);
174 S.Prop(true)
175 .Position(wxEXPAND | wxALL)
176 .MinSize( { 400, 200 } )
177 .AddWindow(mPanel);
178 S.SetBorder(5);
179 }
180 S.EndHorizontalLay();
181
182 S.StartStatic( {} );
183 {
184 S.StartMultiColumn(3, wxEXPAND);
185 {
186 S.SetStretchyCol(1);
187 mThresholdLabel = S.AddVariableText(XO("&Threshold:"), true,
188 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
190 .Name(XO("Threshold"))
191 .Style(wxSL_HORIZONTAL)
192 .AddSlider( {},
196 mThresholdText = S.AddVariableText(ThresholdFormat(999), true,
197 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
198
199 mNoiseFloorLabel = S.AddVariableText(XO("&Noise Floor:"), true,
200 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
202 .Name(XO("Noise Floor"))
203 .Style(wxSL_HORIZONTAL)
204 .AddSlider( {},
208 mNoiseFloorText = S.AddVariableText(ThresholdFormat(999),
209 true, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
210
211 mRatioLabel = S.AddVariableText(XO("&Ratio:"), true,
212 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
214 .Name(XO("Ratio"))
215 .Style(wxSL_HORIZONTAL)
216 .AddSlider( {},
219 Ratio.min * Ratio.scale);
220 mRatioSlider->SetPageSize(5);
221 mRatioText = S.AddVariableText(RatioTextFormat( 1, 99.9 ), true,
222 wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
223
224 /* i18n-hint: Particularly in percussion, sounds can be regarded as having
225 * an 'attack' phase where the sound builds up and a 'decay' where the
226 * sound dies away. So this means 'onset duration'. */
227 mAttackLabel = S.AddVariableText(XO("&Attack Time:"), true,
228 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
230 /* i18n-hint: Particularly in percussion, sounds can be regarded as having
231 * an 'attack' phase where the sound builds up and a 'decay' where the
232 * sound dies away. So this means 'onset duration'. */
233 .Name(XO("Attack Time"))
234 .Style(wxSL_HORIZONTAL)
235 .AddSlider( {},
239 mAttackText = S.AddVariableText(
240 AttackTimeFormat(9.99),
241 true, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
242
243 /* i18n-hint: Particularly in percussion, sounds can be regarded as having
244 * an 'attack' phase where the sound builds up and a 'decay' or 'release' where the
245 * sound dies away. */
246 mDecayLabel = S.AddVariableText(XO("R&elease Time:"), true,
247 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
249 /* i18n-hint: Particularly in percussion, sounds can be regarded as having
250 * an 'attack' phase where the sound builds up and a 'decay' or 'release' where the
251 * sound dies away. */
252 .Name(XO("Release Time"))
253 .Style(wxSL_HORIZONTAL)
254 .AddSlider( {},
258
259 mDecayText = S.AddVariableText(
260 DecayTimeFormat(99.9),
261 true, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
262 }
263 S.EndMultiColumn();
264 }
265 S.EndStatic();
266
267 S.StartHorizontalLay(wxCENTER, false);
268 {
269 /* i18n-hint: Make-up, i.e. correct for any reduction, rather than fabricate it.*/
270 mGainCheckBox = S.AddCheckBox(XXO("Ma&ke-up gain for 0 dB after compressing"),
271 Normalize.def);
272 /* i18n-hint: "Compress" here means reduce variations of sound volume,
273 NOT related to file-size compression; Peaks means extremes in volume */
274 mPeakCheckBox = S.AddCheckBox(XXO("C&ompress based on Peaks"),
275 UsePeak.def);
276 }
277 S.EndHorizontalLay();
278 return nullptr;
279}
280
282{
285 mRatioSlider->SetValue(lrint(mRatio * Ratio.scale));
288 mGainCheckBox->SetValue(mNormalize);
289 mPeakCheckBox->SetValue(mUsePeak);
290
291 UpdateUI();
292
293 return true;
294}
295
297{
298 if (!mUIParent->Validate())
299 {
300 return false;
301 }
303}
304
306{
307 // To do: eliminate this by using control validators instead
308 mThresholdDB = (double) mThresholdSlider->GetValue();
309 mNoiseFloorDB = (double) mNoiseFloorSlider->GetValue() / NoiseFloor.scale;
310 mRatio = (double) mRatioSlider->GetValue() / Ratio.scale;
311 mAttackTime = (double) mAttackSlider->GetValue() / 100.0; //AttackTime.scale;
312 mDecayTime = (double) mDecaySlider->GetValue() / ReleaseTime.scale;
313 mNormalize = mGainCheckBox->GetValue();
314 mUsePeak = mPeakCheckBox->GetValue();
315
316 return true;
317}
318
319// EffectTwoPassSimpleMono implementation
320
322{
325 mNoiseCounter = 100;
326
327 mAttackInverseFactor = exp(log(mThreshold) / (mCurRate * mAttackTime + 0.5));
329 mDecayFactor = exp(log(mThreshold) / (mCurRate * mDecayTime + 0.5));
330
331 if(mRatio > 1)
332 mCompression = 1.0-1.0/mRatio;
333 else
334 mCompression = 0.0;
335
337
338 mCircleSize = 100;
339 mCircle.reinit( mCircleSize, true );
340 mCirclePos = 0;
341 mRMSSum = 0.0;
342
343 return true;
344}
345
347{
348 mMax=0.0;
349 if (!mNormalize)
351
352 // Find the maximum block length required for any track
353 size_t maxlen = inputTracks()->Selected<const WaveTrack>().max(
355 );
356 mFollow1.reset();
357 mFollow2.reset();
358 // Allocate buffers for the envelope
359 if(maxlen > 0) {
360 mFollow1.reinit(maxlen);
361 mFollow2.reinit(maxlen);
362 }
363 mFollowLen = maxlen;
364
365 return true;
366}
367
369{
370 // Actually, this should not even be called, because we call
371 // DisableSecondPass() before, if mNormalize is false.
372 return mNormalize;
373}
374
375// Process the input with 2 buffers available at a time
376// buffer1 will be written upon return
377// buffer2 will be passed as buffer1 on the next call
379 (float *buffer1, size_t len1, float *buffer2, size_t len2)
380{
381 // If buffers are bigger than allocated, then abort
382 // (this should never happen, but if it does, we don't want to crash)
383 if((len1 > mFollowLen) || (len2 > mFollowLen))
384 return false;
385
386 // This makes sure that the initial value is well-chosen
387 // buffer1 == NULL on the first and only the first call
388 if (buffer1 == NULL) {
389 // Initialize the mLastLevel to the peak level in the first buffer
390 // This avoids problems with large spike events near the beginning of the track
392 for(size_t i=0; i<len2; i++) {
393 if(mLastLevel < fabs(buffer2[i]))
394 mLastLevel = fabs(buffer2[i]);
395 }
396 }
397
398 // buffer2 is NULL on the last and only the last call
399 if(buffer2 != NULL) {
400 Follow(buffer2, mFollow2.get(), len2, mFollow1.get(), len1);
401 }
402
403 if(buffer1 != NULL) {
404 for (size_t i = 0; i < len1; i++) {
405 buffer1[i] = DoCompression(buffer1[i], mFollow1[i]);
406 }
407 }
408
409
410#if 0
411 // Copy the envelope over the track data (for debug purposes)
412 memcpy(buffer1, mFollow1, len1*sizeof(float));
413#endif
414
415 // Rotate the buffer pointers
416 mFollow1.swap(mFollow2);
417
418 return true;
419}
420
421bool EffectCompressor::ProcessPass2(float *buffer, size_t len)
422{
423 if (mMax != 0)
424 {
425 for (size_t i = 0; i < len; i++)
426 buffer[i] /= mMax;
427 }
428
429 return true;
430}
431
433{
434 // Recompute the RMS sum periodically to prevent accumulation of rounding errors
435 // during long waveforms
436 mRMSSum = 0;
437 for(size_t i=0; i<mCircleSize; i++)
438 mRMSSum += mCircle[i];
439}
440
442{
443 float level;
444
445 // Calculate current level from root-mean-squared of
446 // circular buffer ("RMS")
448 mCircle[mCirclePos] = value*value;
450 level = sqrt(mRMSSum/mCircleSize);
452
453 return level;
454}
455
456void EffectCompressor::Follow(float *buffer, float *env, size_t len, float *previous, size_t previous_len)
457{
458 /*
459
460 "Follow"ing algorithm by Roger B. Dannenberg, taken from
461 Nyquist. His description follows. -DMM
462
463 Description: this is a sophisticated envelope follower.
464 The input is an envelope, e.g. something produced with
465 the AVG function. The purpose of this function is to
466 generate a smooth envelope that is generally not less
467 than the input signal. In other words, we want to "ride"
468 the peaks of the signal with a smooth function. The
469 algorithm is as follows: keep a current output value
470 (called the "value"). The value is allowed to increase
471 by at most rise_factor and decrease by at most fall_factor.
472 Therefore, the next value should be between
473 value * rise_factor and value * fall_factor. If the input
474 is in this range, then the next value is simply the input.
475 If the input is less than value * fall_factor, then the
476 next value is just value * fall_factor, which will be greater
477 than the input signal. If the input is greater than value *
478 rise_factor, then we compute a rising envelope that meets
479 the input value by working bacwards in time, changing the
480 previous values to input / rise_factor, input / rise_factor^2,
481 input / rise_factor^3, etc. until this NEW envelope intersects
482 the previously computed values. There is only a limited buffer
483 in which we can work backwards, so if the NEW envelope does not
484 intersect the old one, then make yet another pass, this time
485 from the oldest buffered value forward, increasing on each
486 sample by rise_factor to produce a maximal envelope. This will
487 still be less than the input.
488
489 The value has a lower limit of floor to make sure value has a
490 reasonable positive value from which to begin an attack.
491 */
492 double level,last;
493
494 if(!mUsePeak) {
495 // Update RMS sum directly from the circle buffer
496 // to avoid accumulation of rounding errors
498 }
499 // First apply a peak detect with the requested decay rate
500 last = mLastLevel;
501 for(size_t i=0; i<len; i++) {
502 if(mUsePeak)
503 level = fabs(buffer[i]);
504 else // use RMS
505 level = AvgCircle(buffer[i]);
506 // Don't increase gain when signal is continuously below the noise floor
507 if(level < mNoiseFloor) {
509 } else {
510 mNoiseCounter = 0;
511 }
512 if(mNoiseCounter < 100) {
513 last *= mDecayFactor;
514 if(last < mThreshold)
515 last = mThreshold;
516 if(level > last)
517 last = level;
518 }
519 env[i] = last;
520 }
521 mLastLevel = last;
522
523 // Next do the same process in reverse direction to get the requested attack rate
524 last = mLastLevel;
525 for(size_t i = len; i--;) {
526 last *= mAttackInverseFactor;
527 if(last < mThreshold)
528 last = mThreshold;
529 if(env[i] < last)
530 env[i] = last;
531 else
532 last = env[i];
533 }
534
535 if((previous != NULL) && (previous_len > 0)) {
536 // If the previous envelope was passed, propagate the rise back until we intersect
537 for(size_t i = previous_len; i--;) {
538 last *= mAttackInverseFactor;
539 if(last < mThreshold)
540 last = mThreshold;
541 if(previous[i] < last)
542 previous[i] = last;
543 else // Intersected the previous envelope buffer, so we are finished
544 return;
545 }
546 // If we can't back up far enough, project the starting level forward
547 // until we intersect the desired envelope
548 last = previous[0];
549 for(size_t i=1; i<previous_len; i++) {
550 last *= mAttackFactor;
551 if(previous[i] > last)
552 previous[i] = last;
553 else // Intersected the desired envelope, so we are finished
554 return;
555 }
556 // If we still didn't intersect, then continue ramp up into current buffer
557 for(size_t i=0; i<len; i++) {
558 last *= mAttackFactor;
559 if(buffer[i] > last)
560 buffer[i] = last;
561 else // Finally got an intersect
562 return;
563 }
564 // If we still didn't intersect, then reset mLastLevel
565 mLastLevel = last;
566 }
567}
568
569float EffectCompressor::DoCompression(float value, double env)
570{
571 float out;
572 if(mUsePeak) {
573 // Peak values map 1.0 to 1.0 - 'upward' compression
574 out = value * pow(1.0/env, mCompression);
575 } else {
576 // With RMS-based compression don't change values below mThreshold - 'downward' compression
577 out = value * pow(mThreshold/env, mCompression);
578 }
579
580 // Retain the maximum value for use in the normalization pass
581 if(mMax < fabs(out))
582 mMax = fabs(out);
583
584 return out;
585}
586
587void EffectCompressor::OnSlider(wxCommandEvent & WXUNUSED(evt))
588{
590 UpdateUI();
591}
592
594{
595 mThresholdLabel->SetName(wxString::Format(_("Threshold %d dB"), (int) mThresholdDB));
596 mThresholdText->SetLabel(ThresholdFormat((int) mThresholdDB).Translation());
597 mThresholdText->SetName(mThresholdText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
598
599 mNoiseFloorLabel->SetName(wxString::Format(_("Noise Floor %d dB"), (int) mNoiseFloorDB));
600 mNoiseFloorText->SetLabel(ThresholdFormat((int) mNoiseFloorDB).Translation());
601 mNoiseFloorText->SetName(mNoiseFloorText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
602
603 mRatioLabel->SetName(
605 mRatioText->SetLabel(
607 mRatioText->SetName(mRatioText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
608
609 mAttackLabel->SetName(wxString::Format(_("Attack Time %.2f secs"), mAttackTime));
610 mAttackText->SetLabel(AttackTimeFormat(mAttackTime).Translation());
611 mAttackText->SetName(mAttackText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
612
613 mDecayLabel->SetName(wxString::Format(_("Release Time %.1f secs"), mDecayTime));
614 mDecayText->SetLabel(DecayTimeFormat(mDecayTime).Translation());
615 mDecayText->SetName(mDecayText->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
616
617 mPanel->Refresh(false);
618
619 return;
620}
621
622//----------------------------------------------------------------------------
623// EffectCompressorPanel
624//----------------------------------------------------------------------------
625
626BEGIN_EVENT_TABLE(EffectCompressorPanel, wxPanelWrapper)
630
631EffectCompressorPanel::EffectCompressorPanel(wxWindow *parent, wxWindowID winid,
632 double & threshold,
633 double & noiseFloor,
634 double & ratio)
635: wxPanelWrapper(parent, winid),
636 threshold(threshold),
637 noiseFloor(noiseFloor),
638 ratio(ratio)
639{
640}
641
642void EffectCompressorPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
643{
644 wxPaintDC dc(this);
645
646 int width, height;
647 GetSize(&width, &height);
648
649 double rangeDB = 60;
650
651 // Ruler
652 int w = 0;
653 int h = 0;
654
656 vRuler.SetBounds(0, 0, width, height);
657 vRuler.SetOrientation(wxVERTICAL);
658 vRuler.SetRange(0, -rangeDB);
659 vRuler.SetUnits(XO("dB"));
660 vRuler.GetMaxSize(&w, NULL);
661
663 hRuler.SetBounds(0, 0, width, height);
664 hRuler.SetOrientation(wxHORIZONTAL);
665 hRuler.SetRange(-rangeDB, 0);
666 hRuler.SetUnits(XO("dB"));
667 hRuler.SetFlip(true);
668 hRuler.GetMaxSize(NULL, &h);
669
670 vRuler.SetBounds(0, 0, w, height - h);
671 hRuler.SetBounds(w, height - h, width, height);
672
673 vRuler.SetTickColour( theTheme.Colour( clrGraphLabels ));
674 hRuler.SetTickColour( theTheme.Colour( clrGraphLabels ));
675
676#if defined(__WXMSW__)
677 dc.Clear();
678#endif
679
680 wxRect border;
681 border.x = w;
682 border.y = 0;
683 border.width = width - w;
684 border.height = height - h + 1;
685
686 dc.SetBrush(*wxWHITE_BRUSH);
687 dc.SetPen(*wxBLACK_PEN);
688 dc.DrawRectangle(border);
689
690 wxRect envRect = border;
691 envRect.Deflate( 2, 2 );
692
693 int kneeX = lrint((rangeDB+threshold)*envRect.width/rangeDB);
694 int kneeY = lrint((rangeDB+threshold/ratio)*envRect.height/rangeDB);
695
696 int finalY = envRect.height;
697 int startY = lrint((threshold*(1.0/ratio-1.0))*envRect.height/rangeDB);
698
699 // Yellow line for threshold
700/* dc.SetPen(wxPen(wxColour(220, 220, 0), 1, wxSOLID));
701 AColor::Line(dc,
702 envRect.x,
703 envRect.y + envRect.height - kneeY,
704 envRect.x + envRect.width - 1,
705 envRect.y + envRect.height - kneeY);*/
706
707 // Was: Nice dark red line for the compression diagram
708// dc.SetPen(wxPen(wxColour(180, 40, 40), 3, wxSOLID));
709
710 // Nice blue line for compressor, same color as used in the waveform envelope.
711 dc.SetPen( AColor::WideEnvelopePen) ;
712
713 AColor::Line(dc,
714 envRect.x,
715 envRect.y + envRect.height - startY,
716 envRect.x + kneeX - 1,
717 envRect.y + envRect.height - kneeY);
718
719 AColor::Line(dc,
720 envRect.x + kneeX,
721 envRect.y + envRect.height - kneeY,
722 envRect.x + envRect.width - 1,
723 envRect.y + envRect.height - finalY);
724
725 // Paint border again
726 dc.SetBrush(*wxTRANSPARENT_BRUSH);
727 dc.SetPen(*wxBLACK_PEN);
728 dc.DrawRectangle(border);
729
730 vRuler.Draw(dc);
731 hRuler.Draw(dc);
732}
733
734void EffectCompressorPanel::OnSize(wxSizeEvent & WXUNUSED(evt))
735{
736 Refresh(false);
737}
END_EVENT_TABLE()
@ ID_Ratio
Definition: Compressor.cpp:55
@ ID_Threshold
Definition: Compressor.cpp:53
@ ID_Attack
Definition: Compressor.cpp:56
@ ID_NoiseFloor
Definition: Compressor.cpp:54
@ ID_Decay
Definition: Compressor.cpp:57
EffectType
@ EffectTypeProcess
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:9
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:337
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
static wxPen WideEnvelopePen
Definition: AColor.h:116
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:58
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const TrackList * inputTracks() const
Definition: EffectBase.h:91
An Effect derived from EffectTwoPassSimpleMono.
Definition: Compressor.h:29
wxStaticText * mRatioText
Definition: Compressor.h:121
const EffectParameterMethods & Parameters() const override
Definition: Compressor.cpp:60
bool TwoBufferProcessPass1(float *buffer1, size_t len1, float *buffer2, size_t len2) override
Definition: Compressor.cpp:379
wxStaticText * mRatioLabel
Definition: Compressor.h:119
wxCheckBox * mPeakCheckBox
Definition: Compressor.h:132
double mThresholdDB
Definition: Compressor.h:88
static constexpr EffectParameter Ratio
Definition: Compressor.h:141
bool InitPass1() override
Definition: Compressor.cpp:346
bool TransferDataFromWindow(EffectSettings &settings) override
Definition: Compressor.cpp:296
wxStaticText * mAttackLabel
Definition: Compressor.h:123
static constexpr EffectParameter Threshold
Definition: Compressor.h:137
wxSlider * mDecaySlider
Definition: Compressor.h:128
float AvgCircle(float x)
Definition: Compressor.cpp:441
EffectType GetType() const override
Type determines how it behaves.
Definition: Compressor.cpp:119
bool DoTransferDataFromWindow()
Definition: Compressor.cpp:305
static const ComponentInterfaceSymbol Symbol
Definition: Compressor.h:34
bool TransferDataToWindow(const EffectSettings &settings) override
Definition: Compressor.cpp:281
Doubles mCircle
Definition: Compressor.h:85
void Follow(float *buffer, float *env, size_t len, float *previous, size_t previous_len)
Definition: Compressor.cpp:456
size_t mCirclePos
Definition: Compressor.h:84
wxWeakRef< wxWindow > mUIParent
Definition: Compressor.h:80
double mAttackFactor
Definition: Compressor.h:95
wxStaticText * mDecayText
Definition: Compressor.h:129
double mNoiseFloor
Definition: Compressor.h:100
double mAttackTime
Definition: Compressor.h:87
wxSlider * mAttackSlider
Definition: Compressor.h:124
size_t mCircleSize
Definition: Compressor.h:83
static constexpr EffectParameter UsePeak
Definition: Compressor.h:149
wxSlider * mNoiseFloorSlider
Definition: Compressor.h:116
float DoCompression(float x, double env)
Definition: Compressor.cpp:569
wxSlider * mThresholdSlider
Definition: Compressor.h:112
ComponentInterfaceSymbol GetSymbol() const override
Definition: Compressor.cpp:102
wxStaticText * mDecayLabel
Definition: Compressor.h:127
double mDecayTime
Definition: Compressor.h:94
TranslatableString GetDescription() const override
Definition: Compressor.cpp:107
double mDecayFactor
Definition: Compressor.h:97
static constexpr EffectParameter NoiseFloor
Definition: Compressor.h:139
static constexpr EffectParameter ReleaseTime
Definition: Compressor.h:145
double mNoiseFloorDB
Definition: Compressor.h:89
static constexpr EffectParameter AttackTime
Definition: Compressor.h:143
std::unique_ptr< EffectEditor > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
Definition: Compressor.cpp:160
void OnSlider(wxCommandEvent &evt)
Definition: Compressor.cpp:587
EffectCompressorPanel * mPanel
Definition: Compressor.h:109
wxStaticText * mNoiseFloorText
Definition: Compressor.h:117
wxStaticText * mAttackText
Definition: Compressor.h:125
bool ProcessPass2(float *buffer, size_t len) override
Definition: Compressor.cpp:421
double mCompression
Definition: Compressor.h:99
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: Compressor.cpp:112
wxSlider * mRatioSlider
Definition: Compressor.h:120
virtual ~EffectCompressor()
Definition: Compressor.cpp:96
wxCheckBox * mGainCheckBox
Definition: Compressor.h:131
double mAttackInverseFactor
Definition: Compressor.h:96
double mThreshold
Definition: Compressor.h:98
wxStaticText * mThresholdText
Definition: Compressor.h:113
bool InitPass2() override
Definition: Compressor.cpp:368
wxStaticText * mNoiseFloorLabel
Definition: Compressor.h:115
wxStaticText * mThresholdLabel
Definition: Compressor.h:111
bool NewTrackPass1() override
Definition: Compressor.cpp:321
static constexpr EffectParameter Normalize
Definition: Compressor.h:147
void OnSize(wxSizeEvent &evt)
Definition: Compressor.cpp:734
void OnPaint(wxPaintEvent &evt)
Definition: Compressor.cpp:642
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
void DisableSecondPass()
Call this if you know in advance that no second pass will be needed.
static const LinearDBFormat & Instance()
static const LinearUpdater & Instance()
Used to display a Ruler.
Definition: Ruler.h:34
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
wxColour & Colour(int iIndex)
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:967
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:2258
#define lrint(dbl)
Definition: float_cast.h:169
TranslatableString DecayTimeFormat(double value)
Definition: Compressor.cpp:135
TranslatableString RatioTextFormat(int sliderValue, double value)
Definition: Compressor.cpp:138
TranslatableString ThresholdFormat(int value)
Definition: Compressor.cpp:128
BuiltinEffectsModule::Registration< EffectCompressor > reg
Definition: Compressor.cpp:78
TranslatableString AttackTimeFormat(double value)
Definition: Compressor.cpp:132
TranslatableString RatioLabelFormat(int sliderValue, double value)
Definition: Compressor.cpp:150
__finl float_x4 __vecc sqrt(const float_x4 &a)
const Type scale
Scaling factor, for slider control.
const Type def
Default value.
const Type min
Minimum value.
const Type max
Maximum value.
Externalized state of a plug-in.