Audacity 3.2.0
AutoDuck.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 AutoDuck.cpp
6
7 Markus Meyer
8
9*******************************************************************/
20#include "AutoDuck.h"
21#include "LoadEffects.h"
22
23#include <math.h>
24
25#include <wx/dcclient.h>
26#include <wx/dcmemory.h>
27#include <wx/intl.h>
28
29#include "AColor.h"
30#include "AllThemeResources.h"
31#include "Prefs.h"
32#include "../ShuttleGui.h"
33#include "Theme.h"
34#include "../widgets/valnum.h"
35
36#include "../WaveTrack.h"
37#include "../widgets/AudacityMessageBox.h"
38
40{
44 > parameters;
45 return parameters;
46}
47
48/*
49 * Common constants
50 */
51
52static const size_t kBufSize = 131072u; // number of samples to process at once
53static const size_t kRMSWindowSize = 100u; // samples in circular RMS window buffer
54
55/*
56 * A auto duck region and an array of auto duck regions
57 */
58
60{
61 AutoDuckRegion(double t0, double t1)
62 {
63 this->t0 = t0;
64 this->t1 = t1;
65 }
66
67 double t0;
68 double t1;
69};
70
71/*
72 * Effect implementation
73 */
74
76{ XO("Auto Duck") };
77
79
80BEGIN_EVENT_TABLE(EffectAutoDuck, wxEvtHandler)
81 EVT_TEXT(wxID_ANY, EffectAutoDuck::OnValueChanged)
83
85{
86 Parameters().Reset(*this);
87
88 SetLinearEffectFlag(true);
89
90 mControlTrack = NULL;
91
92 mPanel = NULL;
93}
94
96{
97}
98
99// ComponentInterface implementation
100
102{
103 return Symbol;
104}
105
107{
108 return XO("Reduces (ducks) the volume of one or more tracks whenever the volume of a specified \"control\" track reaches a particular level");
109}
110
112{
113 return L"Auto_Duck";
114}
115
116// EffectDefinitionInterface implementation
117
119{
120 return EffectTypeProcess;
121}
122
123// Effect implementation
124
126{
127 mControlTrack = NULL;
128
129 bool lastWasSelectedWaveTrack = false;
130 const WaveTrack *controlTrackCandidate = NULL;
131
132 for (auto t : inputTracks()->Any())
133 {
134 if (lastWasSelectedWaveTrack && !t->GetSelected()) {
135 // This could be the control track, so remember it
136 controlTrackCandidate = track_cast<const WaveTrack *>(t);
137 }
138
139 lastWasSelectedWaveTrack = false;
140
141 if (t->GetSelected()) {
142 bool ok = t->TypeSwitch<bool>(
143 [&](const WaveTrack *) {
144 lastWasSelectedWaveTrack = true;
145 return true;
146 },
147 [&](const Track *) {
149 /* i18n-hint: Auto duck is the name of an effect that 'ducks' (reduces the volume)
150 * of the audio automatically when there is sound on another track. Not as
151 * in 'Donald-Duck'!*/
152 XO("You selected a track which does not contain audio. AutoDuck can only process audio tracks."),
153 wxICON_ERROR );
154 return false;
155 }
156 );
157 if (!ok)
158 return false;
159 }
160 }
161
162 if (!controlTrackCandidate)
163 {
165 /* i18n-hint: Auto duck is the name of an effect that 'ducks' (reduces the volume)
166 * of the audio automatically when there is sound on another track. Not as
167 * in 'Donald-Duck'!*/
168 XO("Auto Duck needs a control track which must be placed below the selected track(s)."),
169 wxICON_ERROR );
170 return false;
171 }
172
173 mControlTrack = controlTrackCandidate;
174
175 return true;
176}
177
179{
180 if (GetNumWaveTracks() == 0 || !mControlTrack)
181 return false;
182
183 bool cancel = false;
184
185 auto start =
187 auto end =
189
190 if (end <= start)
191 return false;
192
193 // the minimum number of samples we have to wait until the maximum
194 // pause has been exceeded
195 double maxPause = mMaximumPause;
196
197 // We don't fade in until we have time enough to actually fade out again
198 if (maxPause < mOuterFadeDownLen + mOuterFadeUpLen)
200
201 auto minSamplesPause =
203
204 double threshold = DB_TO_LINEAR(mThresholdDb);
205
206 // adjust the threshold so we can compare it to the rmsSum value
207 threshold = threshold * threshold * kRMSWindowSize;
208
209 int rmsPos = 0;
210 double rmsSum = 0;
211 // to make the progress bar appear more natural, we first look for all
212 // duck regions and apply them all at once afterwards
213 std::vector<AutoDuckRegion> regions;
214 bool inDuckRegion = false;
215 {
216 Floats rmsWindow{ kRMSWindowSize, true };
217
218 Floats buf{ kBufSize };
219
220 // initialize the following two variables to prevent compiler warning
221 double duckRegionStart = 0;
222 sampleCount curSamplesPause = 0;
223
224 auto pos = start;
225
226 while (pos < end)
227 {
228 const auto len = limitSampleBufferSize( kBufSize, end - pos );
229
230 mControlTrack->GetFloats(buf.get(), pos, len);
231
232 for (auto i = pos; i < pos + len; i++)
233 {
234 rmsSum -= rmsWindow[rmsPos];
235 // i - pos is bounded by len:
236 auto index = ( i - pos ).as_size_t();
237 rmsWindow[rmsPos] = buf[ index ] * buf[ index ];
238 rmsSum += rmsWindow[rmsPos];
239 rmsPos = (rmsPos + 1) % kRMSWindowSize;
240
241 bool thresholdExceeded = rmsSum > threshold;
242
243 if (thresholdExceeded)
244 {
245 // everytime the threshold is exceeded, reset our count for
246 // the number of pause samples
247 curSamplesPause = 0;
248
249 if (!inDuckRegion)
250 {
251 // the threshold has been exceeded for the first time, so
252 // let the duck region begin here
253 inDuckRegion = true;
254 duckRegionStart = mControlTrack->LongSamplesToTime(i);
255 }
256 }
257
258 if (!thresholdExceeded && inDuckRegion)
259 {
260 // the threshold has not been exceeded and we are in a duck
261 // region, but only fade in if the maximum pause has been
262 // exceeded
263 curSamplesPause += 1;
264
265 if (curSamplesPause >= minSamplesPause)
266 {
267 // do the actual duck fade and reset all values
268 double duckRegionEnd =
269 mControlTrack->LongSamplesToTime(i - curSamplesPause);
270
271 regions.push_back(AutoDuckRegion(
272 duckRegionStart - mOuterFadeDownLen,
273 duckRegionEnd + mOuterFadeUpLen));
274
275 inDuckRegion = false;
276 }
277 }
278 }
279
280 pos += len;
281
282 if (TotalProgress(
283 (pos - start).as_double() /
284 (end - start).as_double() /
285 (GetNumWaveTracks() + 1)
286 ))
287 {
288 cancel = true;
289 break;
290 }
291 }
292
293 // apply last duck fade, if any
294 if (inDuckRegion)
295 {
296 double duckRegionEnd =
297 mControlTrack->LongSamplesToTime(end - curSamplesPause);
298 regions.push_back(AutoDuckRegion(
299 duckRegionStart - mOuterFadeDownLen,
300 duckRegionEnd + mOuterFadeUpLen));
301 }
302 }
303
304 if (!cancel)
305 {
306 CopyInputTracks(); // Set up mOutputTracks.
307
308 int trackNum = 0;
309
310 for( auto iterTrack : mOutputTracks->Selected< WaveTrack >() )
311 {
312 for (size_t i = 0; i < regions.size(); i++)
313 {
314 const AutoDuckRegion& region = regions[i];
315 if (ApplyDuckFade(trackNum, iterTrack, region.t0, region.t1))
316 {
317 cancel = true;
318 break;
319 }
320 }
321
322 if (cancel)
323 break;
324
325 trackNum++;
326 }
327 }
328
329 ReplaceProcessedTracks(!cancel);
330 return !cancel;
331}
332
333std::unique_ptr<EffectUIValidator> EffectAutoDuck::PopulateOrExchange(
335 const EffectOutputs *)
336{
337 S.SetBorder(5);
338 S.StartVerticalLay(true);
339 {
340 S.AddSpace(0, 5);
341
342 mPanel = safenew EffectAutoDuck::Panel(S.GetParent(), wxID_ANY, this);
343 S.AddWindow(mPanel);
344
345 S.AddSpace(0, 5);
346
347 S.StartMultiColumn(6, wxCENTER);
348 {
349 mDuckAmountDbBox = S.Validator<FloatingPointValidator<double>>(
350 1, &mDuckAmountDb, NumValidatorStyle::NO_TRAILING_ZEROES,
352 .NameSuffix(XO("db"))
353 .AddTextBox(XXO("Duck &amount:"), wxT(""), 10);
354 S.AddUnits(XO("dB"));
355
356 mMaximumPauseBox = S.Validator<FloatingPointValidator<double>>(
357 2, &mMaximumPause, NumValidatorStyle::NO_TRAILING_ZEROES,
359 .NameSuffix(XO("seconds"))
360 .AddTextBox(XXO("Ma&ximum pause:"), wxT(""), 10);
361 S.AddUnits(XO("seconds"));
362
363 mOuterFadeDownLenBox = S.Validator<FloatingPointValidator<double>>(
364 2, &mOuterFadeDownLen, NumValidatorStyle::NO_TRAILING_ZEROES,
366 .NameSuffix(XO("seconds"))
367 .AddTextBox(XXO("Outer fade &down length:"), wxT(""), 10);
368 S.AddUnits(XO("seconds"));
369
370 mOuterFadeUpLenBox = S.Validator<FloatingPointValidator<double>>(
371 2, &mOuterFadeUpLen, NumValidatorStyle::NO_TRAILING_ZEROES,
373 .NameSuffix(XO("seconds"))
374 .AddTextBox(XXO("Outer fade &up length:"), wxT(""), 10);
375 S.AddUnits(XO("seconds"));
376
377 mInnerFadeDownLenBox = S.Validator<FloatingPointValidator<double>>(
378 2, &mInnerFadeDownLen, NumValidatorStyle::NO_TRAILING_ZEROES,
380 .NameSuffix(XO("seconds"))
381 .AddTextBox(XXO("Inner fade d&own length:"), wxT(""), 10);
382 S.AddUnits(XO("seconds"));
383
384 mInnerFadeUpLenBox = S.Validator<FloatingPointValidator<double>>(
385 2, &mInnerFadeUpLen, NumValidatorStyle::NO_TRAILING_ZEROES,
387 .NameSuffix(XO("seconds"))
388 .AddTextBox(XXO("Inner &fade up length:"), wxT(""), 10);
389 S.AddUnits(XO("seconds"));
390 }
391 S.EndMultiColumn();
392
393 S.StartMultiColumn(3, wxCENTER);
394 {
395 mThresholdDbBox = S.Validator<FloatingPointValidator<double>>(
396 2, &mThresholdDb, NumValidatorStyle::NO_TRAILING_ZEROES,
398 .NameSuffix(XO("db"))
399 .AddTextBox(XXO("&Threshold:"), wxT(""), 10);
400 S.AddUnits(XO("dB"));
401 }
402 S.EndMultiColumn();
403
404 }
405 S.EndVerticalLay();
406
407 return nullptr;
408}
409
411{
412 return DoTransferDataToWindow();
413}
414
416{
417 // Issue 2324: don't remove these two lines
418 if (!mUIParent->TransferDataToWindow())
419 return false;
420
421 mPanel->Refresh(false);
422
423 return true;
424}
425
427{
428 if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
429 {
430 return false;
431 }
432
433 return true;
434}
435
436// EffectAutoDuck implementation
437
438// this currently does an exponential fade
440 double t0, double t1)
441{
442 bool cancel = false;
443
444 auto start = t->TimeToLongSamples(t0);
445 auto end = t->TimeToLongSamples(t1);
446
447 Floats buf{ kBufSize };
448 auto pos = start;
449
450 auto fadeDownSamples = t->TimeToLongSamples(
452 if (fadeDownSamples < 1)
453 fadeDownSamples = 1;
454
455 auto fadeUpSamples = t->TimeToLongSamples(
457 if (fadeUpSamples < 1)
458 fadeUpSamples = 1;
459
460 float fadeDownStep = mDuckAmountDb / fadeDownSamples.as_double();
461 float fadeUpStep = mDuckAmountDb / fadeUpSamples.as_double();
462
463 while (pos < end)
464 {
465 const auto len = limitSampleBufferSize( kBufSize, end - pos );
466
467 t->GetFloats(buf.get(), pos, len);
468
469 for (auto i = pos; i < pos + len; i++)
470 {
471 float gainDown = fadeDownStep * (i - start).as_float();
472 float gainUp = fadeUpStep * (end - i).as_float();
473
474 float gain;
475 if (gainDown > gainUp)
476 gain = gainDown;
477 else
478 gain = gainUp;
479 if (gain < mDuckAmountDb)
480 gain = mDuckAmountDb;
481
482 // i - pos is bounded by len:
483 buf[ ( i - pos ).as_size_t() ] *= DB_TO_LINEAR(gain);
484 }
485
486 t->Set((samplePtr)buf.get(), floatSample, pos, len);
487
488 pos += len;
489
490 float curTime = t->LongSamplesToTime(pos);
491 float fractionFinished = (curTime - mT0) / (mT1 - mT0);
492 if (TotalProgress( (trackNum + 1 + fractionFinished) /
493 (GetNumWaveTracks() + 1) ))
494 {
495 cancel = true;
496 break;
497 }
498 }
499
500 return cancel;
501}
502
503void EffectAutoDuck::OnValueChanged(wxCommandEvent & WXUNUSED(evt))
504{
505 mPanel->Refresh(false);
506}
507
508/*
509 * EffectAutoDuck::Panel implementation
510 */
511
512#define CONTROL_POINT_REGION 10 // pixel distance to click on a control point
513#define CONTROL_POINT_MIN_MOVE 5 // min mouse move until value is changed
514
515#define TEXT_DISTANCE 15 // pixel distance text <-> center of control point
516
517#define FADE_DOWN_START 150 // x coordinate
518#define FADE_UP_START 450 // x coordinate
519#define DUCK_AMOUNT_START 50 // y coordinate
520
521#define FADE_SCALE 40 // scale factor for second -> pixel conversion
522#define DUCK_AMOUNT_SCALE 8 // scale factor for db -> pixel conversion
523
524static int GetDistance(const wxPoint& first, const wxPoint& second)
525{
526 int distanceX = abs(first.x - second.x);
527 int distanceY = abs(first.y - second.y);
528 if (distanceX > distanceY)
529 return distanceX;
530 else
531 return distanceY;
532}
533
534BEGIN_EVENT_TABLE(EffectAutoDuck::Panel, wxPanelWrapper)
536 EVT_MOUSE_CAPTURE_CHANGED(EffectAutoDuck::Panel::OnMouseCaptureChanged)
537 EVT_MOUSE_CAPTURE_LOST(EffectAutoDuck::Panel::OnMouseCaptureLost)
542
544 wxWindow *parent, wxWindowID winid, EffectAutoDuck *effect)
545: wxPanelWrapper(parent, winid, wxDefaultPosition, wxSize(600, 300))
546{
547 mParent = parent;
548 mEffect = effect;
549 mCurrentControlPoint = none;
550 mBackgroundBitmap = NULL;
551
552 ResetControlPoints();
553}
554
556{
557 if(HasCapture())
558 ReleaseMouse();
559}
560
562{
563 mControlPoints[innerFadeDown] = wxPoint(-100,-100);
564 mControlPoints[innerFadeUp] = wxPoint(-100,-100);
565 mControlPoints[outerFadeDown] = wxPoint(-100,-100);
566 mControlPoints[outerFadeUp] = wxPoint(-100,-100);
567 mControlPoints[duckAmount] = wxPoint(-100,-100);
568}
569
570void EffectAutoDuck::Panel::OnPaint(wxPaintEvent & WXUNUSED(evt))
571{
572 int clientWidth, clientHeight;
573 GetSize(&clientWidth, &clientHeight);
574
575 if (!mBackgroundBitmap || mBackgroundBitmap->GetWidth() != clientWidth ||
576 mBackgroundBitmap->GetHeight() != clientHeight)
577 {
578 mBackgroundBitmap = std::make_unique<wxBitmap>(clientWidth, clientHeight,24);
579 }
580
581 wxMemoryDC dc;
582 dc.SelectObject(*mBackgroundBitmap);
583
584 dc.SetBrush(*wxWHITE_BRUSH);
585 dc.SetPen(*wxBLACK_PEN);
586 dc.DrawRectangle(0, 0, clientWidth, clientHeight);
587
588 dc.SetFont(wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
589 wxFONTWEIGHT_NORMAL));
590 dc.SetTextForeground(*wxBLACK);
591 dc.SetTextBackground(*wxWHITE);
592
593 double duckAmountDb = 0;
594 double innerFadeDownLen = 0;
595 double innerFadeUpLen = 0;
596 double outerFadeDownLen = 0;
597 double outerFadeUpLen = 0;
598 mEffect->mDuckAmountDbBox->GetValue().ToDouble(&duckAmountDb);
599 mEffect->mInnerFadeDownLenBox->GetValue().ToDouble(&innerFadeDownLen);
600 mEffect->mInnerFadeUpLenBox->GetValue().ToDouble(&innerFadeUpLen);
601 mEffect->mOuterFadeDownLenBox->GetValue().ToDouble(&outerFadeDownLen);
602 mEffect->mOuterFadeUpLenBox->GetValue().ToDouble(&outerFadeUpLen);
603
604 if (innerFadeDownLen < InnerFadeDownLen.min || innerFadeDownLen > InnerFadeDownLen.max ||
605 innerFadeUpLen < InnerFadeUpLen.min || innerFadeUpLen > InnerFadeUpLen.max ||
606 outerFadeDownLen < OuterFadeDownLen.min || outerFadeDownLen > OuterFadeDownLen.max ||
607 outerFadeUpLen < OuterFadeUpLen.min || outerFadeUpLen > OuterFadeUpLen.max ||
608 duckAmountDb < DuckAmountDb.min || duckAmountDb > DuckAmountDb.max)
609 {
610 // values are out of range, no preview available
611 wxString message = _("Preview not available");
612 int textWidth = 0, textHeight = 0;
613 dc.GetTextExtent(message, &textWidth, &textHeight);
614 dc.DrawText(message, (clientWidth - textWidth) / 2,
615 (clientHeight - textHeight) / 2);
616
617 ResetControlPoints();
618 } else
619 {
620 // draw preview
621 dc.SetBrush(*wxTRANSPARENT_BRUSH);
622 dc.SetPen(wxPen(theTheme.Colour(clrGraphLines), 3, wxPENSTYLE_SOLID));
623
624 wxPoint points[6];
625
626 points[0].x = 10;
627 points[0].y = DUCK_AMOUNT_START;
628
629 points[1].x = FADE_DOWN_START - (int)(outerFadeDownLen * FADE_SCALE);
630 points[1].y = DUCK_AMOUNT_START;
631
632 points[2].x = FADE_DOWN_START + (int)(innerFadeDownLen * FADE_SCALE);
633 points[2].y = DUCK_AMOUNT_START -
634 (int)(duckAmountDb * DUCK_AMOUNT_SCALE);
635
636 points[3].x = FADE_UP_START - (int)(innerFadeUpLen * FADE_SCALE);
637 points[3].y = DUCK_AMOUNT_START -
638 (int)(duckAmountDb * DUCK_AMOUNT_SCALE);
639
640 points[4].x = FADE_UP_START + (int)(outerFadeUpLen * FADE_SCALE);
641 points[4].y = DUCK_AMOUNT_START;
642
643 points[5].x = clientWidth - 10;
644 points[5].y = DUCK_AMOUNT_START;
645
646 AColor::Lines(dc, 6, points);
647
648 dc.SetPen(wxPen(*wxBLACK, 1, wxPENSTYLE_DOT));
649
650 AColor::Line(dc, FADE_DOWN_START, 10, FADE_DOWN_START, clientHeight - 10);
651 AColor::Line(dc, FADE_UP_START, 10, FADE_UP_START, clientHeight - 10);
652
653 dc.SetPen(AColor::envelopePen);
654 dc.SetBrush(*wxWHITE_BRUSH);
655
656 mControlPoints[outerFadeDown] = points[1];
657 mControlPoints[innerFadeDown] = points[2];
658 mControlPoints[innerFadeUp] = points[3];
659 mControlPoints[outerFadeUp] = points[4];
660 mControlPoints[duckAmount] = wxPoint(
661 (points[2].x + points[3].x) / 2, points[2].y);
662
663 for (int i = 0; i < AUTO_DUCK_PANEL_NUM_CONTROL_POINTS; i++)
664 {
666 int digits;
667 float value;
668
669 if (cp == innerFadeDown)
670 {
671 value = innerFadeDownLen;
672 digits = 2;
673 }
674 else if (cp == innerFadeUp)
675 {
676 value = innerFadeUpLen;
677 digits = 2;
678 }
679 else if (cp == outerFadeDown)
680 {
681 value = outerFadeDownLen;
682 digits = 2;
683 } else if (cp == outerFadeUp)
684 {
685 value = outerFadeUpLen;
686 digits = 2;
687 }
688 else
689 {
690 value = duckAmountDb;
691 digits = 1;
692 }
693
694 wxString valueStr = Internat::ToDisplayString(value, digits);
695 valueStr += wxT(" ");
696
697 if (cp == duckAmount)
698 /* i18n-hint: short form of 'decibels'.*/
699 valueStr += _("dB");
700 else
701 /* i18n-hint: short form of 'seconds'.*/
702 valueStr += _("s");
703
704 int textWidth = 0, textHeight = 0;
705 GetTextExtent(valueStr, &textWidth, &textHeight);
706
707 int textPosX = mControlPoints[i].x - textWidth / 2;
708 int textPosY = mControlPoints[i].y;
709
710 if (cp == duckAmount || cp == outerFadeDown || cp == outerFadeUp)
711 textPosY -= TEXT_DISTANCE + textHeight;
712 else
713 textPosY += TEXT_DISTANCE;
714
715 dc.DrawText(valueStr, textPosX, textPosY);
716
717 dc.DrawEllipse(mControlPoints[i].x - 3,
718 mControlPoints[i].y - 3, 6, 6);
719 }
720 }
721
722 // copy background buffer to paint dc
723 wxPaintDC paintDC(this);
724 paintDC.Blit(0, 0, clientWidth, clientHeight, &dc, 0, 0);
725
726 // clean up: necessary to free resources on Windows
727 dc.SetPen(wxNullPen);
728 dc.SetBrush(wxNullBrush);
729 dc.SetFont(wxNullFont);
730 dc.SelectObject(wxNullBitmap);
731}
732
734 wxMouseCaptureChangedEvent & WXUNUSED(evt))
735{
736 SetCursor(wxNullCursor);
737 mCurrentControlPoint = none;
738}
739
741 wxMouseCaptureLostEvent & WXUNUSED(evt))
742{
743 mCurrentControlPoint = none;
744
745 if (HasCapture())
746 {
747 ReleaseMouse();
748 }
749}
750
753{
755 int i;
756
757 for (i = 0; i < AUTO_DUCK_PANEL_NUM_CONTROL_POINTS; i++)
758 dist[i] = GetDistance(pt, mControlPoints[i]);
759
760 int curMinimum = 0;
761 for (i = 0; i < AUTO_DUCK_PANEL_NUM_CONTROL_POINTS; i++)
762 if (dist[i] < dist[curMinimum])
763 curMinimum = i;
764
765 if (dist[curMinimum] <= CONTROL_POINT_REGION)
766 return (EControlPoint)curMinimum;
767 else
768 return none;
769}
770
771void EffectAutoDuck::Panel::OnLeftDown(wxMouseEvent & evt)
772{
773 EControlPoint nearest = GetNearestControlPoint(evt.GetPosition());
774
775 if (nearest != none)
776 {
777 // this control point has been clicked
778 mMouseDownPoint = evt.GetPosition();
779
780 mCurrentControlPoint = nearest;
781 mControlPointMoveActivated = false;
782
783 for (int i = 0; i < AUTO_DUCK_PANEL_NUM_CONTROL_POINTS; i++)
784 mMoveStartControlPoints[i] = mControlPoints[i];
785
786 if( !HasCapture() )
787 CaptureMouse();
788 }
789}
790
791void EffectAutoDuck::Panel::OnLeftUp(wxMouseEvent & WXUNUSED(evt))
792{
793 if (mCurrentControlPoint != none)
794 {
795 mCurrentControlPoint = none;
796 ReleaseMouse();
797 }
798}
799
800void EffectAutoDuck::Panel::OnMotion(wxMouseEvent & evt)
801{
802 switch (GetNearestControlPoint(evt.GetPosition()))
803 {
804 case none:
805 SetCursor(wxNullCursor);
806 break;
807 case innerFadeDown:
808 case innerFadeUp:
809 case outerFadeDown:
810 case outerFadeUp:
811 SetCursor(wxCursor(wxCURSOR_SIZEWE));
812 break;
813 case duckAmount:
814 SetCursor(wxCursor(wxCURSOR_SIZENS));
815 break;
816 }
817
818 if (mCurrentControlPoint != none)
819 {
820 if (!mControlPointMoveActivated)
821 {
822 int dist;
823
824 if (mCurrentControlPoint == duckAmount)
825 dist = abs(evt.GetY() - mMouseDownPoint.y);
826 else
827 dist = abs(evt.GetX() - mMouseDownPoint.x);
828
829 if (dist >= CONTROL_POINT_MIN_MOVE)
830 mControlPointMoveActivated = true;
831 }
832
833 if (mControlPointMoveActivated)
834 {
835 float newValue;
836
837 switch (mCurrentControlPoint)
838 {
839 case outerFadeDown:
840 newValue = ((double)(FADE_DOWN_START - evt.GetX())) / FADE_SCALE;
841 mEffect->mOuterFadeDownLen = std::clamp<double>(newValue, OuterFadeDownLen.min, OuterFadeDownLen.max);
842 break;
843 case outerFadeUp:
844 newValue = ((double)(evt.GetX() - FADE_UP_START)) / FADE_SCALE;
845 mEffect->mOuterFadeUpLen = std::clamp<double>(newValue, OuterFadeUpLen.min, OuterFadeUpLen.max);
846 break;
847 case innerFadeDown:
848 newValue = ((double)(evt.GetX() - FADE_DOWN_START)) / FADE_SCALE;
849 mEffect->mInnerFadeDownLen = std::clamp<double>(newValue, InnerFadeDownLen.min, InnerFadeDownLen.max);
850 break;
851 case innerFadeUp:
852 newValue = ((double)(FADE_UP_START - evt.GetX())) / FADE_SCALE;
853 mEffect->mInnerFadeUpLen = std::clamp<double>(newValue, InnerFadeUpLen.min, InnerFadeUpLen.max);
854 break;
855 case duckAmount:
856 newValue = ((double)(DUCK_AMOUNT_START - evt.GetY())) / DUCK_AMOUNT_SCALE;
857 mEffect->mDuckAmountDb = std::clamp<double>(newValue, DuckAmountDb.min, DuckAmountDb.max);
858 break;
859 case none:
860 wxASSERT(false); // should not happen
861 }
862 mEffect->DoTransferDataToWindow();
863 Refresh(false);
864 }
865 }
866}
wxT("CloseDown"))
static const size_t kBufSize
Definition: AutoDuck.cpp:52
#define FADE_DOWN_START
Definition: AutoDuck.cpp:517
#define FADE_UP_START
Definition: AutoDuck.cpp:518
#define FADE_SCALE
Definition: AutoDuck.cpp:521
#define CONTROL_POINT_REGION
Definition: AutoDuck.cpp:512
static const size_t kRMSWindowSize
Definition: AutoDuck.cpp:53
static int GetDistance(const wxPoint &first, const wxPoint &second)
Definition: AutoDuck.cpp:524
#define DUCK_AMOUNT_SCALE
Definition: AutoDuck.cpp:522
#define DUCK_AMOUNT_START
Definition: AutoDuck.cpp:519
#define TEXT_DISTANCE
Definition: AutoDuck.cpp:515
#define CONTROL_POINT_MIN_MOVE
Definition: AutoDuck.cpp:513
#define AUTO_DUCK_PANEL_NUM_CONTROL_POINTS
Definition: AutoDuck.h:23
END_EVENT_TABLE()
@ none
Definition: Dither.h:20
EffectType
@ EffectTypeProcess
#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 DB_TO_LINEAR(x)
Definition: MemoryX.h:543
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:22
@ floatSample
Definition: SampleFormat.h:34
char * samplePtr
Definition: SampleFormat.h:49
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static void Lines(wxDC &dc, size_t nPoints, const wxPoint points[])
Definition: AColor.cpp:194
static wxPen envelopePen
Definition: AColor.h:115
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
EControlPoint GetNearestControlPoint(const wxPoint &pt)
Definition: AutoDuck.cpp:752
void OnMotion(wxMouseEvent &evt)
Definition: AutoDuck.cpp:800
void OnLeftDown(wxMouseEvent &evt)
Definition: AutoDuck.cpp:771
void OnMouseCaptureChanged(wxMouseCaptureChangedEvent &evt)
Definition: AutoDuck.cpp:733
void OnLeftUp(wxMouseEvent &evt)
Definition: AutoDuck.cpp:791
void OnPaint(wxPaintEvent &evt)
Definition: AutoDuck.cpp:570
void OnMouseCaptureLost(wxMouseCaptureLostEvent &evt)
Definition: AutoDuck.cpp:740
Implements the Auto Ducking effect.
Definition: AutoDuck.h:26
static constexpr EffectParameter InnerFadeDownLen
Definition: AutoDuck.h:90
double mInnerFadeDownLen
Definition: AutoDuck.h:65
wxTextCtrl * mInnerFadeUpLenBox
Definition: AutoDuck.h:76
ComponentInterfaceSymbol GetSymbol() const override
Definition: AutoDuck.cpp:101
static constexpr EffectParameter InnerFadeUpLen
Definition: AutoDuck.h:92
wxTextCtrl * mInnerFadeDownLenBox
Definition: AutoDuck.h:75
static constexpr EffectParameter OuterFadeDownLen
Definition: AutoDuck.h:94
Panel * mPanel
Definition: AutoDuck.h:82
wxTextCtrl * mOuterFadeDownLenBox
Definition: AutoDuck.h:77
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
Definition: AutoDuck.cpp:333
bool Init() override
Call once to set up state for whole list of tracks to be processed.
Definition: AutoDuck.cpp:125
const WaveTrack * mControlTrack
Definition: AutoDuck.h:72
double mThresholdDb
Definition: AutoDuck.h:69
bool ApplyDuckFade(int trackNum, WaveTrack *t, double t0, double t1)
Definition: AutoDuck.cpp:439
static constexpr EffectParameter MaximumPause
Definition: AutoDuck.h:100
bool DoTransferDataToWindow()
Definition: AutoDuck.cpp:415
wxTextCtrl * mThresholdDbBox
Definition: AutoDuck.h:79
static constexpr EffectParameter ThresholdDb
Definition: AutoDuck.h:98
double mMaximumPause
Definition: AutoDuck.h:70
double mDuckAmountDb
Definition: AutoDuck.h:64
const EffectParameterMethods & Parameters() const override
Definition: AutoDuck.cpp:39
double mInnerFadeUpLen
Definition: AutoDuck.h:66
bool TransferDataToWindow(const EffectSettings &settings) override
Update controls for the settings.
Definition: AutoDuck.cpp:410
virtual ~EffectAutoDuck()
Definition: AutoDuck.cpp:95
void OnValueChanged(wxCommandEvent &evt)
Definition: AutoDuck.cpp:503
static constexpr EffectParameter DuckAmountDb
Definition: AutoDuck.h:88
EffectType GetType() const override
Type determines how it behaves.
Definition: AutoDuck.cpp:118
bool TransferDataFromWindow(EffectSettings &settings) override
Update the given settings from controls.
Definition: AutoDuck.cpp:426
double mOuterFadeDownLen
Definition: AutoDuck.h:67
static constexpr EffectParameter OuterFadeUpLen
Definition: AutoDuck.h:96
bool Process(EffectInstance &instance, EffectSettings &settings) override
Actually do the effect here.
Definition: AutoDuck.cpp:178
wxTextCtrl * mMaximumPauseBox
Definition: AutoDuck.h:80
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
Definition: AutoDuck.cpp:111
double mOuterFadeUpLen
Definition: AutoDuck.h:68
static const ComponentInterfaceSymbol Symbol
Definition: AutoDuck.h:30
TranslatableString GetDescription() const override
Definition: AutoDuck.cpp:106
wxTextCtrl * mOuterFadeUpLenBox
Definition: AutoDuck.h:78
wxTextCtrl * mDuckAmountDbBox
Definition: AutoDuck.h:74
double mT1
Definition: EffectBase.h:109
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:107
const TrackList * inputTracks() const
Definition: EffectBase.h:104
double mT0
Definition: EffectBase.h:108
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:240
void CopyInputTracks(bool allSyncLockSelected=false)
Definition: Effect.cpp:733
int MessageBox(const TranslatableString &message, long style=DefaultMessageBoxStyle, const TranslatableString &titleStr={}) const
Definition: Effect.cpp:863
wxWindow * mUIParent
Definition: Effect.h:307
bool TotalProgress(double frac, const TranslatableString &={}) const
Definition: Effect.cpp:675
int GetNumWaveTracks() const
Definition: Effect.h:224
Performs effect computation.
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
static wxString ToDisplayString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, uses the user's locale's decimal separator.
Definition: Internat.cpp:162
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in floating-point format, regardless of the storage format.
Definition: SampleTrack.h:67
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
Definition: SampleTrack.cpp:47
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: SampleTrack.cpp:42
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
wxColour & Colour(int iIndex)
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
void Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len)
Definition: WaveTrack.cpp:2205
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
BuiltinEffectsModule::Registration< EffectAutoDuck > reg
Definition: AutoDuck.cpp:78
a struct that holds a start and end time.
Definition: AutoDuck.cpp:60
AutoDuckRegion(double t0, double t1)
Definition: AutoDuck.cpp:61
const Type min
Minimum value.
Definition: Shuttle.h:30
const Type max
Maximum value.
Definition: Shuttle.h:31
Externalized state of a plug-in.