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.

64 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;
  10. bool bypass = false;
  11. SampleRateConverter() {
  12. int error;
  13. state = speex_resampler_init(CHANNELS, 44100, 44100, SPEEX_RESAMPLER_QUALITY_DEFAULT, &error);
  14. assert(error == RESAMPLER_ERR_SUCCESS);
  15. }
  16. ~SampleRateConverter() {
  17. speex_resampler_destroy(state);
  18. }
  19. void setQuality(int quality) {
  20. speex_resampler_set_quality(state, quality);
  21. }
  22. void setRates(int inRate, int outRate) {
  23. int oldInRate, oldOutRate;
  24. getRates(&oldInRate, &oldOutRate);
  25. if (inRate == oldInRate && outRate == oldOutRate)
  26. return;
  27. int error = speex_resampler_set_rate(state, inRate, outRate);
  28. assert(error == RESAMPLER_ERR_SUCCESS);
  29. }
  30. void getRates(int *inRate, int *outRate) {
  31. spx_uint32_t inRate32, outRate32;
  32. speex_resampler_get_rate(state, &inRate32, &outRate32);
  33. if (inRate) *inRate = inRate32;
  34. if (outRate) *outRate = outRate32;
  35. }
  36. /** `in` and `out` are interlaced with the number of channels */
  37. void process(const Frame<CHANNELS> *in, int *inFrames, Frame<CHANNELS> *out, int *outFrames) {
  38. if (bypass) {
  39. int len = std::min(*inFrames, *outFrames);
  40. memcpy(out, in, len * sizeof(Frame<CHANNELS>));
  41. *inFrames = len;
  42. *outFrames = len;
  43. return;
  44. }
  45. speex_resampler_process_interleaved_float(state, (const float*)in, (unsigned int*)inFrames, (float*)out, (unsigned int*)outFrames);
  46. }
  47. void reset() {
  48. int error = speex_resampler_reset_mem(state);
  49. assert(error == RESAMPLER_ERR_SUCCESS);
  50. }
  51. };
  52. } // namespace rack