Skip to content

Commit fbce3cf

Browse files
committed
Merge branch 'main' of https://github.com/jedlamartin/ReSinc into dev
2 parents e805b48 + 3c32835 commit fbce3cf

File tree

3 files changed

+472
-280
lines changed

3 files changed

+472
-280
lines changed

README.md

Lines changed: 89 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,145 @@
11
# ReSinc
22
[![CI](https://github.com/jedlamartin/ReSinc/actions/workflows/ci.yml/badge.svg)](https://github.com/jedlamartin/ReSinc/actions/workflows/ci.yml)
33
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4-
![Language](https://img.shields.io/badge/language-C%2B%2B-blue.svg)
4+
![Language](https://img.shields.io/badge/language-C%2B%2B17-blue.svg)
55

66
`ReSinc` is a lightweight, real-time safe, header-only C++ library for audio oversampling.
77

8-
It's designed for use in real-time audio applications (like VST/AU plugins) where running a non-linear process (distortion, saturation, etc.) at a higher sample rate is necessary to prevent aliasing artifacts. The library uses a pre-calculated, windowed Sinc filter for interpolation and decimation, ensuring high-fidelity results.
8+
It is designed for real-time audio applications (like VST/AU plugins) where running non-linear processes (distortion, saturation, compression) at a higher sample rate is necessary to prevent aliasing artifacts. The library uses a pre-calculated, windowed Sinc filter for high-fidelity interpolation and decimation.
99

1010
## Features
1111

12-
* **Real-Time Safe:** All memory is pre-allocated on initialization. The real-time processing functions (`interpolate`, `decimate`, `process`) are guaranteed not to allocate heap memory, lock, or block, making them safe for any high-priority audio thread.
13-
* **High-Quality:** Uses a Kaiser-windowed Sinc filter for "perfect" reconstruction and anti-aliasing.
14-
* **Simple Workflow:** Provides a clear `interpolate()` -> `process()` -> `decimate()` workflow.
15-
* **Header-Only:** Just drop `ReSinc.hpp` into your project and include it.
16-
* **Flexible & Template-Based:** Fully configurable via template parameters:
12+
* **Real-Time Safe:** All memory is pre-allocated during configuration. The real-time processing functions (`interpolate`, `decimate`, `process`) are guaranteed not to allocate heap memory, lock, or block.
13+
* **Flexible I/O:** Supports multiple data formats directly:
14+
* **Standard Containers:** `std::vector<float>`, `std::vector<std::vector<float>>`, `std::array`.
15+
* **JUCE Framework:** Directly accepts `juce::AudioBuffer<float>` / `juce::AudioBuffer<double>`.
16+
* **Raw Pointers:** Standard `float**` arrays.
17+
* **High-Quality:** Uses a Kaiser-windowed Sinc filter for near-perfect reconstruction.
18+
* **Header-Only:** Single file `ReSinc.hpp`. No linking required.
19+
* **Configurable:**
1720
* `TYPE`: Sample type (`float` or `double`).
18-
* `OVERSAMPLE_FACTOR`: The factor to oversample by (e.g., `2`, `4`, `8`).
19-
* `SINC_RADIUS`: The "quality" of the filter, which also determines latency.
21+
* `OVERSAMPLE_FACTOR`: e.g., `2`, `4`, `8`, `16`.
22+
* `SINC_RADIUS`: Controls filter steepness and latency.
2023

2124
---
2225

2326
## Quick Start
2427

25-
Here is a minimal example of how to use `Oversampler` to apply 4x oversampling to a simple distortion effect.
28+
Here is a minimal example using `std::vector` to apply 4x oversampling to a simple distortion effect.
2629

2730
```cpp
2831
#include "ReSinc.hpp"
2932
#include <vector>
3033
#include <cmath>
34+
#include <algorithm>
3135

3236
// 1. Define your oversampler instance
3337
// <float, 4x Oversampling, Sinc Radius of 32>
3438
Oversampler<float, 4, 32> oversampler;
3539

3640
// 2. Call configure() once before processing begins
37-
// (e.g., in your plugin's prepareToPlay())
3841
void setupAudio() {
3942
float sampleRate = 44100.0f;
4043
int maxChannels = 2;
41-
int maxBlockSize = 1024;
44+
int maxBlockSize = 512;
4245

4346
oversampler.configure(sampleRate, maxChannels, maxBlockSize);
4447
}
4548

46-
// 3. Run in your real-time audio callback (e.g., processBlock())
47-
void processAudio(const float* const* input, float* const* output, int numChannels, int numSamples) {
49+
// 3. Run in your real-time audio loop
50+
void processBlock(std::vector<std::vector<float>>& input,
51+
std::vector<std::vector<float>>& output) {
4852

49-
// 3a. Upsample the audio into the internal buffer
50-
oversampler.interpolate(input, numChannels, numSamples);
53+
// 3a. Upsample: Input -> Internal Buffer
54+
// (Supports std::vector, juce::AudioBuffer, or float**)
55+
oversampler.interpolate(input);
5156

52-
// 3b. Process the high-resolution internal buffer
53-
// This lambda is called immediately.
54-
oversampler.process([&](std::vector<std::vector<float>>& internalBuffer) {
57+
// 3b. Process: Operate on the high-resolution buffer
58+
// The callback receives the upsampled data (4x larger size)
59+
oversampler.process([&](std::vector<std::vector<float>>& upsampledData) {
5560
56-
// 'internalBuffer' is now 4x larger
57-
int oversampledSamples = numSamples * 4;
58-
59-
for (int ch = 0; ch < numChannels; ++ch) {
60-
for (int s = 0; s < oversampledSamples; ++s) {
61-
// Apply a non-linear process (e.g., distortion)
62-
// This would alias badly at 1x, but is safe at 4x
63-
internalBuffer[ch][s] = std::tanh(internalBuffer[ch][s] * 2.0f);
61+
for (auto& channel : upsampledData) {
62+
for (auto& sample : channel) {
63+
// Apply non-linear process (e.g., Hard Clip)
64+
// Safe from aliasing because we are at 4x rate
65+
sample = std::max(-1.0f, std::min(1.0f, sample * 1.5f));
6466
}
6567
}
6668
});
6769

68-
// 3c. Downsample back to the original rate.
69-
// The Sinc filter automatically anti-aliases the signal.
70-
oversampler.decimate(output, numChannels, numSamples);
70+
// 3c. Downsample: Internal Buffer -> Output
71+
// Automatically applies anti-aliasing filter
72+
oversampler.decimate(output);
7173
}
7274
```
7375
## API
7476
7577
### Template Parameters
7678
`template<typename TYPE, int OVERSAMPLE_FACTOR, int SINC_RADIUS>`
77-
* **`TYPE`**: The sample type to use, e.g., `float` or `double`.
78-
* **`OVERSAMPLE_FACTOR`**: The interpolation factor. `4` means 4x oversampling.
79-
* **`SINC_RADIUS`**: The half-length of the Sinc filter. This controls the filter's quality. A good starting value is `32`. Higher values mean better anti-aliasing but higher CPU cost and latency.
79+
* **`TYPE`**: The sample type (`float` or `double`).
80+
* **`OVERSAMPLE_FACTOR`**: Integer factor (e.g., `2`, `4`, `8`).
81+
* **`SINC_RADIUS`**: Half-length of the Sinc filter.
82+
* Example: `32` taps per side.
83+
* Latency = `2 * SINC_RADIUS` samples (at input rate).
8084
81-
### Public Methods
85+
### Configuration
8286
83-
* **`void configure(TYPE sampleRate, int maxChannels, int maxBlockSize)`**
84-
Pre-allocates all internal memory. This **must** be called once from a non-real-time thread before any processing begins.
87+
#### `void configure(TYPE sampleRate, int maxChannels, int maxBlockSize)`
88+
Pre-allocates all internal memory. **Must** be called once (from a non-real-time thread) before processing.
8589
86-
* **`void interpolate(const TYPE* const* ptrToBuffers, int numChannels, int numSamples)`**
87-
Upsamples a block of audio from `ptrToBuffers` into the internal high-sample-rate buffer.
90+
### Real-Time Processing
8891
89-
* **`void process(std::function<void(std::vector<std::vector<TYPE>>&)> processBlock)`**
90-
Takes a lambda (or other `std::function`) and executes it, giving it direct mutable access to the internal high-sample-rate buffer. This is where you should apply your oversampled processing.
92+
The `interpolate`, `process`, and `decimate` methods provide overloads for three categories of data:
9193
92-
* **`void decimate(TYPE* const* ptrToBuffers, int numChannels, int numSamples)`**
93-
Downsamples the internal high-sample-rate buffer into the provided `ptrToBuffers`, automatically applying the anti-aliasing filter.
94+
1. **JUCE Types:** `juce::AudioBuffer<T>`
95+
2. **Standard Containers:** `std::vector<T>`, `std::vector<std::vector<T>>`
96+
3. **Raw Pointers:** `T**` / `T* const*`
9497
95-
---
98+
#### 1. Interpolate (Input -> Internal)
99+
Upsamples input data and fills the internal buffer.
96100
101+
```cpp
102+
// JUCE Support
103+
void interpolate(const juce::AudioBuffer<TYPE>& buffer);
104+
105+
// STL Support (Multi-channel & Single-channel)
106+
void interpolate(const std::vector<std::vector<TYPE>>& buffer);
107+
void interpolate(const std::vector<TYPE>& buffer);
108+
109+
// Raw Pointer Support
110+
void interpolate(const TYPE* const* ptrToBuffers, int numChannels, int numSamples);
111+
```
112+
#### 2. Process (Callback)
113+
Provides direct access to the upsampled data via a callback/lambda.
114+
115+
```cpp
116+
// 1. Vector Access (Most Common)
117+
// Provides the internal buffer as a vector of vectors
118+
oversampler.process([](std::vector<std::vector<TYPE>>& data) { ... });
119+
120+
// 2. JUCE Wrapper Access
121+
// Wraps the internal pointers in a temporary AudioBuffer for convenience.
122+
// (Only enables if passed a JUCE type)
123+
oversampler.process([](juce::AudioBuffer<TYPE> data) { ... });
124+
125+
// 3. Per-Channel Access
126+
// Calls your lambda once for each channel vector
127+
oversampler.process([](std::vector<TYPE>& channelData) { ... });
128+
```
129+
#### 3. Decimate (Internal -> Output)
130+
Downsamples the internal buffer and writes to the output.
131+
132+
```cpp
133+
// JUCE Support
134+
void decimate(juce::AudioBuffer<TYPE>& buffer);
135+
136+
// STL Support
137+
void decimate(std::vector<std::vector<TYPE>>& buffer);
138+
void decimate(std::vector<TYPE>& buffer);
139+
140+
// Raw Pointer Support
141+
void decimate(TYPE* const* ptrToBuffers, int numChannels, int numSamples);
142+
```
97143
## Latency
98144

99145
This library uses a linear-phase (symmetric) Sinc filter. By design, this introduces a known, fixed processing latency.
@@ -127,8 +173,6 @@ The repository includes a `tests/tests.cpp` file for validation. You can compile
127173
g++ tests/tests.cpp -o run_tests -std=c++17 -O3
128174
./run_tests
129175
```
130-
---
131-
132176
## License
133177

134178
This project is licensed under the **MIT License**. See the `LICENSE` file for details.

0 commit comments

Comments
 (0)