From 930c089cbc29ff02ec2c44f4631f132942ba3e22 Mon Sep 17 00:00:00 2001
From: Tom 7 <499244+tom7@users.noreply.github.com>
Date: Sat, 25 Jun 2022 11:05:25 -0400
Subject: [PATCH 1/3] Fix missing != operator for g++ 11.3 (perhaps it is
defined for you via some generic template that converts operator==, but I
don't think this is standard). Suppress some warnings; fix typo.
---
dfx-library/dfxsettings.cpp | 6 +++---
dfxgui/dfxguislider.cpp | 6 ++++++
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/dfx-library/dfxsettings.cpp b/dfx-library/dfxsettings.cpp
index cf3148a7..fada1015 100644
--- a/dfx-library/dfxsettings.cpp
+++ b/dfx-library/dfxsettings.cpp
@@ -21,7 +21,7 @@ along with Destroy FX Library. If not, see .
To contact the author, use the contact form at http://destroyfx.org/
Destroy FX is a sovereign entity comprised of Sophia Poirier and Tom Murphy 7.
-Welcome to our settings persistance mess.
+Welcome to our settings persistence mess.
------------------------------------------------------------------------*/
#include "dfxsettings.h"
@@ -434,7 +434,7 @@ if (!(oldVST && inIsPreset))
for (size_t i = 0; i < std::min(paramMap.size(), mParameterAssignments.size()); i++)
{
auto const mappedTag = paramMap[i];
- if ((mappedTag != dfx::kParameterID_Invalid) && (mappedTag >= 0) && (mappedTag < numStoredParameters))
+ if ((mappedTag != dfx::kParameterID_Invalid) && (mappedTag >= 0) && ((unsigned)mappedTag < numStoredParameters))
{
memcpy(&(mParameterAssignments[i]),
newParameterAssignments + (mappedTag * storedParameterAssignmentSize),
@@ -1403,7 +1403,7 @@ long DfxSettings::getParameterTagFromID(long inParamID, size_t inNumSearchIDs, i
assert(inSearchIDs || (inNumSearchIDs == 0));
// search for the ID in the table that matches the requested ID
- for (long i = 0; i < inNumSearchIDs; i++)
+ for (size_t i = 0; i < inNumSearchIDs; i++)
{
// return the parameter tag if a match is found
if (inSearchIDs[i] == inParamID)
diff --git a/dfxgui/dfxguislider.cpp b/dfxgui/dfxguislider.cpp
index 7e9a562b..b8ce2268 100644
--- a/dfxgui/dfxguislider.cpp
+++ b/dfxgui/dfxguislider.cpp
@@ -88,6 +88,12 @@ static bool operator==(VSTGUI::Modifiers const& a, VSTGUI::Modifiers const& b) n
return (std::memcmp(&a, &b, sizeof(a)) == 0);
}
+static bool operator!=(VSTGUI::Modifiers const& a, VSTGUI::Modifiers const& b) noexcept
+{
+ static_assert(dfx::IsTriviallySerializable);
+ return (std::memcmp(&a, &b, sizeof(a)) != 0);
+}
+
//-----------------------------------------------------------------------------
static void EndControl(IDGControl* inControl)
{
From c19bac206ec0351b7d2433df4465c52b579379a1 Mon Sep 17 00:00:00 2001
From: Sophia Poirier <2997196+sophiapoirier@users.noreply.github.com>
Date: Tue, 28 Jun 2022 15:26:44 -0700
Subject: [PATCH 2/3] update to and adopt some of C++20 (#65)
---
bufferoverride/bufferoverride-base.h | 4 +-
bufferoverride/bufferoverrideprocess.cpp | 11 +++--
bufferoverride/gui/bufferoverrideview.cpp | 16 +++----
bufferoverride/win32/makefile | 2 +-
dfx-library/dfxenvelope.cpp | 2 +-
dfx-library/dfxmath.h | 4 --
dfx-library/dfxmisc.cpp | 12 +-----
dfx-library/dfxplugin.cpp | 8 ++--
dfx-library/dfxsettings.cpp | 29 +++++--------
dfx-library/dfxsettings.h | 15 +++----
dfx-library/firfilter.cpp | 52 ++++++++++++-----------
dfx-library/firfilter.h | 23 +++++-----
dfx-library/iirfilter.cpp | 32 +++++++++-----
dfx-library/lfo.cpp | 8 ++--
dfx-library/xcode/dfxplugin.xcconfig | 2 +-
dfxgui/dfxguieditor.cpp | 16 +++----
dfxgui/dfxguimisc.cpp | 8 ++--
eqsync/win32/makefile | 2 +-
fonttest/win32/makefile | 2 +-
geometer/geometer.cpp | 9 ++--
geometer/win32/makefile | 2 +-
midigater/win32/makefile | 2 +-
monomaker/win32/makefile | 2 +-
polarizer/win32/makefile | 2 +-
rezsynth/rezsynthformalities.cpp | 3 +-
rezsynth/rezsynthsubprocesses.cpp | 15 ++-----
rezsynth/win32/makefile | 2 +-
scrubby/scrubbyprocess.cpp | 9 ++--
scrubby/win32/makefile | 2 +-
skidder/win32/makefile | 2 +-
thrush/thrush.cpp | 3 +-
transverb/gui/transverbeditor.cpp | 10 ++---
transverb/transverb.h | 3 +-
transverb/transverbprocess.cpp | 14 +++---
transverb/win32/makefile | 2 +-
35 files changed, 157 insertions(+), 173 deletions(-)
diff --git a/bufferoverride/bufferoverride-base.h b/bufferoverride/bufferoverride-base.h
index abf1d58d..63c83bed 100644
--- a/bufferoverride/bufferoverride-base.h
+++ b/bufferoverride/bufferoverride-base.h
@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
-Copyright (C) 2001-2021 Sophia Poirier and Tom Murphy VII
+Copyright (C) 2001-2022 Sophia Poirier and Tom Murphy VII
This file is part of Buffer Override.
@@ -89,7 +89,7 @@ static_assert(dfx::IsTriviallySerializable);
namespace detail
{
// where 16-byte lock-free atomics are not supported, we slice it into halves (Clang can but GCC cannot)
-static constexpr auto getAtomicViewDataInstance()
+static consteval auto getAtomicViewDataInstance()
{
using UnifiedT = std::atomic;
diff --git a/bufferoverride/bufferoverrideprocess.cpp b/bufferoverride/bufferoverrideprocess.cpp
index 9ea376bf..e75b819d 100644
--- a/bufferoverride/bufferoverrideprocess.cpp
+++ b/bufferoverride/bufferoverrideprocess.cpp
@@ -24,8 +24,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
-
-#include "dfxmath.h"
+#include
@@ -233,10 +232,10 @@ void BufferOverride::updateBuffer(unsigned long samplePos, bool& ioViewDataChang
// mSqrtFadeOut = std::sqrt(1.0f - mSmoothStep);
// mSmoothFract = mSmoothStep;
- mFadeOutGain = std::cos(dfx::math::kPi / static_cast(4 * mSmoothDur));
- mFadeInGain = std::sin(dfx::math::kPi / static_cast(4 * mSmoothDur));
- mRealFadePart = (mFadeOutGain * mFadeOutGain) - (mFadeInGain * mFadeInGain); // std::cos(dfx::math::kPi / 2.0f / n)
- mImaginaryFadePart = 2.0f * mFadeOutGain * mFadeInGain; // std::sin(dfx::math::kPi / 2.0f / n)
+ mFadeOutGain = std::cos(std::numbers::pi_v / static_cast(4 * mSmoothDur));
+ mFadeInGain = std::sin(std::numbers::pi_v / static_cast(4 * mSmoothDur));
+ mRealFadePart = (mFadeOutGain * mFadeOutGain) - (mFadeInGain * mFadeInGain); // std::cos(std::numbers::pi_v / 2.f / n)
+ mImaginaryFadePart = 2.f * mFadeOutGain * mFadeInGain; // std::sin(std::numbers::pi_v / 2.f / n)
}
}
diff --git a/bufferoverride/gui/bufferoverrideview.cpp b/bufferoverride/gui/bufferoverrideview.cpp
index d6f7fc71..8d97a8bf 100644
--- a/bufferoverride/gui/bufferoverrideview.cpp
+++ b/bufferoverride/gui/bufferoverrideview.cpp
@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
-Copyright (C) 2021 Tom Murphy 7 and Sophia Poirier
+Copyright (C) 2021-2022 Tom Murphy 7 and Sophia Poirier
This file is part of Buffer Override.
@@ -24,6 +24,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
#include
+#include
#include
#include
@@ -213,8 +214,8 @@ void BufferOverrideView::draw(VSTGUI::CDrawContext *ctx) {
const auto legend_width = legend_right - legend_left;
constexpr CCoord LEGEND_DASH_STRIDE = 2;
constexpr CCoord LEGEND_DASH_WIDTH = 1;
- // TODO: C++20 use std::midpoint
- const auto legend_dash_y = std::floor((legend_top + legend_bottom) * 0.5);
+ const auto legend_dash_y = std::floor(std::midpoint(legend_top,
+ legend_bottom));
// legend bounding
offc->setFrameColor(color_legend);
@@ -231,12 +232,9 @@ void BufferOverrideView::draw(VSTGUI::CDrawContext *ctx) {
}
// legend label
- const auto legend_label = [](auto window_sec) {
- if (window_sec < 1) {
- return std::to_string(std::lround(window_sec * 1000)) + " ms";
- }
- return std::to_string(std::lround(window_sec)) + " sec";
- }(window_sec);
+ const auto legend_label = (window_sec < 1) ?
+ (std::to_string(std::lround(window_sec * 1000)) + " ms") :
+ (std::to_string(std::lround(window_sec)) + " sec");
constexpr bool LABEL_ANTIALIAS = false;
constexpr CCoord LABEL_PADDING = 12;
const auto label_width = offc->getStringWidth(legend_label.c_str()) +
diff --git a/bufferoverride/win32/makefile b/bufferoverride/win32/makefile
index 53c527a2..404c601f 100755
--- a/bufferoverride/win32/makefile
+++ b/bufferoverride/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../bufferoverridedef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/dfx-library/dfxenvelope.cpp b/dfx-library/dfxenvelope.cpp
index 568f9077..8f7f6386 100644
--- a/dfx-library/dfxenvelope.cpp
+++ b/dfx-library/dfxenvelope.cpp
@@ -262,7 +262,7 @@ double DfxEnvelope::calculateRise(double inPosNormalized) const
}
// sine fade (stupendously inefficient)
-// return (std::sin((inPosNormalized * dfx::math::kPi) - (dfx::math::kPi * 0.5)) + 1.0) * 0.5;
+// return (std::sin((inPosNormalized * std::numbers::pi_v) - (std::numbers::pi_v * 0.5)) + 1.) * 0.5;
return inPosNormalized;
}
diff --git a/dfx-library/dfxmath.h b/dfx-library/dfxmath.h
index 3ef95b7b..c2193fed 100644
--- a/dfx-library/dfxmath.h
+++ b/dfx-library/dfxmath.h
@@ -44,10 +44,6 @@ namespace dfx::math
// constants
//-----------------------------------------------------------------------------
-// TODO: C++20 replace usage of this with std::numbers::pi_v
-template >>
-constexpr T kPi(3.14159265358979323846264338327950288);
-
// the AU SDK handles denormals for us, and ARM processors don't have denormal performance issues
constexpr bool kDenormalProblem =
#if defined(TARGET_API_AUDIOUNIT) || defined(__arm__) || defined(__arm64__)
diff --git a/dfx-library/dfxmisc.cpp b/dfx-library/dfxmisc.cpp
index 7e94d965..2a191eb3 100644
--- a/dfx-library/dfxmisc.cpp
+++ b/dfx-library/dfxmisc.cpp
@@ -274,16 +274,8 @@ bool LaunchDocumentation()
// XXX this will load latest docs on our website which may not match the version of the running software
// TODO: embed the documentation into Windows builds somehow?
auto docsFileName = ToLower(PLUGIN_NAME_STRING ".html");
- while (true)
- {
- auto const isSpace = std::bind(std::isspace, std::placeholders::_1, std::locale::classic());
- auto const foundCharacter = std::find_if(docsFileName.cbegin(), docsFileName.cend(), isSpace);
- if (foundCharacter == docsFileName.end())
- {
- break;
- }
- docsFileName.erase(foundCharacter);
- }
+ auto const isSpace = std::bind(std::isspace, std::placeholders::_1, std::locale::classic());
+ std::erase_if(docsFileName, isSpace);
return LaunchURL(DESTROYFX_URL "/docs/" + docsFileName);
#endif // TARGET_OS_MAC
diff --git a/dfx-library/dfxplugin.cpp b/dfx-library/dfxplugin.cpp
index aa51d504..8e00c01a 100644
--- a/dfx-library/dfxplugin.cpp
+++ b/dfx-library/dfxplugin.cpp
@@ -1284,10 +1284,10 @@ void DfxPlugin::registerSmoothedAudioValue(dfx::ISmoothedValue* smoothedValue, D
//-----------------------------------------------------------------------------
void DfxPlugin::unregisterAllSmoothedAudioValues(DfxPluginCore* owner)
{
- mSmoothedAudioValues.erase(std::remove_if(mSmoothedAudioValues.begin(), mSmoothedAudioValues.end(), [owner](auto const& value)
- {
- return (owner == value.second);
- }), mSmoothedAudioValues.cend());
+ std::erase_if(mSmoothedAudioValues, [owner](auto const& value)
+ {
+ return (owner == value.second);
+ });
}
//-----------------------------------------------------------------------------
diff --git a/dfx-library/dfxsettings.cpp b/dfx-library/dfxsettings.cpp
index fada1015..d3a9ba16 100644
--- a/dfx-library/dfxsettings.cpp
+++ b/dfx-library/dfxsettings.cpp
@@ -1,7 +1,7 @@
/*------------------------------------------------------------------------
Destroy FX Library is a collection of foundation code
for creating audio processing plug-ins.
-Copyright (C) 2002-2021 Sophia Poirier
+Copyright (C) 2002-2022 Sophia Poirier
This file is part of the Destroy FX Library (version 1.0).
@@ -321,7 +321,7 @@ try
std::vector paramMap(mNumParameters, dfx::kParameterID_Invalid);
for (size_t tag = 0; tag < mParameterIDs.size(); tag++)
{
- paramMap[tag] = getParameterTagFromID(mParameterIDs[tag], numStoredParameters, newParameterIDs);
+ paramMap[tag] = getParameterTagFromID(mParameterIDs[tag], {newParameterIDs, numStoredParameters});
}
// point to the next data element after the parameter IDs: the first preset name
@@ -434,10 +434,10 @@ if (!(oldVST && inIsPreset))
for (size_t i = 0; i < std::min(paramMap.size(), mParameterAssignments.size()); i++)
{
auto const mappedTag = paramMap[i];
- if ((mappedTag != dfx::kParameterID_Invalid) && (mappedTag >= 0) && ((unsigned)mappedTag < numStoredParameters))
+ if ((mappedTag != dfx::kParameterID_Invalid) && (mappedTag >= 0) && (dfx::math::ToUnsigned(mappedTag) < numStoredParameters))
{
memcpy(&(mParameterAssignments[i]),
- newParameterAssignments + (mappedTag * storedParameterAssignmentSize),
+ newParameterAssignments + (dfx::math::ToUnsigned(mappedTag) * storedParameterAssignmentSize),
copyParameterAssignmentSize);
}
}
@@ -581,9 +581,8 @@ if (!(DFX_IsOldVstVersionNumber(storedVersion) && inIsPreset))
// and reverse the byte order of each event assignment
auto const dataParameterAssignments = reinterpret_cast(dataPresets);
validateRange(dataParameterAssignments, sizeof(*dataParameterAssignments) * numStoredParameters, "parameter assignments");
- for (uint32_t i = 0; i < numStoredParameters; i++)
+ for (auto& pa : std::span(dataParameterAssignments, numStoredParameters))
{
- auto& pa = dataParameterAssignments[i];
dfx::ReverseBytes(pa.mEventType);
dfx::ReverseBytes(pa.mEventChannel);
dfx::ReverseBytes(pa.mEventNum);
@@ -1398,21 +1397,13 @@ dfx::MidiEventType DfxSettings::getParameterAssignmentType(long inParamTag) cons
//-----------------------------------------------------------------------------
// given a parameter ID, find the tag (index) for that parameter in a table of parameter IDs
-long DfxSettings::getParameterTagFromID(long inParamID, size_t inNumSearchIDs, int32_t const* inSearchIDs)
+long DfxSettings::getParameterTagFromID(long inParamID, std::span inSearchIDs)
{
- assert(inSearchIDs || (inNumSearchIDs == 0));
-
- // search for the ID in the table that matches the requested ID
- for (size_t i = 0; i < inNumSearchIDs; i++)
+ auto const foundID = std::find(inSearchIDs.begin(), inSearchIDs.end(), inParamID);
+ if (foundID != inSearchIDs.end())
{
- // return the parameter tag if a match is found
- if (inSearchIDs[i] == inParamID)
- {
- return i;
- }
+ return std::distance(inSearchIDs.begin(), foundID);
}
-
- // if nothing was found, then return the error ID
return dfx::kParameterID_Invalid;
}
@@ -1420,7 +1411,7 @@ long DfxSettings::getParameterTagFromID(long inParamID, size_t inNumSearchIDs, i
// search using the internal table
long DfxSettings::getParameterTagFromID(long inParamID) const
{
- return getParameterTagFromID(inParamID, mParameterIDs.size(), mParameterIDs.data());
+ return getParameterTagFromID(inParamID, mParameterIDs);
}
diff --git a/dfx-library/dfxsettings.h b/dfx-library/dfxsettings.h
index 219b6a87..28277a38 100644
--- a/dfx-library/dfxsettings.h
+++ b/dfx-library/dfxsettings.h
@@ -1,7 +1,7 @@
/*------------------------------------------------------------------------
Destroy FX Library is a collection of foundation code
for creating audio processing plug-ins.
-Copyright (C) 2002-2021 Sophia Poirier
+Copyright (C) 2002-2022 Sophia Poirier
This file is part of the Destroy FX Library (version 1.0).
@@ -73,7 +73,9 @@ This is our Destroy FX plugin data storage stuff
#include
+#include
#include
+#include
#include
#include "dfxdefines.h"
@@ -307,13 +309,9 @@ class DfxSettings
return mCrisisBehavior;
}
- static constexpr bool serializationIsNativeEndian() noexcept
+ static consteval bool serializationIsNativeEndian() noexcept
{
-#if __BIG_ENDIAN__
- return true;
-#else
- return false;
-#endif
+ return std::endian::native == std::endian::big;
}
@@ -396,8 +394,7 @@ class DfxSettings
return (inParamTag >= 0) && (static_cast(inParamTag) < mNumParameters);
}
- // TODO: C++20 use std::span
- static long getParameterTagFromID(long inParamID, size_t inNumSearchIDs, int32_t const* inSearchIDs);
+ static long getParameterTagFromID(long inParamID, std::span inSearchIDs);
long getParameterTagFromID(long inParamID) const;
#if TARGET_PLUGIN_USES_MIDI
diff --git a/dfx-library/firfilter.cpp b/dfx-library/firfilter.cpp
index 28a7816b..4aa5bee2 100644
--- a/dfx-library/firfilter.cpp
+++ b/dfx-library/firfilter.cpp
@@ -1,7 +1,7 @@
/*------------------------------------------------------------------------
Destroy FX Library is a collection of foundation code
for creating audio processing plug-ins.
-Copyright (C) 2002-2021 Sophia Poirier
+Copyright (C) 2002-2022 Sophia Poirier
This file is part of the Destroy FX Library (version 1.0).
@@ -30,59 +30,59 @@ Welcome to our Finite Impulse Response filter.
#include
#include
#include
-
-#include "dfxmath.h"
+#include
//-----------------------------------------------------------------------------
float besselIZero(float input);
-float besselIZero2(float input);
+//float besselIZero2(float input);
//-----------------------------------------------------------------------------
// you're supposed to use use an odd number of taps
void dfx::FIRFilter::calculateIdealLowpassCoefficients(double inCutoff, double inSampleRate,
- size_t inNumTaps, float* outCoefficients)
+ std::span outCoefficients)
{
- assert(inNumTaps > 0);
- assert(inNumTaps % 2);
+ assert(!outCoefficients.empty());
+ assert(outCoefficients.size() % 2);
// get the cutoff as a ratio of cutoff to Nyquist, scaled from 0 to Pi
- double const corner = (inCutoff / (inSampleRate * 0.5)) * dfx::math::kPi;
+ double const corner = (inCutoff / (inSampleRate * 0.5)) * std::numbers::pi_v;
size_t middleCoeff {};
- if (inNumTaps % 2)
+ if (outCoefficients.size() % 2)
{
- middleCoeff = (inNumTaps - 1) / 2;
- outCoefficients[middleCoeff] = corner / dfx::math::kPi;
+ middleCoeff = (outCoefficients.size() - 1) / 2;
+ outCoefficients[middleCoeff] = corner / std::numbers::pi_v;
}
else
{
- middleCoeff = inNumTaps / 2;
+ middleCoeff = outCoefficients.size() / 2;
}
for (size_t n = 0; n < middleCoeff; n++)
{
- double const value = static_cast(n) - (static_cast(inNumTaps - 1) * 0.5);
- outCoefficients[n] = std::sin(value * corner) / (value * dfx::math::kPi);
- outCoefficients[inNumTaps - 1 - n] = outCoefficients[n];
+ double const value = static_cast(n) - (static_cast(outCoefficients.size() - 1) * 0.5);
+ outCoefficients[n] = std::sin(value * corner) / (value * std::numbers::pi_v);
+ outCoefficients[outCoefficients.size() - 1 - n] = outCoefficients[n];
}
}
//-----------------------------------------------------------------------------
void dfx::FIRFilter::calculateIdealLowpassCoefficients(double inCutoff, double inSampleRate,
- size_t inNumTaps, float* outCoefficients,
- float const* inCoefficientsWindow)
+ std::span outCoefficients,
+ std::span inCoefficientsWindow)
{
- calculateIdealLowpassCoefficients(inCutoff, inSampleRate, inNumTaps, outCoefficients);
- std::transform(outCoefficients, outCoefficients + inNumTaps, inCoefficientsWindow, outCoefficients, std::multiplies());
+ assert(outCoefficients.size() == inCoefficientsWindow.size());
+ calculateIdealLowpassCoefficients(inCutoff, inSampleRate, outCoefficients);
+ std::transform(outCoefficients.begin(), outCoefficients.end(), inCoefficientsWindow.begin(), outCoefficients.begin(), std::multiplies<>{});
}
//-----------------------------------------------------------------------------
-void dfx::FIRFilter::applyKaiserWindow(size_t inNumTaps, float* ioCoefficients, float inAttenuation)
+void dfx::FIRFilter::applyKaiserWindow(std::span ioCoefficients, float inAttenuation)
{
- assert(inNumTaps > 0);
+ assert(!ioCoefficients.empty());
// beta is 0 if the attenuation is less than 21 dB
float beta = 0.0f;
@@ -96,12 +96,12 @@ void dfx::FIRFilter::applyKaiserWindow(size_t inNumTaps, float* ioCoefficients,
beta += 0.07886f * (inAttenuation - 21.0f);
}
- size_t const halfLength = (inNumTaps + 1) / 2;
+ size_t const halfLength = (ioCoefficients.size() + 1) / 2;
auto const oneDivBesselIZeroOfBeta = 1.0f / besselIZero(beta);
for (size_t n = 0; n < halfLength; n++)
{
- ioCoefficients[n] *= besselIZero(beta * std::sqrt(1.0f - std::pow((1.0f - ((2.0f * n) / static_cast(inNumTaps - 1))), 2.0f))) * oneDivBesselIZeroOfBeta;
- ioCoefficients[inNumTaps - 1 - n] = ioCoefficients[n];
+ ioCoefficients[n] *= besselIZero(beta * std::sqrt(1.0f - std::pow((1.0f - ((2.0f * n) / static_cast(ioCoefficients.size() - 1))), 2.0f))) * oneDivBesselIZeroOfBeta;
+ ioCoefficients[ioCoefficients.size() - 1 - n] = ioCoefficients[n];
}
}
@@ -109,7 +109,7 @@ void dfx::FIRFilter::applyKaiserWindow(size_t inNumTaps, float* ioCoefficients,
std::vector dfx::FIRFilter::generateKaiserWindow(size_t inNumTaps, float inAttenuation)
{
std::vector coefficientsWindow(inNumTaps, 1.0f);
- applyKaiserWindow(inNumTaps, coefficientsWindow.data(), inAttenuation);
+ applyKaiserWindow(coefficientsWindow, inAttenuation);
return coefficientsWindow;
}
@@ -131,6 +131,7 @@ float besselIZero(float input)
}
//-----------------------------------------------------------------------------
+#if 0
float besselIZero2(float input)
{
float sum = 1.0f;
@@ -147,3 +148,4 @@ float besselIZero2(float input)
return sum;
}
+#endif
diff --git a/dfx-library/firfilter.h b/dfx-library/firfilter.h
index df612218..cd121566 100644
--- a/dfx-library/firfilter.h
+++ b/dfx-library/firfilter.h
@@ -1,7 +1,7 @@
/*------------------------------------------------------------------------
Destroy FX Library is a collection of foundation code
for creating audio processing plug-ins.
-Copyright (C) 2002-2021 Sophia Poirier
+Copyright (C) 2002-2022 Sophia Poirier
This file is part of the Destroy FX Library (version 1.0).
@@ -28,6 +28,7 @@ Welcome to our Finite Impulse Response filter.
#include
+#include
#include
@@ -38,30 +39,28 @@ static constexpr double kShelfStartLowpass = 0.333;
//-----------------------------------------------------------------------------
-// TODO: C++20 use std::span for all pointer+size parameters
void calculateIdealLowpassCoefficients(double inCutoff, double inSampleRate,
- size_t inNumTaps, float* outCoefficients);
+ std::span outCoefficients);
void calculateIdealLowpassCoefficients(double inCutoff, double inSampleRate,
- size_t inNumTaps, float* outCoefficients,
- float const* inCoefficientsWindow);
-void applyKaiserWindow(size_t inNumTaps, float* ioCoefficients, float inAttenuation);
+ std::span outCoefficients,
+ std::span inCoefficientsWindow);
+void applyKaiserWindow(std::span ioCoefficients, float inAttenuation);
std::vector generateKaiserWindow(size_t inNumTaps, float inAttenuation);
//-----------------------------------------------------------------------------
-inline float process(float const* inAudio, size_t inNumTaps, float const* inCoefficients,
- size_t inPos, size_t inBufferSize)
+inline float process(std::span inAudio, std::span inCoefficients, size_t inPos)
{
float outval = 0.0f;
- if ((inPos + inNumTaps) > inBufferSize)
+ if ((inPos + inCoefficients.size()) > inAudio.size())
{
- for (size_t i = 0; i < inNumTaps; i++)
+ for (size_t i = 0; i < inCoefficients.size(); i++)
{
- outval += inAudio[(inPos + i) % inBufferSize] * inCoefficients[i];
+ outval += inAudio[(inPos + i) % inAudio.size()] * inCoefficients[i];
}
}
else
{
- for (size_t i = 0; i < inNumTaps; i++)
+ for (size_t i = 0; i < inCoefficients.size(); i++)
{
outval += inAudio[inPos + i] * inCoefficients[i];
}
diff --git a/dfx-library/iirfilter.cpp b/dfx-library/iirfilter.cpp
index 6f2a8c06..f64a0766 100644
--- a/dfx-library/iirfilter.cpp
+++ b/dfx-library/iirfilter.cpp
@@ -1,7 +1,7 @@
/*------------------------------------------------------------------------
Destroy FX Library is a collection of foundation code
for creating audio processing plug-ins.
-Copyright (C) 2001-2021 Sophia Poirier
+Copyright (C) 2001-2022 Sophia Poirier
This file is part of the Destroy FX Library (version 1.0).
@@ -28,13 +28,15 @@ Welcome to our Infinite Impulse Response filter.
#include
#include
+#include
+#include
#include
#include "dfxmath.h"
//------------------------------------------------------------------------
-static double const kDefaultQ_LP_HP = std::sqrt(2.0) / 2.0; // C++20 constexpr 1.0 / std::numbers::sqrt2_v
+constexpr double kDefaultQ_LP_HP = std::numbers::sqrt2_v / 2.;
constexpr double kUnityGain = 1.;
//------------------------------------------------------------------------
@@ -48,11 +50,11 @@ struct PreCoeff
double mBeta {}; // shelf
PreCoeff(double inFrequency, double inQ, double inSampleRate)
- : mOmega(2. * dfx::math::kPi * inFrequency / inSampleRate),
+ : mOmega(2. * std::numbers::pi_v * inFrequency / inSampleRate),
mSinOmega(std::sin(mOmega)),
mCosOmega(std::cos(mOmega)),
mAlpha(mSinOmega / (2. * inQ))
- //mAlpha(mSinOmega * std::sinh(std::numbers::ln2 / 2. * inQ * mOmega / mSinOmega)) // http://musicdsp.org/showone.php?id=64
+ //mAlpha(mSinOmega * std::sinh(std::numbers::ln2_v / 2. * inQ * mOmega / mSinOmega)) // http://musicdsp.org/showone.php?id=64
{
}
@@ -179,7 +181,13 @@ void dfx::IIRFilter::setCoefficients(Coefficients const& inCoefficients)
dfx::IIRFilter::Coefficients const& dfx::IIRFilter::setCoefficients(FilterType inFilterType, double inFrequency, double inQ, double inGain)
{
assert(inFrequency > 0.);
+ assert(!std::isinf(inFrequency));
+ assert(!std::isnan(inFrequency));
assert(inQ > 0.);
+ assert(!std::isinf(inQ));
+ assert(!std::isnan(inQ));
+ assert(!std::isinf(inGain));
+ assert(!std::isnan(inGain));
mFilterType = inFilterType;
mFilterFrequency = inFrequency;
@@ -197,7 +205,11 @@ dfx::IIRFilter::Coefficients const& dfx::IIRFilter::setCoefficients(FilterType i
(inFilterType != FilterType::LowShelf) &&
(inFilterType != FilterType::HighShelf));
assert(inFrequency > 0.);
+ assert(!std::isinf(inFrequency));
+ assert(!std::isnan(inFrequency));
assert(inQ > 0.);
+ assert(!std::isinf(inQ));
+ assert(!std::isnan(inQ));
mFilterType = inFilterType;
mFilterFrequency = inFrequency;
@@ -225,6 +237,7 @@ dfx::IIRFilter::Coefficients const& dfx::IIRFilter::setLowpassCoefficients(doubl
//------------------------------------------------------------------------
dfx::IIRFilter::Coefficients const& dfx::IIRFilter::setHighpassCoefficients(double inCutoffFrequency)
{
+ assert(inCutoffFrequency <= mSampleRate);
return setCoefficients(FilterType::Highpass, inCutoffFrequency, kDefaultQ_LP_HP);
}
@@ -261,7 +274,7 @@ dfx::Crossover::Crossover(unsigned long inChannelCount, double inSampleRate, dou
{
assert(inSampleRate > 0.);
assert(inFrequency > 0.);
- assert(inFrequency <= (inSampleRate / 2.));
+ //assert(inFrequency <= (inSampleRate / 2.));
inFrequency = std::min(inFrequency, inSampleRate / 2.); // upper-limit to Nyquist
#if !DFX_CROSSOVER_LINKWITZ_RILEY_MUSICDSP
@@ -287,17 +300,16 @@ void dfx::Crossover::setFrequency(double inFrequency)
{
#if DFX_CROSSOVER_LINKWITZ_RILEY_MUSICDSP
// https://www.musicdsp.org/en/latest/Filters/266-4th-order-linkwitz-riley-filters.html
- double const wc = 2. * dfx::math::kPi * inFrequency;
+ double const wc = 2. * std::numbers::pi_v * inFrequency;
auto const wc2 = wc * wc;
auto const wc3 = wc2 * wc;
auto const wc4 = wc2 * wc2;
- double const k = wc / std::tan(dfx::math::kPi * inFrequency / mSampleRate);
+ double const k = wc / std::tan(std::numbers::pi_v * inFrequency / mSampleRate);
auto const k2 = k * k;
auto const k3 = k2 * k;
auto const k4 = k2 * k2;
- static double const sqrt2 = std::sqrt(2.);
- auto const sq_tmp1 = sqrt2 * wc3 * k;
- auto const sq_tmp2 = sqrt2 * wc * k3;
+ auto const sq_tmp1 = std::numbers::sqrt2_v * wc3 * k;
+ auto const sq_tmp2 = std::numbers::sqrt2_v * wc * k3;
auto const a_tmp = (4. * wc2 * k2) + (2. * sq_tmp1) + k4 + (2. * sq_tmp2) + wc4;
auto const a_tmp_inv = (a_tmp != 0.) ? (1. / a_tmp) : 1.;
diff --git a/dfx-library/lfo.cpp b/dfx-library/lfo.cpp
index 55c46ca0..119ca8c7 100644
--- a/dfx-library/lfo.cpp
+++ b/dfx-library/lfo.cpp
@@ -29,8 +29,8 @@ Welcome to our Low Frequency Oscillator.
#include
#include
#include
-
-#include "dfxmath.h"
+#include
+#include
//------------------------------------------------------------------------
@@ -191,7 +191,7 @@ double dfx::LFO::process() const
if (mShape == kShape_RandomInterpolating)
{
// interpolate between the previous random number and the new one
- outValue = (mRandomNumber * mPosition) + (mPrevRandomNumber * (1. - mPosition));
+ outValue = std::lerp(mPrevRandomNumber, mRandomNumber, mPosition);
}
else if (mShape == kShape_Random)
{
@@ -209,7 +209,7 @@ double dfx::LFO::process() const
// oscillates from 0 to 1 and back to 0
double dfx::LFO::sineGenerator(double inPosition)
{
- return (std::sin((inPosition - 0.25) * 2. * dfx::math::kPi) + 1.) * 0.5;
+ return (std::sin((inPosition - 0.25) * 2. * std::numbers::pi_v) + 1.) * 0.5;
}
//-----------------------------------------------------------------------------------------
diff --git a/dfx-library/xcode/dfxplugin.xcconfig b/dfx-library/xcode/dfxplugin.xcconfig
index 19cbaab3..3efd30ef 100644
--- a/dfx-library/xcode/dfxplugin.xcconfig
+++ b/dfx-library/xcode/dfxplugin.xcconfig
@@ -7,7 +7,7 @@ DEPLOYMENT_LOCATION = YES
DSTROOT = /
SKIP_INSTALL = NO
GCC_C_LANGUAGE_STANDARD = c99
-CLANG_CXX_LANGUAGE_STANDARD = c++17
+CLANG_CXX_LANGUAGE_STANDARD = c++20
CLANG_CXX_LIBRARY = libc++
CLANG_ENABLE_OBJC_ARC = YES
ENABLE_STRICT_OBJC_MSGSEND = YES
diff --git a/dfxgui/dfxguieditor.cpp b/dfxgui/dfxguieditor.cpp
index 72ea085c..bf447ae9 100644
--- a/dfxgui/dfxguieditor.cpp
+++ b/dfxgui/dfxguieditor.cpp
@@ -220,10 +220,10 @@ bool DfxGuiEditor::open(void* inWindow)
#else
mParameterList.assign(static_cast(GetNumParameters()), dfx::kParameterID_Invalid);
std::iota(mParameterList.begin(), mParameterList.end(), 0);
- mParameterList.erase(std::remove_if(mParameterList.begin(), mParameterList.end(), [this](auto parameterID)
- {
- return HasParameterAttribute(parameterID, DfxParam::kAttribute_Unused);
- }), mParameterList.cend());
+ std::erase_if(mParameterList, [this](auto parameterID)
+ {
+ return HasParameterAttribute(parameterID, DfxParam::kAttribute_Unused);
+ });
#endif
mEditorOpenErr = OpenEditor();
@@ -576,10 +576,10 @@ void DfxGuiEditor::randomizeparameters(bool inWriteAutomation)
{
auto parameterList = GetParameterList();
// TODO: C++20 use ranges view filter
- parameterList.erase(std::remove_if(parameterList.begin(), parameterList.end(), [this](auto parameterID)
- {
- return HasParameterAttribute(parameterID, DfxParam::kAttribute_OmitFromRandomizeAll);
- }), parameterList.cend());
+ std::erase_if(parameterList, [this](auto parameterID)
+ {
+ return HasParameterAttribute(parameterID, DfxParam::kAttribute_OmitFromRandomizeAll);
+ });
if (inWriteAutomation)
{
diff --git a/dfxgui/dfxguimisc.cpp b/dfxgui/dfxguimisc.cpp
index 72560b44..27aedfda 100644
--- a/dfxgui/dfxguimisc.cpp
+++ b/dfxgui/dfxguimisc.cpp
@@ -26,6 +26,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
#include
+#include
#include
#include "dfxmisc.h"
@@ -128,7 +129,7 @@ DGColor DGColor::getSystem(System inSystemColorID)
};
#define DFX_SELECTOR(x) @selector(x)
#else
- auto const fromNSColorProperty = []()
+ auto const fromNSColorProperty = []
{
return OptionalColor();
};
@@ -197,8 +198,9 @@ std::string dfx::SanitizeNumericalInput(std::string const& inText)
{
// remove digit separators
// XXX TODO: this doesn't support locale, assumes comma
- std::string resultText(inText.size(), '\0');
- resultText.erase(std::remove_copy(inText.cbegin(), inText.cend(), resultText.begin(), ','), resultText.cend());
+ auto resultText = inText;
+ // TODO: C++20 bind_front
+ std::erase_if(resultText, std::bind(std::equal_to<>{}, std::placeholders::_1, ','));
// trim white space and any other noise (with respect to numerical parsing)
while (!resultText.empty())
diff --git a/eqsync/win32/makefile b/eqsync/win32/makefile
index 1370cc5e..720f583f 100755
--- a/eqsync/win32/makefile
+++ b/eqsync/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../eqsyncdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/fonttest/win32/makefile b/fonttest/win32/makefile
index d2aea0ea..d7965e5b 100755
--- a/fonttest/win32/makefile
+++ b/fonttest/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../fonttestdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/geometer/geometer.cpp b/geometer/geometer.cpp
index 0e448244..bb6dd217 100644
--- a/geometer/geometer.cpp
+++ b/geometer/geometer.cpp
@@ -32,6 +32,7 @@ Featuring the Super Destroy FX Windowing System!
#include
#include
#include
+#include
#include
#include
@@ -272,7 +273,7 @@ void PLUGIN::updatewindowcache(PLUGINCORE * geometercore)
std::copy_n(geometercore->getinput(), GeometerViewData::samples, windowcache_writer->inputs.data());
#else
for (int i=0; i < GeometerViewData::samples; i++) {
- windowcache_writer->inputs[i] = std::sin((i * 10 * dfx::math::kPi) / GeometerViewData::samples);
+ windowcache_writer->inputs[i] = std::sin((i * 10 * std::numbers::pi_v) / GeometerViewData::samples);
}
#endif
@@ -1049,7 +1050,7 @@ int PLUGINCORE::processw(float const * in, float * out, int samples,
for(int z=px[u-1]; z < px[u]; z++) {
float const pct = (float)(z-px[u-1]) / denom;
- float p = 0.5f * (-std::cos(dfx::math::kPi * pct) + 1.0f);
+ float p = 0.5f * (-std::cos(std::numbers::pi_v * pct) + 1.0f);
if (interparam > 0.5f) {
p = std::pow(p, (interparam - 0.16666667f) * 3.0f);
@@ -1121,7 +1122,7 @@ int PLUGINCORE::processw(float const * in, float * out, int samples,
for(int z=px[u-1]; z < px[u]; z++) {
float const pct = (float)(z-px[u-1]) * oodenom;
- float const wand = sinf(2.0f * dfx::math::kPi * pct);
+ float const wand = sinf(2.0f * std::numbers::pi_v * pct);
out[z] = wand *
interparam +
((1.0f-interparam) *
@@ -1290,7 +1291,7 @@ void PLUGINCORE::updatewindowshape()
break;
case WINDOW_COS:
for(int z = 0; z < third; z++) {
- float const p = 0.5f * (-std::cos(dfx::math::kPi * (static_cast(z) * oneDivThird)) + 1.0f);
+ float const p = 0.5f * (-std::cos(std::numbers::pi_v * (static_cast(z) * oneDivThird)) + 1.0f);
windowenvelope[z] = p;
windowenvelope[z+third] = (1.0f - p);
}
diff --git a/geometer/win32/makefile b/geometer/win32/makefile
index aae05836..84ea584f 100755
--- a/geometer/win32/makefile
+++ b/geometer/win32/makefile
@@ -19,7 +19,7 @@ VSTGUI=../../vstgui/vstgui
# https://sourceforge.net/p/mingw-w64/mailman/mingw-w64-public/thread/20200920130036.1e6b6508%40ext.localdomain/
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../geometerdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/midigater/win32/makefile b/midigater/win32/makefile
index 6a6b0549..9235f51c 100644
--- a/midigater/win32/makefile
+++ b/midigater/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../midigaterdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/monomaker/win32/makefile b/monomaker/win32/makefile
index 2378c49d..afb69647 100755
--- a/monomaker/win32/makefile
+++ b/monomaker/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../monomakerdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/polarizer/win32/makefile b/polarizer/win32/makefile
index 4b878aab..ca7e3728 100755
--- a/polarizer/win32/makefile
+++ b/polarizer/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../polarizerdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/rezsynth/rezsynthformalities.cpp b/rezsynth/rezsynthformalities.cpp
index 0e985392..fcedba28 100644
--- a/rezsynth/rezsynthformalities.cpp
+++ b/rezsynth/rezsynthformalities.cpp
@@ -22,6 +22,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include "rezsynth.h"
#include
+#include
#include "dfxmath.h"
#include "dfxmisc.h"
@@ -122,7 +123,7 @@ RezSynth::RezSynth(TARGET_API_BASE_INSTANCE_TYPE inInstance)
long RezSynth::initialize()
{
// these are values that are always needed during calculateCoefficients
- mPiDivSR = dfx::math::kPi / getsamplerate();
+ mPiDivSR = std::numbers::pi_v / getsamplerate();
mTwoPiDivSR = mPiDivSR * 2.0;
mNyquist = getsamplerate() / 2.0;
diff --git a/rezsynth/rezsynthsubprocesses.cpp b/rezsynth/rezsynthsubprocesses.cpp
index 642882b2..f32e1f51 100644
--- a/rezsynth/rezsynthsubprocesses.cpp
+++ b/rezsynth/rezsynthsubprocesses.cpp
@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
-Copyright (C) 2001-2021 Sophia Poirier
+Copyright (C) 2001-2022 Sophia Poirier
This file is part of Rez Synth.
@@ -40,7 +40,6 @@ double RezSynth::calculateAmpEvener(int currentNote) const
if (mScaleMode <= kScaleMode_None)
{
-// ampEvener = 0.0000000000009 * std::pow((static_cast(fBandwidth) + 0.72), 1.8) * baseFreq * baseFreq / std::sqrt(static_cast(mNumBands) * 0.0000003);
ampEvener = 0.0000000000009 * std::pow(contractparametervalue(kBandwidthAmount_Hz, noteBandwidth) + 0.72, 1.8) * baseFreq * baseFreq / std::sqrt(static_cast(mNumBands) * 0.0000003);
}
else if (mScaleMode == kScaleMode_RMS)
@@ -210,11 +209,7 @@ void RezSynth::processFilterOuts(float const* const* inAudio, float* const* outA
{
auto const clampInfinities = [](double value)
{
-#if __GNUC__
- if (__builtin_expect(std::isinf(value), 0)) // TODO: C++20 [[unlikely]]
-#else
- if (std::isinf(value))
-#endif
+ if (std::isinf(value)) [[unlikely]]
{
return std::copysign(std::numeric_limits::max(), value);
}
@@ -248,11 +243,7 @@ void RezSynth::processFilterOuts(float const* const* inAudio, float* const* outA
outAudio[ch][sampleIndex] += scaledBandOutputSum * envedTotalAmp;
}
-#if __GNUC__
- if (__builtin_expect(std::isinf(outAudio[ch][sampleIndex]), 0)) // TODO: C++20 [[unlikely]]
-#else
- if (std::isinf(outAudio[ch][sampleIndex]))
-#endif
+ if (std::isinf(outAudio[ch][sampleIndex])) [[unlikely]]
{
outAudio[ch][sampleIndex] = entryOutput;
}
diff --git a/rezsynth/win32/makefile b/rezsynth/win32/makefile
index 173e8672..17311e55 100755
--- a/rezsynth/win32/makefile
+++ b/rezsynth/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../rezsynthdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/scrubby/scrubbyprocess.cpp b/scrubby/scrubbyprocess.cpp
index fff03e1d..f4dfd607 100644
--- a/scrubby/scrubbyprocess.cpp
+++ b/scrubby/scrubbyprocess.cpp
@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
-Copyright (C) 2002-2021 Sophia Poirier
+Copyright (C) 2002-2022 Sophia Poirier
This file is part of Scrubby.
@@ -23,6 +23,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
+#include
#include "dfxmath.h"
@@ -37,7 +38,7 @@ inline double calculateTargetSpeed(double a, double n, double k)
double const lambertInput = (n * a) / k;
double b = k * dfx::math::LambertW(lambertInput) / n; // the target speed
// cuz I don't totally trust my Lambert W function...
- if (std::isnan(b) || !std::isfinite(b))
+ if (!std::isfinite(b))
{
b = 1.0;
}
@@ -430,8 +431,8 @@ void Scrubby::processaudio(float const* const* inAudio, float* const* outAudio,
#if 0 // melody test
for (unsigned long ch = 0; ch < numChannels; ch++)
{
- mAudioBuffers[ch][mWritePos] = 0.69f * std::sin(24.0f * dfx::math::kPi * (static_cast(samplecount) / static_cast(inNumFrames)));
- mAudioBuffers[ch][mWritePos] = 0.69f * std::sin(2.0f * dfx::math::kPi * (static_cast(mSineCount) / 169.0f));
+ mAudioBuffers[ch][mWritePos] = 0.69f * std::sin(24.f * std::numbers::pi_v * (static_cast(samplecount) / static_cast(inNumFrames)));
+ mAudioBuffers[ch][mWritePos] = 0.69f * std::sin(2.f * std::numbers::pi_v * (static_cast(mSineCount) / 169.f));
}
// produce a sine wave of C4 when using 44.1 kHz sample rate
if (++mSineCount > 168)
diff --git a/scrubby/win32/makefile b/scrubby/win32/makefile
index 2a345b46..93788876 100755
--- a/scrubby/win32/makefile
+++ b/scrubby/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../scrubbydef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/skidder/win32/makefile b/skidder/win32/makefile
index c5f686b7..155ad462 100755
--- a/skidder/win32/makefile
+++ b/skidder/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../skidderdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
diff --git a/thrush/thrush.cpp b/thrush/thrush.cpp
index 913b8231..528a375a 100644
--- a/thrush/thrush.cpp
+++ b/thrush/thrush.cpp
@@ -23,6 +23,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
+#include
#include "dfxmisc.h"
@@ -223,7 +224,7 @@ double Thrush::processLFOs(ThrushLFO& lfoLayer1, ThrushLFO& lfoLayer2) const
auto lfoOffset = lfoLayer2.process(); // this is the offset from the first layer LFO's rate, caused by the second layer LFO
// scale the 0 - 1 LFO output value to the depth range of the second layer LFO
- lfoOffset = (lfoOffset * (kLFO2DepthMax - kLFO2DepthMin)) + kLFO2DepthMin;
+ lfoOffset = std::lerp(kLFO2DepthMin, kLFO2DepthMax, lfoOffset);
// update the first layer LFO's cycle phase step size as modulated by the second layer LFO
lfoLayer1.setStepSize(lfoLayer1.mEffectiveRateHz * lfoOffset * mOneDivSR);
diff --git a/transverb/gui/transverbeditor.cpp b/transverb/gui/transverbeditor.cpp
index 8a1e8133..3237e650 100644
--- a/transverb/gui/transverbeditor.cpp
+++ b/transverb/gui/transverbeditor.cpp
@@ -153,12 +153,12 @@ static bool speedDisplayProcedure(float inValue, char* outText, void*)
static std::optional speedTextConvertProcedure(std::string const& inText, DGTextDisplay*)
{
- std::string filteredText(inText.size(), '\0');
+ auto filteredText = inText;
// TODO: does not support locale for number format, and ignores minus and periods that are not part of fractional numbers
- filteredText.erase(std::remove_copy_if(inText.cbegin(), inText.cend(), filteredText.begin(), [](auto character)
- {
- return !(std::isdigit(character) || std::isspace(character) || (character == '-') || (character == '.'));
- }), filteredText.cend());
+ std::erase_if(filteredText, [](auto character)
+ {
+ return !(std::isdigit(character) || std::isspace(character) || (character == '-') || (character == '.'));
+ });
float octaves = 0.0f, semitones = 0.0f;
auto const scanCount = sscanf(filteredText.c_str(), "%f%f", &octaves, &semitones);
diff --git a/transverb/transverb.h b/transverb/transverb.h
index 7d8724a5..2ce28536 100644
--- a/transverb/transverb.h
+++ b/transverb/transverb.h
@@ -25,6 +25,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
#include
+#include
#include
#include "dfxplugin.h"
@@ -74,7 +75,7 @@ class TransverbDSP final : public DfxPluginCore {
static constexpr float interpolateLinear(float value1, float value2, double address)
{
auto const posFract = static_cast(std::fmod(address, 1.));
- return (value1 * (1.0f - posFract)) + (value2 * posFract);
+ return std::lerp(value1, value2, posFract);
}
static constexpr float interpolateLinear(float const* data, double readaddress, int arraysize/*, int writeaddress*/);
diff --git a/transverb/transverbprocess.cpp b/transverb/transverbprocess.cpp
index 65fd9316..803ed4dd 100644
--- a/transverb/transverbprocess.cpp
+++ b/transverb/transverbprocess.cpp
@@ -24,6 +24,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
#include
+#include
#include "dfxmath.h"
#include "firfilter.h"
@@ -90,8 +91,7 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
if (std::exchange(heads[h].speedHasChanged, false))
{
dfx::FIRFilter::calculateIdealLowpassCoefficients((samplerate / heads[h].speed.getValue()) * dfx::FIRFilter::kShelfStartLowpass,
- samplerate, kNumFIRTaps, heads[h].firCoefficients.data(),
- firCoefficientsWindow.data());
+ samplerate, heads[h].firCoefficients, firCoefficientsWindow);
heads[h].filter.reset();
}
}
@@ -138,10 +138,10 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
case FilterMode::LowpassFIR:
{
// get two consecutive FIR output values for linear interpolation
- auto const lp1 = dfx::FIRFilter::process(heads[h].buf.data(), kNumFIRTaps, heads[h].firCoefficients.data(),
- mod_bipolar(read_int - static_cast(kNumFIRTaps), bsize), bsize);
- auto const lp2 = dfx::FIRFilter::process(heads[h].buf.data(), kNumFIRTaps, heads[h].firCoefficients.data(),
- mod_bipolar(read_int - static_cast(kNumFIRTaps) + 1, bsize), bsize);
+ auto const lp1 = dfx::FIRFilter::process(std::span(heads[h].buf).subspan(0, bsize), heads[h].firCoefficients,
+ mod_bipolar(read_int - static_cast(kNumFIRTaps), bsize));
+ auto const lp2 = dfx::FIRFilter::process(std::span(heads[h].buf).subspan(0, bsize), heads[h].firCoefficients,
+ mod_bipolar(read_int - static_cast(kNumFIRTaps) + 1, bsize));
// interpolate output linearly (avoid shit sound) and compensate gain
delayvals[h] = interpolateLinear(lp1, lp2, heads[h].read) * mugs[h];
break;
@@ -157,7 +157,7 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
// the current sample if smoothing is in progress
if (heads[h].smoothcount > 0) {
auto const smoothpos = heads[h].smoothstep * static_cast(heads[h].smoothcount);
- delayvals[h] = (delayvals[h] * (1.f - smoothpos)) + (heads[h].lastdelayval * smoothpos);
+ delayvals[h] = std::lerp(delayvals[h], heads[h].lastdelayval, smoothpos);
heads[h].smoothcount--;
}
diff --git a/transverb/win32/makefile b/transverb/win32/makefile
index 5203e074..2c267450 100755
--- a/transverb/win32/makefile
+++ b/transverb/win32/makefile
@@ -17,7 +17,7 @@ VSTGUI=../../vstgui/vstgui
# -DENABLE_TRACE=1
DEFINES=-DWIN32=1 -D_WIN32_WINNT=0x0601 -DTARGET_OS_WIN32=1 -DTARGET_API_VST=1 -DVSTGUI_ENABLE_DEPRECATED_METHODS=0 -DNDEBUG=1 -DGetMatchingFonts=GetMatchingFonts_
INCLUDES=-I .. -I $(DFXLIB) -I $(VSTSDK) -I $(DFXGUI) -I $(VSTGUI) -I $(VSTGUI)/plugin-bindings -include "../transverbdef.h"
-CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++17 -O2
+CXXFLAGS=$(DEFINES) $(INCLUDES) -m64 -Wall -Wno-unknown-pragmas --std=c++20 -O2
# -mwindows to select the GUI subsystem (not console)
# -s (strip unexported symbols) for release! 18mb DLL unstripped, 2.5mb stripped.
# -static-libgcc and -static-libstdc++ avoid having the output depend on these mingw DLLs.
From 69561071a6d56b5867fcbff256b9bc5be41ea9a2 Mon Sep 17 00:00:00 2001
From: Sophia Poirier <2997196+sophiapoirier@users.noreply.github.com>
Date: Sat, 19 Feb 2022 16:28:32 -0800
Subject: [PATCH 3/3] Transverb: various approaches to adapt to "distance"
changes without crackly glitches
---
transverb/transverb-base.h | 3 ++
transverb/transverb.h | 18 ++++++-
transverb/transverbformalities.cpp | 81 +++++++++++++++++++++++++++---
transverb/transverbprocess.cpp | 66 ++++++++++++++++--------
4 files changed, 137 insertions(+), 31 deletions(-)
diff --git a/transverb/transverb-base.h b/transverb/transverb-base.h
index 969ea82a..27a64631 100644
--- a/transverb/transverb-base.h
+++ b/transverb/transverb-base.h
@@ -47,6 +47,7 @@ enum
kTomsound,
kFreeze,
kAttenuateFeedbackByMixLevel,
+ kDistChangeMode,
kNumParameters
};
@@ -65,6 +66,8 @@ enum { kQualityMode_DirtFi, kQualityMode_HiFi, kQualityMode_UltraHiFi, kQualityM
enum { kSpeedMode_Fine, kSpeedMode_Semitone, kSpeedMode_Octave, kSpeedMode_NumModes };
static constexpr dfx::PropertyID kTransverbProperty_SpeedModeBase = dfx::kPluginProperty_EndOfList;
+enum { kDistChangeMode_Reverse, kDistChangeMode_AdHocVarispeed, kDistChangeMode_DistanceVarispeed, kDistChangeMode_BufferVarispeed, kDistChangeMode_LoopingBufferVarispeed, kDistChangeMode_Count };
+
dfx::PropertyID speedModeIndexToPropertyID(size_t inIndex) noexcept;
size_t speedModePropertyIDToIndex(dfx::PropertyID inPropertyID) noexcept;
diff --git a/transverb/transverb.h b/transverb/transverb.h
index 2ce28536..61804eb1 100644
--- a/transverb/transverb.h
+++ b/transverb/transverb.h
@@ -26,6 +26,7 @@ To contact the author, use the contact form at http://destroyfx.org/
#include
#include
#include
+#include
#include
#include "dfxplugin.h"
@@ -57,6 +58,8 @@ class TransverbDSP final : public DfxPluginCore {
dfx::SmoothedValue mix, feed;
double read = 0.;
+ std::optional targetdist;
+ double distspeedfactor = 1.;
std::vector buf;
dfx::IIRFilter filter;
@@ -83,17 +86,23 @@ class TransverbDSP final : public DfxPluginCore {
static constexpr int mod_bipolar(int value, int modulo);
static inline double fmod_bipolar(double value, double modulo);
+ // distance in samples of a read position from the current write position
+ double getdist(double read) const;
+ void processdist(double distnormalized, Head& head);
+
// these store the parameter values
int bsize = 0;
dfx::SmoothedValue drymix;
- long quality = 0;
- bool tomsound = false;
+ int distchangemode {};
int writer = 0;
std::array heads;
int const MAXBUF; // the size of the audio buffer (dependent on sampling rate)
+ bool firstrendersincereset = false;
+ std::vector& buftemp;
+
std::vector const firCoefficientsWindow;
};
@@ -116,6 +125,10 @@ class Transverb final : public DfxPlugin {
long dfx_SetProperty(dfx::PropertyID inPropertyID, dfx::Scope inScope, unsigned long inItemIndex,
void const* inData, size_t inDataSize) override;
+ auto& getscratchbuffer() noexcept {
+ return buftemp;
+ }
+
protected:
size_t settings_sizeOfExtendedData() const noexcept override;
void settings_saveExtendedData(void* outData, bool isPreset) override;
@@ -132,6 +145,7 @@ class Transverb final : public DfxPlugin {
}
std::array speedModeStates {};
+ std::vector buftemp; // shared between all DSP cores (memory optimization)
};
diff --git a/transverb/transverbformalities.cpp b/transverb/transverbformalities.cpp
index e87b1079..93947a8b 100644
--- a/transverb/transverbformalities.cpp
+++ b/transverb/transverbformalities.cpp
@@ -57,6 +57,7 @@ Transverb::Transverb(TARGET_API_BASE_INSTANCE_TYPE inInstance)
initparameter_b(kTomsound, {"TOMSOUND", "TomSnd", "Tom7"}, false);
initparameter_b(kFreeze, dfx::MakeParameterNames(dfx::kParameterNames_Freeze), false);
initparameter_b(kAttenuateFeedbackByMixLevel, {"attenuate feedback by mix level", "AtnFdbk", "AtnFdb", "-fdb"}, false);
+ initparameter_list(kDistChangeMode, {"distance change mode", "DistMod", "DstMod", "DMod"}, kDistChangeMode_Reverse, kDistChangeMode_Reverse, kDistChangeMode_Count);
setparameterenforcevaluelimits(kBsize, true);
setparameterenforcevaluelimits(kDist1, true);
@@ -66,10 +67,12 @@ Transverb::Transverb(TARGET_API_BASE_INSTANCE_TYPE inInstance)
setparametervaluestring(kQuality, kQualityMode_HiFi, "hi-fi");
setparametervaluestring(kQuality, kQualityMode_UltraHiFi, "ultra hi-fi");
- // distance parameters only have meaningful effect at zero speed which probably will never occur randomly,
- // and otherwise all they do is glitch a lot, so omit them
- addparameterattributes(kDist1, DfxParam::kAttribute_OmitFromRandomizeAll);
- addparameterattributes(kDist2, DfxParam::kAttribute_OmitFromRandomizeAll);
+ setparametervaluestring(kDistChangeMode, kDistChangeMode_Reverse, "reverse");
+ setparametervaluestring(kDistChangeMode, kDistChangeMode_AdHocVarispeed, "ad hoc varispeed");
+ setparametervaluestring(kDistChangeMode, kDistChangeMode_DistanceVarispeed, "distance varispeed");
+ setparametervaluestring(kDistChangeMode, kDistChangeMode_BufferVarispeed, "buffer varispeed");
+ setparametervaluestring(kDistChangeMode, kDistChangeMode_LoopingBufferVarispeed, "looping buffer varispeed");
+
addparameterattributes(kFreeze, DfxParam::kAttribute_OmitFromRandomizeAll);
addparameterattributes(kAttenuateFeedbackByMixLevel, DfxParam::kAttribute_OmitFromRandomizeAll);
@@ -108,8 +111,11 @@ void Transverb::dfx_PostConstructor() {
TransverbDSP::TransverbDSP(DfxPlugin* inDfxPlugin)
: DfxPluginCore(inDfxPlugin),
MAXBUF(static_cast(getparametermax_f(kBsize) * 0.001 * getsamplerate())),
+ buftemp(dynamic_cast(inDfxPlugin)->getscratchbuffer()),
firCoefficientsWindow(dfx::FIRFilter::generateKaiserWindow(kNumFIRTaps, 60.0f)) {
+ buftemp.assign(MAXBUF, 0.f);
+
registerSmoothedAudioValue(&drymix);
for (auto& head : heads) {
@@ -125,12 +131,15 @@ TransverbDSP::TransverbDSP(DfxPlugin* inDfxPlugin)
void TransverbDSP::reset() {
std::for_each(heads.begin(), heads.end(), [](Head& head){ head.reset(); });
+
+ firstrendersincereset = true;
}
void TransverbDSP::Head::reset() {
smoothcount = 0;
lastdelayval = 0.f;
+ targetdist.reset();
filter.reset();
speedHasChanged = true;
@@ -163,8 +172,6 @@ void TransverbDSP::processparameters() {
heads[head].feed = *value;
}
}
- quality = getparameter_i(kQuality);
- tomsound = getparameter_b(kTomsound);
if (auto const value = getparameterifchanged_f(kBsize))
{
@@ -192,12 +199,12 @@ void TransverbDSP::processparameters() {
std::for_each(heads.begin(), heads.end(), [bsize_f](Head& head){ head.read = fmod_bipolar(head.read, bsize_f); });
}
+ distchangemode = getparameter_i(kDistChangeMode);
for (size_t head = 0; head < kNumDelays; head++)
{
if (auto const dist = getparameterifchanged_f(kDistParameters[head]))
{
- auto const bsize_f = static_cast(bsize);
- heads[head].read = fmod_bipolar(static_cast(writer) - (*dist * bsize_f), bsize_f);
+ processdist(*dist, heads[head]);
}
}
@@ -220,6 +227,64 @@ void TransverbDSP::processparameters() {
heads[0].mix.setValueNow(getparametermin_f(kMix1));
}
}
+
+ firstrendersincereset = false;
+}
+
+double TransverbDSP::getdist(double read) const {
+
+ return fmod_bipolar(static_cast(writer) - read, static_cast(bsize));
+}
+
+void TransverbDSP::processdist(double distnormalized, Head& head) {
+
+ auto const bsize_f = static_cast(bsize);
+ auto const distsamples = distnormalized * bsize_f;
+ auto const targetread = fmod_bipolar(static_cast(writer) - distsamples, bsize_f);
+
+ if (firstrendersincereset)
+ {
+ head.read = targetread;
+ }
+ else
+ {
+ if (distchangemode == kDistChangeMode_Reverse)
+ {
+ head.targetdist = distsamples;
+ }
+ else if (auto const resamplerate = getdist(head.read) / std::max(distsamples, 1.); distchangemode == kDistChangeMode_AdHocVarispeed)
+ {
+ head.targetdist = distsamples;
+ head.distspeedfactor = resamplerate;
+ head.speedHasChanged = true;
+ }
+ else
+ {
+ constexpr double modulationthresholdsamples = 1.;
+ if (std::fabs(targetread - head.read) >= modulationthresholdsamples)
+ {
+ auto const bsizesteps = bsize_f / resamplerate;
+ bool const subslice = (distchangemode == kDistChangeMode_DistanceVarispeed);
+ bool const looping = (distchangemode == kDistChangeMode_LoopingBufferVarispeed);
+ auto const copylength_f = subslice ? distsamples : (looping ? bsize_f : std::min(bsize_f, bsizesteps));
+ auto const copylength = static_cast(std::lround(copylength_f));
+ assert(copylength <= buftemp.size());
+ assert(static_cast(copylength) <= bsize);
+ auto const sourcestart = subslice ? head.read : fmod_bipolar(static_cast(writer) - (copylength_f * resamplerate), bsize_f);
+ for (size_t i = 0; i < copylength; i++)
+ {
+ auto const sourcepos = std::fmod(sourcestart + (resamplerate * static_cast(i)), bsize_f);
+ buftemp[i] = interpolateHermite(head.buf.data(), sourcepos, bsize, writer);
+ }
+ auto const destinationstart = subslice ? std::lround(targetread) : mod_bipolar(writer - static_cast(copylength), bsize);
+ auto const copylength1 = std::min(static_cast(bsize - destinationstart), copylength);
+ auto const copylength2 = copylength - copylength1;
+ std::copy_n(buftemp.cbegin(), copylength1, std::next(head.buf.begin(), destinationstart));
+ std::copy_n(std::next(buftemp.cbegin(), copylength1), copylength2, head.buf.begin());
+ }
+ head.read = targetread;
+ }
+ }
}
diff --git a/transverb/transverbprocess.cpp b/transverb/transverbprocess.cpp
index 803ed4dd..5927940c 100644
--- a/transverb/transverbprocess.cpp
+++ b/transverb/transverbprocess.cpp
@@ -36,11 +36,13 @@ using namespace dfx::TV;
void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long numSampleFrames) {
- std::array delayvals {}; // delay buffer output values
auto const bsize_float = static_cast(bsize); // cut down on casting
+ auto const quality = getparameter_i(kQuality);
+ auto const tomsound = getparameter_b(kTomsound);
auto const freeze = getparameter_b(kFreeze);
int const writerIncrement = freeze ? 0 : 1;
auto const attenuateFeedbackByMixLevel = getparameter_b(kAttenuateFeedbackByMixLevel);
+ std::array delayvals {}; // delay buffer output values
///////////// S O P H I A S O U N D //////////////
@@ -69,6 +71,9 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
for (size_t h = 0; h < kNumDelays; h++) // delay heads loop
{
auto const read_int = static_cast(heads[h].read);
+ auto const reverseread = (distchangemode == kDistChangeMode_Reverse) && heads[h].targetdist.has_value();
+ auto const distcatchup = (distchangemode == kDistChangeMode_AdHocVarispeed) && heads[h].targetdist.has_value();
+ auto const speed = heads[h].speed.getValue() * (distcatchup ? heads[h].distspeedfactor : 1.);
// filter setup
if (quality == kQualityMode_UltraHiFi)
@@ -77,27 +82,27 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
{
lowpasspos[h] = read_int;
// check to see if we need to lowpass the first delay head and init coefficients if so
- if (heads[h].speed.getValue() > kUnitySpeed)
+ if (speed > kUnitySpeed)
{
filtermodes[h] = FilterMode::LowpassIIR;
- speed_ints[h] = static_cast(heads[h].speed.getValue());
+ speed_ints[h] = static_cast(speed);
// it becomes too costly to try to IIR at higher speeds, so switch to FIR filtering
- if (heads[h].speed.getValue() >= kFIRSpeedThreshold)
+ if (speed >= kFIRSpeedThreshold)
{
filtermodes[h] = FilterMode::LowpassFIR;
// compensate for gain lost from filtering
- mugs[h] = static_cast(std::pow(heads[h].speed.getValue() / kFIRSpeedThreshold, 0.78));
+ mugs[h] = static_cast(std::pow(speed / kFIRSpeedThreshold, 0.78));
// update the coefficients only if necessary
if (std::exchange(heads[h].speedHasChanged, false))
{
- dfx::FIRFilter::calculateIdealLowpassCoefficients((samplerate / heads[h].speed.getValue()) * dfx::FIRFilter::kShelfStartLowpass,
+ dfx::FIRFilter::calculateIdealLowpassCoefficients((samplerate / speed) * dfx::FIRFilter::kShelfStartLowpass,
samplerate, heads[h].firCoefficients, firCoefficientsWindow);
heads[h].filter.reset();
}
}
else if (std::exchange(heads[h].speedHasChanged, false))
{
- heads[h].filter.setLowpassCoefficients((samplerate / heads[h].speed.getValue()) * dfx::IIRFilter::kShelfStartLowpass);
+ heads[h].filter.setLowpassCoefficients((samplerate / speed) * dfx::IIRFilter::kShelfStartLowpass);
}
}
// we need to highpass the delay head to remove mega sub bass
@@ -106,7 +111,7 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
filtermodes[h] = FilterMode::Highpass;
if (std::exchange(heads[h].speedHasChanged, false))
{
- heads[h].filter.setHighpassCoefficients(kHighpassFilterCutoff / heads[h].speed.getValue());
+ heads[h].filter.setHighpassCoefficients(kHighpassFilterCutoff / speed);
}
}
}
@@ -173,18 +178,18 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
// start smoothing if the writer has passed a reader or vice versa,
// though not if reader and writer move at the same speed
// (check the positions before wrapping around the heads)
- auto const nextRead = static_cast(heads[h].read + heads[h].speed.getValue());
+ auto const nextRead = static_cast(heads[h].read + speed);
auto const nextWrite = writer + 1;
bool const readCrossingAhead = (read_int < writer) && (nextRead >= nextWrite);
bool const readCrossingBehind = (read_int >= writer) && (nextRead <= nextWrite);
- bool const speedIsUnity = heads[h].speed.getValue() == kUnitySpeed;
+ bool const speedIsUnity = (speed == kUnitySpeed);
if ((readCrossingAhead || readCrossingBehind) && !speedIsUnity) {
// check because, at slow speeds, it's possible to go into this twice or more in a row
if (heads[h].smoothcount <= 0) {
// store the most recent output as the head's smoothing sample
heads[h].lastdelayval = delayvals[h];
// truncate the smoothing duration if we're using too small of a buffer size
- auto const bufferReadSteps = static_cast(bsize_float / heads[h].speed.getValue());
+ auto const bufferReadSteps = static_cast(bsize_float / speed);
auto const smoothdur = std::min(bufferReadSteps, kAudioSmoothingDur_samples);
heads[h].smoothstep = 1.f / static_cast(smoothdur); // the scalar step value
heads[h].smoothcount = smoothdur; // set the counter to the total duration
@@ -192,9 +197,21 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
}
// update read heads, wrapping around if they have gone past the end of the buffer
- heads[h].read += heads[h].speed.getValue();
- if (heads[h].read >= bsize_float) {
- heads[h].read = fmod_bipolar(heads[h].read, bsize_float);
+ if (reverseread) {
+ heads[h].read -= speed;
+ while (heads[h].read < 0.) {
+ heads[h].read += bsize_float;
+ }
+ } else {
+ heads[h].read += speed;
+ if (heads[h].read >= bsize_float) {
+ heads[h].read = fmod_bipolar(heads[h].read, bsize_float);
+ }
+ }
+ if (distcatchup || reverseread) {
+ if (std::fabs(getdist(heads[h].read) - *heads[h].targetdist) < speed) {
+ heads[h].targetdist.reset();
+ }
}
// if we're doing IIR lowpass filtering,
@@ -204,40 +221,47 @@ void TransverbDSP::process(float const* inAudio, float* outAudio, unsigned long
if (filtermodes[h] == FilterMode::LowpassIIR)
{
int lowpasscount = 0;
+ int const direction = reverseread ? -1 : 1;
while (lowpasscount < speed_ints[h])
{
switch (speed_ints[h] - lowpasscount)
{
case 1:
heads[h].filter.processToCacheH1(heads[h].buf[lowpasspos[h]]);
- lowpasspos[h] = (lowpasspos[h] + 1) % bsize;
+ lowpasspos[h] = mod_bipolar(lowpasspos[h] + (1 * direction), bsize);
lowpasscount++;
break;
case 2:
heads[h].filter.processToCacheH2(heads[h].buf.data(), lowpasspos[h], bsize);
- lowpasspos[h] = (lowpasspos[h] + 2) % bsize;
+ lowpasspos[h] = mod_bipolar(lowpasspos[h] + (2 * direction), bsize);
lowpasscount += 2;
break;
case 3:
heads[h].filter.processToCacheH3(heads[h].buf.data(), lowpasspos[h], bsize);
- lowpasspos[h] = (lowpasspos[h] + 3) % bsize;
+ lowpasspos[h] = mod_bipolar(lowpasspos[h] + (3 * direction), bsize);
lowpasscount += 3;
break;
default:
heads[h].filter.processToCacheH4(heads[h].buf.data(), lowpasspos[h], bsize);
- lowpasspos[h] = (lowpasspos[h] + 4) % bsize;
+ lowpasspos[h] = mod_bipolar(lowpasspos[h] + (4 * direction), bsize);
lowpasscount += 4;
break;
}
}
auto const nextread_int = static_cast(heads[h].read);
// check whether we need to consume one more sample
- bool const extrasample = ((lowpasspos[h] < nextread_int) && ((lowpasspos[h] + 1) == nextread_int)) ||
- ((lowpasspos[h] == (bsize - 1)) && (nextread_int == 0));
+ bool const extrasample = [=] {
+ if (reverseread) {
+ return ((lowpasspos[h] > nextread_int) && ((lowpasspos[h] - 1) == nextread_int)) ||
+ ((lowpasspos[h] == 0) && (nextread_int == (bsize - 1)));
+ }
+ return ((lowpasspos[h] < nextread_int) && ((lowpasspos[h] + 1) == nextread_int)) ||
+ ((lowpasspos[h] == (bsize - 1)) && (nextread_int == 0));
+ }();
if (extrasample)
{
heads[h].filter.processToCacheH1(heads[h].buf[lowpasspos[h]]);
- lowpasspos[h] = (lowpasspos[h] + 1) % bsize;
+ lowpasspos[h] = mod_bipolar(lowpasspos[h] + (1 * direction), bsize);
}
}
// it's simpler for highpassing;