revsc.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * RevSC
  3. *
  4. * This code has been extracted from the Csound opcode "reverbsc".
  5. * It has been modified to work as a Soundpipe module.
  6. *
  7. * Original Author(s): Sean Costello, Istvan Varga
  8. * Year: 1999, 2005
  9. * Location: Opcodes/reverbsc.c
  10. *
  11. */
  12. #include <math.h>
  13. #include <stdlib.h>
  14. #include <stdint.h>
  15. #include <string.h>
  16. #include "base.h"
  17. #include "revsc.h"
  18. #define DEFAULT_SRATE 44100.0
  19. #define MIN_SRATE 5000.0
  20. #define MAX_SRATE 1000000.0
  21. #define MAX_PITCHMOD 20.0
  22. #define DELAYPOS_SHIFT 28
  23. #define DELAYPOS_SCALE 0x10000000
  24. #define DELAYPOS_MASK 0x0FFFFFFF
  25. #ifndef M_PI
  26. #define M_PI 3.14159265358979323846 /* pi */
  27. #endif
  28. /* reverbParams[n][0] = delay time (in seconds) */
  29. /* reverbParams[n][1] = random variation in delay time (in seconds) */
  30. /* reverbParams[n][2] = random variation frequency (in 1/sec) */
  31. /* reverbParams[n][3] = random seed (0 - 32767) */
  32. static const SPFLOAT reverbParams[8][4] = {
  33. { (2473.0 / DEFAULT_SRATE), 0.0010, 3.100, 1966.0 },
  34. { (2767.0 / DEFAULT_SRATE), 0.0011, 3.500, 29491.0 },
  35. { (3217.0 / DEFAULT_SRATE), 0.0017, 1.110, 22937.0 },
  36. { (3557.0 / DEFAULT_SRATE), 0.0006, 3.973, 9830.0 },
  37. { (3907.0 / DEFAULT_SRATE), 0.0010, 2.341, 20643.0 },
  38. { (4127.0 / DEFAULT_SRATE), 0.0011, 1.897, 22937.0 },
  39. { (2143.0 / DEFAULT_SRATE), 0.0017, 0.891, 29491.0 },
  40. { (1933.0 / DEFAULT_SRATE), 0.0006, 3.221, 14417.0 }
  41. };
  42. static int delay_line_max_samples(SPFLOAT sr, SPFLOAT iPitchMod, int n);
  43. static int init_delay_line(sp_revsc *p, sp_revsc_dl *lp, int n);
  44. static int delay_line_bytes_alloc(SPFLOAT sr, SPFLOAT iPitchMod, int n);
  45. static const SPFLOAT outputGain = 0.35;
  46. static const SPFLOAT jpScale = 0.25;
  47. int sp_revsc_create(sp_revsc **p){
  48. *p = malloc(sizeof(sp_revsc));
  49. return SP_OK;
  50. }
  51. int sp_revsc_init(sp_data *sp, sp_revsc *p)
  52. {
  53. p->iSampleRate = sp->sr;
  54. p->sampleRate = sp->sr;
  55. p->feedback = 0.97;
  56. p->lpfreq = 10000;
  57. p->iPitchMod = 1;
  58. p->iSkipInit = 0;
  59. p->dampFact = 1.0;
  60. p->prv_LPFreq = 0.0;
  61. p->initDone = 1;
  62. int i, nBytes = 0;
  63. for(i = 0; i < 8; i++){
  64. nBytes += delay_line_bytes_alloc(sp->sr, 1, i);
  65. }
  66. sp_auxdata_alloc(&p->aux, nBytes);
  67. nBytes = 0;
  68. for (i = 0; i < 8; i++) {
  69. p->delayLines[i].buf = (SPFLOAT*) (((char*) p->aux.ptr) + nBytes);
  70. init_delay_line(p, &p->delayLines[i], i);
  71. nBytes += delay_line_bytes_alloc(sp->sr, 1, i);
  72. }
  73. return SP_OK;
  74. }
  75. int sp_revsc_destroy(sp_revsc **p)
  76. {
  77. sp_revsc *pp = *p;
  78. sp_auxdata_free(&pp->aux);
  79. free(*p);
  80. return SP_OK;
  81. }
  82. static int delay_line_max_samples(SPFLOAT sr, SPFLOAT iPitchMod, int n)
  83. {
  84. SPFLOAT maxDel;
  85. maxDel = reverbParams[n][0];
  86. maxDel += (reverbParams[n][1] * (SPFLOAT) iPitchMod * 1.125);
  87. return (int) (maxDel * sr + 16.5);
  88. }
  89. static int delay_line_bytes_alloc(SPFLOAT sr, SPFLOAT iPitchMod, int n)
  90. {
  91. int nBytes = 0;
  92. nBytes += (delay_line_max_samples(sr, iPitchMod, n) * (int) sizeof(SPFLOAT));
  93. return nBytes;
  94. }
  95. static void next_random_lineseg(sp_revsc *p, sp_revsc_dl *lp, int n)
  96. {
  97. SPFLOAT prvDel, nxtDel, phs_incVal;
  98. /* update random seed */
  99. if (lp->seedVal < 0)
  100. lp->seedVal += 0x10000;
  101. lp->seedVal = (lp->seedVal * 15625 + 1) & 0xFFFF;
  102. if (lp->seedVal >= 0x8000)
  103. lp->seedVal -= 0x10000;
  104. /* length of next segment in samples */
  105. lp->randLine_cnt = (int) ((p->sampleRate / reverbParams[n][2]) + 0.5);
  106. prvDel = (SPFLOAT) lp->writePos;
  107. prvDel -= ((SPFLOAT) lp->readPos
  108. + ((SPFLOAT) lp->readPosFrac / (SPFLOAT) DELAYPOS_SCALE));
  109. while (prvDel < 0.0)
  110. prvDel += lp->bufferSize;
  111. prvDel = prvDel / p->sampleRate; /* previous delay time in seconds */
  112. nxtDel = (SPFLOAT) lp->seedVal * reverbParams[n][1] / 32768.0;
  113. /* next delay time in seconds */
  114. nxtDel = reverbParams[n][0] + (nxtDel * (SPFLOAT) p->iPitchMod);
  115. /* calculate phase increment per sample */
  116. phs_incVal = (prvDel - nxtDel) / (SPFLOAT) lp->randLine_cnt;
  117. phs_incVal = phs_incVal * p->sampleRate + 1.0;
  118. lp->readPosFrac_inc = (int) (phs_incVal * DELAYPOS_SCALE + 0.5);
  119. }
  120. static int init_delay_line(sp_revsc *p, sp_revsc_dl *lp, int n)
  121. {
  122. SPFLOAT readPos;
  123. /* int i; */
  124. /* calculate length of delay line */
  125. lp->bufferSize = delay_line_max_samples(p->sampleRate, 1, n);
  126. lp->dummy = 0;
  127. lp->writePos = 0;
  128. /* set random seed */
  129. lp->seedVal = (int) (reverbParams[n][3] + 0.5);
  130. /* set initial delay time */
  131. readPos = (SPFLOAT) lp->seedVal * reverbParams[n][1] / 32768;
  132. readPos = reverbParams[n][0] + (readPos * (SPFLOAT) p->iPitchMod);
  133. readPos = (SPFLOAT) lp->bufferSize - (readPos * p->sampleRate);
  134. lp->readPos = (int) readPos;
  135. readPos = (readPos - (SPFLOAT) lp->readPos) * (SPFLOAT) DELAYPOS_SCALE;
  136. lp->readPosFrac = (int) (readPos + 0.5);
  137. /* initialise first random line segment */
  138. next_random_lineseg(p, lp, n);
  139. /* clear delay line to zero */
  140. lp->filterState = 0.0;
  141. memset(lp->buf, 0, sizeof(SPFLOAT) * lp->bufferSize);
  142. return SP_OK;
  143. }
  144. int sp_revsc_compute(sp_data *sp, sp_revsc *p, SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out1, SPFLOAT *out2)
  145. {
  146. SPFLOAT ainL, ainR, aoutL, aoutR;
  147. SPFLOAT vm1, v0, v1, v2, am1, a0, a1, a2, frac;
  148. sp_revsc_dl *lp;
  149. int readPos;
  150. uint32_t n;
  151. int bufferSize; /* Local copy */
  152. SPFLOAT dampFact = p->dampFact;
  153. if (p->initDone <= 0) return SP_NOT_OK;
  154. /* calculate tone filter coefficient if frequency changed */
  155. if (p->lpfreq != p->prv_LPFreq) {
  156. p->prv_LPFreq = p->lpfreq;
  157. dampFact = 2.0 - cos(p->prv_LPFreq * (2 * M_PI) / p->sampleRate);
  158. dampFact = p->dampFact = dampFact - sqrt(dampFact * dampFact - 1.0);
  159. }
  160. /* calculate "resultant junction pressure" and mix to input signals */
  161. ainL = aoutL = aoutR = 0.0;
  162. for (n = 0; n < 8; n++) {
  163. ainL += p->delayLines[n].filterState;
  164. }
  165. ainL *= jpScale;
  166. ainR = ainL + *in2;
  167. ainL = ainL + *in1;
  168. /* loop through all delay lines */
  169. for (n = 0; n < 8; n++) {
  170. lp = &p->delayLines[n];
  171. bufferSize = lp->bufferSize;
  172. /* send input signal and feedback to delay line */
  173. lp->buf[lp->writePos] = (SPFLOAT) ((n & 1 ? ainR : ainL)
  174. - lp->filterState);
  175. if (++lp->writePos >= bufferSize) {
  176. lp->writePos -= bufferSize;
  177. }
  178. /* read from delay line with cubic interpolation */
  179. if (lp->readPosFrac >= DELAYPOS_SCALE) {
  180. lp->readPos += (lp->readPosFrac >> DELAYPOS_SHIFT);
  181. lp->readPosFrac &= DELAYPOS_MASK;
  182. }
  183. if (lp->readPos >= bufferSize)
  184. lp->readPos -= bufferSize;
  185. readPos = lp->readPos;
  186. frac = (SPFLOAT) lp->readPosFrac * (1.0 / (SPFLOAT) DELAYPOS_SCALE);
  187. /* calculate interpolation coefficients */
  188. a2 = frac * frac; a2 -= 1.0; a2 *= (1.0 / 6.0);
  189. a1 = frac; a1 += 1.0; a1 *= 0.5; am1 = a1 - 1.0;
  190. a0 = 3.0 * a2; a1 -= a0; am1 -= a2; a0 -= frac;
  191. /* read four samples for interpolation */
  192. if (readPos > 0 && readPos < (bufferSize - 2)) {
  193. vm1 = (SPFLOAT) (lp->buf[readPos - 1]);
  194. v0 = (SPFLOAT) (lp->buf[readPos]);
  195. v1 = (SPFLOAT) (lp->buf[readPos + 1]);
  196. v2 = (SPFLOAT) (lp->buf[readPos + 2]);
  197. }
  198. else {
  199. /* at buffer wrap-around, need to check index */
  200. if (--readPos < 0) readPos += bufferSize;
  201. vm1 = (SPFLOAT) lp->buf[readPos];
  202. if (++readPos >= bufferSize) readPos -= bufferSize;
  203. v0 = (SPFLOAT) lp->buf[readPos];
  204. if (++readPos >= bufferSize) readPos -= bufferSize;
  205. v1 = (SPFLOAT) lp->buf[readPos];
  206. if (++readPos >= bufferSize) readPos -= bufferSize;
  207. v2 = (SPFLOAT) lp->buf[readPos];
  208. }
  209. v0 = (am1 * vm1 + a0 * v0 + a1 * v1 + a2 * v2) * frac + v0;
  210. /* update buffer read position */
  211. lp->readPosFrac += lp->readPosFrac_inc;
  212. /* apply feedback gain and lowpass filter */
  213. v0 *= (SPFLOAT) p->feedback;
  214. v0 = (lp->filterState - v0) * dampFact + v0;
  215. lp->filterState = v0;
  216. /* mix to output */
  217. if (n & 1) {
  218. aoutR += v0;
  219. }else{
  220. aoutL += v0;
  221. }
  222. /* start next random line segment if current one has reached endpoint */
  223. if (--(lp->randLine_cnt) <= 0) {
  224. next_random_lineseg(p, lp, n);
  225. }
  226. }
  227. /* someday, use aoutR for multimono out */
  228. *out1 = aoutL * outputGain;
  229. *out2 = aoutR * outputGain;
  230. return SP_OK;
  231. }