You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
1.6KB

  1. #pragma once
  2. #include <assert.h>
  3. #include <string.h>
  4. #include <speex/speex_resampler.h>
  5. #include "frame.hpp"
  6. namespace rack {
  7. template<int CHANNELS>
  8. struct SampleRateConverter {
  9. SpeexResamplerState *state = NULL;
  10. bool noConversion = true;
  11. int inRate = 44100;
  12. int outRate = 44100;
  13. SampleRateConverter() {
  14. int error;
  15. state = speex_resampler_init(CHANNELS, inRate, outRate, SPEEX_RESAMPLER_QUALITY_DEFAULT, &error);
  16. assert(error == RESAMPLER_ERR_SUCCESS);
  17. }
  18. ~SampleRateConverter() {
  19. speex_resampler_destroy(state);
  20. }
  21. void setRates(int in, int out) {
  22. if (in != inRate || out != outRate) { // speex doesn't optimize setting the rates to the existing values.
  23. int error = speex_resampler_set_rate(state, in, out);
  24. assert(error == RESAMPLER_ERR_SUCCESS);
  25. inRate = in;
  26. outRate = out;
  27. noConversion = in == out;
  28. }
  29. }
  30. void setRatioSmooth(float ratio) DEPRECATED {
  31. // FIXME: this doesn't do a smooth change -- speex doesn't appear to support that.
  32. const int base = 1000;
  33. setRates(base, ratio * base);
  34. }
  35. /** `in` and `out` are interlaced with the number of channels */
  36. void process(const Frame<CHANNELS> *in, int *inFrames, Frame<CHANNELS> *out, int *outFrames) {
  37. if (noConversion) {
  38. int len = std::min(*inFrames, *outFrames);
  39. memcpy(out, in, len * sizeof(Frame<CHANNELS>));
  40. *inFrames = len;
  41. *outFrames = len;
  42. return;
  43. }
  44. speex_resampler_process_interleaved_float(state, (const float*)in, (unsigned int*)inFrames, (float*)out, (unsigned int*)outFrames);
  45. }
  46. void reset() {
  47. int error = speex_resampler_reset_mem(state);
  48. assert(error == RESAMPLER_ERR_SUCCESS);
  49. }
  50. };
  51. } // namespace rack