Skip to content

Commit db2337b

Browse files
authored
Merge pull request #6 from fleximeter/class_refactor_2
Class refactor 2
2 parents e31085f + 4dade64 commit db2337b

14 files changed

Lines changed: 239 additions & 222 deletions

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ A phase vocoder pitch shifter and time stretcher using the [RubberBand library](
2828
### RubberBandStretcherBuf
2929
A phase vocoder pitch shifter and time stretcher using the [RubberBand library](https://breakfastquay.com/rubberband/). This version writes the stretched audio to a buffer rather than outputting it directly.
3030

31+
### FIR
32+
A flexible FIR filter that allows you to provide an arbitrary number of coefficients directly (as opposed to loading them in a buffer with Convolution3).
33+
3134
### ImpulseDropout
3235
A modified version of Impulse that randomly drops a percentage of impulses, producing a stuttering effect.
3336

src/filters/FIR.schelp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,26 @@ related:: Classes/Convolution3, Classes/FOS, Classes/SOS, Classes/OneZero
44
categories:: Libraries>FlexUGens, UGens>Filters>Linear
55

66
Description::
7-
A no-nonsense FIR filter where you provide your own coefficients. FIR duplicates the functionality
7+
A flexible time-domain FIR filter where you provide your own coefficients. FIR duplicates the functionality
88
of link::Classes/Convolution3::. The difference is that FIR does not require you to load your
99
filter coefficients into a link::Classes/Buffer::. Instead, you can provide them directly as a
1010
link::Classes/Ref:: in the same way as is done in link::Classes/DynKlank::.
1111

12+
FIR internally limits the number of coefficients to 32. This is because time-domain convolution only makes sense for
13+
very short impulse responses--Frank Wefers writes that "the
14+
theoretical break-even point where FFT-based convolution becomes
15+
faster is between 16-32 samples."footnote::Frank Wefers, "Partitioned convolution algorithms
16+
for real-time auralization," Logos Verlag Berlin (2015), 224.:: One potential use of this UGen is
17+
to perform Savitsky-Golay filtering for control signal smoothing
18+
(see link::https://en.wikipedia.org/wiki/Savitzky%E2%80%93Golay_filter:: for coefficient tables).
19+
1220
classmethods::
1321

14-
method::ar
22+
method::ar, kr
1523

1624
argument::coefs
1725
A link::Classes/Ref:: to a list of FIR filter coefficients. The number of coefficients can change
18-
over time, but can never exceed the server block size (if it does, extra coefficients will be truncated).
26+
over time, but can never exceed 32 (if it does, extra coefficients will be truncated).
1927

2028
argument::in
2129
The input signal to filter

src/filters/filters.sc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
// You should have received a copy of the GNU General Public License
2121
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2222

23+
// A flexible FIR filter
2324
FIR : UGen {
2425
*ar {
2526
arg coefs, in, mul=1, add=0;

src/filters/fir.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ File: fir.cpp
33
Author: Jeff Martin
44
55
Description:
6-
A raw FIR filter
6+
A flexible FIR filter
77
88
Copyright © 2026 by Jeffrey Martin. All rights reserved.
99
Website: https://www.jeffreymartincomposer.com
@@ -26,8 +26,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2626
extern InterfaceTable *ft;
2727

2828
FlexPlugins::FIR::FIR() {
29-
m_z = static_cast<float*>(RTAlloc(mWorld, fullBufferSize() * sizeof(float)));
30-
for (size_t i = 0; i < fullBufferSize(); i++) {
29+
m_z = static_cast<float*>(RTAlloc(mWorld, MAX_COEFS * sizeof(float)));
30+
for (size_t i = 0; i < MAX_COEFS; i++) {
3131
m_z[i] = 0.f;
3232
}
3333
set_calc_function<FIR, &FIR::next>();
@@ -40,13 +40,13 @@ FlexPlugins::FIR::~FIR() {
4040

4141
void FlexPlugins::FIR::next(int inNumSamples) {
4242
size_t numCoefs = static_cast<size_t>(mNumInputs - 1);
43-
numCoefs = sc_clip(numCoefs, 0, static_cast<size_t>(fullBufferSize()));
43+
numCoefs = sc_clip(numCoefs, 0, static_cast<size_t>(MAX_COEFS));
4444
const float *inBuf = in(0);
4545
float *outBuf = out(0);
4646
for (size_t i = 0; i < inNumSamples; i++) {
4747
float convResult = 0.f;
4848
// unit delay
49-
for (size_t j = fullBufferSize() - 1; j > 0; j--) {
49+
for (size_t j = MAX_COEFS - 1; j > 0; j--) {
5050
m_z[j] = m_z[j-1];
5151
}
5252
m_z[0] = inBuf[i];

src/filters/fir.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ File: fir.hpp
33
Author: Jeff Martin
44
55
Description:
6-
A raw FIR filter
6+
A flexible FIR filter
77
88
Copyright © 2026 by Jeffrey Martin. All rights reserved.
99
Website: https://www.jeffreymartincomposer.com
@@ -26,6 +26,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2626

2727
#include "SC_PlugIn.hpp"
2828

29+
#define MAX_COEFS 32
30+
2931
namespace FlexPlugins {
3032
class FIR : public SCUnit {
3133
public:

src/generators/ImpulseJitter.schelp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,19 @@ This value will be added to the output.
3232

3333
Examples::
3434

35+
Generating audio:
3536
code::
36-
(
37-
SynthDef(\jitter, {
38-
arg freq, jitterFrac, amp;
39-
var sig;
40-
sig = ImpulseJitter.ar(freq, 0.0, jitterFrac, amp);
41-
sig = LPF.ar(sig, freq);
42-
sig = LeakDC.ar(sig);
43-
Out.ar(0, sig);
44-
}).add;
45-
46-
Synth(\jitter, [\freq, 440.0, \jitterFrac, 0.1, \amp, -12.dbamp]);
47-
)
37+
{
38+
var sig;
39+
sig = ImpulseJitter.ar(440, 0, XLine.kr(1, 2, 5)-1);
40+
Pan2.ar(sig);
41+
}.play;
42+
::
43+
44+
An increasingly noisy impulse train as a control signal:
45+
code::
46+
{
47+
var sig;
48+
sig = ImpulseJitter.kr(10, 0, XLine.kr(1, 2, 2) - 1);
49+
}.plot(2);
4850
::

src/generators/arrayheap.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2525
#include "arrayheap.hpp"
2626

2727
// Inserts into the heap
28-
int heapInsert(IntMinHeap* heap, int data) {
28+
int FlexPlugins::heapInsert(IntMinHeap* heap, int data) {
2929
if (heap->size == heap->maxSize) {
3030
return 0;
3131
} else {
@@ -54,7 +54,7 @@ int heapInsert(IntMinHeap* heap, int data) {
5454
}
5555

5656
// Removes from the heap and returns the value popped. Returns 0 if the heap is empty.
57-
int heapPop(IntMinHeap* heap) {
57+
int FlexPlugins::heapPop(IntMinHeap* heap) {
5858
if (heap->size > 1) {
5959
int val = heap->heap[1];
6060
heap->heap[1] = heap->heap[heap->size-1];
@@ -97,7 +97,7 @@ int heapPop(IntMinHeap* heap) {
9797
}
9898

9999
// Safe peek at the top of the heap
100-
int heapPeek(IntMinHeap* heap) {
100+
int FlexPlugins::heapPeek(IntMinHeap* heap) {
101101
if (heap->size > 1) {
102102
return heap->heap[1];
103103
} else {

src/generators/arrayheap.hpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2525
#pragma once
2626
#include <cstddef>
2727

28-
/// A min heap for ints.
29-
typedef struct {
30-
int* heap;
31-
size_t size;
32-
size_t maxSize;
33-
} IntMinHeap;
34-
35-
/// Inserts into the heap
36-
int heapInsert(IntMinHeap* heap, int data);
37-
38-
/// Removes from the heap and returns the value popped. Returns 0 if the heap is empty.
39-
int heapPop(IntMinHeap* heap);
40-
41-
/// Safe peek at the top of the heap
42-
int heapPeek(IntMinHeap* heap);
28+
namespace FlexPlugins {
29+
/// A min heap for ints.
30+
typedef struct {
31+
int* heap;
32+
size_t size;
33+
size_t maxSize;
34+
} IntMinHeap;
35+
36+
/// Inserts into the heap
37+
int heapInsert(IntMinHeap* heap, int data);
38+
39+
/// Removes from the heap and returns the value popped. Returns 0 if the heap is empty.
40+
int heapPop(IntMinHeap* heap);
41+
42+
/// Safe peek at the top of the heap
43+
int heapPeek(IntMinHeap* heap);
44+
}

src/pv/pvCFreeze.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,22 @@ void FlexPlugins::PV_CFreeze::next(int inNumSamples) {
6363
// Pull random DC and nyquist magnitudes
6464
p->dc = mDc[rgen.irand(mNumFrames)];
6565
p->nyq = mNyq[rgen.irand(mNumFrames)];
66-
for (int xxn = 0; xxn < mNumBins; xxn++) {
66+
for (int k = 0; k < mNumBins; k++) {
6767
// For each bin, grab a random magnitude and phase diff pair
6868
int idx = rgen.irand(mNumFrames);
69-
idx = idx * mNumBins + xxn;
70-
p->bin[xxn].mag = mMags[idx];
71-
mPhase[xxn] = sc_wrap(mPhase[xxn] + mPhaseDiffs[idx], 0.f, static_cast<float>(twopi));
72-
p->bin[xxn].phase = mPhase[xxn];
69+
idx = idx * mNumBins + k;
70+
p->bin[k].mag = mMags[idx];
71+
mPhase[k] = sc_wrap(mPhase[k] + mPhaseDiffs[idx], 0.f, static_cast<float>(twopi));
72+
p->bin[k].phase = mPhase[k];
7373
}
7474
} else {
7575
// We're writing to a circular buffer, so pull the current magnitude and phase diff arrays
7676
float *currentMagArr = mMags + (mWritePtr * mNumBins);
7777
float *currentPhaseDiffArr = mPhaseDiffs + (mWritePtr * mNumBins);
78-
for (int xxn = 0; xxn < numbins; xxn++) {
79-
currentMagArr[xxn] = p->bin[xxn].mag;
80-
currentPhaseDiffArr[xxn] = sc_wrap(p->bin[xxn].phase - mPhase[xxn], 0.f, static_cast<float>(twopi));
81-
mPhase[xxn] = p->bin[xxn].phase;
78+
for (int k = 0; k < numbins; k++) {
79+
currentMagArr[k] = p->bin[k].mag;
80+
currentPhaseDiffArr[k] = sc_wrap(p->bin[k].phase - mPhase[k], 0.f, static_cast<float>(twopi));
81+
mPhase[k] = p->bin[k].phase;
8282
}
8383
mDc[mWritePtr] = p->dc;
8484
mNyq[mWritePtr] = p->nyq;

0 commit comments

Comments
 (0)