-
Notifications
You must be signed in to change notification settings - Fork 14
/
OversampledClipper.h
136 lines (110 loc) · 5.54 KB
/
OversampledClipper.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
==============================================================================
OversampledClipper.h
Created: 3 Feb 2021 1:03:59pm
Author: Vladyslav Voinov
==============================================================================
*/
#pragma once
#include <cmath>
#include <juce_dsp/juce_dsp.h>
#include "Clipper.h"
// ==============================================================================
namespace pe
{
namespace dsp
{
namespace waveshaping
{
// ==============================================================================
template <typename T>
class OversampledClipper : public juce::dsp::ProcessorBase
{
public:
//==============================================================================
/** Aliases */
using Oversampling = juce::dsp::Oversampling<T>;
using ProcessorSpec = juce::dsp::ProcessSpec;
//==============================================================================
OversampledClipper (const unsigned int factor = 1) noexcept
: oversampler (2, factor, Oversampling::filterHalfBandPolyphaseIIR, true)
{
}
~OversampledClipper() override {}
//==============================================================================
/** Inheritet implemented methods */
void prepare (const ProcessorSpec& spec) noexcept override
{
/** Setup oversampler */
oversampler.reset();
oversampler.initProcessing (spec.maximumBlockSize);
const auto oversampledSpec = createOversampledSpec (spec);
/** Setup pre-filter*/
*preFilter.state = *juce::dsp::IIR::Coefficients<T>::makeLowPass (
oversampledSpec.sampleRate, calculateCutoff (oversampledSpec.sampleRate));
preFilter.prepare (oversampledSpec);
/** Setup clipper*/
clipper.prepare (oversampledSpec);
setCeiling (DEFAULT_CEILING);
setClippingType (DEFAULT_CLIPPING_TYPE);
/** Setup post-filter*/
*postFilter.state = *juce::dsp::IIR::Coefficients<T>::makeLowPass (
oversampledSpec.sampleRate, calculateCutoff (oversampledSpec.sampleRate));
postFilter.prepare (oversampledSpec);
}
void reset() noexcept override
{
oversampler.reset();
preFilter.reset();
clipper.reset();
postFilter.reset();
}
void process (const juce::dsp::ProcessContextReplacing<T>& context) noexcept override
{
auto oversampledAudioBlock = oversampler.processSamplesUp (context.getInputBlock());
auto oversampledContext = juce::dsp::ProcessContextReplacing<T> (oversampledAudioBlock);
preFilter.process (oversampledContext);
clipper.process (oversampledContext);
postFilter.process (oversampledContext);
oversampler.processSamplesDown (context.getOutputBlock());
}
// ==============================================================================
/** Public interface */
void setCeiling (float ceilingDbValue) noexcept { clipper.setThreshold (ceilingDbValue); }
void setClippingType (ClippingType clippingType) noexcept { clipper.setClippingType (clippingType); }
private:
//==============================================================================
/** Default values */
const float DEFAULT_FILTER_Q_OCTAVES = 2.0f;
const float DEFAULT_CEILING = 0.0f;
const ClippingType DEFAULT_CLIPPING_TYPE = ClippingType::HARD;
//==============================================================================
/** DSP */
Oversampling oversampler;
Clipper<T> clipper;
juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<T>, juce::dsp::IIR::Coefficients<T>> preFilter;
juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<T>, juce::dsp::IIR::Coefficients<T>> postFilter;
//==============================================================================
/** Filter calculations based on input params */
unsigned int calculateCutoff (double sampleRate) const noexcept
{
return static_cast<unsigned int> ((sampleRate / 2) * 0.98f);
}
double calculateQ (float octaves) const noexcept
{
jassert (octaves >= 0.0f & octaves <= 4); // maximum 4 octaves allowed, no negative octaves
return 1.0f / sqrtf (octaves);
}
//==============================================================================
/** Helper builders */
const ProcessorSpec createOversampledSpec (ProcessorSpec const& src) const noexcept
{
const unsigned int xOversample = static_cast<unsigned int> (sqrt (oversampler.getOversamplingFactor()));
return { src.sampleRate * xOversample, src.maximumBlockSize * xOversample, src.numChannels };
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversampledClipper)
};
} // namespace waveshaping
} // namespace dsp
} // namespace pe