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.

93 lines
2.1KB

  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 *st = NULL;
  10. int channels = CHANNELS;
  11. int quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
  12. int inRate = 44100;
  13. int outRate = 44100;
  14. SampleRateConverter() {
  15. refreshState();
  16. }
  17. ~SampleRateConverter() {
  18. if (st) {
  19. speex_resampler_destroy(st);
  20. }
  21. }
  22. /** Sets the number of channels to actually process. This can be at most CHANNELS. */
  23. void setChannels(int channels) {
  24. assert(channels <= CHANNELS);
  25. this->channels = channels;
  26. refreshState();
  27. }
  28. void setQuality(int quality) {
  29. this->quality = quality;
  30. refreshState();
  31. }
  32. void setRates(int inRate, int outRate) {
  33. this->inRate = inRate;
  34. this->outRate = outRate;
  35. refreshState();
  36. }
  37. void refreshState() {
  38. if (st) {
  39. speex_resampler_destroy(st);
  40. st = NULL;
  41. }
  42. if (channels > 0 && inRate != outRate) {
  43. int err;
  44. st = speex_resampler_init(channels, inRate, outRate, quality, &err);
  45. assert(st);
  46. assert(err == RESAMPLER_ERR_SUCCESS);
  47. speex_resampler_set_input_stride(st, CHANNELS);
  48. speex_resampler_set_output_stride(st, CHANNELS);
  49. }
  50. }
  51. /** `in` and `out` are interlaced with the number of channels */
  52. void process(const Frame<CHANNELS> *in, int *inFrames, Frame<CHANNELS> *out, int *outFrames) {
  53. assert(in);
  54. assert(inFrames);
  55. assert(out);
  56. assert(outFrames);
  57. if (st) {
  58. // Resample each channel at a time
  59. spx_uint32_t inLen;
  60. spx_uint32_t outLen;
  61. for (int i = 0; i < channels; i++) {
  62. inLen = *inFrames;
  63. outLen = *outFrames;
  64. int err = speex_resampler_process_float(st, i, ((const float*) in) + i, &inLen, ((float*) out) + i, &outLen);
  65. assert(err == RESAMPLER_ERR_SUCCESS);
  66. }
  67. *inFrames = inLen;
  68. *outFrames = outLen;
  69. }
  70. else {
  71. // Simply copy the buffer without conversion
  72. int frames = min(*inFrames, *outFrames);
  73. memcpy(out, in, frames * sizeof(Frame<CHANNELS>));
  74. *inFrames = frames;
  75. *outFrames = frames;
  76. }
  77. }
  78. };
  79. } // namespace rack