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