Skip to content

Resampling

Phil Schatzmann edited this page Jun 13, 2025 · 34 revisions

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:

Resampling of Input

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();
}

Resampling of Output

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();
}

Extended Resampling With an Interpolation Class

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
Clone this wiki locally