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)."),
197 const auto t1 = pControlTrack->LongSamplesToTime(
end);
199 pFirstTrack = pControlTrack->Duplicate()->SharedPointer<
WaveTrack>();
203 pFirstTrack->ApplyPitchAndSpeed(
204 { { t0, t1 } }, reportProgress);
207 XO(
"Rendering Control-Track Time-Stretched Audio"));
208 pControlTrack = pFirstTrack.get();
221 auto minSamplesPause =
222 pControlTrack->TimeToLongSamples(maxPause);
233 std::vector<AutoDuckRegion> regions;
234 bool inDuckRegion =
false;
241 double duckRegionStart = 0;
246 const auto pControlChannel = *pControlTrack->Channels().begin();
251 pControlChannel->GetFloats(buf.get(), pos, len);
253 for (
auto i = pos; i < pos + len; i++)
255 rmsSum -= rmsWindow[rmsPos];
257 auto index = ( i - pos ).as_size_t();
258 rmsWindow[rmsPos] = buf[ index ] * buf[ index ];
259 rmsSum += rmsWindow[rmsPos];
262 bool thresholdExceeded = rmsSum > threshold;
264 if (thresholdExceeded)
275 duckRegionStart = pControlTrack->LongSamplesToTime(i);
279 if (!thresholdExceeded && inDuckRegion)
284 curSamplesPause += 1;
286 if (curSamplesPause >= minSamplesPause)
289 double duckRegionEnd =
290 pControlTrack->LongSamplesToTime(i - curSamplesPause);
296 inDuckRegion =
false;
304 (pos - start).as_double() /
305 (
end - start).as_double() /
317 double duckRegionEnd =
318 pControlTrack->LongSamplesToTime(
end - curSamplesPause);
330 for (
auto iterTrack : outputs.Get().Selected<
WaveTrack>()) {
331 for (
const auto pChannel : iterTrack->Channels())
332 for (
size_t i = 0; i < regions.size(); ++i) {
358 S.StartVerticalLay(
true);
367 S.StartMultiColumn(6, wxCENTER);
372 .NameSuffix(
XO(
"db"))
373 .AddTextBox(
XXO(
"Duck &amount:"),
wxT(
""), 10);
374 S.AddUnits(
XO(
"dB"));
379 .NameSuffix(
XO(
"seconds"))
380 .AddTextBox(
XXO(
"Ma&ximum pause:"),
wxT(
""), 10);
381 S.AddUnits(
XO(
"seconds"));
386 .NameSuffix(
XO(
"seconds"))
387 .AddTextBox(
XXO(
"Outer fade &down length:"),
wxT(
""), 10);
388 S.AddUnits(
XO(
"seconds"));
393 .NameSuffix(
XO(
"seconds"))
394 .AddTextBox(
XXO(
"Outer fade &up length:"),
wxT(
""), 10);
395 S.AddUnits(
XO(
"seconds"));
400 .NameSuffix(
XO(
"seconds"))
401 .AddTextBox(
XXO(
"Inner fade d&own length:"),
wxT(
""), 10);
402 S.AddUnits(
XO(
"seconds"));
407 .NameSuffix(
XO(
"seconds"))
408 .AddTextBox(
XXO(
"Inner &fade up length:"),
wxT(
""), 10);
409 S.AddUnits(
XO(
"seconds"));
413 S.StartMultiColumn(3, wxCENTER);
416 2, &
mThresholdDb, NumValidatorStyle::NO_TRAILING_ZEROES,
418 .NameSuffix(
XO(
"db"))
419 .AddTextBox(
XXO(
"&Threshold:"),
wxT(
""), 10);
420 S.AddUnits(
XO(
"dB"));
460 double t0,
double t1)
472 if (fadeDownSamples < 1)
477 if (fadeUpSamples < 1)
480 float fadeDownStep =
mDuckAmountDb / fadeDownSamples.as_double();
481 float fadeUpStep =
mDuckAmountDb / fadeUpSamples.as_double();
486 for (
auto i = pos; i < pos + len; ++i) {
487 float gainDown = fadeDownStep * (i - start).as_float();
488 float gainUp = fadeUpStep * (
end - i).as_float();
491 if (gainDown > gainUp)
502 if (!track.
SetFloats(buf.get(), pos, len)) {
510 float fractionFinished = (curTime -
mT0) / (
mT1 -
mT0);
531#define CONTROL_POINT_REGION 10
532#define CONTROL_POINT_MIN_MOVE 5
534#define TEXT_DISTANCE 15
536#define FADE_DOWN_START 150
537#define FADE_UP_START 450
538#define DUCK_AMOUNT_START 50
541#define DUCK_AMOUNT_SCALE 8
543static int GetDistance(
const wxPoint& first,
const wxPoint& second)
545 int distanceX = abs(first.x - second.x);
546 int distanceY = abs(first.y - second.y);
547 if (distanceX > distanceY)
564:
wxPanelWrapper(parent, winid, wxDefaultPosition, wxSize(600, 300))
568 mCurrentControlPoint =
none;
569 mBackgroundBitmap = NULL;
571 ResetControlPoints();
582 mControlPoints[innerFadeDown] = wxPoint(-100,-100);
583 mControlPoints[innerFadeUp] = wxPoint(-100,-100);
584 mControlPoints[outerFadeDown] = wxPoint(-100,-100);
585 mControlPoints[outerFadeUp] = wxPoint(-100,-100);
586 mControlPoints[duckAmount] = wxPoint(-100,-100);
591 int clientWidth, clientHeight;
592 GetSize(&clientWidth, &clientHeight);
594 if (!mBackgroundBitmap || mBackgroundBitmap->GetWidth() != clientWidth ||
595 mBackgroundBitmap->GetHeight() != clientHeight)
597 mBackgroundBitmap = std::make_unique<wxBitmap>(clientWidth, clientHeight,24);
601 dc.SelectObject(*mBackgroundBitmap);
603 dc.SetBrush(*wxWHITE_BRUSH);
604 dc.SetPen(*wxBLACK_PEN);
605 dc.DrawRectangle(0, 0, clientWidth, clientHeight);
607 dc.SetFont(wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
608 wxFONTWEIGHT_NORMAL));
609 dc.SetTextForeground(*wxBLACK);
610 dc.SetTextBackground(*wxWHITE);
612 double duckAmountDb = 0;
613 double innerFadeDownLen = 0;
614 double innerFadeUpLen = 0;
615 double outerFadeDownLen = 0;
616 double outerFadeUpLen = 0;
617 mEffect->mDuckAmountDbBox->GetValue().ToDouble(&duckAmountDb);
618 mEffect->mInnerFadeDownLenBox->GetValue().ToDouble(&innerFadeDownLen);
619 mEffect->mInnerFadeUpLenBox->GetValue().ToDouble(&innerFadeUpLen);
620 mEffect->mOuterFadeDownLenBox->GetValue().ToDouble(&outerFadeDownLen);
621 mEffect->mOuterFadeUpLenBox->GetValue().ToDouble(&outerFadeUpLen);
630 wxString message =
_(
"Preview not available");
631 int textWidth = 0, textHeight = 0;
632 dc.GetTextExtent(message, &textWidth, &textHeight);
633 dc.DrawText(message, (clientWidth - textWidth) / 2,
634 (clientHeight - textHeight) / 2);
636 ResetControlPoints();
640 dc.SetBrush(*wxTRANSPARENT_BRUSH);
641 dc.SetPen(wxPen(
theTheme.
Colour(clrGraphLines), 3, wxPENSTYLE_SOLID));
662 points[5].x = clientWidth - 10;
667 dc.SetPen(wxPen(*wxBLACK, 1, wxPENSTYLE_DOT));
673 dc.SetBrush(*wxWHITE_BRUSH);
675 mControlPoints[outerFadeDown] = points[1];
676 mControlPoints[innerFadeDown] = points[2];
677 mControlPoints[innerFadeUp] = points[3];
678 mControlPoints[outerFadeUp] = points[4];
679 mControlPoints[duckAmount] = wxPoint(
680 (points[2].x + points[3].x) / 2, points[2].y);
688 if (cp == innerFadeDown)
690 value = innerFadeDownLen;
693 else if (cp == innerFadeUp)
695 value = innerFadeUpLen;
698 else if (cp == outerFadeDown)
700 value = outerFadeDownLen;
702 }
else if (cp == outerFadeUp)
704 value = outerFadeUpLen;
709 value = duckAmountDb;
714 valueStr +=
wxT(
" ");
716 if (cp == duckAmount)
723 int textWidth = 0, textHeight = 0;
724 GetTextExtent(valueStr, &textWidth, &textHeight);
726 int textPosX = mControlPoints[i].x - textWidth / 2;
727 int textPosY = mControlPoints[i].y;
729 if (cp == duckAmount || cp == outerFadeDown || cp == outerFadeUp)
734 dc.DrawText(valueStr, textPosX, textPosY);
736 dc.DrawEllipse(mControlPoints[i].x - 3,
737 mControlPoints[i].y - 3, 6, 6);
742 wxPaintDC paintDC(
this);
743 paintDC.Blit(0, 0, clientWidth, clientHeight, &dc, 0, 0);
746 dc.SetPen(wxNullPen);
747 dc.SetBrush(wxNullBrush);
748 dc.SetFont(wxNullFont);
749 dc.SelectObject(wxNullBitmap);
753 wxMouseCaptureChangedEvent & WXUNUSED(evt))
755 SetCursor(wxNullCursor);
756 mCurrentControlPoint =
none;
760 wxMouseCaptureLostEvent & WXUNUSED(evt))
762 mCurrentControlPoint =
none;
781 if (dist[i] < dist[curMinimum])
792 EControlPoint nearest = GetNearestControlPoint(evt.GetPosition());
797 mMouseDownPoint = evt.GetPosition();
799 mCurrentControlPoint = nearest;
800 mControlPointMoveActivated =
false;
803 mMoveStartControlPoints[i] = mControlPoints[i];
812 if (mCurrentControlPoint !=
none)
814 mCurrentControlPoint =
none;
821 switch (GetNearestControlPoint(evt.GetPosition()))
824 SetCursor(wxNullCursor);
830 SetCursor(wxCursor(wxCURSOR_SIZEWE));
833 SetCursor(wxCursor(wxCURSOR_SIZENS));
837 if (mCurrentControlPoint !=
none)
839 if (!mControlPointMoveActivated)
843 if (mCurrentControlPoint == duckAmount)
844 dist = abs(evt.GetY() - mMouseDownPoint.y);
846 dist = abs(evt.GetX() - mMouseDownPoint.x);
849 mControlPointMoveActivated =
true;
852 if (mControlPointMoveActivated)
856 switch (mCurrentControlPoint)
881 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
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.
static void WithCancellableProgress(std::function< void(const ProgressReporter &)> action, TranslatableString title, TranslatableString message)
A frequently useful convenience wraps a lambda and may throw this type.
bool SetFloats(const float *buffer, 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.
std::shared_ptr< WaveTrack > Holder
double LongSamplesToTime(sampleCount pos) const
sampleCount TimeToLongSamples(double t0) const
Positions or offsets within audio files need a wide type.
WAVE_TRACK_API const TranslatableString defaultStretchRenderingTitle
WAVE_TRACK_API bool HasPitchOrSpeed(const WaveTrack &track, double t0, double t1)
BuiltinEffectsModule::Registration< EffectAutoDuck > reg
const char * end(const char *str) noexcept
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.