Skip to content

Commit

Permalink
FFTNoiseGate: Expose to Python; add invert input
Browse files Browse the repository at this point in the history
  • Loading branch information
ideoforms committed Jan 5, 2024
1 parent 2998a67 commit ea06399
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 6 deletions.
2 changes: 1 addition & 1 deletion auxiliary/scripts/auto-generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def identifier(self):


node_superclasses = ["Node", "UnaryOpNode", "BinaryOpNode", "StochasticNode", "FFTNode", "FFTOpNode", "LFO"]
omitted_classes = ["VampAnalysis", "GrainSegments", "FFTNoiseGate", "FFTZeroPhase", "FFTOpNode", "FFTNode",
omitted_classes = ["VampAnalysis", "GrainSegments", "FFTZeroPhase", "FFTOpNode", "FFTNode",
"StochasticNode"]
macos_only_classes = ["MouseX", "MouseY", "MouseDown", "FFTConvolve"]
known_parent_classes = ["Node", "StochasticNode"]
Expand Down
3 changes: 2 additions & 1 deletion source/include/signalflow/node/fft/noise-gate.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ namespace signalflow
class FFTNoiseGate : public FFTOpNode
{
public:
FFTNoiseGate(NodeRef input = 0, NodeRef threshold = 0.5);
FFTNoiseGate(NodeRef input = 0, NodeRef threshold = 0.5, NodeRef invert = 0.0);
virtual void process(Buffer &out, int num_frames);

NodeRef threshold = nullptr;
NodeRef invert = nullptr;

private:
float mags[SIGNALFLOW_MAX_FFT_SIZE / 2];
Expand Down
8 changes: 5 additions & 3 deletions source/src/node/fft/noise-gate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
namespace signalflow
{

FFTNoiseGate::FFTNoiseGate(NodeRef input, NodeRef threshold)
: FFTOpNode(input), threshold(threshold)
FFTNoiseGate::FFTNoiseGate(NodeRef input, NodeRef threshold, NodeRef invert)
: FFTOpNode(input), threshold(threshold), invert(invert)
{
this->name = "fft_noise_gate";
this->create_input("threshold", this->threshold);
this->create_input("invert", this->invert);
}

void FFTNoiseGate::process(Buffer &out, int num_frames)
Expand All @@ -26,12 +27,13 @@ void FFTNoiseGate::process(Buffer &out, int num_frames)
memcpy(this->mags, &input->out[hop][0], sizeof(float) * num_bins);
std::sort(this->mags, mags + num_bins);
float cutoff = this->mags[(int) (this->threshold->out[0][0] * num_bins)];
bool invert = (bool) this->invert->out[0][0];

for (int frame = 0; frame < this->fft_size; frame++)
{
if (frame < this->num_bins)
{
if (input->out[hop][frame] > cutoff)
if ((!invert && (input->out[hop][frame] > cutoff)) || (invert && (input->out[hop][frame] < cutoff)))
out[hop][frame] = input->out[hop][frame];
else
out[hop][frame] = 0.0;
Expand Down
5 changes: 4 additions & 1 deletion source/src/python/nodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ void init_python_nodes(py::module &m)
py::class_<FFTLPF, Node, NodeRefTemplate<FFTLPF>>(m, "FFTLPF", "FFT-based brick wall low pass filter. Requires an FFT* input.")
.def(py::init<NodeRef, NodeRef>(), "input"_a = 0, "frequency"_a = 2000);

py::class_<FFTNoiseGate, Node, NodeRefTemplate<FFTNoiseGate>>(m, "FFTNoiseGate", "FFT-based noise gate. Requires an FFT* input.")
.def(py::init<NodeRef, NodeRef, NodeRef>(), "input"_a = 0, "threshold"_a = 0.5, "invert"_a = 0.0);

py::class_<FFTPhaseVocoder, Node, NodeRefTemplate<FFTPhaseVocoder>>(m, "FFTPhaseVocoder", "Phase vocoder. Requires an FFT* input.")
.def(py::init<NodeRef>(), "input"_a = nullptr);

Expand Down Expand Up @@ -289,7 +292,7 @@ void init_python_nodes(py::module &m)
py::class_<Squiz, Node, NodeRefTemplate<Squiz>>(m, "Squiz", "Implementation of Dan Stowell's Squiz algorithm, a kind of downsampler.")
.def(py::init<NodeRef, NodeRef, NodeRef>(), "input"_a = 0.0, "rate"_a = 2.0, "chunk_size"_a = 1);

py::class_<WaveShaper, Node, NodeRefTemplate<WaveShaper>>(m, "WaveShaper", "Applies wave-shaping as described in `buffer`.")
py::class_<WaveShaper, Node, NodeRefTemplate<WaveShaper>>(m, "WaveShaper", "Applies wave-shaping as described in the WaveShaperBuffer `buffer`.")
.def(py::init<NodeRef, BufferRef>(), "input"_a = 0.0, "buffer"_a = nullptr);

py::class_<Compressor, Node, NodeRefTemplate<Compressor>>(m, "Compressor", "Dynamic range compression, with optional `sidechain` input. When the input amplitude is above `threshold`, compresses the amplitude with the given `ratio`, following the given `attack_time` and `release_time` in seconds.")
Expand Down

0 comments on commit ea06399

Please sign in to comment.