-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Starting work on Fuzz Machine module
- Loading branch information
1 parent
d2639c7
commit 1e94959
Showing
7 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# %% | ||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
|
||
# %% | ||
FS = 48000 | ||
fc = 100 | ||
N = 20000 | ||
|
||
x = 0.125 * np.sin(2 * np.pi * np.arange(N) * fc / FS) | ||
plt.plot(x) | ||
|
||
# %% | ||
def process(x, gain_01): | ||
gr4 = 1 / 100.0e3 | ||
gain_factor = (gain_01 * 0.98 + 0.01)**5 | ||
grfp = 1 / ((1 - gain_factor) * 1.0e3) | ||
grfm = 1 / (gain_factor * 1.0e3) | ||
gc1 = 2 * FS * 2.2e-6 | ||
gc2 = 2 * FS * 20.0e-6 | ||
|
||
vt = 0.026 * 0.5 | ||
Iq = 0.5e-10 | ||
|
||
y = np.zeros_like(x) | ||
|
||
ic1eq = 0 | ||
ic2eq = 0 | ||
|
||
vo = 0 | ||
io = 0 | ||
for n in range(len(x)): | ||
vi = x[n] | ||
|
||
# initial guess | ||
v1 = -((-gr4*(grfp*ic2eq+(gc2+grfm+grfp)*io) + (gr4*(gc2+grfm)+(gc2+gr4+grfm)*grfp) * (ic1eq+io-gc1*vi)) / (gc1*gr4*(gc2+grfm) + gr4*(gc2+grfm)*grfp + gc1*(gc2+gr4+grfm)*grfp)) | ||
|
||
delta = 100 | ||
n_iters = 0 | ||
while np.abs(delta) > 1.0e-5 or n_iters > 5: | ||
io = Iq * np.exp(-v1 / vt) | ||
vo = (ic1eq + io + (gc1+gr4)*v1 - gc1*vi) / gr4 | ||
# vo = ((gc1+gr4) * grfp*ic2eq+(gc2+grfm+grfp) * (-gr4*ic1eq+gc1*io+gc1*gr4*vi)) / (gc1*gr4*(gc2+grfm) + gr4*(gc2+grfm)*grfp + gc1*(gc2+gr4+grfm)*grfp) | ||
|
||
F = (gc1*(vi - v1) - ic1eq) + gr4*(vo - v1) - io | ||
F_p = -gc1 - gr4 + (Iq/vt) * np.exp(-v1 / vt) | ||
delta = F / F_p | ||
v1 -= delta | ||
|
||
n_iters += 1 | ||
|
||
io = Iq * np.exp(-v1 / vt) | ||
vo = (ic1eq + io + (gc1+gr4)*v1 - gc1*vi) / gr4 | ||
# vo = ((gc1+gr4) * grfp*ic2eq+(gc2+grfm+grfp) * (-gr4*ic1eq+gc1*io+gc1*gr4*vi)) / (gc1*gr4*(gc2+grfm) + gr4*(gc2+grfm)*grfp + gc1*(gc2+gr4+grfm)*grfp) | ||
|
||
v2 = -((io + gr4*v1 - (gr4+grfp)*vo) / grfp) | ||
ic1eq = 2 * gc1 * (vi - v1) - ic1eq | ||
ic2eq = 2 * gc2 * (v2) - ic2eq | ||
|
||
y[n] = 4 * vo | ||
|
||
return y - np.mean(y) | ||
|
||
# %% | ||
|
||
plt.plot(x[N - 2000:]) | ||
|
||
for g in [0, 0.25, 0.5, 0.75, 1.0]: | ||
y = process(x, g) | ||
plt.plot(y[N - 2000:], '--') | ||
|
||
# %% |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#include "FuzzFaceSolver.h" | ||
|
||
namespace | ||
{ | ||
constexpr auto vt = 0.026 * 0.5; | ||
constexpr auto Iq = 1.0e-10; | ||
} // namespace | ||
|
||
void FuzzFaceSolver::prepare (double sample_rate) | ||
{ | ||
fs = sample_rate; | ||
gc1 = 2.0 * fs * C1; | ||
gc2 = 2.0 * fs * C2; | ||
|
||
reset(); | ||
} | ||
|
||
void FuzzFaceSolver::reset() | ||
{ | ||
std::fill (ic1eq.begin(), ic1eq.end(), 0.0); | ||
std::fill (ic2eq.begin(), ic2eq.end(), 0.0); | ||
std::fill (vo.begin(), vo.end(), 0.0); | ||
std::fill (io.begin(), io.end(), 0.0); | ||
} | ||
|
||
void FuzzFaceSolver::set_gain (double gain_01) noexcept | ||
{ | ||
const auto gain_factor = chowdsp::Power::ipow<4> (gain_01 * 0.98 + 0.01); | ||
grfp = 1.0 / ((1.0 - gain_factor) * Rf); | ||
grfm = 1.0 / (gain_factor * Rf); | ||
} | ||
|
||
void FuzzFaceSolver::process (std::span<float> data, size_t ch) noexcept | ||
{ | ||
for (auto& sample : data) | ||
{ | ||
const auto vi = std::tanh (0.1 * (double) sample); | ||
|
||
// initial guess | ||
auto v1 = -((-gr4 * (grfp * ic2eq[ch] + (gc2 + grfm + grfp) * io[ch]) + (gr4 * (gc2 + grfm) + (gc2 + gr4 + grfm) * grfp) * (ic1eq[ch] + io[ch] - gc1 * vi)) / (gc1 * gr4 * (gc2 + grfm) + gr4 * (gc2 + grfm) * grfp + gc1 * (gc2 + gr4 + grfm) * grfp)); | ||
|
||
// Newton-Raphson Solver | ||
double delta; | ||
int n_iters = 0; | ||
auto v1_exp = std::exp (-v1 / vt); | ||
do | ||
{ | ||
io[ch] = Iq * v1_exp; | ||
vo[ch] = (ic1eq[ch] + io[ch] + (gc1 + gr4) * v1 - gc1 * vi) / gr4; | ||
|
||
const auto F = (gc1 * (vi - v1) - ic1eq[ch]) + gr4 * (vo[ch] - v1) - io[ch]; | ||
const auto F_p = -gc1 - gr4 + (Iq / vt) * v1_exp; | ||
delta = F / F_p; | ||
v1 -= delta; | ||
|
||
v1_exp = std::exp (-v1 / vt); | ||
n_iters++; | ||
} while (std::abs (delta) > 1.0e-5 && n_iters < 5); | ||
|
||
// compute output | ||
io[ch] = Iq * v1_exp; | ||
vo[ch] = (ic1eq[ch] + io[ch] + (gc1 + gr4) * v1 - gc1 * vi) / gr4; | ||
|
||
//update state | ||
const auto v2 = -((io[ch] + gr4 * v1 - (gr4 + grfp) * vo[ch]) / grfp); | ||
ic1eq[ch] = 2.0 * gc1 * (vi - v1) - ic1eq[ch]; | ||
ic2eq[ch] = 2.0 * gc2 * (v2) -ic2eq[ch]; | ||
|
||
sample = float (-100.0 * vo[ch]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#pragma once | ||
|
||
#include <pch.h> | ||
|
||
struct FuzzFaceSolver | ||
{ | ||
double fs = 48000.0; | ||
|
||
double gr4 = 1.0 / 100.0e3; | ||
double Rf = 1.0e3; | ||
double grfp = 1.0 / (0.5 * Rf); | ||
double grfm = 1.0 / (0.5 * Rf); | ||
|
||
double C1 = 2.2e-6; | ||
double C2 = 20.0e-6; | ||
double gc1 = 2.0 * fs * C1; | ||
double gc2 = 2.0 * fs * C2; | ||
|
||
std::array<double, 2> ic1eq {}; | ||
std::array<double, 2> ic2eq {}; | ||
std::array<double, 2> vo {}; | ||
std::array<double, 2> io {}; | ||
|
||
void prepare (double sample_rate); | ||
void reset(); | ||
|
||
void set_gain (double gain_01) noexcept; | ||
void process (std::span<float> data, size_t channel_index) noexcept; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include "FuzzMachine.h" | ||
#include "processors/ParameterHelpers.h" | ||
|
||
FuzzMachine::FuzzMachine (UndoManager* um) | ||
: BaseProcessor ("Fuzz Machine", createParameterLayout(), um) | ||
{ | ||
using namespace ParameterHelpers; | ||
fuzzParam.setParameterHandle (getParameterPointer<chowdsp::PercentParameter*> (vts, "fuzz")); | ||
loadParameterPointer (volumeParam, vts, "vol"); | ||
|
||
uiOptions.backgroundColour = Colours::red.darker (0.15f); | ||
uiOptions.powerColour = Colours::silver.brighter (0.1f); | ||
uiOptions.info.description = "Fuzz effect based loosely on the \"Fuzz Face\" pedal."; | ||
uiOptions.info.authors = StringArray { "Jatin Chowdhury" }; | ||
} | ||
|
||
ParamLayout FuzzMachine::createParameterLayout() | ||
{ | ||
using namespace ParameterHelpers; | ||
auto params = createBaseParams(); | ||
|
||
createPercentParameter (params, "fuzz", "Fuzz", 0.5f); | ||
createPercentParameter (params, "vol", "Volume", 0.5f); | ||
|
||
return { params.begin(), params.end() }; | ||
} | ||
|
||
void FuzzMachine::prepare (double sampleRate, int samplesPerBlock) | ||
{ | ||
model.prepare (sampleRate); | ||
|
||
fuzzParam.setRampLength (0.025); | ||
fuzzParam.prepare (sampleRate, samplesPerBlock); | ||
|
||
const auto spec = juce::dsp::ProcessSpec { sampleRate, (uint32_t) samplesPerBlock, 2 }; | ||
dcBlocker.prepare (spec); | ||
dcBlocker.calcCoefs (30.0f, (float) sampleRate); | ||
|
||
volume.setGainLinear (volumeParam->getCurrentValue()); | ||
volume.setRampDurationSeconds (0.05); | ||
volume.prepare (spec); | ||
|
||
// pre-buffering | ||
AudioBuffer<float> buffer (2, samplesPerBlock); | ||
float level = 100.0f; | ||
while (level > 1.0e-4f) | ||
{ | ||
buffer.clear(); | ||
processAudio (buffer); | ||
level = buffer.getMagnitude (0, samplesPerBlock); | ||
} | ||
} | ||
|
||
void FuzzMachine::processAudio (AudioBuffer<float>& buffer) | ||
{ | ||
const auto numSamples = buffer.getNumSamples(); | ||
fuzzParam.process (numSamples); | ||
|
||
for (auto [ch, n, data] : chowdsp::buffer_iters::sub_blocks<32, true> (buffer)) | ||
{ | ||
if (ch == 0) | ||
model.set_gain (fuzzParam.getSmoothedBuffer()[n]); | ||
model.process (data, ch); | ||
} | ||
|
||
if (! chowdsp::BufferMath::sanitizeBuffer (buffer)) | ||
model.reset(); | ||
|
||
dcBlocker.processBlock (buffer); | ||
|
||
volume.setGainLinear (volumeParam->getCurrentValue()); | ||
volume.process (buffer); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
|
||
#include "processors/BaseProcessor.h" | ||
|
||
#include "FuzzFaceSolver.h" | ||
|
||
class FuzzMachine : public BaseProcessor | ||
{ | ||
public: | ||
explicit FuzzMachine (UndoManager* um); | ||
|
||
ProcessorType getProcessorType() const override { return Drive; } | ||
static ParamLayout createParameterLayout(); | ||
|
||
void prepare (double sampleRate, int samplesPerBlock) override; | ||
void processAudio (AudioBuffer<float>& buffer) override; | ||
|
||
private: | ||
chowdsp::SmoothedBufferValue<float> fuzzParam; | ||
chowdsp::PercentParameter* volumeParam = nullptr; | ||
|
||
FuzzFaceSolver model; | ||
|
||
chowdsp::FirstOrderHPF<float> dcBlocker; | ||
chowdsp::Gain<float> volume; | ||
|
||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FuzzMachine) | ||
}; |