-
-
Notifications
You must be signed in to change notification settings - Fork 287
Resampling
I have implemented some simple functionality to resample from an input rate to a output rate. This can be achieved with the help of the ResampleStream class. The resampling is done with the help of the step_size parameter. In an earlier version I was only supporting integer values, but I refactored the class to support a floating point step size:
- If step_size is > 1.0 we perform an upsamping and the pitch gets higher
- If step_size is < 1.0 we perform an downsamping and the pitch gets lower.
There are quite a few other possibilities to specify the resampling: please have a look at the different begin methods in the class documentation.
We can resample both on the input and on the output side:
We wrap the original input stream in a ResampleStream. In the configuration we can indicate the from rate and the (fixed) target rate or a step size. In this example we perform a upsampling because we define a step size (factor) 1.5 times the input rate. There are also quite a few begin() method alternatives that let you do define the same thing.
AudioInfo info(44100,2,16);
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
ResampleStream resample(sound);
CsvOutput<int16_t> out(Serial);
StreamCopy copier(out, resample); // copies sound to out
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// define resampling info
auto rcfg = resample.defaultConfig();
rcfg.copyFrom(info);
rcrg.step_size = 1.5;
resample.begin(rcfg);
// Define CSV Output
auto config = out.defaultConfig();
config.sample_rate = sample_rate;
config.channels = channels;
out.begin(config);
// Setup sine wave
sineWave.begin(channels, sample_rate, N_B4);
Serial.println("started...");
}
// Arduino loop - copy sound to out
void loop() {
copier.copy();
}
We can achieve the same result on the output side: We wrap the target output stream in a ResampleStream. In the configuration we indicate the from rate and the target rate. In this example we perform a upsampling because the target rate is 1.5 times the input rate.
AudioInfo info(44100,2,16);
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> in(sineWave); // Stream generated from sine wave
CsvOutput<int16_t> out(Serial);
ResampleStream resample(out);
StreamCopy copier(resample, in); // copies sound to out
// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// define resampling info
auto rcfg = resample.defaultConfig();
rcfg.copyFrom(info);
rcrg.step_size = 1.5;
resample.begin(rcfg);
// Define CSV Output
auto config = out.defaultConfig();
config.sample_rate = sample_rate;
config.channels = channels;
out.begin(config);
// Setup sine wave
sineWave.begin(channels, sample_rate, N_B4);
Serial.println("started...");
}
// Arduino loop - copy sound to out
void loop() {
copier.copy();
}
The examples above were using the ResampleStream class which uses an efficient linear interpolation to calculate the examples. In addition we provide the ResampleStreamT template class where you can specify some alternative Interpolation Calculations
// We use a Parabolic Interpolator
ResampleStreamT<ParabolicInterpolator> resample(out);
Method | Quality | CPU Cost | Artifacts | Interpolates Sample Points |
---|---|---|---|---|
Linear | Low | Very Low | High | ✅ |
B-Spline (Cubic) | Moderate | Medium | Low | ❌ |
Lagrange (order 3) | High (order-dependent) | High | Moderate (oscillation) | ✅ |
Cubic Hermite | High | Medium | Low | ✅ |
Parabolic | Moderate | Low | Moderate | ✅ |