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.

178 lines
4.2KB

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