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.

183 lines
4.2KB

  1. #pragma once
  2. #ifndef RACK_SKIP_RESAMPLER
  3. #include <assert.h>
  4. #include <string.h>
  5. #include <speex/speex_resampler.h>
  6. #include "frame.hpp"
  7. #include "ringbuffer.hpp"
  8. #include "fir.hpp"
  9. namespace rack {
  10. template<int CHANNELS>
  11. struct SampleRateConverter {
  12. SpeexResamplerState *st = NULL;
  13. int channels = CHANNELS;
  14. int quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
  15. int inRate = 44100;
  16. int outRate = 44100;
  17. SampleRateConverter() {
  18. refreshState();
  19. }
  20. ~SampleRateConverter() {
  21. if (st) {
  22. speex_resampler_destroy(st);
  23. }
  24. }
  25. /** Sets the number of channels to actually process. This can be at most CHANNELS. */
  26. void setChannels(int channels) {
  27. assert(channels <= CHANNELS);
  28. if (channels == this->channels)
  29. return;
  30. this->channels = channels;
  31. refreshState();
  32. }
  33. /** From 0 (worst, fastest) to 10 (best, slowest) */
  34. void setQuality(int quality) {
  35. if (quality == this->quality)
  36. return;
  37. this->quality = quality;
  38. refreshState();
  39. }
  40. void setRates(int inRate, int outRate) {
  41. if (inRate == this->inRate && outRate == this->outRate)
  42. return;
  43. this->inRate = inRate;
  44. this->outRate = outRate;
  45. refreshState();
  46. }
  47. void refreshState() {
  48. if (st) {
  49. speex_resampler_destroy(st);
  50. st = NULL;
  51. }
  52. if (channels > 0 && inRate != outRate) {
  53. int err;
  54. st = speex_resampler_init(channels, inRate, outRate, quality, &err);
  55. #if 0
  56. assert(st);
  57. assert(err == RESAMPLER_ERR_SUCCESS);
  58. #endif
  59. speex_resampler_set_input_stride(st, CHANNELS);
  60. speex_resampler_set_output_stride(st, CHANNELS);
  61. }
  62. }
  63. /** `in` and `out` are interlaced with the number of channels */
  64. void process(const Frame<CHANNELS> *in, int *inFrames, Frame<CHANNELS> *out, int *outFrames) {
  65. #if 0
  66. assert(in);
  67. assert(inFrames);
  68. assert(out);
  69. assert(outFrames);
  70. #endif
  71. if (st) {
  72. // Resample each channel at a time
  73. spx_uint32_t inLen;
  74. spx_uint32_t outLen;
  75. for (int i = 0; i < channels; i++) {
  76. inLen = *inFrames;
  77. outLen = *outFrames;
  78. int err = speex_resampler_process_float(st, i, ((const float*) in) + i, &inLen, ((float*) out) + i, &outLen);
  79. #if 0
  80. assert(err == RESAMPLER_ERR_SUCCESS);
  81. #endif
  82. }
  83. *inFrames = inLen;
  84. *outFrames = outLen;
  85. }
  86. else {
  87. // Simply copy the buffer without conversion
  88. int frames = min(*inFrames, *outFrames);
  89. memcpy(out, in, frames * sizeof(Frame<CHANNELS>));
  90. *inFrames = frames;
  91. *outFrames = frames;
  92. }
  93. }
  94. };
  95. template<int OVERSAMPLE, int QUALITY>
  96. struct Decimator {
  97. float inBuffer[OVERSAMPLE*QUALITY];
  98. float kernel[OVERSAMPLE*QUALITY];
  99. int inIndex;
  100. Decimator(float cutoff = 0.9f) {
  101. boxcarLowpassIR(kernel, OVERSAMPLE*QUALITY, cutoff * 0.5f / OVERSAMPLE);
  102. blackmanHarrisWindow(kernel, OVERSAMPLE*QUALITY);
  103. reset();
  104. }
  105. void reset() {
  106. inIndex = 0;
  107. memset(inBuffer, 0, sizeof(inBuffer));
  108. }
  109. /** `in` must be length OVERSAMPLE */
  110. float process(float *in) {
  111. // Copy input to buffer
  112. memcpy(&inBuffer[inIndex], in, OVERSAMPLE*sizeof(float));
  113. // Advance index
  114. inIndex += OVERSAMPLE;
  115. inIndex %= OVERSAMPLE*QUALITY;
  116. // Perform naive convolution
  117. float out = 0.f;
  118. for (int i = 0; i < OVERSAMPLE*QUALITY; i++) {
  119. int index = inIndex - 1 - i;
  120. index = (index + OVERSAMPLE*QUALITY) % (OVERSAMPLE*QUALITY);
  121. out += kernel[i] * inBuffer[index];
  122. }
  123. return out;
  124. }
  125. };
  126. template<int OVERSAMPLE, int QUALITY>
  127. struct Upsampler {
  128. float inBuffer[QUALITY];
  129. float kernel[OVERSAMPLE*QUALITY];
  130. int inIndex;
  131. Upsampler(float cutoff = 0.9f) {
  132. boxcarLowpassIR(kernel, OVERSAMPLE*QUALITY, cutoff * 0.5f / OVERSAMPLE);
  133. blackmanHarrisWindow(kernel, OVERSAMPLE*QUALITY);
  134. reset();
  135. }
  136. void reset() {
  137. inIndex = 0;
  138. memset(inBuffer, 0, sizeof(inBuffer));
  139. }
  140. /** `out` must be length OVERSAMPLE */
  141. void process(float in, float *out) {
  142. // Zero-stuff input buffer
  143. inBuffer[inIndex] = OVERSAMPLE * in;
  144. // Advance index
  145. inIndex++;
  146. inIndex %= QUALITY;
  147. // Naively convolve each sample
  148. // TODO replace with polyphase filter hierarchy
  149. for (int i = 0; i < OVERSAMPLE; i++) {
  150. float y = 0.f;
  151. for (int j = 0; j < QUALITY; j++) {
  152. int index = inIndex - 1 - j;
  153. index = (index + QUALITY) % QUALITY;
  154. int kernelIndex = OVERSAMPLE * j + i;
  155. y += kernel[kernelIndex] * inBuffer[index];
  156. }
  157. out[i] = y;
  158. }
  159. }
  160. };
  161. } // namespace rack
  162. #endif // RACK_SKIP_RESAMPLER