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.

181 lines
4.4KB

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