Skip to content

Commit

Permalink
Add SpectralPhaser presets
Browse files Browse the repository at this point in the history
  • Loading branch information
ryukau committed Oct 24, 2024
1 parent 918aef9 commit b2fbd03
Show file tree
Hide file tree
Showing 46 changed files with 50,453 additions and 116 deletions.
2 changes: 1 addition & 1 deletion SpectralPhaser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set(UHHYOU_USE_FFTW True)
include(../common/cmake/non_simd.cmake)

if(TEST_PLUGIN)
build_test("")
build_test(source/dsp/spectralfilter.cpp)
else()
# VST 3 source files.
set(plug_sources
Expand Down
13 changes: 7 additions & 6 deletions SpectralPhaser/source/dsp/dspcore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,18 @@ size_t DSPCore::getLatency() { return spcParam.reportLatency ? spcParam.frmSize
feedback.METHOD(pv[ID::feedback]->getFloat()); \
const auto spcShift = Sample(0.5) * pv[ID::spectralShift]->getFloat(); \
spectralShift.METHOD(spcShift - std::floor(spcShift)); \
octaveDown.METHOD(pv[ID::octaveDown]->getFloat()); \
\
constexpr Sample twopi = Sample(2) * std::numbers::pi_v<Sample>; \
maskMix.METHOD(pv[ID::maskMix]->getFloat()); \
maskPhase.METHOD(pv[ID::maskPhase]->getFloat()); \
maskFreq.METHOD(pv[ID::maskFreq]->getFloat() / spcParam.frmSize); \
maskChirp.METHOD(pv[ID::maskChirp]->getFloat()); \
maskThreshold.METHOD(pv[ID::maskThreshold]->getFloat()); \
maskRotation.METHOD(pv[ID::maskRotation]->getFloat() * twopi); \
lfoToMaskMix.METHOD(pv[ID::lfoToMaskMix]->getFloat()); \
lfoToMaskPhase.METHOD(pv[ID::lfoToMaskPhase]->getFloat()); \
lfoToMaskFreq.METHOD(pv[ID::lfoToMaskFreq]->getFloat()); \
lfoToMaskChirp.METHOD(pv[ID::lfoToMaskChirp]->getFloat() * Sample(2)); \
lfoToMaskThreshold.METHOD(pv[ID::lfoToMaskThreshold]->getFloat()); \
lfoToMaskRotation.METHOD(pv[ID::lfoToMaskRotation]->getFloat() * twopi); \
lfoToSpectralShift.METHOD(pv[ID::lfoToSpectralShift]->getFloat() * Sample(2)); \
Expand Down Expand Up @@ -127,19 +128,19 @@ DSPCore::processFrame(int frameIndex, Sample in0, Sample in1, Sample side0, Samp
spcParam.dryWetMix = dryWetMix.process();
spcParam.feedback = feedback.process();
spectralShift.process();
octaveDown.process();
maskMix.process();
maskPhase.process();
maskFreq.process();
maskChirp.process();
maskThreshold.process();
maskRotation.process();
lfoToSpectralShift.process();
lfoToMaskMix.process();
lfoToMaskPhase.process();
lfoToMaskFreq.process();
lfoToMaskChirp.process();
lfoToMaskThreshold.process();
lfoToMaskRotation.process();
lfoToSpectralShift.process();
lfoToOctaveDown.process();

const auto modulateParam = [&](Sample unipoler) {
const auto bipoler = unipoler - Sample(0.5);
Expand All @@ -148,8 +149,8 @@ DSPCore::processFrame(int frameIndex, Sample in0, Sample in1, Sample side0, Samp
= spectralShift.getValue() + lfoToSpectralShift.getValue() * bipoler;
spcParam.spectralShift = spcParam.spectralShift - std::floor(spcParam.spectralShift);

spcParam.octaveDown = octaveDown.getValue() + lfoToOctaveDown.getValue() * unipoler;
spcParam.octaveDown -= std::floor(spcParam.octaveDown);
spcParam.maskChirp = maskChirp.getValue() + lfoToMaskChirp.getValue() * unipoler;
spcParam.maskChirp -= std::floor(spcParam.maskChirp);

spcParam.maskMix = std::clamp(
maskMix.getValue() + lfoToMaskMix.getValue() * bipoler, Sample(0), Sample(1));
Expand Down
6 changes: 3 additions & 3 deletions SpectralPhaser/source/dsp/dspcore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,19 @@ class DSPCore {
RotarySmoother<Sample> lfoInitialPhase;
ExpSmoother<Sample> feedback;
ExpSmoother<Sample> spectralShift;
ExpSmoother<Sample> octaveDown;
ExpSmoother<Sample> maskMix;
ExpSmoother<Sample> maskPhase;
RotarySmoother<Sample> maskFreq;
ExpSmoother<Sample> maskChirp;
ExpSmoother<Sample> maskThreshold;
ExpSmoother<Sample> maskRotation;
ExpSmoother<Sample> lfoToSpectralShift;
ExpSmoother<Sample> lfoToMaskMix;
ExpSmoother<Sample> lfoToMaskPhase;
ExpSmoother<Sample> lfoToMaskFreq;
ExpSmoother<Sample> lfoToMaskChirp;
ExpSmoother<Sample> lfoToMaskThreshold;
ExpSmoother<Sample> lfoToMaskRotation;
ExpSmoother<Sample> lfoToSpectralShift;
ExpSmoother<Sample> lfoToOctaveDown;
ExpSmoother<Sample> outputGain;
ExpSmoother<Sample> dryWetMix;

Expand Down
47 changes: 3 additions & 44 deletions SpectralPhaser/source/dsp/spectralfilter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,27 +279,12 @@ template<int maxFrameSizeLog2> struct SpectralDelay {
const int spcShift = prm.spectralShift * spectrumSize;
std::rotate(spcTmp, spcTmp + spcShift, spcTmp + spectrumSize);

spcTmp[0] *= float(1) - prm.octaveDown;

for (int idx = 0; idx < spectrumSize; ++idx) {
spcTmp[idx] *= prm.feedback;
const auto maskValue = mask[idx] > prm.maskThreshold
? mask[idx] * std::polar(float(1), prm.maskRotation * mask[idx])
: float(0);

if ((idx & 1) == 0) {
auto value = spcTmp[idx];
spcTmp[idx] = (float(1) - prm.octaveDown) * value;
spcTmp[idx / 2] += prm.octaveDown * value;
} else {
auto value = spcTmp[idx];
spcTmp[idx] = (float(1) - prm.octaveDown) * value;
spcTmp[idx / 2] += prm.octaveDown * value / float(2);
spcTmp[idx / 2 + 1] += prm.octaveDown * value / float(2);
}

const auto maskValue = mask[idx] > prm.maskThreshold ? mask[idx] : float(0);
spcTmp[idx] += spcSrc[idx] / float(prm.frmSize) * maskValue;
spcSrc[idx] = spcTmp[idx] * std::abs(maskValue);
spcSrc[idx]
= spcTmp[idx] * std::polar(std::abs(maskValue), prm.maskRotation * mask[idx]);
}

fftwf_execute(inversePlan[planIndex]);
Expand Down Expand Up @@ -330,25 +315,12 @@ template<int maxFrameSizeLog2> struct SpectralDelay {
rotation -= std::floor(rotation);
int rotIdx = int(prm.frmSize * rotation);

bufR[0] *= float(1) - prm.octaveDown;

for (int idx = 0; idx < prm.frmSize; ++idx) {
// Using an implementation detail that `prm.frmSize` is always 2^n.
const auto permSrc = (idx + rotIdx) & (prm.frmSize - 1);
const auto permuted = binaryToGrayCode(bitReversal(permSrc, prm.frameSizeLog2));
bufR[idx] *= prm.feedback;

if ((idx & 1) == 0) {
auto value = bufR[idx];
bufR[idx] = (float(1) - prm.octaveDown) * value;
bufR[idx / 2] += prm.octaveDown * value;
} else {
auto value = bufR[idx];
bufR[idx] = (float(1) - prm.octaveDown) * value;
bufR[idx / 2] += prm.octaveDown * value / float(2);
bufR[idx / 2 + 1] += prm.octaveDown * value / float(2);
}

const auto maskValue = mask[idx] > prm.maskThreshold ? mask[idx] : 0;
bufR[idx] += bufW[permuted] * maskValue / float(prm.frmSize);
bufW[permuted] = bufR[idx] * std::abs(maskValue);
Expand Down Expand Up @@ -380,23 +352,10 @@ template<int maxFrameSizeLog2> struct SpectralDelay {
rotation -= std::floor(rotation);
int rotIdx = int(prm.frmSize * rotation);

bufR[0] *= float(1) - prm.octaveDown;

fillMask(prm.frmSize, mask.data(), prm);
for (int idx = 0; idx < prm.frmSize; ++idx) {
bufR[idx] *= prm.feedback;

if ((idx & 1) == 0) {
auto value = bufR[idx];
bufR[idx] = (float(1) - prm.octaveDown) * value;
bufR[idx / 2] += prm.octaveDown * value;
} else {
auto value = bufR[idx];
bufR[idx] = (float(1) - prm.octaveDown) * value;
bufR[idx / 2] += prm.octaveDown * value / float(2);
bufR[idx / 2 + 1] += prm.octaveDown * value / float(2);
}

const auto maskValue = mask[idx] > prm.maskThreshold ? mask[idx] : 0;
bufR[idx] *= std::abs(maskValue);

Expand Down
30 changes: 25 additions & 5 deletions SpectralPhaser/source/dsp/spectralmask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ struct SpectralParameter {
float dryWetMix = float(1);
float feedback = 0;
float spectralShift = 0;
float octaveDown = 0;
float maskMix = float(1);
float maskPhase = 0;
float maskFreq = 0;
float maskChirp = 0;
float maskThreshold = 0;
float maskRotation = 0;
};
Expand All @@ -41,7 +41,8 @@ inline void fillMask(int maskSize, float *mask, SpectralParameter &prm)
phase -= std::floor(phase);
mask[idx] = std::cos(twopi * phase);
mask[idx] = std::lerp(float(1), mask[idx], prm.maskMix);
phase += prm.maskFreq;
phase += prm.maskFreq
* std::lerp(float(1), float(idx) / float(maskSize), prm.maskChirp);
}
} break;
case MaskWaveform::square: {
Expand All @@ -50,7 +51,8 @@ inline void fillMask(int maskSize, float *mask, SpectralParameter &prm)
phase -= std::floor(phase);
mask[idx] = phase < float(0.5) ? float(1) : float(-1);
mask[idx] = std::lerp(float(1), mask[idx], prm.maskMix);
phase += prm.maskFreq;
phase += prm.maskFreq
* std::lerp(float(1), float(idx) / float(maskSize), prm.maskChirp);
}
} break;
case MaskWaveform::sawtoothUp: {
Expand All @@ -59,7 +61,8 @@ inline void fillMask(int maskSize, float *mask, SpectralParameter &prm)
phase -= std::floor(phase);
mask[idx] = float(2) * phase - float(1);
mask[idx] = std::lerp(float(1), mask[idx], prm.maskMix);
phase += prm.maskFreq;
phase += prm.maskFreq
* std::lerp(float(1), float(idx) / float(maskSize), prm.maskChirp);
}
} break;
case MaskWaveform::sawtoothDown: {
Expand All @@ -68,7 +71,8 @@ inline void fillMask(int maskSize, float *mask, SpectralParameter &prm)
phase -= std::floor(phase);
mask[idx] = float(1) - float(2) * phase;
mask[idx] = std::lerp(float(1), mask[idx], prm.maskMix);
phase += prm.maskFreq;
phase += prm.maskFreq
* std::lerp(float(1), float(idx) / float(maskSize), prm.maskChirp);
}
} break;
case MaskWaveform::noise: {
Expand All @@ -79,6 +83,22 @@ inline void fillMask(int maskSize, float *mask, SpectralParameter &prm)
int startIndex = int((prm.maskPhase - std::floor(prm.maskPhase)) * maskSize);
for (int idx = startIndex; idx < maskSize; ++idx) mask[idx] = dist(rng);
for (int idx = 0; idx < startIndex; ++idx) mask[idx] = dist(rng);

float kp = float(1) - prm.maskChirp * float(0.999);
float value = mask[maskSize - 1];
float maxAbs = 0;
for (int idx = maskSize - 1; idx >= 0; --idx) {
value += kp * (mask[idx] - value);
mask[idx] = value;
if (maxAbs < std::abs(value)) maxAbs = value;
}
// if (maxAbs >= std::numeric_limits<float>::epsilon()) {
// for (int idx = 0; idx < maskSize; ++idx) mask[idx] /= maxAbs;
// } else {
for (int idx = 0; idx < maskSize; ++idx) {
mask[idx] = std::clamp(mask[idx], float(-1), float(1));
}
// }
} break;
}
}
Expand Down
20 changes: 15 additions & 5 deletions SpectralPhaser/source/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,22 @@ bool Editor::prepareUI()
lfoLeft1, lfoTop5, labelWidth, labelHeight, uiTextSize, ID::lfoRate, Scales::lfoRate,
false, 5);
addLabel(lfoLeft0, lfoTop6, labelWidth, labelHeight, uiTextSize, "Sync.");
addTextKnob(
auto lfoTempoUpperKnob = addTextKnob(
lfoLeft1, lfoTop6, labelWidthHalf, labelHeight, uiTextSize, ID::lfoTempoUpper,
Scales::lfoTempoSync, false, 0, 1);
addTextKnob(
if (lfoTempoUpperKnob) {
const auto denom = double(Scales::lfoTempoSync.getMax());
lfoTempoUpperKnob->sensitivity = 0.1 / denom;
lfoTempoUpperKnob->lowSensitivity = 0.0125 / denom;
}
auto lfoTempoLowerKnob = addTextKnob(
lfoLeft1 + labelWidthHalf, lfoTop6, labelWidthHalf, labelHeight, uiTextSize,
ID::lfoTempoLower, Scales::lfoTempoSync, false, 0, 1);
if (lfoTempoLowerKnob) {
const auto denom = double(Scales::lfoTempoSync.getMax());
lfoTempoLowerKnob->sensitivity = 0.1 / denom;
lfoTempoLowerKnob->lowSensitivity = 0.0125 / denom;
}

constexpr auto dlyTop0 = top0;
constexpr auto dlyTop1 = dlyTop0 + 1 * labelY;
Expand Down Expand Up @@ -230,11 +240,11 @@ bool Editor::prepareUI()
maskLeft1, maskTop7, labelWidth, labelHeight, uiTextSize, ID::spectralShift,
Scales::bipolarScale, false, 5);
addSmallKnob(maskLeft2Knob, maskTop7, labelHeight, labelHeight, ID::lfoToSpectralShift);
addLabel(maskLeft0, maskTop8, labelWidth, labelHeight, uiTextSize, "Octave Down");
addLabel(maskLeft0, maskTop8, labelWidth, labelHeight, uiTextSize, "Texture");
addTextKnob(
maskLeft1, maskTop8, labelWidth, labelHeight, uiTextSize, ID::octaveDown,
maskLeft1, maskTop8, labelWidth, labelHeight, uiTextSize, ID::maskChirp,
Scales::defaultScale, false, 5);
addSmallKnob(maskLeft2Knob, maskTop8, labelHeight, labelHeight, ID::lfoToOctaveDown);
addSmallKnob(maskLeft2Knob, maskTop8, labelHeight, labelHeight, ID::lfoToMaskChirp);

// Plugin name.
constexpr auto splashMargin = uiMargin - margin;
Expand Down
14 changes: 7 additions & 7 deletions SpectralPhaser/source/parameter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ enum ID {
maskThreshold,
maskRotation,
spectralShift,
octaveDown,
maskChirp,

lfoWaveform,
lfoWaveMod,
Expand All @@ -98,7 +98,7 @@ enum ID {
lfoToMaskThreshold,
lfoToMaskRotation,
lfoToSpectralShift,
lfoToOctaveDown,
lfoToMaskChirp,

reservedParameter0,
reservedGuiParameter0 = reservedParameter0 + nReservedParameter,
Expand Down Expand Up @@ -184,8 +184,8 @@ struct GlobalParameter : public ParameterInterface {
value[ID::spectralShift] = std::make_unique<LinearValue>(
Scales::bipolarScale.invmap(0), Scales::bipolarScale, "spectralShift",
Info::kCanAutomate);
value[ID::octaveDown] = std::make_unique<LinearValue>(
Scales::defaultScale.invmap(0), Scales::defaultScale, "octaveDown",
value[ID::maskChirp] = std::make_unique<LinearValue>(
Scales::defaultScale.invmap(0), Scales::defaultScale, "maskChirp",
Info::kCanAutomate);

value[ID::lfoWaveform] = std::make_unique<UIntValue>(
Expand Down Expand Up @@ -224,8 +224,8 @@ struct GlobalParameter : public ParameterInterface {
value[ID::lfoToSpectralShift] = std::make_unique<LinearValue>(
Scales::bipolarScale.invmap(0), Scales::bipolarScale, "lfoToSpectralShift",
Info::kCanAutomate);
value[ID::lfoToOctaveDown] = std::make_unique<LinearValue>(
Scales::bipolarScale.invmap(0), Scales::bipolarScale, "lfoToOctaveDown",
value[ID::lfoToMaskChirp] = std::make_unique<LinearValue>(
Scales::bipolarScale.invmap(0), Scales::bipolarScale, "lfoToMaskChirp",
Info::kCanAutomate);

for (size_t idx = 0; idx < nReservedParameter; ++idx) {
Expand All @@ -238,7 +238,7 @@ struct GlobalParameter : public ParameterInterface {
for (size_t idx = 0; idx < nReservedGuiParameter; ++idx) {
auto indexStr = std::to_string(idx);
value[ID::reservedGuiParameter0 + idx] = std::make_unique<LinearValue>(
Scales::defaultScale.invmap(1.0), Scales::defaultScale,
Scales::defaultScale.invmap(0.0), Scales::defaultScale,
("reservedGuiParameter" + indexStr).c_str(), Info::kIsHidden);
}

Expand Down
1 change: 1 addition & 0 deletions SpectralPhaser/test/testdsp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only

#define SET_PARAMETERS dsp->setParameters();
#define HAS_SIDECHAIN 1

#include "../../test/fxtester.hpp"
#include "../source/dsp/dspcore.hpp"
Expand Down
17 changes: 9 additions & 8 deletions docs/manual/SpectralPhaser/SpectralPhaser_en.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="dcterms.date" content="2024-10-23" />
<meta name="dcterms.date" content="2024-10-24" />
<title>SpectralPhaser_en – Uhhyou Plugins</title>
<link rel="icon" type="image/svg+xml" href="../../img/favicon/favicon.svg">
<link rel="icon" type="image/png" href="../../img/favicon/favicon.svgindex-relative-path=../../index.html">
Expand Down Expand Up @@ -285,7 +285,7 @@
<header>
<p><a href="../../index.html">Back to Index</a></p>
<p>
Update: 2024-10-23
Update: 2024-10-24
</p>
<details>
<summary translate="yes">Table of Contents</summary>
Expand Down Expand Up @@ -827,6 +827,8 @@ <h3 id="mask"><a href="#mask" class="header-anchor"
<p>Frequency of frequency mask waveform.</p>
<p>Higher the <code>Freq.</code>, more notches.</p>
<p>Setting <code>Freq.</code> to 0 disables frequency masking.</p>
<p>When <code>Waveform</code> is Noise, there is no waveform
frequency, so instead the random seed value is changed.</p>
</dd>
<dt>Threshold</dt>
<dd>
Expand All @@ -845,13 +847,12 @@ <h3 id="mask"><a href="#mask" class="header-anchor"
<dd>
<p>Frequency shift amount for each feedback.</p>
</dd>
<dt>Octave Down</dt>
<dt>Texture</dt>
<dd>
<p>Amount of octave down effect. Octave down is applied for each
feedback.</p>
<p>Depending on the settings, the effect may not be noticeable. To get
the effect, try setting <code>Feedback</code> to 1 and
<code>Octave Down</code> to around 0.1.</p>
<p>Scaling that changes the location of the notches in the frequency
mask.</p>
<p>When <code>Waveform</code> is Noise, the frequency mask is smoothed
by applying a low-pass filter.</p>
</dd>
</dl>
<h2 id="change-log"><a href="#change-log" class="header-anchor"
Expand Down
Loading

0 comments on commit b2fbd03

Please sign in to comment.