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.

182 lines
4.3KB

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