27#include <wx/dcclient.h>
28#include <wx/dcmemory.h>
35#include "../widgets/valnum.h"
89 Parameters().Reset(*
this);
90 SetLinearEffectFlag(
true);
106 return XO(
"Reduces (ducks) the volume of one or more tracks whenever the volume of a specified \"control\" track reaches a particular level");
130 bool lastWasSelectedWaveTrack =
false;
131 const WaveTrack *controlTrackCandidate =
nullptr;
133 if (lastWasSelectedWaveTrack && !t->GetSelected())
135 controlTrackCandidate =
dynamic_cast<const WaveTrack *
>(t);
137 lastWasSelectedWaveTrack =
false;
138 if (t->GetSelected()) {
141 lastWasSelectedWaveTrack =
true;
142 controlTrackCandidate =
nullptr;
150 XO(
"You selected a track which does not contain audio. "
151 "AutoDuck can only process audio tracks."),
161 if (!controlTrackCandidate) {
166 XO(
"Auto Duck needs a control track which must be placed below the "
167 "selected track(s)."),
196 auto &clips = pControlTrack->
GetClips();
197 const auto t0 = pControlTrack->LongSamplesToTime(start);
198 const auto t1 = pControlTrack->LongSamplesToTime(
end);
200 tempTracks = pControlTrack->Duplicate();
207 pFirstTrack->ApplyPitchAndSpeed(
208 { { t0, t1 } }, reportProgress);
211 XO(
"Rendering Control-Track Time-Stretched Audio"));
212 pControlTrack = pFirstTrack;
226 auto minSamplesPause =
227 pControlTrack->TimeToLongSamples(maxPause);
238 std::vector<AutoDuckRegion> regions;
239 bool inDuckRegion =
false;
246 double duckRegionStart = 0;
255 pControlTrack->GetFloats(buf.get(), pos, len);
257 for (
auto i = pos; i < pos + len; i++)
259 rmsSum -= rmsWindow[rmsPos];
261 auto index = ( i - pos ).as_size_t();
262 rmsWindow[rmsPos] = buf[ index ] * buf[ index ];
263 rmsSum += rmsWindow[rmsPos];
266 bool thresholdExceeded = rmsSum > threshold;
268 if (thresholdExceeded)
279 duckRegionStart = pControlTrack->LongSamplesToTime(i);
283 if (!thresholdExceeded && inDuckRegion)
288 curSamplesPause += 1;
290 if (curSamplesPause >= minSamplesPause)
293 double duckRegionEnd =
294 pControlTrack->LongSamplesToTime(i - curSamplesPause);
300 inDuckRegion =
false;
308 (pos - start).as_double() /
309 (
end - start).as_double() /
321 double duckRegionEnd =
322 pControlTrack->LongSamplesToTime(
end - curSamplesPause);
334 for (
auto iterTrack : outputs.Get().Selected<
WaveTrack>()) {
335 for (
const auto pChannel : iterTrack->Channels())
336 for (
size_t i = 0; i < regions.size(); ++i) {
362 S.StartVerticalLay(
true);
371 S.StartMultiColumn(6, wxCENTER);
376 .NameSuffix(
XO(
"db"))
377 .AddTextBox(
XXO(
"Duck &amount:"),
wxT(
""), 10);
378 S.AddUnits(
XO(
"dB"));
383 .NameSuffix(
XO(
"seconds"))
384 .AddTextBox(
XXO(
"Ma&ximum pause:"),
wxT(
""), 10);
385 S.AddUnits(
XO(
"seconds"));
390 .NameSuffix(
XO(
"seconds"))
391 .AddTextBox(
XXO(
"Outer fade &down length:"),
wxT(
""), 10);
392 S.AddUnits(
XO(
"seconds"));
397 .NameSuffix(
XO(
"seconds"))
398 .AddTextBox(
XXO(
"Outer fade &up length:"),
wxT(
""), 10);
399 S.AddUnits(
XO(
"seconds"));
404 .NameSuffix(
XO(
"seconds"))
405 .AddTextBox(
XXO(
"Inner fade d&own length:"),
wxT(
""), 10);
406 S.AddUnits(
XO(
"seconds"));
411 .NameSuffix(
XO(
"seconds"))
412 .AddTextBox(
XXO(
"Inner &fade up length:"),
wxT(
""), 10);
413 S.AddUnits(
XO(
"seconds"));
417 S.StartMultiColumn(3, wxCENTER);
420 2, &
mThresholdDb, NumValidatorStyle::NO_TRAILING_ZEROES,
422 .NameSuffix(
XO(
"db"))
423 .AddTextBox(
XXO(
"&Threshold:"),
wxT(
""), 10);
424 S.AddUnits(
XO(
"dB"));
464 double t0,
double t1)
476 if (fadeDownSamples < 1)
481 if (fadeUpSamples < 1)
484 float fadeDownStep =
mDuckAmountDb / fadeDownSamples.as_double();
485 float fadeUpStep =
mDuckAmountDb / fadeUpSamples.as_double();
490 for (
auto i = pos; i < pos + len; ++i) {
491 float gainDown = fadeDownStep * (i - start).as_float();
492 float gainUp = fadeUpStep * (
end - i).as_float();
495 if (gainDown > gainUp)
514 float fractionFinished = (curTime -
mT0) / (
mT1 -
mT0);
535#define CONTROL_POINT_REGION 10
536#define CONTROL_POINT_MIN_MOVE 5
538#define TEXT_DISTANCE 15
540#define FADE_DOWN_START 150
541#define FADE_UP_START 450
542#define DUCK_AMOUNT_START 50
545#define DUCK_AMOUNT_SCALE 8
547static int GetDistance(
const wxPoint& first,
const wxPoint& second)
549 int distanceX = abs(first.x - second.x);
550 int distanceY = abs(first.y - second.y);
551 if (distanceX > distanceY)
568:
wxPanelWrapper(parent, winid, wxDefaultPosition, wxSize(600, 300))
572 mCurrentControlPoint =
none;
573 mBackgroundBitmap = NULL;
575 ResetControlPoints();
586 mControlPoints[innerFadeDown] = wxPoint(-100,-100);
587 mControlPoints[innerFadeUp] = wxPoint(-100,-100);
588 mControlPoints[outerFadeDown] = wxPoint(-100,-100);
589 mControlPoints[outerFadeUp] = wxPoint(-100,-100);
590 mControlPoints[duckAmount] = wxPoint(-100,-100);
595 int clientWidth, clientHeight;
596 GetSize(&clientWidth, &clientHeight);
598 if (!mBackgroundBitmap || mBackgroundBitmap->GetWidth() != clientWidth ||
599 mBackgroundBitmap->GetHeight() != clientHeight)
601 mBackgroundBitmap = std::make_unique<wxBitmap>(clientWidth, clientHeight,24);
605 dc.SelectObject(*mBackgroundBitmap);
607 dc.SetBrush(*wxWHITE_BRUSH);
608 dc.SetPen(*wxBLACK_PEN);
609 dc.DrawRectangle(0, 0, clientWidth, clientHeight);
611 dc.SetFont(wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
612 wxFONTWEIGHT_NORMAL));
613 dc.SetTextForeground(*wxBLACK);
614 dc.SetTextBackground(*wxWHITE);
616 double duckAmountDb = 0;
617 double innerFadeDownLen = 0;
618 double innerFadeUpLen = 0;
619 double outerFadeDownLen = 0;
620 double outerFadeUpLen = 0;
621 mEffect->mDuckAmountDbBox->GetValue().ToDouble(&duckAmountDb);
622 mEffect->mInnerFadeDownLenBox->GetValue().ToDouble(&innerFadeDownLen);
623 mEffect->mInnerFadeUpLenBox->GetValue().ToDouble(&innerFadeUpLen);
624 mEffect->mOuterFadeDownLenBox->GetValue().ToDouble(&outerFadeDownLen);
625 mEffect->mOuterFadeUpLenBox->GetValue().ToDouble(&outerFadeUpLen);
634 wxString message =
_(
"Preview not available");
635 int textWidth = 0, textHeight = 0;
636 dc.GetTextExtent(message, &textWidth, &textHeight);
637 dc.DrawText(message, (clientWidth - textWidth) / 2,
638 (clientHeight - textHeight) / 2);
640 ResetControlPoints();
644 dc.SetBrush(*wxTRANSPARENT_BRUSH);
645 dc.SetPen(wxPen(
theTheme.
Colour(clrGraphLines), 3, wxPENSTYLE_SOLID));
666 points[5].x = clientWidth - 10;
671 dc.SetPen(wxPen(*wxBLACK, 1, wxPENSTYLE_DOT));
677 dc.SetBrush(*wxWHITE_BRUSH);
679 mControlPoints[outerFadeDown] = points[1];
680 mControlPoints[innerFadeDown] = points[2];
681 mControlPoints[innerFadeUp] = points[3];
682 mControlPoints[outerFadeUp] = points[4];
683 mControlPoints[duckAmount] = wxPoint(
684 (points[2].x + points[3].x) / 2, points[2].y);
692 if (cp == innerFadeDown)
694 value = innerFadeDownLen;
697 else if (cp == innerFadeUp)
699 value = innerFadeUpLen;
702 else if (cp == outerFadeDown)
704 value = outerFadeDownLen;
706 }
else if (cp == outerFadeUp)
708 value = outerFadeUpLen;
713 value = duckAmountDb;
718 valueStr +=
wxT(
" ");
720 if (cp == duckAmount)
727 int textWidth = 0, textHeight = 0;
728 GetTextExtent(valueStr, &textWidth, &textHeight);
730 int textPosX = mControlPoints[i].x - textWidth / 2;
731 int textPosY = mControlPoints[i].y;
733 if (cp == duckAmount || cp == outerFadeDown || cp == outerFadeUp)
738 dc.DrawText(valueStr, textPosX, textPosY);
740 dc.DrawEllipse(mControlPoints[i].x - 3,
741 mControlPoints[i].y - 3, 6, 6);
746 wxPaintDC paintDC(
this);
747 paintDC.Blit(0, 0, clientWidth, clientHeight, &dc, 0, 0);
750 dc.SetPen(wxNullPen);
751 dc.SetBrush(wxNullBrush);
752 dc.SetFont(wxNullFont);
753 dc.SelectObject(wxNullBitmap);
757 wxMouseCaptureChangedEvent & WXUNUSED(evt))
759 SetCursor(wxNullCursor);
760 mCurrentControlPoint =
none;
764 wxMouseCaptureLostEvent & WXUNUSED(evt))
766 mCurrentControlPoint =
none;
785 if (dist[i] < dist[curMinimum])
796 EControlPoint nearest = GetNearestControlPoint(evt.GetPosition());
801 mMouseDownPoint = evt.GetPosition();
803 mCurrentControlPoint = nearest;
804 mControlPointMoveActivated =
false;
807 mMoveStartControlPoints[i] = mControlPoints[i];
816 if (mCurrentControlPoint !=
none)
818 mCurrentControlPoint =
none;
825 switch (GetNearestControlPoint(evt.GetPosition()))
828 SetCursor(wxNullCursor);
834 SetCursor(wxCursor(wxCURSOR_SIZEWE));
837 SetCursor(wxCursor(wxCURSOR_SIZENS));
841 if (mCurrentControlPoint !=
none)
843 if (!mControlPointMoveActivated)
847 if (mCurrentControlPoint == duckAmount)
848 dist = abs(evt.GetY() - mMouseDownPoint.y);
850 dist = abs(evt.GetX() - mMouseDownPoint.x);
853 mControlPointMoveActivated =
true;
856 if (mControlPointMoveActivated)
860 switch (mCurrentControlPoint)
885 mEffect->DoTransferDataToWindow();
static const size_t kBufSize
#define CONTROL_POINT_REGION
static const size_t kRMSWindowSize
static int GetDistance(const wxPoint &first, const wxPoint &second)
#define DUCK_AMOUNT_SCALE
#define DUCK_AMOUNT_START
#define CONTROL_POINT_MIN_MOVE
#define AUTO_DUCK_PANEL_NUM_CONTROL_POINTS
Toolkit-neutral facade for basic user interface services.
XXO("&Cut/Copy/Paste Toolbar")
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
std::function< void(double)> ProgressReporter
std::shared_ptr< TrackList > TrackListHolder
An AudacityException with no visible message.
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
static void Lines(wxDC &dc, size_t nPoints, const wxPoint points[])
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
EControlPoint GetNearestControlPoint(const wxPoint &pt)
void OnMotion(wxMouseEvent &evt)
void OnLeftDown(wxMouseEvent &evt)
void OnMouseCaptureChanged(wxMouseCaptureChangedEvent &evt)
void OnLeftUp(wxMouseEvent &evt)
void ResetControlPoints()
void OnPaint(wxPaintEvent &evt)
void OnMouseCaptureLost(wxMouseCaptureLostEvent &evt)
Implements the Auto Ducking effect.
static constexpr EffectParameter InnerFadeDownLen
wxTextCtrl * mInnerFadeUpLenBox
ComponentInterfaceSymbol GetSymbol() const override
static constexpr EffectParameter InnerFadeUpLen
wxTextCtrl * mInnerFadeDownLenBox
static constexpr EffectParameter OuterFadeDownLen
wxTextCtrl * mOuterFadeDownLenBox
const WaveTrack * mControlTrack
static constexpr EffectParameter MaximumPause
bool DoTransferDataToWindow()
wxTextCtrl * mThresholdDbBox
static constexpr EffectParameter ThresholdDb
wxWeakRef< wxWindow > mUIParent
const EffectParameterMethods & Parameters() const override
bool ApplyDuckFade(int trackNum, WaveChannel &track, double t0, double t1)
bool TransferDataToWindow(const EffectSettings &settings) override
virtual ~EffectAutoDuck()
void OnValueChanged(wxCommandEvent &evt)
static constexpr EffectParameter DuckAmountDb
EffectType GetType() const override
Type determines how it behaves.
bool TransferDataFromWindow(EffectSettings &settings) override
static constexpr EffectParameter OuterFadeUpLen
bool Process(EffectInstance &instance, EffectSettings &settings) override
wxTextCtrl * mMaximumPauseBox
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
static const ComponentInterfaceSymbol Symbol
TranslatableString GetDescription() const override
wxTextCtrl * mOuterFadeUpLenBox
wxTextCtrl * mDuckAmountDbBox
std::unique_ptr< EffectEditor > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
const TrackList * inputTracks() const
std::shared_ptr< TrackList > mTracks
bool TotalProgress(double frac, const TranslatableString &={}) const
int GetNumWaveTracks() const
Performs effect computation.
Use this object to copy the input tracks to tentative outputTracks.
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.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
wxColour & Colour(int iIndex)
Abstract base class for an object holding data associated with points on a time axis.
R TypeSwitch(const Functions &...functions)
Holds a msgid for the translation catalog; may also bind format arguments.
bool Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len, sampleFormat effectiveFormat=widestSampleFormat)
Random-access assignment of a range of samples.
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=FillFormat::fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
"narrow" overload fetches from the unique channel
A Track that contains audio waveform data.
WaveClipHolders & GetClips()
double LongSamplesToTime(sampleCount pos) const
sampleCount TimeToLongSamples(double t0) const
Positions or offsets within audio files need a wide type.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
WAVE_TRACK_API const TranslatableString defaultStretchRenderingTitle
WAVE_TRACK_API bool HasPitchOrSpeed(const WaveTrack &track, double t0, double t1)
WAVE_TRACK_API void WithClipRenderingProgress(std::function< void(const ProgressReporter &)> action, TranslatableString title=defaultStretchRenderingTitle, TranslatableString message=XO("Rendering Clip"))
BuiltinEffectsModule::Registration< EffectAutoDuck > reg
a struct that holds a start and end time.
AutoDuckRegion(double t0, double t1)
const Type min
Minimum value.
const Type max
Maximum value.
Externalized state of a plug-in.