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.

324 lines
7.1KB

  1. #pragma once
  2. #include <assert.h>
  3. #include <string.h>
  4. #include <samplerate.h>
  5. #include <complex>
  6. #include "math.hpp"
  7. namespace rack {
  8. /** Useful for storing arrays of samples in ring buffers and casting them to `float*` to be used by interleaved processors, like SampleRateConverter */
  9. template <size_t CHANNELS>
  10. struct Frame {
  11. float samples[CHANNELS];
  12. };
  13. /** Simple FFT implementation
  14. If you need something fast, use pffft, KissFFT, etc instead.
  15. The size N must be a power of 2
  16. */
  17. struct SimpleFFT {
  18. int N;
  19. /** Twiddle factors e^(2pi k/N), interleaved complex numbers */
  20. std::complex<float> *tw;
  21. SimpleFFT(int N, bool inverse) : N(N) {
  22. tw = new std::complex<float>[N];
  23. for (int i = 0; i < N; i++) {
  24. float phase = 2*M_PI * (float)i / N;
  25. if (inverse)
  26. phase *= -1.0;
  27. tw[i] = std::exp(std::complex<float>(0.0, phase));
  28. }
  29. }
  30. ~SimpleFFT() {
  31. delete[] tw;
  32. }
  33. /** Reference naive implementation
  34. x and y are arrays of interleaved complex numbers
  35. y must be size N/s
  36. s is the stride factor for the x array which divides the size N
  37. */
  38. void dft(const std::complex<float> *x, std::complex<float> *y, int s=1) {
  39. for (int k = 0; k < N/s; k++) {
  40. std::complex<float> yk = 0.0;
  41. for (int n = 0; n < N; n += s) {
  42. int m = (n*k) % N;
  43. yk += x[n] * tw[m];
  44. }
  45. y[k] = yk;
  46. }
  47. }
  48. void fft(const std::complex<float> *x, std::complex<float> *y, int s=1) {
  49. if (N/s <= 2) {
  50. // Naive DFT is faster than further FFT recursions at this point
  51. dft(x, y, s);
  52. return;
  53. }
  54. std::complex<float> *e = new std::complex<float>[N/(2*s)]; // Even inputs
  55. std::complex<float> *o = new std::complex<float>[N/(2*s)]; // Odd inputs
  56. fft(x, e, 2*s);
  57. fft(x + s, o, 2*s);
  58. for (int k = 0; k < N/(2*s); k++) {
  59. int m = (k*s) % N;
  60. y[k] = e[k] + tw[m] * o[k];
  61. y[k + N/(2*s)] = e[k] - tw[m] * o[k];
  62. }
  63. delete[] e;
  64. delete[] o;
  65. }
  66. };
  67. /** A simple cyclic buffer.
  68. S must be a power of 2.
  69. push() is constant time O(1)
  70. */
  71. template <typename T, int S>
  72. struct RingBuffer {
  73. T data[S];
  74. int start = 0;
  75. int end = 0;
  76. int mask(int i) const {
  77. return i & (S - 1);
  78. }
  79. void push(T t) {
  80. int i = mask(end++);
  81. data[i] = t;
  82. }
  83. T shift() {
  84. return data[mask(start++)];
  85. }
  86. void clear() {
  87. start = end;
  88. }
  89. bool empty() const {
  90. return start >= end;
  91. }
  92. bool full() const {
  93. return end - start >= S;
  94. }
  95. int size() const {
  96. return end - start;
  97. }
  98. int capacity() const {
  99. return S - size();
  100. }
  101. };
  102. /** A cyclic buffer which maintains a valid linear array of size S by keeping a copy of the buffer in adjacent memory.
  103. S must be a power of 2.
  104. push() is constant time O(2) relative to RingBuffer
  105. */
  106. template <typename T, int S>
  107. struct DoubleRingBuffer {
  108. T data[S*2];
  109. int start = 0;
  110. int end = 0;
  111. int mask(int i) const {
  112. return i & (S - 1);
  113. }
  114. void push(T t) {
  115. int i = mask(end++);
  116. data[i] = t;
  117. data[i + S] = t;
  118. }
  119. T shift() {
  120. return data[mask(start++)];
  121. }
  122. void clear() {
  123. start = end;
  124. }
  125. bool empty() const {
  126. return start >= end;
  127. }
  128. bool full() const {
  129. return end - start >= S;
  130. }
  131. int size() const {
  132. return end - start;
  133. }
  134. int capacity() const {
  135. return S - size();
  136. }
  137. /** Returns a pointer to S consecutive elements for appending.
  138. If any data is appended, you must call endIncr afterwards.
  139. Pointer is invalidated when any other method is called.
  140. */
  141. T *endData() {
  142. return &data[mask(end)];
  143. }
  144. void endIncr(int n) {
  145. int e = mask(end);
  146. int e1 = e + n;
  147. int e2 = mini(e1, S);
  148. // Copy data forward
  149. memcpy(data + S + e, data + e, sizeof(T) * (e2 - e));
  150. if (e1 > S) {
  151. // Copy data backward from the doubled block to the main block
  152. memcpy(data, data + S, sizeof(T) * (e1 - S));
  153. }
  154. end += n;
  155. }
  156. /** Returns a pointer to S consecutive elements for consumption
  157. If any data is consumed, call startIncr afterwards.
  158. */
  159. const T *startData() const {
  160. return &data[mask(start)];
  161. }
  162. void startIncr(int n) {
  163. start += n;
  164. }
  165. };
  166. /** A cyclic buffer which maintains a valid linear array of size S by sliding along a larger block of size N.
  167. The linear array of S elements are moved back to the start of the block once it outgrows past the end.
  168. This happens every N - S pushes, so the push() time is O(1 + S / (N - S)).
  169. For example, a float buffer of size 64 in a block of size 1024 is nearly as efficient as RingBuffer.
  170. */
  171. template <typename T, size_t S, size_t N>
  172. struct AppleRingBuffer {
  173. T data[N];
  174. size_t start = 0;
  175. size_t end = 0;
  176. void push(T t) {
  177. data[end++] = t;
  178. if (end >= N) {
  179. // move end block to beginning
  180. memmove(data, &data[N - S], sizeof(T) * S);
  181. start -= N - S;
  182. end = S;
  183. }
  184. }
  185. T shift() {
  186. return data[start++];
  187. }
  188. bool empty() const {
  189. return start >= end;
  190. }
  191. bool full() const {
  192. return end - start >= S;
  193. }
  194. size_t size() const {
  195. return end - start;
  196. }
  197. /** Returns a pointer to S consecutive elements for appending, requesting to append n elements.
  198. */
  199. T *endData(size_t n) {
  200. // TODO
  201. return &data[end];
  202. }
  203. /** Returns a pointer to S consecutive elements for consumption
  204. If any data is consumed, call startIncr afterwards.
  205. */
  206. const T *startData() const {
  207. return &data[start];
  208. }
  209. void startIncr(size_t n) {
  210. // This is valid as long as n < S
  211. start += n;
  212. }
  213. };
  214. template<int CHANNELS>
  215. struct SampleRateConverter {
  216. SRC_STATE *state;
  217. SRC_DATA data;
  218. SampleRateConverter() {
  219. int error;
  220. state = src_new(SRC_SINC_FASTEST, CHANNELS, &error);
  221. assert(!error);
  222. data.src_ratio = 1.0;
  223. data.end_of_input = false;
  224. }
  225. ~SampleRateConverter() {
  226. src_delete(state);
  227. }
  228. void setRatio(float r) {
  229. src_set_ratio(state, r);
  230. data.src_ratio = r;
  231. }
  232. /** `in` and `out` are interlaced with the number of channels */
  233. void process(const float *in, int *inFrames, float *out, int *outFrames) {
  234. // The const cast is okay since src_process does not modify it
  235. data.data_in = const_cast<float*>(in);
  236. data.input_frames = *inFrames;
  237. data.data_out = out;
  238. data.output_frames = *outFrames;
  239. src_process(state, &data);
  240. *inFrames = data.input_frames_used;
  241. *outFrames = data.output_frames_gen;
  242. }
  243. void reset() {
  244. src_reset(state);
  245. }
  246. };
  247. // Pre-made minBLEP samples in minBLEP.cpp
  248. extern const float minblep_16_32[];
  249. template<int ZERO_CROSSINGS>
  250. struct MinBLEP {
  251. float buf[2*ZERO_CROSSINGS] = {};
  252. int pos = 0;
  253. const float *minblep;
  254. int oversample;
  255. /** Places a discontinuity with magnitude dx at -1 < p <= 0 relative to the current frame */
  256. void jump(float p, float dx) {
  257. if (p <= -1 || 0 < p)
  258. return;
  259. for (int j = 0; j < 2*ZERO_CROSSINGS; j++) {
  260. float minblepIndex = ((float)j - p) * oversample;
  261. int index = (pos + j) % (2*ZERO_CROSSINGS);
  262. buf[index] += dx * (-1.0 + interpf(minblep, minblepIndex));
  263. }
  264. }
  265. float shift() {
  266. float v = buf[pos];
  267. buf[pos] = 0.0;
  268. pos = (pos + 1) % (2*ZERO_CROSSINGS);
  269. return v;
  270. }
  271. };
  272. struct RCFilter {
  273. float c = 0.0;
  274. float xstate[1] = {};
  275. float ystate[1] = {};
  276. // `r` is the ratio between the cutoff frequency and sample rate, i.e. r = f_c / f_s
  277. void setCutoff(float r) {
  278. c = 2.0 / r;
  279. }
  280. void process(float x) {
  281. float y = (x + xstate[0] - ystate[0] * (1 - c)) / (1 + c);
  282. xstate[0] = x;
  283. ystate[0] = y;
  284. }
  285. float lowpass() {
  286. return ystate[0];
  287. }
  288. float highpass() {
  289. return xstate[0] - ystate[0];
  290. }
  291. };
  292. } // namespace rack