VCV Rack API v2
Loading...
Searching...
No Matches
resampler.hpp
Go to the documentation of this file.
1#pragma once
2#include <speex/speex_resampler.h>
3
4#include <dsp/common.hpp>
5#include <dsp/ringbuffer.hpp>
6#include <dsp/fir.hpp>
7#include <dsp/window.hpp>
8
9
10namespace rack {
11namespace dsp {
12
13
15template <int MAX_CHANNELS>
17 SpeexResamplerState* st = NULL;
18 int channels = MAX_CHANNELS;
19 int quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
20 int inRate = 44100;
21 int outRate = 44100;
22
27 if (st) {
28 speex_resampler_destroy(st);
29 }
30 }
31
34 assert(channels <= MAX_CHANNELS);
35 if (channels == this->channels)
36 return;
37 this->channels = channels;
39 }
40
42 void setQuality(int quality) {
43 if (quality == this->quality)
44 return;
45 this->quality = quality;
47 }
48
49 void setRates(int inRate, int outRate) {
50 if (inRate == this->inRate && outRate == this->outRate)
51 return;
52 this->inRate = inRate;
53 this->outRate = outRate;
55 }
56
57 void refreshState() {
58 if (st) {
59 speex_resampler_destroy(st);
60 st = NULL;
61 }
62
63 if (channels > 0 && inRate != outRate) {
64 int err;
65 st = speex_resampler_init(channels, inRate, outRate, quality, &err);
66 (void) err;
67 }
68 }
69
70 void process(const float* in, int inStride, int* inFrames, float* out, int outStride, int* outFrames) {
71 assert(in);
72 assert(inFrames);
73 assert(out);
74 assert(outFrames);
75
76 if (st) {
77 speex_resampler_set_input_stride(st, inStride);
78 speex_resampler_set_output_stride(st, outStride);
79 // Resample each channel at a time
80 spx_uint32_t inLen = 0;
81 spx_uint32_t outLen = 0;
82 for (int c = 0; c < channels; c++) {
83 inLen = *inFrames;
84 outLen = *outFrames;
85 int err = speex_resampler_process_float(st, c, &in[c], &inLen, &out[c], &outLen);
86 (void) err;
87 }
88 *inFrames = inLen;
89 *outFrames = outLen;
90 }
91 else {
92 // Simply copy the buffer without conversion
93 int frames = std::min(*inFrames, *outFrames);
94 for (int i = 0; i < frames; i++) {
95 for (int c = 0; c < channels; c++) {
96 out[outStride * i + c] = in[inStride * i + c];
97 }
98 }
99 *inFrames = frames;
100 *outFrames = frames;
101 }
102 }
103
104 void process(const Frame<MAX_CHANNELS>* in, int* inFrames, Frame<MAX_CHANNELS>* out, int* outFrames) {
105 process((const float*) in, MAX_CHANNELS, inFrames, (float*) out, MAX_CHANNELS, outFrames);
106 }
107};
108
109
111template <int OVERSAMPLE, int QUALITY, typename T = float>
112struct Decimator {
113 T inBuffer[OVERSAMPLE * QUALITY];
114 float kernel[OVERSAMPLE * QUALITY];
116
117 Decimator(float cutoff = 0.9f) {
118 boxcarLowpassIR(kernel, OVERSAMPLE * QUALITY, cutoff * 0.5f / OVERSAMPLE);
119 blackmanHarrisWindow(kernel, OVERSAMPLE * QUALITY);
120 reset();
121 }
122 void reset() {
123 inIndex = 0;
124 std::memset(inBuffer, 0, sizeof(inBuffer));
125 }
127 T process(T* in) {
128 // Copy input to buffer
129 std::memcpy(&inBuffer[inIndex], in, OVERSAMPLE * sizeof(T));
130 // Advance index
131 inIndex += OVERSAMPLE;
132 inIndex %= OVERSAMPLE * QUALITY;
133 // Perform naive convolution
134 T out = 0.f;
135 for (int i = 0; i < OVERSAMPLE * QUALITY; i++) {
136 int index = inIndex - 1 - i;
137 index = (index + OVERSAMPLE * QUALITY) % (OVERSAMPLE * QUALITY);
138 out += kernel[i] * inBuffer[index];
139 }
140 return out;
141 }
142};
143
144
146template <int OVERSAMPLE, int QUALITY>
147struct Upsampler {
148 float inBuffer[QUALITY];
149 float kernel[OVERSAMPLE * QUALITY];
151
152 Upsampler(float cutoff = 0.9f) {
153 boxcarLowpassIR(kernel, OVERSAMPLE * QUALITY, cutoff * 0.5f / OVERSAMPLE);
154 blackmanHarrisWindow(kernel, OVERSAMPLE * QUALITY);
155 reset();
156 }
157 void reset() {
158 inIndex = 0;
159 std::memset(inBuffer, 0, sizeof(inBuffer));
160 }
162 void process(float in, float* out) {
163 // Zero-stuff input buffer
164 inBuffer[inIndex] = OVERSAMPLE * in;
165 // Advance index
166 inIndex++;
167 inIndex %= QUALITY;
168 // Naively convolve each sample
169 // TODO replace with polyphase filter hierarchy
170 for (int i = 0; i < OVERSAMPLE; i++) {
171 float y = 0.f;
172 for (int j = 0; j < QUALITY; j++) {
173 int index = inIndex - 1 - j;
174 index = (index + QUALITY) % QUALITY;
175 int kernelIndex = OVERSAMPLE * j + i;
176 y += kernel[kernelIndex] * inBuffer[index];
177 }
178 out[i] = y;
179 }
180 }
181};
182
183
184} // namespace dsp
185} // namespace rack
void boxcarLowpassIR(float *out, int len, float cutoff=0.5f)
Computes the impulse response of a boxcar lowpass filter.
Definition fir.hpp:21
void blackmanHarrisWindow(float *x, int len)
Definition window.hpp:76
Root namespace for the Rack API.
Definition AudioDisplay.hpp:9
Downsamples by an integer factor.
Definition resampler.hpp:112
T inBuffer[OVERSAMPLE *QUALITY]
Definition resampler.hpp:113
void reset()
Definition resampler.hpp:122
int inIndex
Definition resampler.hpp:115
float kernel[OVERSAMPLE *QUALITY]
Definition resampler.hpp:114
T process(T *in)
in must be length OVERSAMPLE
Definition resampler.hpp:127
Decimator(float cutoff=0.9f)
Definition resampler.hpp:117
Useful for storing arrays of samples in ring buffers and casting them to float* to be used by interle...
Definition common.hpp:92
Resamples by a fixed rational factor.
Definition resampler.hpp:16
~SampleRateConverter()
Definition resampler.hpp:26
void setChannels(int channels)
Sets the number of channels to actually process.
Definition resampler.hpp:33
void setRates(int inRate, int outRate)
Definition resampler.hpp:49
SampleRateConverter()
Definition resampler.hpp:23
SpeexResamplerState * st
Definition resampler.hpp:17
int inRate
Definition resampler.hpp:20
void process(const float *in, int inStride, int *inFrames, float *out, int outStride, int *outFrames)
Definition resampler.hpp:70
int quality
Definition resampler.hpp:19
void setQuality(int quality)
From 0 (worst, fastest) to 10 (best, slowest)
Definition resampler.hpp:42
int outRate
Definition resampler.hpp:21
void process(const Frame< MAX_CHANNELS > *in, int *inFrames, Frame< MAX_CHANNELS > *out, int *outFrames)
Definition resampler.hpp:104
void refreshState()
Definition resampler.hpp:57
int channels
Definition resampler.hpp:18
Upsamples by an integer factor.
Definition resampler.hpp:147
void reset()
Definition resampler.hpp:157
Upsampler(float cutoff=0.9f)
Definition resampler.hpp:152
int inIndex
Definition resampler.hpp:150
void process(float in, float *out)
out must be length OVERSAMPLE
Definition resampler.hpp:162
float inBuffer[QUALITY]
Definition resampler.hpp:148
float kernel[OVERSAMPLE *QUALITY]
Definition resampler.hpp:149