Audacity 3.2.0
ScienFilter.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Effect/ScienFilter.cpp
6
7 Norm C
8 Mitch Golden
9 Vaughan Johnson (Preview)
10
11*******************************************************************//****************************************************************//****************************************************************//*******************************************************************/
34
35
36#include "ScienFilter.h"
37#include "LoadEffects.h"
38
39#include <math.h>
40
41#include <wx/setup.h> // for wxUSE_* macros
42
43#include <wx/brush.h>
44#include <wx/choice.h>
45#include <wx/dcclient.h>
46#include <wx/dcmemory.h>
47#include <wx/intl.h>
48#include <wx/settings.h>
49#include <wx/slider.h>
50#include <wx/stattext.h>
51#include <wx/utils.h>
52#include <wx/valgen.h>
53
54#include "AColor.h"
55#include "AllThemeResources.h"
57#include "Prefs.h"
58#include "Project.h"
59#include "../ShuttleGui.h"
60#include "Theme.h"
61#include "../WaveTrack.h"
62#include "../widgets/valnum.h"
63#include "../widgets/AudacityMessageBox.h"
64#include "../widgets/Ruler.h"
65#include "../widgets/WindowAccessible.h"
66
67#if !defined(M_PI)
68#define PI = 3.1415926535897932384626433832795
69#else
70#define PI M_PI
71#endif
72#define square(a) ((a)*(a))
73
74enum
75{
85};
86
88{
89 /*i18n-hint: Butterworth is the name of the person after whom the filter type is named.*/
90 { XO("Butterworth") },
91 /*i18n-hint: Chebyshev is the name of the person after whom the filter type is named.*/
92 { XO("Chebyshev Type I") },
93 /*i18n-hint: Chebyshev is the name of the person after whom the filter type is named.*/
94 { XO("Chebyshev Type II") }
95};
96
98{
99 // These are acceptable dual purpose internal/visible names
100 { XO("Lowpass") },
101 { XO("Highpass") }
102};
103
105{
108 > parameters{
110 bool updating){
111 if (updating) {
112 e.mOrderIndex = e.mOrder - 1;
113 e.CalcFilter();
114 }
115 return true;
116 },
117 };
118 return parameters;
119}
120
121//----------------------------------------------------------------------------
122// EffectScienFilter
123//----------------------------------------------------------------------------
124
126{ XO("Classic Filters") };
127
128#ifdef EXPERIMENTAL_SCIENCE_FILTERS
129// true argument means don't automatically enable this effect
131#endif
132
133BEGIN_EVENT_TABLE(EffectScienFilter, wxEvtHandler)
135
145
147{
148 Parameters().Reset(*this);
149 SetLinearEffectFlag(true);
150
151 mOrderIndex = mOrder - 1;
152
153 mdBMin = -30.0;
154 mdBMax = 30.0;
155
156 mLoFreq = 20; // Lowest frequency to display in response graph
157 mNyquist = 44100.0 / 2.0; // only used during initialization, updated when effect is used
158}
159
161{
162}
163
164// ComponentInterface implementation
165
167{
168 return Symbol;
169}
170
172{
173 /* i18n-hint: "infinite impulse response" */
174 return XO("Performs IIR filtering that emulates analog filters");
175}
176
178{
179 return L"Classic_Filters";
180}
181
182
183// EffectDefinitionInterface implementation
184
186{
187 return EffectTypeProcess;
188}
189
191{
192 return 1;
193}
194
196{
197 return 1;
198}
199
201 EffectSettings &, double, ChannelNames chanMap)
202{
203 for (int iPair = 0; iPair < (mOrder + 1) / 2; iPair++)
204 mpBiquad[iPair].Reset();
205 return true;
206}
207
209 const float *const *inBlock, float *const *outBlock, size_t blockLen)
210{
211 const float *ibuf = inBlock[0];
212 for (int iPair = 0; iPair < (mOrder + 1) / 2; iPair++)
213 {
214 mpBiquad[iPair].Process(ibuf, outBlock[0], blockLen);
215 ibuf = outBlock[0];
216 }
217
218 return blockLen;
219}
220
221// Effect implementation
222
224{
225 int selcount = 0;
226 double rate = 0.0;
227
228 auto trackRange = inputTracks()->Selected< const WaveTrack >();
229
230 {
231 auto t = *trackRange.begin();
232 mNyquist =
233 (t
234 ? t->GetRate()
235 : mProjectRate)
236 / 2.0;
237 }
238
239 for (auto t : trackRange)
240 {
241 if (selcount == 0)
242 {
243 rate = t->GetRate();
244 }
245 else
246 {
247 if (t->GetRate() != rate)
248 {
250 XO(
251"To apply a filter, all selected tracks must have the same sample rate.") );
252 return false;
253 }
254 }
255 selcount++;
256 }
257
258 return true;
259}
260
261std::unique_ptr<EffectUIValidator> EffectScienFilter::PopulateOrExchange(
263 const EffectOutputs *)
264{
265 S.AddSpace(5);
266 S.SetSizerProportion(1);
267 S.StartMultiColumn(3, wxEXPAND);
268 {
269 S.SetStretchyCol(1);
270 S.SetStretchyRow(0);
271
272 // -------------------------------------------------------------------
273 // ROW 1: Freq response panel and sliders for vertical scale
274 // -------------------------------------------------------------------
275
276 S.StartVerticalLay();
277 {
279 S.GetParent(), wxID_ANY, wxVERTICAL,
280 wxSize{ 100, 100 }, // Ruler can't handle small sizes
281 RulerPanel::Range{ 30.0, -120.0 },
283 XO("dB"),
285 .LabelEdges(true)
286 );
287
288 S.SetBorder(1);
289 S.AddSpace(1, 1);
290 S.Prop(1)
291 .Position(wxALIGN_RIGHT | wxTOP)
292 .AddWindow(mdBRuler);
293 S.AddSpace(1, 1);
294 }
295 S.EndVerticalLay();
296
298 S.GetParent(), wxID_ANY,
299 this, mLoFreq, mNyquist
300 );
301
302 S.SetBorder(5);
303 S.Prop(1)
304 .Position(wxEXPAND | wxRIGHT)
305 .MinSize( { -1, -1 } )
306 .AddWindow(mPanel);
307
308 S.StartVerticalLay();
309 {
310 S.AddVariableText(XO("+ dB"), false, wxCENTER);
312 .Name(XO("Max dB"))
313 .Style(wxSL_VERTICAL | wxSL_INVERSE)
314 .AddSlider( {}, 10, 20, 0);
315#if wxUSE_ACCESSIBILITY
316 mdBMaxSlider->SetAccessible(safenew SliderAx(mdBMaxSlider, XO("%d dB")));
317#endif
319 .Name(XO("Min dB"))
320 .Style(wxSL_VERTICAL | wxSL_INVERSE)
321 .AddSlider( {}, -10, -10, -120);
322#if wxUSE_ACCESSIBILITY
323 mdBMinSlider->SetAccessible(safenew SliderAx(mdBMinSlider, XO("%d dB")));
324#endif
325
326 S.AddVariableText(XO("- dB"), false, wxCENTER);
327 }
328 S.EndVerticalLay();
329
330 // -------------------------------------------------------------------
331 // ROW 2: Frequency ruler
332 // -------------------------------------------------------------------
333
334 S.AddSpace(1, 1);
335
337 S.GetParent(), wxID_ANY, wxHORIZONTAL,
338 wxSize{ 100, 100 }, // Ruler can't handle small sizes
339 RulerPanel::Range{ mLoFreq, mNyquist },
341 {},
343 .Log(true)
344 .Flip(true)
345 .LabelEdges(true)
346 );
347
348 S.Prop(1)
349 .Position(wxEXPAND | wxALIGN_LEFT | wxRIGHT)
350 .AddWindow(mfreqRuler);
351
352 S.AddSpace(1, 1);
353
354 // -------------------------------------------------------------------
355 // ROW 3 and 4: Type, Order, Ripple, Subtype, Cutoff
356 // -------------------------------------------------------------------
357
358 S.AddSpace(1, 1);
359 S.SetSizerProportion(0);
360 S.StartMultiColumn(8, wxALIGN_CENTER);
361 {
362 wxASSERT(nTypes == WXSIZEOF(kTypeStrings));
363
365 .Focus()
366 .Validator<wxGenericValidator>(&mFilterType)
367 .MinSize( { -1, -1 } )
368 .AddChoice(XXO("&Filter Type:"),
370 );
371
373 .Validator<wxGenericValidator>(&mOrderIndex)
374 .MinSize( { -1, -1 } )
375 /*i18n-hint: 'Order' means the complexity of the filter, and is a number between 1 and 10.*/
376 .AddChoice(XXO("O&rder:"),
377 []{
378 TranslatableStrings orders;
379 for (int i = 1; i <= 10; i++)
380 orders.emplace_back( Verbatim("%d").Format( i ) );
381 return orders;
382 }()
383 );
384 S.AddSpace(1, 1);
385
386 mRippleCtlP = S.AddVariableText( XO("&Passband Ripple:"),
387 false, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
389 .Name(XO("Passband Ripple (dB)"))
390 .Validator<FloatingPointValidator<float>>(
391 1, &mRipple, NumValidatorStyle::DEFAULT,
393 .AddTextBox( {}, L"", 10);
394 mRippleCtlU = S.AddVariableText(XO("dB"),
395 false, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
396
398 .Validator<wxGenericValidator>(&mFilterSubtype)
399 .MinSize( { -1, -1 } )
400 .AddChoice(XXO("&Subtype:"),
402 );
403
405 .Name(XO("Cutoff (Hz)"))
406 .Validator<FloatingPointValidator<float>>(
407 1, &mCutoff, NumValidatorStyle::DEFAULT,
408 Cutoff.min, mNyquist - 1)
409 .AddTextBox(XXO("C&utoff:"), L"", 10);
410 S.AddUnits(XO("Hz"));
411
413 S.AddVariableText(XO("Minimum S&topband Attenuation:"),
414 false, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
416 .Name(XO("Minimum S&topband Attenuation (dB)"))
417 .Validator<FloatingPointValidator<float>>(
418 1, &mStopbandRipple, NumValidatorStyle::DEFAULT,
420 .AddTextBox( {}, L"", 10);
422 S.AddVariableText(XO("dB"),
423 false, wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
424 }
425 S.EndMultiColumn();
426 S.AddSpace(1, 1);
427 }
428 S.EndMultiColumn();
429
430 return nullptr;
431}
432
433//
434// Populate the window with relevant variables
435//
437{
438 mOrderIndex = mOrder - 1;
439
440 if (!mUIParent->TransferDataToWindow())
441 {
442 return false;
443 }
444
445 mdBMinSlider->SetValue((int) mdBMin);
446 mdBMin = 0.0; // force refresh in TransferGraphLimitsFromWindow()
447
448 mdBMaxSlider->SetValue((int) mdBMax);
449 mdBMax = 0.0; // force refresh in TransferGraphLimitsFromWindow()
450
452
454}
455
457{
458 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
459 {
460 return false;
461 }
462
463 mOrder = mOrderIndex + 1;
464
465 CalcFilter();
466
467 return true;
468}
469
470// EffectScienFilter implementation
471
472//
473// Retrieve data from the window
474//
476{
477 // Read the sliders and send to the panel
478 wxString tip;
479
480 bool rr = false;
481 int dB = mdBMinSlider->GetValue();
482 if (dB != mdBMin) {
483 rr = true;
484 mdBMin = dB;
485 tip.Printf(_("%d dB"), (int)mdBMin);
486 mdBMinSlider->SetToolTip(tip);
487 }
488
489 dB = mdBMaxSlider->GetValue();
490 if (dB != mdBMax) {
491 rr = true;
492 mdBMax = dB;
493 tip.Printf(_("%d dB"),(int)mdBMax);
494 mdBMaxSlider->SetToolTip(tip);
495 }
496
497 if (rr) {
499 }
500
501 // Refresh ruler if values have changed
502 if (rr) {
503 int w1, w2, h;
504 mdBRuler->ruler.GetMaxSize(&w1, &h);
506 mdBRuler->ruler.GetMaxSize(&w2, &h);
507 if( w1 != w2 ) // Reduces flicker
508 {
509 mdBRuler->SetSize(wxSize(w2,h));
510 mUIParent->Layout();
511 mfreqRuler->Refresh(false);
512 }
513 mdBRuler->Refresh(false);
514 }
515
516 mPanel->Refresh(false);
517
518 return true;
519}
520
522{
523 switch (mFilterType)
524 {
525 case kButterworth:
527 break;
528 case kChebyshevTypeI:
530 break;
531 case kChebyshevTypeII:
533 break;
534 }
535}
536
538{
539 float Magn;
540 if (Freq >= mNyquist)
541 Freq = mNyquist - 1; // prevent tan(PI/2)
542 float FreqWarped = tan (PI * Freq/(2*mNyquist));
543 if (mCutoff >= mNyquist)
544 mCutoff = mNyquist - 1;
545 float CutoffWarped = tan (PI * mCutoff/(2*mNyquist));
546 float fOverflowThresh = pow (10.0, 12.0 / (2*mOrder)); // once we exceed 10^12 there's not much to be gained and overflow could happen
547
548 switch (mFilterType)
549 {
550 case kButterworth: // Butterworth
551 default:
552 switch (mFilterSubtype)
553 {
554 case kLowPass: // lowpass
555 default:
556 if (FreqWarped/CutoffWarped > fOverflowThresh) // prevent pow() overflow
557 Magn = 0;
558 else
559 Magn = sqrt (1 / (1 + pow (FreqWarped/CutoffWarped, 2*mOrder)));
560 break;
561 case kHighPass: // highpass
562 if (FreqWarped/CutoffWarped > fOverflowThresh)
563 Magn = 1;
564 else
565 Magn = sqrt (pow (FreqWarped/CutoffWarped, 2*mOrder) / (1 + pow (FreqWarped/CutoffWarped, 2*mOrder)));
566 break;
567 }
568 break;
569
570 case kChebyshevTypeI: // Chebyshev Type 1
571 double eps; eps = sqrt(pow (10.0, wxMax(0.001, mRipple)/10.0) - 1);
572 double chebyPolyVal;
573 switch (mFilterSubtype)
574 {
575 case 0: // lowpass
576 default:
577 chebyPolyVal = Biquad::ChebyPoly(mOrder, FreqWarped/CutoffWarped);
578 Magn = sqrt (1 / (1 + square(eps) * square(chebyPolyVal)));
579 break;
580 case 1:
581 chebyPolyVal = Biquad::ChebyPoly(mOrder, CutoffWarped/FreqWarped);
582 Magn = sqrt (1 / (1 + square(eps) * square(chebyPolyVal)));
583 break;
584 }
585 break;
586
587 case kChebyshevTypeII: // Chebyshev Type 2
588 eps = 1 / sqrt(pow (10.0, wxMax(0.001, mStopbandRipple)/10.0) - 1);
589 switch (mFilterSubtype)
590 {
591 case kLowPass: // lowpass
592 default:
593 chebyPolyVal = Biquad::ChebyPoly(mOrder, CutoffWarped/FreqWarped);
594 Magn = sqrt (1 / (1 + 1 / (square(eps) * square(chebyPolyVal))));
595 break;
596 case kHighPass:
597 chebyPolyVal = Biquad::ChebyPoly(mOrder, FreqWarped/CutoffWarped);
598 Magn = sqrt (1 / (1 + 1 / (square(eps) * square(chebyPolyVal))));
599 break;
600 }
601 break;
602 }
603
604 return Magn;
605}
606
607void EffectScienFilter::OnOrder(wxCommandEvent & WXUNUSED(evt))
608{
609 mOrderIndex = mFilterOrderCtl->GetSelection();
610 mOrder = mOrderIndex + 1; // 0..n-1 -> 1..n
611 mPanel->Refresh(false);
612}
613
614void EffectScienFilter::OnFilterType(wxCommandEvent & WXUNUSED(evt))
615{
616 mFilterType = mFilterTypeCtl->GetSelection();
618 mPanel->Refresh(false);
619}
620
621void EffectScienFilter::OnFilterSubtype(wxCommandEvent & WXUNUSED(evt))
622{
623 mFilterSubtype = mFilterSubTypeCtl->GetSelection();
624 mPanel->Refresh(false);
625}
626
627void EffectScienFilter::OnCutoff(wxCommandEvent & WXUNUSED(evt))
628{
629 if (!EnableApply(mUIParent->TransferDataFromWindow()))
630 {
631 return;
632 }
633
634 mPanel->Refresh(false);
635}
636
637void EffectScienFilter::OnRipple(wxCommandEvent & WXUNUSED(evt))
638{
639 if (!EnableApply(mUIParent->TransferDataFromWindow()))
640 {
641 return;
642 }
643
644 mPanel->Refresh(false);
645}
646
647void EffectScienFilter::OnStopbandRipple(wxCommandEvent & WXUNUSED(evt))
648{
649 if (!EnableApply(mUIParent->TransferDataFromWindow()))
650 {
651 return;
652 }
653
654 mPanel->Refresh(false);
655}
656
657void EffectScienFilter::OnSliderDBMIN(wxCommandEvent & WXUNUSED(evt))
658{
660}
661
662void EffectScienFilter::OnSliderDBMAX(wxCommandEvent & WXUNUSED(evt))
663{
665}
666
667void EffectScienFilter::OnSize(wxSizeEvent & evt)
668{
669 // On Windows the Passband and Stopband boxes do not refresh properly
670 // on a resize...no idea why.
671 mUIParent->Refresh();
672 evt.Skip();
673}
674
676{
677 bool ripple;
678 bool stop;
679
680 if (FilterType == kButterworth) // Butterworth
681 {
682 ripple = false;
683 stop = false;
684 }
685 else if (FilterType == kChebyshevTypeI) // Chebyshev Type1
686 {
687 ripple = true;
688 stop = false;
689 }
690 else // Chebyshev Type2
691 {
692 ripple = false;
693 stop = true;
694 }
695
696 mRippleCtlP->Enable(ripple);
697 mRippleCtl->Enable(ripple);
698 mRippleCtlU->Enable(ripple);
699 mStopbandRippleCtlP->Enable(stop);
700 mStopbandRippleCtl->Enable(stop);
701 mStopbandRippleCtlU->Enable(stop);
702}
703
704//----------------------------------------------------------------------------
705// EffectScienFilterPanel
706//----------------------------------------------------------------------------
707
708BEGIN_EVENT_TABLE(EffectScienFilterPanel, wxPanelWrapper)
712
714 wxWindow *parent, wxWindowID winid,
715 EffectScienFilter *effect, double lo, double hi)
716: wxPanelWrapper(parent, winid, wxDefaultPosition, wxSize(400, 200))
717{
718 mEffect = effect;
719 mParent = parent;
720
721 mBitmap = NULL;
722 mWidth = 0;
723 mHeight = 0;
724 mLoFreq = 0.0;
725 mHiFreq = 0.0;
726 mDbMin = 0.0;
727 mDbMax = 0.0;
728
729 SetFreqRange(lo, hi);
730}
731
733{
734}
735
736void EffectScienFilterPanel::SetFreqRange(double lo, double hi)
737{
738 mLoFreq = lo;
739 mHiFreq = hi;
740 Refresh(false);
741}
742
744{
745 mDbMin = min;
746 mDbMax = max;
747 Refresh(false);
748}
749
751{
752 return false;
753}
754
756{
757 return false;
758}
759
760void EffectScienFilterPanel::OnSize(wxSizeEvent & WXUNUSED(evt))
761{
762 Refresh(false);
763}
764
765void EffectScienFilterPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
766{
767 wxPaintDC dc(this);
768 int width, height;
769 GetSize(&width, &height);
770
771 if (!mBitmap || mWidth != width || mHeight != height)
772 {
773 mWidth = width;
774 mHeight = height;
775 mBitmap = std::make_unique<wxBitmap>(mWidth, mHeight,24);
776 }
777
778 wxBrush bkgndBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
779
780 wxMemoryDC memDC;
781 memDC.SelectObject(*mBitmap);
782
783 wxRect bkgndRect;
784 bkgndRect.x = 0;
785 bkgndRect.y = 0;
786 bkgndRect.width = mWidth;
787 bkgndRect.height = mHeight;
788 memDC.SetBrush(bkgndBrush);
789 memDC.SetPen(*wxTRANSPARENT_PEN);
790 memDC.DrawRectangle(bkgndRect);
791
792 bkgndRect.y = mHeight;
793 memDC.DrawRectangle(bkgndRect);
794
795 wxRect border;
796 border.x = 0;
797 border.y = 0;
798 border.width = mWidth;
799 border.height = mHeight;
800
801 memDC.SetBrush(*wxWHITE_BRUSH);
802 memDC.SetPen(*wxBLACK_PEN);
803 memDC.DrawRectangle(border);
804
805 mEnvRect = border;
806 mEnvRect.Deflate(2, 2);
807
808 // Pure blue x-axis line
809 memDC.SetPen(wxPen(theTheme.Colour(clrGraphLines), 1, wxPENSTYLE_SOLID));
810 int center = (int) (mEnvRect.height * mDbMax / (mDbMax - mDbMin) + 0.5);
811 AColor::Line(memDC,
812 mEnvRect.GetLeft(), mEnvRect.y + center,
813 mEnvRect.GetRight(), mEnvRect.y + center);
814
815 //Now draw the actual response that you will get.
816 //mFilterFunc has a linear scale, window has a log one so we have to fiddle about
817 memDC.SetPen(wxPen(theTheme.Colour(clrResponseLines), 3, wxPENSTYLE_SOLID));
818 double scale = (double) mEnvRect.height / (mDbMax - mDbMin); // pixels per dB
819 double yF; // gain at this freq
820
821 double loLog = log10(mLoFreq);
822 double step = log10(mHiFreq) - loLog;
823 step /= ((double) mEnvRect.width - 1.0);
824 double freq; // actual freq corresponding to x position
825 int x, y, xlast = 0, ylast = 0;
826 for (int i = 0; i < mEnvRect.width; i++)
827 {
828 x = mEnvRect.x + i;
829 freq = pow(10.0, loLog + i * step); //Hz
830 yF = mEffect->FilterMagnAtFreq (freq);
831 yF = LINEAR_TO_DB(yF);
832
833 if (yF < mDbMin)
834 {
835 yF = mDbMin;
836 }
837
838 yF = center-scale * yF;
839 if (yF > mEnvRect.height)
840 {
841 yF = (double) mEnvRect.height - 1.0;
842 }
843 if (yF < 0.0)
844 {
845 yF = 0.0;
846 }
847 y = (int) (yF + 0.5);
848
849 if (i != 0 && (y < mEnvRect.height - 1 || ylast < mEnvRect.y + mEnvRect.height - 1))
850 {
851 AColor::Line(memDC, xlast, ylast, x, mEnvRect.y + y);
852 }
853 xlast = x;
854 ylast = mEnvRect.y + y;
855 }
856
857 memDC.SetPen(*wxBLACK_PEN);
858 mEffect->mfreqRuler->ruler.DrawGrid(memDC, mEnvRect.height + 2, true, true, 0, 1);
859 mEffect->mdBRuler->ruler.DrawGrid(memDC, mEnvRect.width + 2, true, true, 1, 2);
860
861 dc.Blit(0, 0, mWidth, mHeight, &memDC, 0, 0, wxCOPY, FALSE);
862
863 memDC.SelectObject(wxNullBitmap);
864}
END_EVENT_TABLE()
int min(int a, int b)
EffectType
@ EffectTypeProcess
ChannelName
@ nTypes
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
#define LINEAR_TO_DB(x)
Definition: MemoryX.h:544
#define square(a)
Definition: ScienFilter.cpp:72
#define PI
Definition: ScienFilter.cpp:68
@ ID_Cutoff
Definition: ScienFilter.cpp:83
@ ID_SubType
Definition: ScienFilter.cpp:80
@ ID_dBMax
Definition: ScienFilter.cpp:77
@ ID_Ripple
Definition: ScienFilter.cpp:82
@ ID_StopbandRipple
Definition: ScienFilter.cpp:84
@ ID_Order
Definition: ScienFilter.cpp:81
@ ID_FilterPanel
Definition: ScienFilter.cpp:76
@ ID_Type
Definition: ScienFilter.cpp:79
@ ID_dBMin
Definition: ScienFilter.cpp:78
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
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:104
double mProjectRate
Definition: EffectBase.h:101
int MessageBox(const TranslatableString &message, long style=DefaultMessageBoxStyle, const TranslatableString &titleStr={}) const
Definition: Effect.cpp:863
bool EnableApply(bool enable=true)
Definition: Effect.cpp:612
wxWindow * mUIParent
Definition: Effect.h:307
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
An Effect that applies 'classical' IIR filters.
Definition: ScienFilter.h:36
void OnFilterSubtype(wxCommandEvent &evt)
EffectScienFilterPanel * mPanel
Definition: ScienFilter.h:109
TranslatableString GetDescription() const override
void OnSliderDBMAX(wxCommandEvent &evt)
static const EnumValueSymbol kSubTypeStrings[nSubTypes]
Definition: ScienFilter.h:141
wxStaticText * mRippleCtlU
Definition: ScienFilter.h:115
void OnStopbandRipple(wxCommandEvent &evt)
friend class EffectScienFilterPanel
Definition: ScienFilter.h:133
bool ProcessInitialize(EffectSettings &settings, double sampleRate, ChannelNames chanMap) override
void OnCutoff(wxCommandEvent &evt)
static const EnumValueSymbol kTypeStrings[nTypes]
Definition: ScienFilter.h:150
ArrayOf< Biquad > mpBiquad
Definition: ScienFilter.h:100
wxTextCtrl * mRippleCtl
Definition: ScienFilter.h:114
void EnableDisableRippleCtl(int FilterType)
wxChoice * mFilterSubTypeCtl
Definition: ScienFilter.h:124
virtual ~EffectScienFilter()
static constexpr EffectParameter Stopband
Definition: ScienFilter.h:164
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
static constexpr EffectParameter Cutoff
Definition: ScienFilter.h:160
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
static constexpr EnumParameter Subtype
Definition: ScienFilter.h:156
bool TransferDataFromWindow(EffectSettings &settings) override
Update the given settings from controls.
wxTextCtrl * mCutoffCtl
Definition: ScienFilter.h:117
wxSlider * mdBMaxSlider
Definition: ScienFilter.h:111
wxChoice * mFilterTypeCtl
Definition: ScienFilter.h:123
void OnFilterType(wxCommandEvent &evt)
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
wxChoice * mFilterOrderCtl
Definition: ScienFilter.h:125
wxStaticText * mStopbandRippleCtlP
Definition: ScienFilter.h:119
const EffectParameterMethods & Parameters() const override
static constexpr EnumParameter Type
Definition: ScienFilter.h:154
static constexpr EffectParameter Passband
Definition: ScienFilter.h:162
RulerPanel * mdBRuler
Definition: ScienFilter.h:127
EffectType GetType() const override
Type determines how it behaves.
static constexpr EffectParameter Order
Definition: ScienFilter.h:158
wxTextCtrl * mStopbandRippleCtl
Definition: ScienFilter.h:120
bool TransferGraphLimitsFromWindow()
static const ComponentInterfaceSymbol Symbol
Definition: ScienFilter.h:40
bool TransferDataToWindow(const EffectSettings &settings) override
Update controls for the settings.
void OnSliderDBMIN(wxCommandEvent &evt)
bool Init() override
Call once to set up state for whole list of tracks to be processed.
void OnOrder(wxCommandEvent &evt)
void OnRipple(wxCommandEvent &evt)
RulerPanel * mfreqRuler
Definition: ScienFilter.h:128
wxStaticText * mRippleCtlP
Definition: ScienFilter.h:113
float FilterMagnAtFreq(float Freq)
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
ComponentInterfaceSymbol GetSymbol() const override
wxStaticText * mStopbandRippleCtlU
Definition: ScienFilter.h:121
void OnSize(wxSizeEvent &evt)
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
wxSlider * mdBMinSlider
Definition: ScienFilter.h:110
EffectScienFilterPanel is used with EffectScienFilter and controls a graph for EffectScienFilter.
Definition: ScienFilter.h:169
void OnPaint(wxPaintEvent &evt)
void OnSize(wxSizeEvent &evt)
virtual ~EffectScienFilterPanel()
void SetDbRange(double min, double max)
bool AcceptsFocus() const
bool AcceptsFocusFromKeyboard() const
EffectScienFilter * mEffect
Definition: ScienFilter.h:189
std::unique_ptr< wxBitmap > mBitmap
Definition: ScienFilter.h:198
void SetFreqRange(double lo, double hi)
void DrawGrid(wxDC &dc, int length, bool minor=true, bool major=true, int xOffset=0, int yOffset=0) const
Definition: Ruler.cpp:1521
void GetMaxSize(wxCoord *width, wxCoord *height)
Definition: Ruler.cpp:1603
void SetRange(double min, double max)
Definition: Ruler.cpp:188
@ LinearDBFormat
Definition: Ruler.h:34
@ IntFormat
Definition: Ruler.h:30
RulerPanel class allows you to work with a Ruler like any other wxWindow.
Definition: Ruler.h:228
Ruler ruler
Definition: Ruler.h:288
std::pair< double, double > Range
Definition: Ruler.h:232
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
wxColour & Colour(int iIndex)
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1454
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
A Validator is an object which checks whether a wxVariant satisfies a certain criterion....
Definition: Validators.h:53
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
static ArrayOf< Biquad > CalcButterworthFilter(int order, double fn, double fc, int type)
Definition: Biquad.cpp:64
static ArrayOf< Biquad > CalcChebyshevType2Filter(int order, double fn, double fc, double ripple, int type)
Definition: Biquad.cpp:228
static double ChebyPoly(int Order, double NormFreq)
Definition: Biquad.cpp:329
static ArrayOf< Biquad > CalcChebyshevType1Filter(int order, double fn, double fc, double ripple, int type)
Definition: Biquad.cpp:146
const Type min
Minimum value.
Definition: Shuttle.h:30
const Type max
Maximum value.
Definition: Shuttle.h:31
Externalized state of a plug-in.
Options & LabelEdges(bool l)
Definition: Ruler.h:250
Options & Flip(bool f)
Definition: Ruler.h:247
Options & Log(bool l)
Definition: Ruler.h:244