Team Fortress 2 Source Code as on 22/4/2020
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.

9679 lines
239 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // snd_dsp.c -- audio processing routines
  9. #include "audio_pch.h"
  10. #include "snd_mix_buf.h"
  11. #include "iprediction.h"
  12. #include "../../common.h" // for parsing routines
  13. #include "vstdlib/random.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. #define SIGN(d) ((d)<0?-1:1)
  17. #define ABS(a) abs(a)
  18. #define MSEC_TO_SAMPS(a) (((a)*SOUND_DMA_SPEED) / 1000) // convert milliseconds to # samples in equivalent time
  19. #define SEC_TO_SAMPS(a) ((a)*SOUND_DMA_SPEED) // convert seconds to # samples in equivalent time
  20. // Suppress the noisy warnings caused by CLIP_DSP
  21. #if defined(__clang__)
  22. #pragma GCC diagnostic ignored "-Wself-assign"
  23. #endif
  24. #define CLIP_DSP(x) (x)
  25. extern ConVar das_debug;
  26. #define SOUND_MS_PER_FT 1 // sound travels approx 1 foot per millisecond
  27. #define ROOM_MAX_SIZE 1000 // max size in feet of room simulation for dsp
  28. void DSP_ReleaseMemory( void );
  29. bool DSP_LoadPresetFile( void );
  30. extern float Gain_To_dB ( float gain );
  31. extern float dB_To_Gain ( float dB );
  32. extern float Gain_To_Amplitude ( float gain );
  33. extern float Amplitude_To_Gain ( float amplitude );
  34. extern bool g_bdas_room_init;
  35. extern bool g_bdas_init_nodes;
  36. //===============================================================================
  37. //
  38. // Digital Signal Processing algorithms for audio FX.
  39. //
  40. // KellyB 2/18/03
  41. //===============================================================================
  42. // Performance notes:
  43. // DSP processing should take no more than 3ms total time per frame to remain on par with hl1
  44. // Assume a min frame rate of 24fps = 42ms per frame
  45. // at 24fps, to maintain 44.1khz output rate, we must process about 1840 mono samples per frame.
  46. // So we must process 1840 samples in 3ms.
  47. // on a 1Ghz CPU (mid-low end CPU) 3ms provides roughly 3,000,000 cycles.
  48. // Thus we have 3e6 / 1840 = 1630 cycles per sample.
  49. #define PBITS 12 // parameter bits
  50. #define PMAX ((1 << PBITS)) // parameter max
  51. // crossfade from y2 to y1 at point r (0 < r < PMAX)
  52. #define XFADE(y1,y2,r) ((y2) + ( ( ((y1) - (y2)) * (r) ) >> PBITS) )
  53. // exponential crossfade from y2 to y1 at point r (0 < r < PMAX)
  54. #define XFADE_EXP(y1, y2, r) ((y2) + ((((((y1) - (y2)) * (r) ) >> PBITS) * (r)) >> PBITS) )
  55. /////////////////////
  56. // dsp helpers
  57. /////////////////////
  58. // reverse delay pointer
  59. inline void DlyPtrReverse (int dlysize, int *psamps, int **ppsamp)
  60. {
  61. // when *ppsamp = psamps - 1, it wraps around to *ppsamp = psamps + dlysize
  62. if ( *ppsamp < psamps )
  63. *ppsamp += dlysize + 1;
  64. }
  65. // advance delay pointer
  66. inline void DlyPtrForward (int dlysize, int *psamps, int **ppsamp)
  67. {
  68. // when *ppsamp = psamps + dlysize + 1, it wraps around to *ppsamp = psamps
  69. if ( *ppsamp > psamps + dlysize )
  70. *ppsamp -= dlysize + 1;
  71. }
  72. // Infinite Impulse Response (feedback) filter, cannonical form
  73. // returns single sample 'out' for current input value 'in'
  74. // in: input sample
  75. // psamp: internal state array, dimension max(cdenom,cnumer) + 1
  76. // cnumer,cdenom: numerator and denominator filter orders
  77. // denom,numer: cdenom+1 dimensional arrays of filter params
  78. //
  79. // for cdenom = 4:
  80. //
  81. // 1 psamp0(n) numer0
  82. // in(n)--->(+)--(*)---.------(*)---->(+)---> out(n)
  83. // ^ | ^
  84. // | [Delay d] |
  85. // | | |
  86. // | -denom1 |psamp1 numer1 |
  87. // ----(*)---.------(*)-------
  88. // ^ | ^
  89. // | [Delay d] |
  90. // | | |
  91. // | -denom2 |psamp2 numer2 |
  92. // ----(*)---.------(*)-------
  93. // ^ | ^
  94. // | [Delay d] |
  95. // | | |
  96. // | -denom3 |psamp3 numer3 |
  97. // ----(*)---.------(*)-------
  98. // ^ | ^
  99. // | [Delay d] |
  100. // | | |
  101. // | -denom4 |psamp4 numer4 |
  102. // ----(*)---.------(*)-------
  103. //
  104. // for each input sample in:
  105. // psamp0 = in - denom1*psamp1 - denom2*psamp2 - ...
  106. // out = numer0*psamp0 + numer1*psamp1 + ...
  107. // psampi = psampi-1, i = cmax, cmax-1, ..., 1
  108. inline int IIRFilter_Update_OrderN ( int cdenom, int *denom, int cnumer, int *numer, int *psamp, int in )
  109. {
  110. int cmax, i;
  111. int out;
  112. int in0;
  113. out = 0;
  114. in0 = in;
  115. cmax = max ( cdenom, cnumer );
  116. // add input values
  117. // for (i = 1; i <= cdenom; i++)
  118. // psamp[0] -= ( denom[i] * psamp[i] ) >> PBITS;
  119. switch (cdenom)
  120. {
  121. case 12: in0 -= ( denom[12] * psamp[12] ) >> PBITS;
  122. case 11: in0 -= ( denom[11] * psamp[11] ) >> PBITS;
  123. case 10: in0 -= ( denom[10] * psamp[10] ) >> PBITS;
  124. case 9: in0 -= ( denom[9] * psamp[9] ) >> PBITS;
  125. case 8: in0 -= ( denom[8] * psamp[8] ) >> PBITS;
  126. case 7: in0 -= ( denom[7] * psamp[7] ) >> PBITS;
  127. case 6: in0 -= ( denom[6] * psamp[6] ) >> PBITS;
  128. case 5: in0 -= ( denom[5] * psamp[5] ) >> PBITS;
  129. case 4: in0 -= ( denom[4] * psamp[4] ) >> PBITS;
  130. case 3: in0 -= ( denom[3] * psamp[3] ) >> PBITS;
  131. case 2: in0 -= ( denom[2] * psamp[2] ) >> PBITS;
  132. default:
  133. case 1: in0 -= ( denom[1] * psamp[1] ) >> PBITS;
  134. }
  135. psamp[0] = in0;
  136. // add output values
  137. //for (i = 0; i <= cnumer; i++)
  138. // out += ( numer[i] * psamp[i] ) >> PBITS;
  139. switch (cnumer)
  140. {
  141. case 12: out += ( numer[12] * psamp[12] ) >> PBITS;
  142. case 11: out += ( numer[11] * psamp[11] ) >> PBITS;
  143. case 10: out += ( numer[10] * psamp[10] ) >> PBITS;
  144. case 9: out += ( numer[9] * psamp[9] ) >> PBITS;
  145. case 8: out += ( numer[8] * psamp[8] ) >> PBITS;
  146. case 7: out += ( numer[7] * psamp[7] ) >> PBITS;
  147. case 6: out += ( numer[6] * psamp[6] ) >> PBITS;
  148. case 5: out += ( numer[5] * psamp[5] ) >> PBITS;
  149. case 4: out += ( numer[4] * psamp[4] ) >> PBITS;
  150. case 3: out += ( numer[3] * psamp[3] ) >> PBITS;
  151. case 2: out += ( numer[2] * psamp[2] ) >> PBITS;
  152. default:
  153. case 1: out += ( numer[1] * psamp[1] ) >> PBITS;
  154. case 0: out += ( numer[0] * psamp[0] ) >> PBITS;
  155. }
  156. // update internal state (reverse order)
  157. for (i = cmax; i >= 1; i--)
  158. psamp[i] = psamp[i-1];
  159. // return current output sample
  160. return out;
  161. }
  162. // 1st order filter - faster version
  163. inline int IIRFilter_Update_Order1 ( int *denom, int cnumer, int *numer, int *psamp, int in )
  164. {
  165. int out;
  166. if (!psamp[0] && !psamp[1] && !in)
  167. return 0;
  168. psamp[0] = in - (( denom[1] * psamp[1] ) >> PBITS);
  169. out = ( ( numer[1] * psamp[1] ) + ( numer[0] * psamp[0] ) ) >> PBITS;
  170. psamp[1] = psamp[0];
  171. return out;
  172. }
  173. // return 'tdelay' delayed sample from delay buffer
  174. // dlysize: delay samples
  175. // psamps: head of delay buffer psamps[0...dlysize]
  176. // psamp: current data pointer
  177. // sdly: 0...dlysize
  178. inline int GetDly ( int dlysize, int *psamps, int *psamp, int tdelay )
  179. {
  180. int *pout;
  181. pout = psamp + tdelay;
  182. if ( pout <= (psamps + dlysize))
  183. return *pout;
  184. else
  185. return *(pout - dlysize - 1);
  186. }
  187. // update the delay buffer pointer
  188. // dlysize: delay samples
  189. // psamps: head of delay buffer psamps[0...dlysize]
  190. // ppsamp: data pointer
  191. inline void DlyUpdate ( int dlysize, int *psamps, int **ppsamp )
  192. {
  193. // decrement pointer and fix up on buffer boundary
  194. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  195. (*ppsamp)--;
  196. DlyPtrReverse ( dlysize, psamps, ppsamp );
  197. }
  198. // simple delay with feedback, no filter in feedback line.
  199. // delaysize: delay line size in samples
  200. // tdelay: tap from this location - <= delaysize
  201. // psamps: delay line buffer pointer of dimension delaysize+1
  202. // ppsamp: circular pointer, must be init to &psamps[0] before first call
  203. // fbgain: feedback value, 0-PMAX (normalized to 0.0-1.0)
  204. // outgain: gain
  205. // in: input sample
  206. // psamps0(n) outgain
  207. // in(n)--->(+)--------.-----(*)-> out(n)
  208. // ^ |
  209. // | [Delay d]
  210. // | |
  211. // | fbgain |Wd(n)
  212. // ----(*)---.
  213. inline int ReverbSimple ( int delaysize, int tdelay, int *psamps, int **ppsamp, int fbgain, int outgain, int in )
  214. {
  215. int out, sD;
  216. // get current delay output
  217. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  218. // calculate output + delay * gain
  219. out = in + (( fbgain * sD ) >> PBITS);
  220. // write to delay
  221. **ppsamp = out;
  222. // advance internal delay pointers
  223. DlyUpdate ( delaysize, psamps, ppsamp );
  224. return ( (out * outgain) >> PBITS );
  225. }
  226. inline int ReverbSimple_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, int *psamps, int **ppsamp, int fbgain, int outgain, int in )
  227. {
  228. int out, sD;
  229. int sDnew;
  230. // crossfade from tdelay to tdelaynew samples. xfade is 0..PMAX
  231. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  232. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  233. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  234. out = in + (( fbgain * sD ) >> PBITS);
  235. **ppsamp = out;
  236. DlyUpdate ( delaysize, psamps, ppsamp );
  237. return ( (out * outgain) >> PBITS );
  238. }
  239. // multitap simple reverb
  240. // NOTE: tdelay3 > tdelay2 > tdelay1 > t0
  241. // NOTE: fbgain * 4 < 1!
  242. inline int ReverbSimple_multitap ( int delaysize, int tdelay0, int tdelay1, int tdelay2, int tdelay3, int *psamps, int **ppsamp, int fbgain, int outgain, int in )
  243. {
  244. int s1, s2, s3, s4, sum;
  245. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  246. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  247. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  248. s4 = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  249. sum = s1 + s2 + s3 + s4;
  250. // write to delay
  251. **ppsamp = in + ((s4 * fbgain) >> PBITS);
  252. // update delay pointers
  253. DlyUpdate ( delaysize, psamps, ppsamp );
  254. return ( ((sum + in) * outgain ) >> PBITS );
  255. }
  256. // modulate smallest tap delay only
  257. inline int ReverbSimple_multitap_xfade ( int delaysize, int tdelay0, int tdelaynew, int xf, int tdelay1, int tdelay2, int tdelay3, int *psamps, int **ppsamp, int fbgain, int outgain, int in )
  258. {
  259. int s1, s2, s3, s4, sum;
  260. int sD, sDnew;
  261. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  262. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  263. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  264. s4 = sD + (((sDnew - sD) * xf) >> PBITS);
  265. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  266. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  267. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  268. sum = s1 + s2 + s3 + s4;
  269. // write to delay
  270. **ppsamp = in + ((s4 * fbgain) >> PBITS);
  271. // update delay pointers
  272. DlyUpdate ( delaysize, psamps, ppsamp );
  273. return ( ((sum + in) * outgain ) >> PBITS );
  274. }
  275. // straight delay, no feedback
  276. //
  277. // delaysize: delay line size in samples
  278. // tdelay: tap from this location - <= delaysize
  279. // psamps: delay line buffer pointer of dimension delaysize+1
  280. // ppsamp: circular pointer, must be init to &psamps[0] before first call
  281. // in: input sample
  282. //
  283. // in(n)--->[Delay d]---> out(n)
  284. //
  285. inline int DelayLinear ( int delaysize, int tdelay, int *psamps, int **ppsamp, int in )
  286. {
  287. int out;
  288. out = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  289. **ppsamp = in;
  290. DlyUpdate ( delaysize, psamps, ppsamp );
  291. return ( out );
  292. }
  293. // crossfade delay values from tdelay to tdelaynew, with xfade1 for tdelay and xfade2 for tdelaynew. xfade = 0...PMAX
  294. inline int DelayLinear_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, int *psamps, int **ppsamp, int in )
  295. {
  296. int out;
  297. int outnew;
  298. out = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  299. outnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  300. out = out + (((outnew - out) * xf) >> PBITS);
  301. **ppsamp = in;
  302. DlyUpdate ( delaysize, psamps, ppsamp );
  303. return ( out );
  304. }
  305. // lowpass reverberator, replace feedback multiplier 'fbgain' in
  306. // reverberator with a low pass filter
  307. // delaysize: delay line size in samples
  308. // tdelay: tap from this location - <= delaysize
  309. // psamps: delay line buffer pointer of dimension delaysize+1
  310. // ppsamp: circular pointer, must be init to &w[0] before first call
  311. // fbgain: feedback gain (built into filter gain)
  312. // outgain: output gain
  313. // cnumer: filter order
  314. // numer: filter numerator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  315. // denom: filter denominator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  316. // pfsamps: filter state, cnumer+1 dimensional
  317. // in: input sample
  318. // psamps0(n) outgain
  319. // in(n)--->(+)--------------.----(*)--> out(n)
  320. // ^ |
  321. // | [Delay d]
  322. // | |
  323. // | fbgain |Wd(n)
  324. // --(*)--[Filter])-
  325. inline int DelayLowpass ( int delaysize, int tdelay, int *psamps, int **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  326. {
  327. int out, sD;
  328. // delay output is filter input
  329. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  330. // filter output, with feedback 'fbgain' baked into filter params
  331. out = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  332. // write to delay
  333. **ppsamp = out;
  334. // update delay pointers
  335. DlyUpdate ( delaysize, psamps, ppsamp );
  336. // output with gain
  337. return ( (out * outgain) >> PBITS );
  338. }
  339. inline int DelayLowpass_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, int *psamps, int **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  340. {
  341. int out, sD;
  342. int sDnew;
  343. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  344. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  345. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  346. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  347. // filter output with feedback 'fbgain' baked into filter params
  348. out = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  349. // write to delay
  350. **ppsamp = out;
  351. // update delay ptrs
  352. DlyUpdate ( delaysize, psamps, ppsamp );
  353. // output with gain
  354. return ( (out * outgain) >> PBITS );
  355. }
  356. // delay is multitap tdelay0,tdelay1,tdelay2,tdelay3
  357. // NOTE: tdelay3 > tdelay2 > tdelay1 > tdelay0
  358. // NOTE: fbgain * 4 < 1!
  359. inline int DelayLowpass_multitap ( int delaysize, int tdelay0, int tdelay1, int tdelay2, int tdelay3, int *psamps, int **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  360. {
  361. int s0, s1, s2, s3, s4, sum;
  362. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  363. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  364. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  365. s4 = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  366. sum = s1 + s2 + s3 + s4;
  367. s0 = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, s4 );
  368. // write to delay
  369. **ppsamp = s0;
  370. // update delay ptrs
  371. DlyUpdate ( delaysize, psamps, ppsamp );
  372. return ( ((sum + in) * outgain ) >> PBITS );
  373. }
  374. inline int DelayLowpass_multitap_xfade ( int delaysize, int tdelay0, int tdelaynew, int xf, int tdelay1, int tdelay2, int tdelay3, int *psamps, int **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  375. {
  376. int s0, s1, s2, s3, s4, sum;
  377. int sD, sDnew;
  378. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  379. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  380. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  381. s4 = sD + (((sDnew - sD) * xf) >> PBITS);
  382. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  383. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  384. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  385. sum = s1 + s2 + s3 + s4;
  386. s0 = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, s4 );
  387. **ppsamp = s0;
  388. DlyUpdate ( delaysize, psamps, ppsamp );
  389. return ( ((sum + in) * outgain ) >> PBITS );
  390. }
  391. // linear delay with lowpass filter on delay output and gain stage
  392. // delaysize: delay line size in samples
  393. // tdelay: delay tap from this location - <= delaysize
  394. // psamps: delay line buffer pointer of dimension delaysize+1
  395. // ppsamp: circular pointer, must init &psamps[0] before first call
  396. // fbgain: feedback gain (ignored)
  397. // outgain: output gain
  398. // cnumer: filter order
  399. // numer: filter numerator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  400. // denom: filter denominator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  401. // pfsamps: filter state, cnumer+1 dimensional
  402. // in: input sample
  403. // in(n)--->[Delay d]--->[Filter]-->(*outgain)---> out(n)
  404. inline int DelayLinear_lowpass ( int delaysize, int tdelay, int *psamps, int **ppsamp, int fbgain, int outgain, int *denom, int cnumer, int *numer, int *pfsamps, int in )
  405. {
  406. int out, sD;
  407. // delay output is filter input
  408. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  409. // calc filter output
  410. out = IIRFilter_Update_Order1 ( denom, cnumer, numer, pfsamps, sD );
  411. // input sample to delay input
  412. **ppsamp = in;
  413. // update delay pointers
  414. DlyUpdate ( delaysize, psamps, ppsamp );
  415. // output with gain
  416. return ( (out * outgain) >> PBITS );
  417. }
  418. inline int DelayLinear_lowpass_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, int *psamps, int **ppsamp, int fbgain, int outgain, int *denom, int cnumer, int *numer, int *pfsamps, int in )
  419. {
  420. int out, sD;
  421. int sDnew;
  422. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  423. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  424. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  425. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  426. out = IIRFilter_Update_Order1 ( denom, cnumer, numer, pfsamps, sD );
  427. **ppsamp = in;
  428. DlyUpdate ( delaysize, psamps, ppsamp );
  429. return ( (out * outgain) >> PBITS );
  430. }
  431. // classic allpass reverb
  432. // delaysize: delay line size in samples
  433. // tdelay: tap from this location - <= D
  434. // psamps: delay line buffer pointer of dimension delaysize+1
  435. // ppsamp: circular pointer, must be init to &psamps[0] before first call
  436. // fbgain: feedback value, 0-PMAX (normalized to 0.0-1.0)
  437. // outgain: gain
  438. // psamps0(n) -fbgain outgain
  439. // in(n)--->(+)--------.-----(*)-->(+)--(*)-> out(n)
  440. // ^ | ^
  441. // | [Delay d] |
  442. // | | |
  443. // | fbgain |psampsd(n) |
  444. // ----(*)---.-------------
  445. //
  446. // for each input sample 'in':
  447. // psamps0 = in + fbgain * psampsd
  448. // y = -fbgain * psamps0 + psampsd
  449. // delay (d, psamps) - psamps is the delay buffer array
  450. //
  451. // or, using circular delay, for each input sample 'in':
  452. //
  453. // Sd = GetDly (delaysize,psamps,ppsamp,delaysize)
  454. // S0 = in + fbgain*Sd
  455. // y = -fbgain*S0 + Sd
  456. // *ppsamp = S0
  457. // DlyUpdate(delaysize, psamps, &ppsamp)
  458. inline int DelayAllpass ( int delaysize, int tdelay, int *psamps, int **ppsamp, int fbgain, int outgain, int in )
  459. {
  460. int out, s0, sD;
  461. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  462. s0 = in + (( fbgain * sD ) >> PBITS);
  463. out = ( ( -fbgain * s0 ) >> PBITS ) + sD;
  464. **ppsamp = s0;
  465. DlyUpdate ( delaysize, psamps, ppsamp );
  466. return ( (out * outgain) >> PBITS );
  467. }
  468. inline int DelayAllpass_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, int *psamps, int **ppsamp, int fbgain, int outgain, int in )
  469. {
  470. int out, s0, sD;
  471. int sDnew;
  472. // crossfade from t to tnew tap. xfade is 0..PMAX
  473. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  474. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  475. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  476. s0 = in + (( fbgain * sD ) >> PBITS);
  477. out = ( ( -fbgain * s0 ) >> PBITS ) + sD;
  478. **ppsamp = s0;
  479. DlyUpdate ( delaysize, psamps, ppsamp );
  480. return ( (out * outgain) >> PBITS );
  481. }
  482. ///////////////////////////////////////////////////////////////////////////////////
  483. // fixed point math for real-time wave table traversing, pitch shifting, resampling
  484. ///////////////////////////////////////////////////////////////////////////////////
  485. #define FIX20_BITS 20 // 20 bits of fractional part
  486. #define FIX20_SCALE (1 << FIX20_BITS)
  487. #define FIX20_INTMAX ((1 << (32 - FIX20_BITS))-1) // maximum step integer
  488. #define FLOAT_TO_FIX20(a) ((int)((a) * (float)FIX20_SCALE)) // convert float to fixed point
  489. #define INT_TO_FIX20(a) (((int)(a)) << FIX20_BITS) // convert int to fixed point
  490. #define FIX20_TO_FLOAT(a) ((float)(a) / (float)FIX20_SCALE) // convert fix20 to float
  491. #define FIX20_INTPART(a) (((int)(a)) >> FIX20_BITS) // get integer part of fixed point
  492. #define FIX20_FRACPART(a) ((a) - (((a) >> FIX20_BITS) << FIX20_BITS)) // get fractional part of fixed point
  493. #define FIX20_FRACTION(a,b) (FIX(a)/(b)) // convert int a to fixed point, divide by b
  494. typedef int fix20int;
  495. /////////////////////////////////
  496. // DSP processor parameter block
  497. /////////////////////////////////
  498. // NOTE: these prototypes must match the XXX_Params ( prc_t *pprc ) and XXX_GetNext ( XXX_t *p, int x ) functions
  499. typedef void * (*prc_Param_t)( void *pprc ); // individual processor allocation functions
  500. typedef int (*prc_GetNext_t) ( void *pdata, int x ); // get next function for processor
  501. typedef int (*prc_GetNextN_t) ( void *pdata, portable_samplepair_t *pbuffer, int SampleCount, int op); // batch version of getnext
  502. typedef void (*prc_Free_t) ( void *pdata ); // free function for processor
  503. typedef void (*prc_Mod_t) (void *pdata, float v); // modulation function for processor
  504. #define OP_LEFT 0 // batch process left channel in place
  505. #define OP_RIGHT 1 // batch process right channel in place
  506. #define OP_LEFT_DUPLICATE 2 // batch process left channel in place, duplicate to right channel
  507. #define PRC_NULL 0 // pass through - must be 0
  508. #define PRC_DLY 1 // simple feedback reverb
  509. #define PRC_RVA 2 // parallel reverbs
  510. #define PRC_FLT 3 // lowpass or highpass filter
  511. #define PRC_CRS 4 // chorus
  512. #define PRC_PTC 5 // pitch shifter
  513. #define PRC_ENV 6 // adsr envelope
  514. #define PRC_LFO 7 // lfo
  515. #define PRC_EFO 8 // envelope follower
  516. #define PRC_MDY 9 // mod delay
  517. #define PRC_DFR 10 // diffusor - n series allpass delays
  518. #define PRC_AMP 11 // amplifier with distortion
  519. #define QUA_LO 0 // quality of filter or reverb. Must be 0,1,2,3.
  520. #define QUA_MED 1
  521. #define QUA_HI 2
  522. #define QUA_VHI 3
  523. #define QUA_MAX QUA_VHI
  524. #define CPRCPARAMS 16 // up to 16 floating point params for each processor type
  525. // processor definition - one for each running instance of a dsp processor
  526. struct prc_t
  527. {
  528. int type; // PRC type
  529. float prm[CPRCPARAMS]; // dsp processor parameters - array of floats
  530. prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
  531. prc_GetNext_t pfnGetNext; // get next function
  532. prc_GetNextN_t pfnGetNextN; // batch version of get next
  533. prc_Free_t pfnFree; // free function
  534. prc_Mod_t pfnMod; // modulation function
  535. void *pdata; // processor state data - ie: pdly, pflt etc.
  536. };
  537. // processor parameter ranges - for validating parameters during allocation of new processor
  538. typedef struct prm_rng_t
  539. {
  540. int iprm; // parameter index
  541. float lo; // min value of parameter
  542. float hi; // max value of parameter
  543. } prm_rng_s;
  544. void PRC_CheckParams ( prc_t *pprc, prm_rng_t *prng );
  545. ///////////
  546. // Filters
  547. ///////////
  548. #define CFLTS 64 // max number of filters simultaneously active
  549. #define FLT_M 12 // max order of any filter
  550. #define FLT_LP 0 // lowpass filter
  551. #define FLT_HP 1 // highpass filter
  552. #define FLT_BP 2 // bandpass filter
  553. #define FTR_MAX FLT_BP
  554. // flt parameters
  555. struct flt_t
  556. {
  557. bool fused; // true if slot in use
  558. int b[FLT_M+1]; // filter numerator parameters (convert 0.0-1.0 to 0-PMAX representation)
  559. int a[FLT_M+1]; // filter denominator parameters (convert 0.0-1.0 to 0-PMAX representation)
  560. int w[FLT_M+1]; // filter state - samples (dimension of max (M, L))
  561. int L; // filter order numerator (dimension of a[M+1])
  562. int M; // filter order denominator (dimension of b[L+1])
  563. int N; // # of series sections - 1 (0 = 1 section, 1 = 2 sections etc)
  564. flt_t *pf1; // series cascaded versions of filter
  565. flt_t *pf2;
  566. flt_t *pf3;
  567. };
  568. // flt flts
  569. flt_t flts[CFLTS];
  570. void FLT_Init ( flt_t *pf ) { if ( pf ) Q_memset ( pf, 0, sizeof (flt_t) ); }
  571. void FLT_InitAll ( void ) { for ( int i = 0 ; i < CFLTS; i++ ) FLT_Init ( &flts[i] ); }
  572. void FLT_Free ( flt_t *pf )
  573. {
  574. if ( pf )
  575. {
  576. if (pf->pf1)
  577. Q_memset ( pf->pf1, 0, sizeof (flt_t) );
  578. if (pf->pf2)
  579. Q_memset ( pf->pf2, 0, sizeof (flt_t) );
  580. if (pf->pf3)
  581. Q_memset ( pf->pf3, 0, sizeof (flt_t) );
  582. Q_memset ( pf, 0, sizeof (flt_t) );
  583. }
  584. }
  585. void FLT_FreeAll ( void ) { for (int i = 0 ; i < CFLTS; i++) FLT_Free ( &flts[i] ); }
  586. // find a free filter from the filter pool
  587. // initialize filter numerator, denominator b[0..M], a[0..L]
  588. // gain scales filter numerator
  589. // N is # of series sections - 1
  590. flt_t * FLT_Alloc ( int N, int M, int L, int *a, int *b, float gain )
  591. {
  592. int i, j;
  593. flt_t *pf = NULL;
  594. for (i = 0; i < CFLTS; i++)
  595. {
  596. if ( !flts[i].fused )
  597. {
  598. pf = &flts[i];
  599. // transfer filter params into filter struct
  600. pf->M = M;
  601. pf->L = L;
  602. pf->N = N;
  603. for (j = 0; j <= M; j++)
  604. pf->a[j] = a[j];
  605. for (j = 0; j <= L; j++)
  606. pf->b[j] = (int)((float)(b[j]) * gain);
  607. pf->pf1 = NULL;
  608. pf->pf2 = NULL;
  609. pf->pf3 = NULL;
  610. pf->fused = true;
  611. break;
  612. }
  613. }
  614. Assert(pf); // make sure we're not trying to alloc more than CFLTS flts
  615. return pf;
  616. }
  617. // convert filter params cutoff and type into
  618. // iir transfer function params M, L, a[], b[]
  619. // iir filter, 1st order, transfer function is H(z) = b0 + b1 Z^-1 / a0 + a1 Z^-1
  620. // or H(z) = b0 - b1 Z^-1 / a0 + a1 Z^-1 for lowpass
  621. // design cutoff filter at 3db (.5 gain) p579
  622. void FLT_Design_3db_IIR ( float cutoff, float ftype, int *pM, int *pL, int *a, int *b )
  623. {
  624. // ftype: FLT_LP, FLT_HP, FLT_BP
  625. double Wc = 2.0 * M_PI * cutoff / SOUND_DMA_SPEED; // radians per sample
  626. double Oc;
  627. double fa;
  628. double fb;
  629. // calculations:
  630. // Wc = 2pi * fc/44100 convert to radians
  631. // Oc = tan (Wc/2) * Gc / sqt ( 1 - Gc^2) get analog version, low pass
  632. // Oc = tan (Wc/2) * (sqt (1 - Gc^2)) / Gc analog version, high pass
  633. // Gc = 10 ^ (-Ac/20) gain at cutoff. Ac = 3db, so Gc^2 = 0.5
  634. // a = ( 1 - Oc ) / ( 1 + Oc )
  635. // b = ( 1 - a ) / 2
  636. Oc = tan ( Wc / 2.0 );
  637. fa = ( 1.0 - Oc ) / ( 1.0 + Oc );
  638. fb = ( 1.0 - fa ) / 2.0;
  639. if ( ftype == FLT_HP )
  640. fb = ( 1.0 + fa ) / 2.0;
  641. a[0] = 0; // a0 always ignored
  642. a[1] = (int)( -fa * PMAX ); // quantize params down to 0-PMAX >> PBITS
  643. b[0] = (int)( fb * PMAX );
  644. b[1] = b[0];
  645. if ( ftype == FLT_HP )
  646. b[1] = -b[1];
  647. *pM = *pL = 1;
  648. return;
  649. }
  650. // filter parameter order
  651. typedef enum
  652. {
  653. flt_iftype,
  654. flt_icutoff,
  655. flt_iqwidth,
  656. flt_iquality,
  657. flt_igain,
  658. flt_cparam // # of params
  659. } flt_e;
  660. // filter parameter ranges
  661. prm_rng_t flt_rng[] = {
  662. {flt_cparam, 0, 0}, // first entry is # of parameters
  663. {flt_iftype, 0, FTR_MAX}, // filter type FLT_LP, FLT_HP, FLT_BP
  664. {flt_icutoff, 10, 22050}, // cutoff frequency in hz at -3db gain
  665. {flt_iqwidth, 0, 11025}, // width of BP (cut in starts at cutoff)
  666. {flt_iquality, 0, QUA_MAX}, // QUA_LO, _MED, _HI, _VHI = # of series sections
  667. {flt_igain, 0.0, 10.0}, // output gain 0-10.0
  668. };
  669. // convert prc float params to iir filter params, alloc filter and return ptr to it
  670. // filter quality set by prc quality - 0,1,2
  671. flt_t * FLT_Params ( prc_t *pprc )
  672. {
  673. float qual = pprc->prm[flt_iquality];
  674. float cutoff = pprc->prm[flt_icutoff];
  675. float ftype = pprc->prm[flt_iftype];
  676. float qwidth = pprc->prm[flt_iqwidth];
  677. float gain = pprc->prm[flt_igain];
  678. int L = 0; // numerator order
  679. int M = 0; // denominator order
  680. int b[FLT_M+1]; // numerator params 0..PMAX
  681. int b_scaled[FLT_M+1]; // gain scaled numerator
  682. int a[FLT_M+1]; // denominator params 0..PMAX
  683. int L_bp = 0; // bandpass numerator order
  684. int M_bp = 0; // bandpass denominator order
  685. int b_bp[FLT_M+1]; // bandpass numerator params 0..PMAX
  686. int b_bp_scaled[FLT_M+1]; // gain scaled numerator
  687. int a_bp[FLT_M+1]; // bandpass denominator params 0..PMAX
  688. int N; // # of series sections
  689. bool bpass = false;
  690. // if qwidth > 0 then alloc bandpass filter (pf is lowpass)
  691. if ( qwidth > 0.0 )
  692. bpass = true;
  693. if (bpass)
  694. {
  695. ftype = FLT_LP;
  696. }
  697. // low pass and highpass filter design
  698. // 1st order IIR filter, 3db cutoff at fc
  699. if ( bpass )
  700. {
  701. // highpass section
  702. FLT_Design_3db_IIR ( cutoff, FLT_HP, &M_bp, &L_bp, a_bp, b_bp );
  703. M_bp = clamp (M_bp, 1, FLT_M);
  704. L_bp = clamp (L_bp, 1, FLT_M);
  705. cutoff += qwidth;
  706. }
  707. // lowpass section
  708. FLT_Design_3db_IIR ( cutoff, (int)ftype, &M, &L, a, b );
  709. M = clamp (M, 1, FLT_M);
  710. L = clamp (L, 1, FLT_M);
  711. // quality = # of series sections - 1
  712. N = clamp ((int)qual, 0, 3);
  713. // make sure we alloc at least 2 filters
  714. if (bpass)
  715. N = max(N, 1);
  716. flt_t *pf0 = NULL;
  717. flt_t *pf1 = NULL;
  718. flt_t *pf2 = NULL;
  719. flt_t *pf3 = NULL;
  720. // scale b numerators with gain - only scale for first filter if series filters
  721. for (int i = 0; i < FLT_M; i++)
  722. {
  723. b_bp_scaled[i] = (int)((float)(b_bp[i]) * gain );
  724. b_scaled[i] = (int)((float)(b[i]) * gain );
  725. }
  726. if (bpass)
  727. {
  728. // 1st filter is lowpass
  729. pf0 = FLT_Alloc ( N, M_bp, L_bp, a_bp, b_bp_scaled, 1.0 );
  730. }
  731. else
  732. {
  733. pf0 = FLT_Alloc ( N, M, L, a, b_scaled, 1.0 );
  734. }
  735. // allocate series filters
  736. if (pf0)
  737. {
  738. switch (N)
  739. {
  740. case 3:
  741. // alloc last filter as lowpass also if FLT_BP
  742. if (bpass)
  743. pf3 = FLT_Alloc ( 0, M_bp, L_bp, a_bp, b_bp, 1.0 );
  744. else
  745. pf3 = FLT_Alloc ( 0, M, L, a, b, 1.0 );
  746. case 2:
  747. pf2 = FLT_Alloc ( 0, M, L, a, b, 1.0 );
  748. case 1:
  749. pf1 = FLT_Alloc ( 0, M, L, a, b, 1.0 );
  750. case 0:
  751. break;
  752. }
  753. pf0->pf1 = pf1;
  754. pf0->pf2 = pf2;
  755. pf0->pf3 = pf3;
  756. }
  757. return pf0;
  758. }
  759. inline void * FLT_VParams ( void *p )
  760. {
  761. PRC_CheckParams( (prc_t *)p, flt_rng);
  762. return (void *) FLT_Params ((prc_t *)p);
  763. }
  764. inline void FLT_Mod ( void *p, float v ) { return; }
  765. // get next filter value for filter pf and input x
  766. inline int FLT_GetNext ( flt_t *pf, int x )
  767. {
  768. flt_t *pf1;
  769. flt_t *pf2;
  770. flt_t *pf3;
  771. int y;
  772. switch( pf->N )
  773. {
  774. default:
  775. case 0:
  776. return IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  777. case 1:
  778. pf1 = pf->pf1;
  779. y = IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  780. return IIRFilter_Update_Order1(pf1->a, pf1->L, pf1->b, pf1->w, y);
  781. case 2:
  782. pf1 = pf->pf1;
  783. pf2 = pf->pf2;
  784. y = IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  785. y = IIRFilter_Update_Order1(pf1->a, pf1->L, pf1->b, pf1->w, y);
  786. return IIRFilter_Update_Order1(pf2->a, pf2->L, pf2->b, pf2->w, y);
  787. case 3:
  788. pf1 = pf->pf1;
  789. pf2 = pf->pf2;
  790. pf3 = pf->pf3;
  791. y = IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  792. y = IIRFilter_Update_Order1(pf1->a, pf1->L, pf1->b, pf1->w, y);
  793. y = IIRFilter_Update_Order1(pf2->a, pf2->L, pf2->b, pf2->w, y);
  794. return IIRFilter_Update_Order1(pf3->a, pf3->L, pf3->b, pf3->w, y);
  795. }
  796. }
  797. // batch version for performance
  798. inline void FLT_GetNextN( flt_t *pflt, portable_samplepair_t *pbuffer, int SampleCount, int op )
  799. {
  800. int count = SampleCount;
  801. portable_samplepair_t *pb = pbuffer;
  802. switch (op)
  803. {
  804. default:
  805. case OP_LEFT:
  806. while (count--)
  807. {
  808. pb->left = FLT_GetNext( pflt, pb->left );
  809. pb++;
  810. }
  811. return;
  812. case OP_RIGHT:
  813. while (count--)
  814. {
  815. pb->right = FLT_GetNext( pflt, pb->right );
  816. pb++;
  817. }
  818. return;
  819. case OP_LEFT_DUPLICATE:
  820. while (count--)
  821. {
  822. pb->left = pb->right = FLT_GetNext( pflt, pb->left );
  823. pb++;
  824. }
  825. return;
  826. }
  827. }
  828. ///////////////////////////////////////////////////////////////////////////
  829. // Positional updaters for pitch shift etc
  830. ///////////////////////////////////////////////////////////////////////////
  831. // looping position within a wav, with integer and fractional parts
  832. // used for pitch shifting, upsampling/downsampling
  833. // 20 bits of fraction, 8+ bits of integer
  834. struct pos_t
  835. {
  836. fix20int step; // wave table whole and fractional step value
  837. fix20int cstep; // current cummulative step value
  838. int pos; // current position within wav table
  839. int D; // max dimension of array w[0...D] ie: # of samples = D+1
  840. };
  841. // circular wrap of pointer p, relative to array w
  842. // D max buffer index w[0...D] (count of samples in buffer is D+1)
  843. // i circular index
  844. inline void POS_Wrap ( int D, int *i )
  845. {
  846. if ( *i > D )
  847. *i -= D + 1; // when *pi = D + 1, it wraps around to *pi = 0
  848. if ( *i < 0 )
  849. *i += D + 1; // when *pi = - 1, it wraps around to *pi = D
  850. }
  851. // set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
  852. // D is array max dimension w[0...D] (ie: size D+1)
  853. // w is ptr to array
  854. // p is ptr to pos_t to initialize
  855. inline void POS_Init( pos_t *p, int D, float fstep )
  856. {
  857. float step = fstep;
  858. // make sure int part of step is capped at fix20_intmax
  859. if ((int)step > FIX20_INTMAX)
  860. step = (step - (int)step) + FIX20_INTMAX;
  861. p->step = FLOAT_TO_FIX20(step); // convert fstep to fixed point
  862. p->cstep = 0;
  863. p->pos = 0; // current update value
  864. p->D = D; // always init to end value, in case we're stepping backwards
  865. }
  866. // change step value - this is an instantaneous change, not smoothed.
  867. inline void POS_ChangeVal( pos_t *p, float fstepnew )
  868. {
  869. p->step = FLOAT_TO_FIX20( fstepnew ); // convert fstep to fixed point
  870. }
  871. // return current integer position, then update internal position value
  872. inline int POS_GetNext ( pos_t *p )
  873. {
  874. //float f = FIX20_TO_FLOAT(p->cstep);
  875. //int i1 = FIX20_INTPART(p->cstep);
  876. //float f1 = FIX20_TO_FLOAT(FIX20_FRACPART(p->cstep));
  877. //float f2 = FIX20_TO_FLOAT(p->step);
  878. p->cstep += p->step; // update accumulated fraction step value (fixed point)
  879. p->pos += FIX20_INTPART( p->cstep ); // update pos with integer part of accumulated step
  880. p->cstep = FIX20_FRACPART( p->cstep ); // throw away the integer part of accumulated step
  881. // wrap pos around either end of buffer if needed
  882. POS_Wrap(p->D, &(p->pos));
  883. // make sure returned position is within array bounds
  884. Assert (p->pos <= p->D);
  885. return p->pos;
  886. }
  887. // oneshot position within wav
  888. struct pos_one_t
  889. {
  890. pos_t p; // pos_t
  891. bool fhitend; // flag indicating we hit end of oneshot wav
  892. };
  893. // set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
  894. // one shot position - play only once, don't wrap, when hit end of buffer, return last position
  895. inline void POS_ONE_Init( pos_one_t *p1, int D, float fstep )
  896. {
  897. POS_Init( &p1->p, D, fstep ) ;
  898. p1->fhitend = false;
  899. }
  900. // return current integer position, then update internal position value
  901. inline int POS_ONE_GetNext ( pos_one_t *p1 )
  902. {
  903. int pos;
  904. pos_t *p0;
  905. pos = p1->p.pos; // return current position
  906. if (p1->fhitend)
  907. return pos;
  908. p0 = &(p1->p);
  909. p0->cstep += p0->step; // update accumulated fraction step value (fixed point)
  910. p0->pos += FIX20_INTPART( p0->cstep ); // update pos with integer part of accumulated step
  911. //p0->cstep = SIGN(p0->cstep) * FIX20_FRACPART( p0->cstep );
  912. p0->cstep = FIX20_FRACPART( p0->cstep ); // throw away the integer part of accumulated step
  913. // if we wrapped, stop updating, always return last position
  914. // if step value is 0, return hit end
  915. if (!p0->step || p0->pos < 0 || p0->pos >= p0->D )
  916. p1->fhitend = true;
  917. else
  918. pos = p0->pos;
  919. // make sure returned value is within array bounds
  920. Assert ( pos <= p0->D );
  921. return pos;
  922. }
  923. /////////////////////
  924. // Reverbs and delays
  925. /////////////////////
  926. #define CDLYS 128 // max delay lines active. Also used for lfos.
  927. #define DLY_PLAIN 0 // single feedback loop
  928. #define DLY_ALLPASS 1 // feedback and feedforward loop - flat frequency response (diffusor)
  929. #define DLY_LOWPASS 2 // lowpass filter in feedback loop
  930. #define DLY_LINEAR 3 // linear delay, no feedback, unity gain
  931. #define DLY_FLINEAR 4 // linear delay with lowpass filter and output gain
  932. #define DLY_LOWPASS_4TAP 5 // lowpass filter in feedback loop, 4 delay taps
  933. #define DLY_PLAIN_4TAP 6 // single feedback loop, 4 delay taps
  934. #define DLY_MAX DLY_PLAIN_4TAP
  935. #define DLY_HAS_MULTITAP(a) ((a) == DLY_LOWPASS_4TAP || (a) == DLY_PLAIN_4TAP)
  936. #define DLY_HAS_FILTER(a) ((a) == DLY_FLINEAR || (a) == DLY_LOWPASS || (a) == DLY_LOWPASS_4TAP)
  937. #define DLY_TAP_FEEDBACK_GAIN 0.25 // drop multitap feedback to compensate for sum of taps in dly_*multitap()
  938. #define DLY_NORMALIZING_REDUCTION_MAX 0.25 // don't reduce gain (due to feedback) below N% of original gain
  939. // delay line
  940. struct dly_t
  941. {
  942. bool fused; // true if dly is in use
  943. int type; // delay type
  944. int D; // delay size, in samples
  945. int t; // current tap, <= D
  946. int tnew; // crossfading to tnew
  947. int xf; // crossfade value of t (0..PMAX)
  948. int t1,t2,t3; // additional taps for multi-tap delays
  949. int a1,a2,a3; // feedback values for taps
  950. int D0; // original delay size (only relevant if calling DLY_ChangeVal)
  951. int *p; // circular buffer pointer
  952. int *w; // array of samples
  953. int a; // feedback value 0..PMAX,normalized to 0-1.0
  954. int b; // gain value 0..PMAX, normalized to 0-1.0
  955. flt_t *pflt; // pointer to filter, if type DLY_LOWPASS
  956. };
  957. dly_t dlys[CDLYS]; // delay lines
  958. void DLY_Init ( dly_t *pdly ) { if ( pdly ) Q_memset( pdly, 0, sizeof (dly_t)); }
  959. void DLY_InitAll ( void ) { for (int i = 0 ; i < CDLYS; i++) DLY_Init ( &dlys[i] ); }
  960. void DLY_Free ( dly_t *pdly )
  961. {
  962. // free memory buffer
  963. if ( pdly )
  964. {
  965. FLT_Free ( pdly->pflt );
  966. if ( pdly->w )
  967. {
  968. delete[] pdly->w;
  969. }
  970. // free dly slot
  971. Q_memset ( pdly, 0, sizeof (dly_t) );
  972. }
  973. }
  974. void DLY_FreeAll ( void ) { for (int i = 0; i < CDLYS; i++ ) DLY_Free ( &dlys[i] ); }
  975. // return adjusted feedback value for given dly
  976. // such that decay time is same as that for dmin and fbmin
  977. // dmin - minimum delay
  978. // fbmin - minimum feedback
  979. // dly - delay to match decay to dmin, fbmin
  980. float DLY_NormalizeFeedback ( int dmin, float fbmin, int dly )
  981. {
  982. // minimum decay time T to -60db for a simple reverb is:
  983. // Tmin = (ln 10^-3 / Ln fbmin) * (Dmin / fs)
  984. // where fs = sample frequency
  985. // similarly,
  986. // Tdly = (ln 10^-3 / Ln fb) * (D / fs)
  987. // setting Tdly = Tmin and solving for fb gives:
  988. // D / Dmin = ln fb / ln fbmin
  989. // since y^x = z gives x = ln z / ln y
  990. // fb = fbmin ^ (D/Dmin)
  991. float fb = powf (fbmin, (float)dly / (float) dmin);
  992. return fb;
  993. }
  994. // set up 'b' gain parameter of feedback delay to
  995. // compensate for gain caused by feedback 'fb'.
  996. void DLY_SetNormalizingGain ( dly_t *pdly, int feedback )
  997. {
  998. // compute normalized gain, set as output gain
  999. // calculate gain of delay line with feedback, and use it to
  1000. // reduce output. ie: force delay line with feedback to unity gain
  1001. // for constant input x with feedback fb:
  1002. // out = x + x*fb + x * fb^2 + x * fb^3...
  1003. // gain = out/x
  1004. // so gain = 1 + fb + fb^2 + fb^3...
  1005. // which, by the miracle of geometric series, equates to 1/1-fb
  1006. // thus, gain = 1/(1-fb)
  1007. float fgain = 0;
  1008. float gain;
  1009. int b;
  1010. float fb = (float)feedback;
  1011. fb = fb / (float)PMAX;
  1012. fb = fpmin(fb, 0.999f);
  1013. // if b is 0, set b to PMAX (1)
  1014. b = pdly->b ? pdly->b : PMAX;
  1015. fgain = 1.0 / (1.0 - fb);
  1016. // compensating gain - multiply rva output by gain then >> PBITS
  1017. gain = (int)((1.0 / fgain) * PMAX);
  1018. gain = gain * 4; // compensate for fact that gain calculation is for +/- 32767 amplitude wavs
  1019. // ie: ok to allow a bit more gain because most wavs are not at theoretical peak amplitude at all times
  1020. // limit gain reduction to N% PMAX
  1021. gain = clamp (gain, (float)(PMAX * DLY_NORMALIZING_REDUCTION_MAX), (float)PMAX);
  1022. gain = ((float)b/(float)PMAX) * gain; // scale final gain by pdly->b.
  1023. pdly->b = (int)gain;
  1024. }
  1025. void DLY_ChangeTaps ( dly_t *pdly, int t0, int t1, int t2, int t3 );
  1026. // allocate a new delay line
  1027. // D number of samples to delay
  1028. // a feedback value (0-PMAX normalized to 0.0-1.0)
  1029. // b gain value (0-PMAX normalized to 0.0-1.0) - this is folded into the filter fb params
  1030. // if DLY_LOWPASS or DLY_FLINEAR:
  1031. // L - numerator order of filter
  1032. // M - denominator order of filter
  1033. // fb - numerator params, M+1
  1034. // fa - denominator params, L+1
  1035. dly_t * DLY_AllocLP ( int D, int a, int b, int type, int M, int L, int *fa, int *fb )
  1036. {
  1037. int *w;
  1038. int i;
  1039. dly_t *pdly = NULL;
  1040. int feedback;
  1041. // find open slot
  1042. for (i = 0; i < CDLYS; i++)
  1043. {
  1044. if (!dlys[i].fused)
  1045. {
  1046. pdly = &dlys[i];
  1047. DLY_Init( pdly );
  1048. break;
  1049. }
  1050. }
  1051. if ( i == CDLYS )
  1052. {
  1053. DevMsg ("DSP: Warning, failed to allocate delay line.\n" );
  1054. return NULL; // all delay lines in use
  1055. }
  1056. // save original feedback value
  1057. feedback = a;
  1058. // adjust feedback a, gain b if delay is multitap unit
  1059. if ( DLY_HAS_MULTITAP(type) )
  1060. {
  1061. // split output gain over 4 taps
  1062. b = (int)((float)(b) * DLY_TAP_FEEDBACK_GAIN);
  1063. }
  1064. if ( DLY_HAS_FILTER(type) )
  1065. {
  1066. // alloc lowpass iir_filter
  1067. // delay feedback gain is built into filter gain
  1068. float gain = (float)a / (float)(PMAX);
  1069. pdly->pflt = FLT_Alloc( 0, M, L, fa, fb, gain );
  1070. if ( !pdly->pflt )
  1071. {
  1072. DevMsg ("DSP: Warning, failed to allocate filter for delay line.\n" );
  1073. return NULL;
  1074. }
  1075. }
  1076. // alloc delay memory
  1077. w = new int[D+1];
  1078. if ( !w )
  1079. {
  1080. Warning( "Sound DSP: Failed to lock.\n");
  1081. FLT_Free ( pdly->pflt );
  1082. return NULL;
  1083. }
  1084. // clear delay array
  1085. Q_memset (w, 0, sizeof(int) * (D+1));
  1086. // init values
  1087. pdly->type = type;
  1088. pdly->D = D;
  1089. pdly->t = D; // set delay tap to full delay
  1090. pdly->tnew = D;
  1091. pdly->xf = 0;
  1092. pdly->D0 = D;
  1093. pdly->p = w; // init circular pointer to head of buffer
  1094. pdly->w = w;
  1095. pdly->a = min( a, PMAX - 1 ); // do not allow 100% feedback
  1096. pdly->b = b;
  1097. pdly->fused = true;
  1098. if ( type == DLY_LINEAR || type == DLY_FLINEAR )
  1099. {
  1100. // linear delay has no feedback and unity gain
  1101. pdly->a = 0;
  1102. pdly->b = PMAX;
  1103. }
  1104. else
  1105. {
  1106. // adjust b to compensate for feedback gain of steady state max input
  1107. DLY_SetNormalizingGain( pdly, feedback );
  1108. }
  1109. if ( DLY_HAS_MULTITAP(type) )
  1110. {
  1111. // initially set up all taps to same value - caller uses DLY_ChangeTaps to change values
  1112. DLY_ChangeTaps( pdly, D, D, D, D );
  1113. }
  1114. return (pdly);
  1115. }
  1116. // allocate lowpass or allpass delay
  1117. dly_t * DLY_Alloc( int D, int a, int b, int type )
  1118. {
  1119. return DLY_AllocLP( D, a, b, type, 0, 0, 0, 0 );
  1120. }
  1121. // Allocate new delay, convert from float params in prc preset to internal parameters
  1122. // Uses filter params in prc if delay is type lowpass
  1123. // delay parameter order
  1124. typedef enum {
  1125. dly_idtype, // NOTE: first 8 params must match those in mdy_e
  1126. dly_idelay,
  1127. dly_ifeedback,
  1128. dly_igain,
  1129. dly_iftype,
  1130. dly_icutoff,
  1131. dly_iqwidth,
  1132. dly_iquality,
  1133. dly_itap1,
  1134. dly_itap2,
  1135. dly_itap3,
  1136. dly_cparam
  1137. } dly_e;
  1138. // delay parameter ranges
  1139. prm_rng_t dly_rng[] = {
  1140. {dly_cparam, 0, 0}, // first entry is # of parameters
  1141. // delay params
  1142. {dly_idtype, 0, DLY_MAX}, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS etc
  1143. {dly_idelay, -1.0, 1000.0}, // delay in milliseconds (-1 forces auto dsp to set delay value from room size)
  1144. {dly_ifeedback, 0.0, 0.99}, // feedback 0-1.0
  1145. {dly_igain, 0.0, 10.0}, // final gain of output stage, 0-10.0
  1146. // filter params if dly type DLY_LOWPASS or DLY_FLINEAR
  1147. {dly_iftype, 0, FTR_MAX},
  1148. {dly_icutoff, 10.0, 22050.0},
  1149. {dly_iqwidth, 100.0, 11025.0},
  1150. {dly_iquality, 0, QUA_MAX},
  1151. // note: -1 flag tells auto dsp to get value directly from room size
  1152. {dly_itap1, -1.0, 1000.0}, // delay in milliseconds NOTE: delay > tap3 > tap2 > tap1
  1153. {dly_itap2, -1.0, 1000.0}, // delay in milliseconds
  1154. {dly_itap3, -1.0, 1000.0}, // delay in milliseconds
  1155. };
  1156. dly_t * DLY_Params ( prc_t *pprc )
  1157. {
  1158. dly_t *pdly = NULL;
  1159. int D, a, b;
  1160. float delay = fabs(pprc->prm[dly_idelay]);
  1161. float feedback = pprc->prm[dly_ifeedback];
  1162. float gain = pprc->prm[dly_igain];
  1163. int type = pprc->prm[dly_idtype];
  1164. float ftype = pprc->prm[dly_iftype];
  1165. float cutoff = pprc->prm[dly_icutoff];
  1166. float qwidth = pprc->prm[dly_iqwidth];
  1167. float qual = pprc->prm[dly_iquality];
  1168. float t1 = fabs(pprc->prm[dly_itap1]);
  1169. float t2 = fabs(pprc->prm[dly_itap2]);
  1170. float t3 = fabs(pprc->prm[dly_itap3]);
  1171. D = MSEC_TO_SAMPS(delay); // delay samples
  1172. a = feedback * PMAX; // feedback
  1173. b = gain * PMAX; // gain
  1174. switch ( (int) type )
  1175. {
  1176. case DLY_PLAIN:
  1177. case DLY_PLAIN_4TAP:
  1178. case DLY_ALLPASS:
  1179. case DLY_LINEAR:
  1180. pdly = DLY_Alloc( D, a, b, type );
  1181. break;
  1182. case DLY_FLINEAR:
  1183. case DLY_LOWPASS:
  1184. case DLY_LOWPASS_4TAP:
  1185. {
  1186. // set up dummy lowpass filter to convert params
  1187. prc_t prcf;
  1188. prcf.prm[flt_iquality] = qual; // 0,1,2 - (0 or 1 low quality implies faster execution time)
  1189. prcf.prm[flt_icutoff] = cutoff;
  1190. prcf.prm[flt_iftype] = ftype;
  1191. prcf.prm[flt_iqwidth] = qwidth;
  1192. prcf.prm[flt_igain] = 1.0;
  1193. flt_t *pflt = (flt_t *)FLT_Params ( &prcf );
  1194. if ( !pflt )
  1195. {
  1196. DevMsg ("DSP: Warning, failed to allocate filter.\n" );
  1197. return NULL;
  1198. }
  1199. pdly = DLY_AllocLP ( D, a, b, type, pflt->M, pflt->L, pflt->a, pflt->b );
  1200. FLT_Free ( pflt );
  1201. break;
  1202. }
  1203. }
  1204. // set up multi-tap delays
  1205. if ( pdly && DLY_HAS_MULTITAP((int)type) )
  1206. DLY_ChangeTaps( pdly, D, MSEC_TO_SAMPS(t1), MSEC_TO_SAMPS(t2), MSEC_TO_SAMPS(t3) );
  1207. return pdly;
  1208. }
  1209. inline void * DLY_VParams ( void *p )
  1210. {
  1211. PRC_CheckParams( (prc_t *)p, dly_rng );
  1212. return (void *) DLY_Params ((prc_t *)p);
  1213. }
  1214. // get next value from delay line, move x into delay line
  1215. inline int DLY_GetNext ( dly_t *pdly, int x )
  1216. {
  1217. switch (pdly->type)
  1218. {
  1219. default:
  1220. case DLY_PLAIN:
  1221. return ReverbSimple( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  1222. case DLY_ALLPASS:
  1223. return DelayAllpass( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  1224. case DLY_LOWPASS:
  1225. return DelayLowpass( pdly->D, pdly->t, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
  1226. case DLY_LINEAR:
  1227. return DelayLinear( pdly->D, pdly->t, pdly->w, &pdly->p, x );
  1228. case DLY_FLINEAR:
  1229. return DelayLinear_lowpass( pdly->D, pdly->t, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
  1230. case DLY_PLAIN_4TAP:
  1231. return ReverbSimple_multitap( pdly->D, pdly->t, pdly->t1, pdly->t2, pdly->t3, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  1232. case DLY_LOWPASS_4TAP:
  1233. return DelayLowpass_multitap( pdly->D, pdly->t, pdly->t1, pdly->t2,pdly->t3, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
  1234. }
  1235. }
  1236. inline int DLY_GetNextXfade ( dly_t *pdly, int x )
  1237. {
  1238. switch (pdly->type)
  1239. {
  1240. default:
  1241. case DLY_PLAIN:
  1242. return ReverbSimple_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  1243. case DLY_ALLPASS:
  1244. return DelayAllpass_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  1245. case DLY_LOWPASS:
  1246. return DelayLowpass_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
  1247. case DLY_LINEAR:
  1248. return DelayLinear_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &pdly->p, x );
  1249. case DLY_FLINEAR:
  1250. return DelayLinear_lowpass_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
  1251. case DLY_PLAIN_4TAP:
  1252. return ReverbSimple_multitap_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->t1, pdly->t2, pdly->t3, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  1253. case DLY_LOWPASS_4TAP:
  1254. return DelayLowpass_multitap_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->t1, pdly->t2, pdly->t3, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
  1255. }
  1256. }
  1257. // batch version for performance
  1258. // UNDONE: a) unwind this more - pb increments by 2 to avoid pb->left or pb->right deref.
  1259. // UNDONE: b) all filter and delay params are dereferenced outside of DLY_GetNext and passed as register values
  1260. // UNDONE: c) pull case statement in dly_getnext out, so loop directly calls the inline dly_*() routine.
  1261. inline void DLY_GetNextN( dly_t *pdly, portable_samplepair_t *pbuffer, int SampleCount, int op )
  1262. {
  1263. int count = SampleCount;
  1264. portable_samplepair_t *pb = pbuffer;
  1265. switch (op)
  1266. {
  1267. default:
  1268. case OP_LEFT:
  1269. while (count--)
  1270. {
  1271. pb->left = DLY_GetNext( pdly, pb->left );
  1272. pb++;
  1273. }
  1274. return;
  1275. case OP_RIGHT:
  1276. while (count--)
  1277. {
  1278. pb->right = DLY_GetNext( pdly, pb->right );
  1279. pb++;
  1280. }
  1281. return;
  1282. case OP_LEFT_DUPLICATE:
  1283. while (count--)
  1284. {
  1285. pb->left = pb->right = DLY_GetNext( pdly, pb->left );
  1286. pb++;
  1287. }
  1288. return;
  1289. }
  1290. }
  1291. // get tap on t'th sample in delay - don't update buffer pointers, this is done via DLY_GetNext
  1292. // Only valid for DLY_LINEAR.
  1293. inline int DLY_GetTap ( dly_t *pdly, int t )
  1294. {
  1295. return GetDly (pdly->D, pdly->w, pdly->p, t );
  1296. }
  1297. #define SWAP(a,b,t) {(t) = (a); (a) = (b); (b) = (t);}
  1298. // make instantaneous change to tap values t0..t3
  1299. // all values of t must be less than original delay D
  1300. // only processed for DLY_LOWPASS_4TAP & DLY_PLAIN_4TAP
  1301. // NOTE: pdly->a feedback must have been set before this call!
  1302. void DLY_ChangeTaps ( dly_t *pdly, int t0, int t1, int t2, int t3 )
  1303. {
  1304. if (!pdly)
  1305. return;
  1306. int temp;
  1307. // sort taps to make sure t3 > t2 > t1 > t0 !
  1308. for (int i = 0; i < 4; i++)
  1309. {
  1310. if (t0 > t1) SWAP(t0, t1, temp);
  1311. if (t1 > t2) SWAP(t1, t2, temp);
  1312. if (t2 > t3) SWAP(t2, t3, temp);
  1313. }
  1314. pdly->t = min ( t0, pdly->D0 );
  1315. pdly->t1 = min ( t1, pdly->D0 );
  1316. pdly->t2 = min ( t2, pdly->D0 );
  1317. pdly->t3 = min ( t3, pdly->D0 );
  1318. }
  1319. // make instantaneous change for first delay tap 't' to new delay value.
  1320. // t tap value must be <= original D (ie: we don't do any reallocation here)
  1321. void DLY_ChangeVal ( dly_t *pdly, int t )
  1322. {
  1323. // never set delay > original delay
  1324. pdly->t = min ( t, pdly->D0 );
  1325. }
  1326. // ignored - use MDY_ for modulatable delay
  1327. inline void DLY_Mod ( void *p, float v ) { return; }
  1328. /////////////////////////////////////////////////////////////////////////////
  1329. // Ramp - used for varying smoothly between int parameters ie: modulation delays
  1330. /////////////////////////////////////////////////////////////////////////////
  1331. struct rmp_t
  1332. {
  1333. int initval; // initial ramp value
  1334. int target; // final ramp value
  1335. int sign; // increasing (1) or decreasing (-1) ramp
  1336. int yprev; // previous output value
  1337. bool fhitend; // true if hit end of ramp
  1338. bool bEndAtTime; // if true, fhitend is true when ramp time is hit (even if target not hit)
  1339. // if false, then fhitend is true only when target is hit
  1340. pos_one_t ps; // current ramp output
  1341. };
  1342. // ramp smoothly between initial value and target value in approx 'ramptime' seconds.
  1343. // (initial value may be greater or less than target value)
  1344. // never changes output by more than +1 or -1 (which can cause the ramp to take longer to complete than ramptime - see bEndAtTime)
  1345. // called once per sample while ramping
  1346. // ramptime - duration of ramp in seconds
  1347. // initval - initial ramp value
  1348. // targetval - target ramp value
  1349. // if bEndAtTime is true, then RMP_HitEnd returns true when ramp time is reached, EVEN IF TARGETVAL IS NOT REACHED
  1350. // if bEndAtTime is false, then RMP_HitEnd returns true when targetval is reached, EVEN IF DELTA IN RAMP VALUES IS > +/- 1
  1351. void RMP_Init( rmp_t *prmp, float ramptime, int initval, int targetval, bool bEndAtTime )
  1352. {
  1353. int rise;
  1354. int run;
  1355. if (prmp)
  1356. Q_memset( prmp, 0, sizeof (rmp_t) );
  1357. else
  1358. return;
  1359. run = (int) (ramptime * SOUND_DMA_SPEED); // 'samples' in ramp
  1360. rise = (targetval - initval); // height of ramp
  1361. // init fixed point iterator to iterate along the height of the ramp 'rise'
  1362. // always iterates from 0..'rise', increasing in value
  1363. POS_ONE_Init( &prmp->ps, ABS( rise ), ABS((float) rise) / ((float) run) );
  1364. prmp->yprev = initval;
  1365. prmp->initval = initval;
  1366. prmp->target = targetval;
  1367. prmp->sign = SIGN( rise );
  1368. prmp->bEndAtTime = bEndAtTime;
  1369. }
  1370. // continues from current position to new target position
  1371. void RMP_SetNext( rmp_t *prmp, float ramptime, int targetval )
  1372. {
  1373. RMP_Init ( prmp, ramptime, prmp->yprev, targetval, prmp->bEndAtTime );
  1374. }
  1375. inline bool RMP_HitEnd ( rmp_t *prmp )
  1376. {
  1377. return prmp->fhitend;
  1378. }
  1379. inline void RMP_SetEnd ( rmp_t *prmp )
  1380. {
  1381. prmp->fhitend = true;
  1382. }
  1383. // get next ramp value & update ramp, if bEndAtTime is true, never varies by more than +1 or -1 between calls
  1384. // when ramp hits target value, it thereafter always returns last value
  1385. inline int RMP_GetNext( rmp_t *prmp )
  1386. {
  1387. int y;
  1388. int d;
  1389. // if we hit ramp end, return last value
  1390. if (prmp->fhitend)
  1391. return prmp->yprev;
  1392. // get next integer position in ramp height.
  1393. d = POS_ONE_GetNext( &prmp->ps );
  1394. if ( prmp->ps.fhitend )
  1395. prmp->fhitend = true;
  1396. // increase or decrease from initval, depending on ramp sign
  1397. if ( prmp->sign > 0 )
  1398. y = prmp->initval + d;
  1399. else
  1400. y = prmp->initval - d;
  1401. // if bEndAtTime is true, only update current height by a max of +1 or -1
  1402. // this also means that for short ramp times, we may not hit target
  1403. if (prmp->bEndAtTime)
  1404. {
  1405. if ( ABS( y - prmp->yprev ) >= 1 )
  1406. prmp->yprev += prmp->sign;
  1407. }
  1408. else
  1409. {
  1410. // always hits target - but varies by more than +/- 1
  1411. prmp->yprev = y;
  1412. }
  1413. return prmp->yprev;
  1414. }
  1415. // get current ramp value, don't update ramp
  1416. inline int RMP_GetCurrent( rmp_t *prmp )
  1417. {
  1418. return prmp->yprev;
  1419. }
  1420. //////////////
  1421. // mod delay
  1422. //////////////
  1423. // modulate delay time anywhere from 0..D using MDY_ChangeVal. no output glitches (uses RMP)
  1424. #define CMDYS 64 // max # of mod delays active (steals from delays)
  1425. struct mdy_t
  1426. {
  1427. bool fused;
  1428. bool fchanging; // true if modulating to new delay value
  1429. dly_t *pdly; // delay
  1430. float ramptime; // ramp 'glide' time - time in seconds to change between values
  1431. int mtime; // time in samples between delay changes. 0 implies no self-modulating
  1432. int mtimecur; // current time in samples until next delay change
  1433. float depth; // modulate delay from D to D - (D*depth) depth 0-1.0
  1434. int mix; // PMAX as % processed fx signal mix
  1435. rmp_t rmp_interp; // interpolation ramp 0...PMAX
  1436. bool bPhaseInvert; // if true, invert phase of output
  1437. };
  1438. mdy_t mdys[CMDYS];
  1439. void MDY_Init( mdy_t *pmdy ) { if (pmdy) Q_memset( pmdy, 0, sizeof (mdy_t) ); };
  1440. void MDY_Free( mdy_t *pmdy ) { if (pmdy) { DLY_Free (pmdy->pdly); Q_memset( pmdy, 0, sizeof (mdy_t) ); } };
  1441. void MDY_InitAll() { for (int i = 0; i < CMDYS; i++) MDY_Init( &mdys[i] ); };
  1442. void MDY_FreeAll() { for (int i = 0; i < CMDYS; i++) MDY_Free( &mdys[i] ); };
  1443. // allocate mod delay, given previously allocated dly (NOTE: mod delay only sweeps tap 0, not t1,t2 or t3)
  1444. // ramptime is time in seconds for delay to change from dcur to dnew
  1445. // modtime is time in seconds between modulations. 0 if no self-modulation
  1446. // depth is 0-1.0 multiplier, new delay values when modulating are Dnew = randomlong (D - D*depth, D)
  1447. // mix - 0-1.0, default 1.0 for 100% fx mix - pans between input signal and fx signal
  1448. mdy_t *MDY_Alloc ( dly_t *pdly, float ramptime, float modtime, float depth, float mix )
  1449. {
  1450. int i;
  1451. mdy_t *pmdy;
  1452. if ( !pdly )
  1453. return NULL;
  1454. for (i = 0; i < CMDYS; i++)
  1455. {
  1456. if ( !mdys[i].fused )
  1457. {
  1458. pmdy = &mdys[i];
  1459. MDY_Init ( pmdy );
  1460. pmdy->pdly = pdly;
  1461. if ( !pmdy->pdly )
  1462. {
  1463. DevMsg ("DSP: Warning, failed to allocate delay for mod delay.\n" );
  1464. return NULL;
  1465. }
  1466. pmdy->fused = true;
  1467. pmdy->ramptime = ramptime;
  1468. pmdy->mtime = SEC_TO_SAMPS(modtime);
  1469. pmdy->mtimecur = pmdy->mtime;
  1470. pmdy->depth = depth;
  1471. pmdy->mix = int ( PMAX * mix );
  1472. pmdy->bPhaseInvert = false;
  1473. return pmdy;
  1474. }
  1475. }
  1476. DevMsg ("DSP: Warning, failed to allocate mod delay.\n" );
  1477. return NULL;
  1478. }
  1479. // change to new delay tap value t samples, ramp linearly over ramptime seconds
  1480. void MDY_ChangeVal ( mdy_t *pmdy, int t )
  1481. {
  1482. // if D > original delay value, cap at original value
  1483. t = min (pmdy->pdly->D0, t);
  1484. pmdy->fchanging = true;
  1485. // init interpolation ramp - always hit target
  1486. RMP_Init ( &pmdy->rmp_interp, pmdy->ramptime, 0, PMAX, false );
  1487. // init delay xfade values
  1488. pmdy->pdly->tnew = t;
  1489. pmdy->pdly->xf = 0;
  1490. }
  1491. // interpolate between current and target delay values
  1492. inline int MDY_GetNext( mdy_t *pmdy, int x )
  1493. {
  1494. int xout;
  1495. if ( !pmdy->fchanging )
  1496. {
  1497. // not modulating...
  1498. xout = DLY_GetNext( pmdy->pdly, x );
  1499. if ( !pmdy->mtime )
  1500. {
  1501. // return right away if not modulating (not changing and not self modulating)
  1502. goto mdy_return;
  1503. }
  1504. }
  1505. else
  1506. {
  1507. // modulating...
  1508. xout = DLY_GetNextXfade( pmdy->pdly, x );
  1509. // get xfade ramp & set up delay xfade value for next call to DLY_GetNextXfade()
  1510. pmdy->pdly->xf = RMP_GetNext( &pmdy->rmp_interp ); // 0...PMAX
  1511. if ( RMP_HitEnd( &pmdy->rmp_interp ) )
  1512. {
  1513. // done. set delay tap & value = target
  1514. DLY_ChangeVal( pmdy->pdly, pmdy->pdly->tnew );
  1515. pmdy->pdly->t = pmdy->pdly->tnew;
  1516. pmdy->fchanging = false;
  1517. }
  1518. }
  1519. // if self-modulating and timer has expired, get next change
  1520. if ( pmdy->mtime && !pmdy->mtimecur-- )
  1521. {
  1522. pmdy->mtimecur = pmdy->mtime;
  1523. int D0 = pmdy->pdly->D0;
  1524. int Dnew;
  1525. float D1;
  1526. // modulate between 0 and 100% of d0
  1527. D1 = (float)D0 * (1.0 - pmdy->depth);
  1528. Dnew = RandomInt( (int)D1, D0 );
  1529. // set up modulation to new value
  1530. MDY_ChangeVal ( pmdy, Dnew );
  1531. }
  1532. mdy_return:
  1533. // reverse phase of output
  1534. if ( pmdy->bPhaseInvert )
  1535. xout = -xout;
  1536. // 100% fx mix
  1537. if ( pmdy->mix == PMAX)
  1538. return xout;
  1539. // special case 50/50 mix
  1540. if ( pmdy->mix == PMAX / 2)
  1541. return ( (xout + x) >> 1 );
  1542. // return mix of input and processed signal
  1543. return ( x + (((xout - x) * pmdy->mix) >> PBITS) );
  1544. }
  1545. // batch version for performance
  1546. // UNDONE: unwind MDY_GetNext so that it directly calls DLY_GetNextN:
  1547. // UNDONE: a) if not currently modulating and never self-modulating, then just unwind like DLY_GetNext
  1548. // UNDONE: b) if not currently modulating, figure out how many samples N until self-modulation timer kicks in again
  1549. // and stream out N samples just like DLY_GetNext
  1550. inline void MDY_GetNextN( mdy_t *pmdy, portable_samplepair_t *pbuffer, int SampleCount, int op )
  1551. {
  1552. int count = SampleCount;
  1553. portable_samplepair_t *pb = pbuffer;
  1554. switch (op)
  1555. {
  1556. default:
  1557. case OP_LEFT:
  1558. while (count--)
  1559. {
  1560. pb->left = MDY_GetNext( pmdy, pb->left );
  1561. pb++;
  1562. }
  1563. return;
  1564. case OP_RIGHT:
  1565. while (count--)
  1566. {
  1567. pb->right = MDY_GetNext( pmdy, pb->right );
  1568. pb++;
  1569. }
  1570. return;
  1571. case OP_LEFT_DUPLICATE:
  1572. while (count--)
  1573. {
  1574. pb->left = pb->right = MDY_GetNext( pmdy, pb->left );
  1575. pb++;
  1576. }
  1577. return;
  1578. }
  1579. }
  1580. // parameter order
  1581. typedef enum {
  1582. mdy_idtype, // NOTE: first 8 params must match params in dly_e
  1583. mdy_idelay,
  1584. mdy_ifeedback,
  1585. mdy_igain,
  1586. mdy_iftype,
  1587. mdy_icutoff,
  1588. mdy_iqwidth,
  1589. mdy_iquality,
  1590. mdy_imodrate,
  1591. mdy_imoddepth,
  1592. mdy_imodglide,
  1593. mdy_imix,
  1594. mdy_ibxfade,
  1595. mdy_cparam
  1596. } mdy_e;
  1597. // parameter ranges
  1598. prm_rng_t mdy_rng[] = {
  1599. {mdy_cparam, 0, 0}, // first entry is # of parameters
  1600. // delay params
  1601. {mdy_idtype, 0, DLY_MAX}, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  1602. {mdy_idelay, 0.0, 1000.0}, // delay in milliseconds
  1603. {mdy_ifeedback, 0.0, 0.99}, // feedback 0-1.0
  1604. {mdy_igain, 0.0, 1.0}, // final gain of output stage, 0-1.0
  1605. // filter params if mdy type DLY_LOWPASS
  1606. {mdy_iftype, 0, FTR_MAX},
  1607. {mdy_icutoff, 10.0, 22050.0},
  1608. {mdy_iqwidth, 100.0, 11025.0},
  1609. {mdy_iquality, 0, QUA_MAX},
  1610. {mdy_imodrate, 0.01, 200.0}, // frequency at which delay values change to new random value. 0 is no self-modulation
  1611. {mdy_imoddepth, 0.0, 1.0}, // how much delay changes (decreases) from current value (0-1.0)
  1612. {mdy_imodglide, 0.01, 100.0}, // glide time between dcur and dnew in milliseconds
  1613. {mdy_imix, 0.0, 1.0} // 1.0 = full fx mix, 0.5 = 50% fx, 50% dry
  1614. };
  1615. // convert user parameters to internal parameters, allocate and return
  1616. mdy_t * MDY_Params ( prc_t *pprc )
  1617. {
  1618. mdy_t *pmdy;
  1619. dly_t *pdly;
  1620. float ramptime = pprc->prm[mdy_imodglide] / 1000.0; // get ramp time in seconds
  1621. float modtime = 0.0f;
  1622. if ( pprc->prm[mdy_imodrate] != 0.0f )
  1623. {
  1624. modtime = 1.0 / pprc->prm[mdy_imodrate]; // time between modulations in seconds
  1625. }
  1626. float depth = pprc->prm[mdy_imoddepth]; // depth of modulations 0-1.0
  1627. float mix = pprc->prm[mdy_imix];
  1628. // alloc plain, allpass or lowpass delay
  1629. pdly = DLY_Params( pprc );
  1630. if ( !pdly )
  1631. return NULL;
  1632. pmdy = MDY_Alloc ( pdly, ramptime, modtime, depth, mix );
  1633. return pmdy;
  1634. }
  1635. inline void * MDY_VParams ( void *p )
  1636. {
  1637. PRC_CheckParams ( (prc_t *)p, mdy_rng );
  1638. return (void *) MDY_Params ((prc_t *)p);
  1639. }
  1640. // v is +/- 0-1.0
  1641. // change current delay value 0..D
  1642. void MDY_Mod ( mdy_t *pmdy, float v )
  1643. {
  1644. int D0 = pmdy->pdly->D0; // base delay value
  1645. float v2;
  1646. // if v is < -2.0 then delay is v + 10.0
  1647. // invert phase of output. hack.
  1648. if ( v < -2.0 )
  1649. {
  1650. v = v + 10.0;
  1651. pmdy->bPhaseInvert = true;
  1652. }
  1653. else
  1654. {
  1655. pmdy->bPhaseInvert = false;
  1656. }
  1657. v2 = -(v + 1.0)/2.0; // v2 varies -1.0-0.0
  1658. // D0 varies 0..D0
  1659. D0 = D0 + (int)((float)D0 * v2);
  1660. // change delay
  1661. MDY_ChangeVal( pmdy, D0 );
  1662. return;
  1663. }
  1664. ///////////////////
  1665. // Parallel reverbs
  1666. ///////////////////
  1667. // Reverb A
  1668. // M parallel reverbs, mixed to mono output
  1669. #define CRVAS 64 // max number of parallel series reverbs active
  1670. #define CRVA_DLYS 12 // max number of delays making up reverb_a
  1671. struct rva_t
  1672. {
  1673. bool fused;
  1674. int m; // number of parallel plain or lowpass delays
  1675. int fparallel; // true if filters in parallel with delays, otherwise single output filter
  1676. flt_t *pflt; // series filters
  1677. dly_t *pdlys[CRVA_DLYS]; // array of pointers to delays
  1678. mdy_t *pmdlys[CRVA_DLYS]; // array of pointers to mod delays
  1679. bool fmoddly; // true if using mod delays
  1680. };
  1681. rva_t rvas[CRVAS];
  1682. void RVA_Init ( rva_t *prva ) { if ( prva ) Q_memset (prva, 0, sizeof (rva_t)); }
  1683. void RVA_InitAll( void ) { for (int i = 0; i < CRVAS; i++) RVA_Init ( &rvas[i] ); }
  1684. // free parallel series reverb
  1685. void RVA_Free( rva_t *prva )
  1686. {
  1687. int i;
  1688. if ( prva )
  1689. {
  1690. // free all delays
  1691. for (i = 0; i < CRVA_DLYS; i++)
  1692. DLY_Free ( prva->pdlys[i] );
  1693. // zero all ptrs to delays in mdy array
  1694. for (i = 0; i < CRVA_DLYS; i++)
  1695. {
  1696. if ( prva->pmdlys[i] )
  1697. prva->pmdlys[i]->pdly = NULL;
  1698. }
  1699. // free all mod delays
  1700. for (i = 0; i < CRVA_DLYS; i++)
  1701. MDY_Free ( prva->pmdlys[i] );
  1702. FLT_Free( prva->pflt );
  1703. Q_memset( prva, 0, sizeof (rva_t) );
  1704. }
  1705. }
  1706. void RVA_FreeAll( void ) { for (int i = 0; i < CRVAS; i++) RVA_Free( &rvas[i] ); }
  1707. // create parallel reverb - m parallel reverbs summed
  1708. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  1709. // a array of reverb feedback parms for parallel reverbs (CRVB_P_DLYS)
  1710. // if a[i] < 0 then this is a predelay - use DLY_FLINEAR instead of DLY_LOWPASS
  1711. // b array of CRVB_P_DLYS - mix params for parallel reverbs
  1712. // m - number of parallel delays
  1713. // pflt - filter template, to be used by all parallel delays
  1714. // fparallel - true if filter operates in parallel with delays, otherwise filter output only
  1715. // fmoddly - > 0 if delays are all mod delays (milliseconds of delay modulation)
  1716. // fmodrate - # of delay repetitions between changes to mod delay
  1717. // ftaps - if > 0, use 4 taps per reverb delay unit (increases density) tap = D - n*ftaps n = 0,1,2,3
  1718. rva_t * RVA_Alloc ( int *D, int *a, int *b, int m, flt_t *pflt, int fparallel, float fmoddly, float fmodrate, float ftaps )
  1719. {
  1720. int i;
  1721. int dtype;
  1722. rva_t *prva;
  1723. flt_t *pflt2 = NULL;
  1724. bool btaps = ftaps > 0.0;
  1725. // find open slot
  1726. for ( i = 0; i < CRVAS; i++ )
  1727. {
  1728. if ( !rvas[i].fused )
  1729. break;
  1730. }
  1731. // return null if no free slots
  1732. if (i == CRVAS)
  1733. {
  1734. DevMsg ("DSP: Warning, failed to allocate reverb.\n" );
  1735. return NULL;
  1736. }
  1737. prva = &rvas[i];
  1738. // if series filter specified, alloc two series filters
  1739. if ( pflt && !fparallel)
  1740. {
  1741. // use filter data as template for a filter on output (2 cascaded filters)
  1742. pflt2 = FLT_Alloc (0, pflt->M, pflt->L, pflt->a, pflt->b, 1.0);
  1743. if (!pflt2)
  1744. {
  1745. DevMsg ("DSP: Warning, failed to allocate flt for reverb.\n" );
  1746. return NULL;
  1747. }
  1748. pflt2->pf1 = FLT_Alloc (0, pflt->M, pflt->L, pflt->a, pflt->b, 1.0);
  1749. pflt2->N = 1;
  1750. }
  1751. // allocate parallel delays
  1752. for (i = 0; i < m; i++)
  1753. {
  1754. // set delay type
  1755. if ( pflt && fparallel )
  1756. // if a[i] param is < 0, allocate delay as predelay instead of feedback delay
  1757. dtype = a[i] < 0 ? DLY_FLINEAR : DLY_LOWPASS;
  1758. else
  1759. // if no filter specified, alloc as plain or multitap plain delay
  1760. dtype = btaps ? DLY_PLAIN_4TAP : DLY_PLAIN;
  1761. if ( dtype == DLY_LOWPASS && btaps )
  1762. dtype = DLY_LOWPASS_4TAP;
  1763. // if filter specified and parallel specified, alloc 1 filter per delay
  1764. if ( DLY_HAS_FILTER(dtype) )
  1765. prva->pdlys[i] = DLY_AllocLP( D[i], abs(a[i]), b[i], dtype, pflt->M, pflt->L, pflt->a, pflt->b );
  1766. else
  1767. prva->pdlys[i] = DLY_Alloc( D[i], abs(a[i]), b[i], dtype );
  1768. if ( DLY_HAS_MULTITAP(dtype) )
  1769. {
  1770. // set up delay taps to increase density around delay value.
  1771. // value of ftaps is the seed for all tap values
  1772. float t1 = max((double)MSEC_TO_SAMPS(5), D[i] * (1.0 - ftaps * 3.141592) );
  1773. float t2 = max((double)MSEC_TO_SAMPS(7), D[i] * (1.0 - ftaps * 1.697043) );
  1774. float t3 = max((double)MSEC_TO_SAMPS(10), D[i] * (1.0 - ftaps * 0.96325) );
  1775. DLY_ChangeTaps( prva->pdlys[i], (int)t1, (int)t2, (int)t3, D[i] );
  1776. }
  1777. }
  1778. if ( fmoddly > 0.0 )
  1779. {
  1780. // alloc mod delays, using previously alloc'd delays
  1781. // ramptime is time in seconds for delay to change from dcur to dnew
  1782. // modtime is time in seconds between modulations. 0 if no self-modulation
  1783. // depth is 0-1.0 multiplier, new delay values when modulating are Dnew = randomlong (D - D*depth, D)
  1784. float ramptime;
  1785. float modtime;
  1786. float depth;
  1787. for (i = 0; i < m; i++)
  1788. {
  1789. int Do = prva->pdlys[i]->D;
  1790. modtime = (float)Do / (float)(SOUND_DMA_SPEED); // seconds per delay
  1791. depth = (fmoddly * 0.001f) / modtime; // convert milliseconds to 'depth' %
  1792. depth = clamp (depth, 0.01f, 0.99f);
  1793. modtime = modtime * fmodrate; // modulate every N delay passes
  1794. ramptime = fpmin(20.0f/1000.0f, modtime / 2); // ramp between delay values in N ms
  1795. prva->pmdlys[i] = MDY_Alloc( prva->pdlys[i], ramptime, modtime, depth, 1.0 );
  1796. }
  1797. prva->fmoddly = true;
  1798. }
  1799. // if we failed to alloc any reverb, free all, return NULL
  1800. for (i = 0; i < m; i++)
  1801. {
  1802. if ( !prva->pdlys[i] )
  1803. {
  1804. FLT_Free( pflt2 );
  1805. RVA_Free( prva );
  1806. DevMsg ("DSP: Warning, failed to allocate delay for reverb.\n" );
  1807. return NULL;
  1808. }
  1809. }
  1810. prva->fused = true;
  1811. prva->m = m;
  1812. prva->fparallel = fparallel;
  1813. prva->pflt = pflt2;
  1814. return prva;
  1815. }
  1816. // parallel reverberator
  1817. //
  1818. // for each input sample x do:
  1819. // x0 = plain(D0,w0,&p0,a0,x)
  1820. // x1 = plain(D1,w1,&p1,a1,x)
  1821. // x2 = plain(D2,w2,&p2,a2,x)
  1822. // x3 = plain(D3,w3,&p3,a3,x)
  1823. // y = b0*x0 + b1*x1 + b2*x2 + b3*x3
  1824. //
  1825. // rgdly - array of M delays:
  1826. // D - Delay values (typical - 29, 37, 44, 50, 27, 31)
  1827. // w - array of delayed values
  1828. // p - array of pointers to circular delay line pointers
  1829. // a - array of M feedback values (typical - all equal, like 0.75 * PMAX)
  1830. // b - array of M gain values for plain reverb outputs (1, .9, .8, .7)
  1831. // xin - input value
  1832. // if fparallel, filters are built into delays,
  1833. // otherwise, filter is in feedback loop
  1834. int g_MapIntoPBITSDivInt[] =
  1835. {
  1836. 0, PMAX/1, PMAX/2, PMAX/3, PMAX/4, PMAX/5, PMAX/6, PMAX/7, PMAX/8,
  1837. PMAX/9, PMAX/10, PMAX/11,PMAX/12,PMAX/13,PMAX/14,PMAX/15,PMAX/16,
  1838. };
  1839. inline int RVA_GetNext( rva_t *prva, int x )
  1840. {
  1841. int m = prva->m;
  1842. int y = 0;
  1843. if ( prva->fmoddly )
  1844. {
  1845. // get output of parallel mod delays
  1846. for (int i = 0; i < m; i++ )
  1847. y += MDY_GetNext( prva->pmdlys[i], x );
  1848. }
  1849. else
  1850. {
  1851. // get output of parallel delays
  1852. for (int i = 0; i < m; i++ )
  1853. y += DLY_GetNext( prva->pdlys[i], x );
  1854. }
  1855. // PERFORMANCE: y/m is now baked into the 'b' gain params for each delay ( b = b/m )
  1856. // y = (y * g_MapIntoPBITSDivInt[m]) >> PBITS;
  1857. if ( prva->fparallel )
  1858. return y;
  1859. // run series filters if present
  1860. if ( prva->pflt )
  1861. {
  1862. y = FLT_GetNext( prva->pflt, y);
  1863. }
  1864. return y;
  1865. }
  1866. // batch version for performance
  1867. // UNDONE: unwind RVA_GetNextN so that it directly calls DLY_GetNextN or MDY_GetNextN
  1868. inline void RVA_GetNextN( rva_t *prva, portable_samplepair_t *pbuffer, int SampleCount, int op )
  1869. {
  1870. int count = SampleCount;
  1871. portable_samplepair_t *pb = pbuffer;
  1872. switch (op)
  1873. {
  1874. default:
  1875. case OP_LEFT:
  1876. while (count--)
  1877. {
  1878. pb->left = RVA_GetNext( prva, pb->left );
  1879. pb++;
  1880. }
  1881. return;
  1882. case OP_RIGHT:
  1883. while (count--)
  1884. {
  1885. pb->right = RVA_GetNext( prva, pb->right );
  1886. pb++;
  1887. }
  1888. return;
  1889. case OP_LEFT_DUPLICATE:
  1890. while (count--)
  1891. {
  1892. pb->left = pb->right = RVA_GetNext( prva, pb->left );
  1893. pb++;
  1894. }
  1895. return;
  1896. }
  1897. }
  1898. // reverb parameter order
  1899. typedef enum
  1900. {
  1901. // parameter order
  1902. rva_size_max,
  1903. rva_size_min,
  1904. rva_inumdelays,
  1905. rva_ifeedback,
  1906. rva_igain,
  1907. rva_icutoff,
  1908. rva_ifparallel,
  1909. rva_imoddly,
  1910. rva_imodrate,
  1911. rva_width,
  1912. rva_depth,
  1913. rva_height,
  1914. rva_fbwidth,
  1915. rva_fbdepth,
  1916. rva_fbheight,
  1917. rva_iftaps,
  1918. rva_cparam // # of params
  1919. } rva_e;
  1920. // filter parameter ranges
  1921. prm_rng_t rva_rng[] = {
  1922. {rva_cparam, 0, 0}, // first entry is # of parameters
  1923. // reverb params
  1924. {rva_size_max, 0.0, 1000.0}, // max room delay in milliseconds
  1925. {rva_size_min, 0.0, 1000.0}, // min room delay in milliseconds
  1926. {rva_inumdelays,1.0, 12.0}, // controls # of parallel or series delays
  1927. {rva_ifeedback, 0.0, 1.0}, // feedback of delays
  1928. {rva_igain, 0.0, 10.0}, // output gain
  1929. // filter params for each parallel reverb (quality set to 0 for max execution speed)
  1930. {rva_icutoff, 10, 22050},
  1931. {rva_ifparallel, 0, 1}, // if 1, then all filters operate in parallel with delays. otherwise filter output only
  1932. {rva_imoddly, 0.0, 50.0}, // if > 0 then all delays are modulating delays, mod param controls milliseconds of mod depth
  1933. {rva_imodrate, 0.0, 10.0}, // how many delay repetitions pass between mod changes to delayl
  1934. // override params - for more detailed description of room
  1935. // note: width/depth/height < 0 only for some automatic dsp presets
  1936. {rva_width, -1000.0, 1000.0}, // 0-1000.0 millisec (room width in feet) - used instead of size if non-zero
  1937. {rva_depth, -1000.0, 1000.0}, // 0-1000.0 room depth in feet - used instead of size if non-zero
  1938. {rva_height, -1000.0, 1000.0}, // 0-1000.0 room height in feet - used instead of size if non-zero
  1939. {rva_fbwidth, -1.0, 1.0}, // 0-1.0 material reflectivity - used as feedback param instead of decay if non-zero
  1940. {rva_fbdepth, -1.0, 1.0}, // 0-1.0 material reflectivity - used as feedback param instead of decay if non-zero
  1941. {rva_fbheight, -1.0, 1.0}, // 0-1.0 material reflectivity - used as feedback param instead of decay if non-zero
  1942. // if < 0, a predelay is allocated, then feedback is -1*param given
  1943. {rva_iftaps, 0.0, 0.333} // if > 0, use 3 extra taps with delay values = d * (1 - faps*n) n = 0,1,2,3
  1944. };
  1945. #define RVA_BASEM 1 // base number of parallel delays
  1946. // nominal delay and feedback values. More delays = more density.
  1947. #define RVADLYSMAX 49
  1948. float rvadlys[] = {18, 23, 28, 33, 42, 21, 26, 36, 39, 45, 47, 30};
  1949. float rvafbs[] = {0.9, 0.9, 0.9, 0.85, 0.8, 0.9, 0.9, 0.85, 0.8, 0.8, 0.8, 0.85};
  1950. #define SWAP(a,b,t) {(t) = (a); (a) = (b); (b) = (t);}
  1951. #define RVA_MIN_SEPARATION 7 // minimum separation between reverbs, in ms.
  1952. // Construct D,a,b delay arrays given array of length,width,height sizes and feedback values
  1953. // rgd[] array of delay values in milliseconds (feet)
  1954. // rgf[] array of feedback values 0..1
  1955. // m # of parallel reverbs to construct
  1956. // D[] array of output delay values for parallel reverbs
  1957. // a[] array of output feedback values
  1958. // b[] array of output gain values = 1/m
  1959. // gain - output gain
  1960. // feedback - default feedback if rgf members are 0
  1961. void RVA_ConstructDelays( float *rgd, float *rgf, int m, int *D, int *a, int *b, float gain, float feedback )
  1962. {
  1963. int i;
  1964. float r;
  1965. int d;
  1966. float t, d1, d2, dm;
  1967. bool bpredelay;
  1968. // sort descending, so rgd[0] is largest delay & rgd[2] is smallest
  1969. if (rgd[2] > rgd[1]) { SWAP(rgd[2], rgd[1], t); SWAP(rgf[2], rgf[1], t); }
  1970. if (rgd[1] > rgd[0]) { SWAP(rgd[0], rgd[1], t); SWAP(rgf[0], rgf[1], t); }
  1971. if (rgd[2] > rgd[1]) { SWAP(rgd[2], rgd[1], t); SWAP(rgf[2], rgf[1], t); }
  1972. // if all feedback values 0, use default feedback
  1973. if (rgf[0] == 0.0 && rgf[1] == 0.0 && rgf[2] == 0.0 )
  1974. {
  1975. // use feedback param for all
  1976. rgf[0] = rgf[1] = rgf[2] = feedback;
  1977. // adjust feedback down for larger delays so that decay is constant for all delays
  1978. rgf[0] = DLY_NormalizeFeedback( rgd[2], rgf[2], rgd[0] );
  1979. rgf[1] = DLY_NormalizeFeedback( rgd[2], rgf[2], rgd[1] );
  1980. }
  1981. // make sure all reverbs are different by at least RVA_MIN_SEPARATION * m/3 m is 3,6,9 or 12
  1982. int dmin = (m/3) * RVA_MIN_SEPARATION;
  1983. d1 = rgd[1] - rgd[2];
  1984. if (d1 <= dmin)
  1985. rgd[1] += (dmin-d1); // make difference = dmin
  1986. d2 = rgd[0] - rgd[1];
  1987. if (d2 <= dmin)
  1988. rgd[0] += (dmin-d1); // make difference = dmin
  1989. for ( i = 0; i < m; i++ )
  1990. {
  1991. // reverberations due to room width, depth, height
  1992. // assume sound moves at approx 1ft/ms
  1993. int j = (int)(fmod ((float)i, 3.0f)); // j counts 0,1,2 0,1,2 0,1..
  1994. d = (int)rgd[j];
  1995. r = fabs(rgf[j]);
  1996. bpredelay = ((rgf[j] < 0) && i < 3);
  1997. // re-use predelay values as reverb values:
  1998. if (rgf[j] < 0 && !bpredelay)
  1999. d = max((int)(rgd[j] / 4.0), RVA_MIN_SEPARATION);
  2000. if (i < 3)
  2001. dm = 0.0;
  2002. else
  2003. dm = max( (double)(RVA_MIN_SEPARATION * (i/3)), ((i/3) * ((float)d * 0.18)) );
  2004. d += (int)dm;
  2005. D[i] = MSEC_TO_SAMPS(d);
  2006. // D[i] = MSEC_TO_SAMPS(d + ((i/3) * RVA_MIN_SEPARATION)); // (i/3) counts 0,0,0 1,1,1 2,2,2 ... separate all reverbs by 5ms
  2007. // feedback - due to wall/floor/ceiling reflectivity
  2008. a[i] = (int) min (0.999 * PMAX, (double)PMAX * r);
  2009. if (bpredelay)
  2010. a[i] = -a[i]; // flag delay as predelay
  2011. b[i] = (int)((float)(gain * PMAX) / (float)m);
  2012. }
  2013. }
  2014. void RVA_PerfTest()
  2015. {
  2016. double time1, time2;
  2017. int i;
  2018. int k;
  2019. int j;
  2020. int m;
  2021. int a[100];
  2022. time1 = Plat_FloatTime();
  2023. for (m = 0; m < 1000; m++)
  2024. {
  2025. for (i = 0, j = 10000; i < 10000; i++, j--)
  2026. {
  2027. // j = j % 6;
  2028. // k = (i * j) >> PBITS;
  2029. k = i / ((j % 6) + 1);
  2030. }
  2031. }
  2032. time2 = Plat_FloatTime();
  2033. DevMsg("divide = %2.5f \n", (time2-time1));
  2034. for (i=1;i<10;i++)
  2035. a[i] = PMAX / i;
  2036. time1 = Plat_FloatTime();
  2037. for (m = 0; m < 1000; m++)
  2038. {
  2039. for (i = 0, j = 10000; i < 10000; i++, j--)
  2040. {
  2041. k = (i * a[(j % 6) + 1] ) >> PBITS;
  2042. }
  2043. }
  2044. time2 = Plat_FloatTime();
  2045. DevMsg("shift & multiply = %2.5f \n", (time2-time1));
  2046. }
  2047. rva_t * RVA_Params ( prc_t *pprc )
  2048. {
  2049. rva_t *prva;
  2050. float size_max = pprc->prm[rva_size_max]; // max delay size
  2051. float size_min = pprc->prm[rva_size_min]; // min delay size
  2052. float numdelays = pprc->prm[rva_inumdelays]; // controls # of parallel delays
  2053. float feedback = pprc->prm[rva_ifeedback]; // 0-1.0 controls feedback parameters
  2054. float gain = pprc->prm[rva_igain]; // 0-10.0 controls output gain
  2055. float cutoff = pprc->prm[rva_icutoff]; // filter cutoff
  2056. float fparallel = pprc->prm[rva_ifparallel]; // if true, all filters are in delay feedback paths - otherwise single flt on output
  2057. float fmoddly = pprc->prm[rva_imoddly]; // if > 0, milliseconds of delay mod depth
  2058. float fmodrate = pprc->prm[rva_imodrate]; // if fmoddly > 0, # of delay repetitions between modulations
  2059. float width = fabs(pprc->prm[rva_width]); // 0-1000 controls size of 1/3 of delays - used instead of size if non-zero
  2060. float depth = fabs(pprc->prm[rva_depth]); // 0-1000 controls size of 1/3 of delays - used instead of size if non-zero
  2061. float height = fabs(pprc->prm[rva_height]); // 0-1000 controls size of 1/3 of delays - used instead of size if non-zero
  2062. float fbwidth = pprc->prm[rva_fbwidth]; // feedback parameter for walls 0..2
  2063. float fbdepth = pprc->prm[rva_fbdepth]; // feedback parameter for floor
  2064. float fbheight = pprc->prm[rva_fbheight]; // feedback parameter for ceiling
  2065. float ftaps = pprc->prm[rva_iftaps]; // if > 0 increase reverb density using 3 extra taps d = (1.0 - ftaps * n) n = 0,1,2,3
  2066. // RVA_PerfTest();
  2067. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  2068. // a array of reverb feedback parms for parallel delays
  2069. // b array of CRVB_P_DLYS - mix params for parallel reverbs
  2070. // m - number of parallel delays
  2071. int D[CRVA_DLYS];
  2072. int a[CRVA_DLYS];
  2073. int b[CRVA_DLYS];
  2074. int m;
  2075. // limit # delays 1-12
  2076. m = clamp (numdelays, (float)RVA_BASEM, (float)CRVA_DLYS);
  2077. // set up D (delay) a (feedback) b (gain) arrays
  2078. if ( int(width) || int(height) || int(depth) )
  2079. {
  2080. // if width, height, depth given, use values as simple delays
  2081. float rgd[3];
  2082. float rgfb[3];
  2083. // force m to 3, 6, 9 or 12
  2084. if (m < 3) m = 3;
  2085. if (m > 3 && m < 6) m = 6;
  2086. if (m > 6 && m < 9) m = 9;
  2087. if (m > 9) m = 12;
  2088. rgd[0] = width; rgfb[0] = fbwidth;
  2089. rgd[1] = depth; rgfb[1] = fbdepth;
  2090. rgd[2] = height; rgfb[2] = fbheight;
  2091. RVA_ConstructDelays( rgd, rgfb, m, D, a, b, gain, feedback );
  2092. }
  2093. else
  2094. {
  2095. // use size parameter instead of width/depth/height
  2096. for ( int i = 0; i < m; i++ )
  2097. {
  2098. // delays of parallel reverb. D[0] = size_min.
  2099. D[i] = MSEC_TO_SAMPS( size_min + (int)( ((float)(size_max - size_min) / (float)m) * (float)i) );
  2100. // feedback and gain of parallel reverb
  2101. if (i == 0)
  2102. {
  2103. // set feedback for smallest delay
  2104. a[i] = (int) min (0.999 * PMAX, (double)PMAX * feedback );
  2105. }
  2106. else
  2107. {
  2108. // adjust feedback down for larger delays so that decay time is constant
  2109. a[i] = (int) min (0.999 * PMAX, (double)PMAX * DLY_NormalizeFeedback( D[0], feedback, D[i] ) );
  2110. }
  2111. b[i] = (int) ((float)(gain * PMAX) / (float)m);
  2112. }
  2113. }
  2114. // add filter
  2115. flt_t *pflt = NULL;
  2116. if ( cutoff )
  2117. {
  2118. // set up dummy lowpass filter to convert params
  2119. prc_t prcf;
  2120. prcf.prm[flt_iquality] = QUA_LO; // force filter to low quality for faster execution time
  2121. prcf.prm[flt_icutoff] = cutoff;
  2122. prcf.prm[flt_iftype] = FLT_LP;
  2123. prcf.prm[flt_iqwidth] = 0;
  2124. prcf.prm[flt_igain] = 1.0;
  2125. pflt = (flt_t *)FLT_Params ( &prcf );
  2126. }
  2127. prva = RVA_Alloc ( D, a, b, m, pflt, fparallel, fmoddly, fmodrate, ftaps );
  2128. FLT_Free( pflt );
  2129. return prva;
  2130. }
  2131. inline void * RVA_VParams ( void *p )
  2132. {
  2133. PRC_CheckParams ( (prc_t *)p, rva_rng );
  2134. return (void *) RVA_Params ((prc_t *)p);
  2135. }
  2136. inline void RVA_Mod ( void *p, float v ) { return; }
  2137. ////////////
  2138. // Diffusor
  2139. ///////////
  2140. // (N series allpass reverbs)
  2141. #define CDFRS 64 // max number of series reverbs active
  2142. #define CDFR_DLYS 16 // max number of delays making up diffusor
  2143. struct dfr_t
  2144. {
  2145. bool fused;
  2146. int n; // series allpass delays
  2147. int w[CDFR_DLYS]; // internal state array for series allpass filters
  2148. dly_t *pdlys[CDFR_DLYS]; // array of pointers to delays
  2149. };
  2150. dfr_t dfrs[CDFRS];
  2151. void DFR_Init ( dfr_t *pdfr ) { if ( pdfr ) Q_memset (pdfr, 0, sizeof (dfr_t)); }
  2152. void DFR_InitAll( void ) { for (int i = 0; i < CDFRS; i++) DFR_Init ( &dfrs[i] ); }
  2153. // free parallel series reverb
  2154. void DFR_Free( dfr_t *pdfr )
  2155. {
  2156. if ( pdfr )
  2157. {
  2158. // free all delays
  2159. for (int i = 0; i < CDFR_DLYS; i++)
  2160. DLY_Free ( pdfr->pdlys[i] );
  2161. Q_memset( pdfr, 0, sizeof (dfr_t) );
  2162. }
  2163. }
  2164. void DFR_FreeAll( void ) { for (int i = 0; i < CDFRS; i++) DFR_Free( &dfrs[i] ); }
  2165. // create n series allpass reverbs
  2166. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  2167. // a array of reverb feedback parms for series delays
  2168. // b array of gain params for parallel reverbs
  2169. // n - number of series delays
  2170. dfr_t * DFR_Alloc ( int *D, int *a, int *b, int n )
  2171. {
  2172. int i;
  2173. dfr_t *pdfr;
  2174. // find open slot
  2175. for (i = 0; i < CDFRS; i++)
  2176. {
  2177. if (!dfrs[i].fused)
  2178. break;
  2179. }
  2180. // return null if no free slots
  2181. if (i == CDFRS)
  2182. {
  2183. DevMsg ("DSP: Warning, failed to allocate diffusor.\n" );
  2184. return NULL;
  2185. }
  2186. pdfr = &dfrs[i];
  2187. DFR_Init( pdfr );
  2188. // alloc reverbs
  2189. for (i = 0; i < n; i++)
  2190. pdfr->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_ALLPASS );
  2191. // if we failed to alloc any reverb, free all, return NULL
  2192. for (i = 0; i < n; i++)
  2193. {
  2194. if ( !pdfr->pdlys[i])
  2195. {
  2196. DFR_Free( pdfr );
  2197. DevMsg ("DSP: Warning, failed to allocate delay for diffusor.\n" );
  2198. return NULL;
  2199. }
  2200. }
  2201. pdfr->fused = true;
  2202. pdfr->n = n;
  2203. return pdfr;
  2204. }
  2205. // series reverberator
  2206. inline int DFR_GetNext( dfr_t *pdfr, int x )
  2207. {
  2208. int i;
  2209. int y;
  2210. dly_t *pdly;
  2211. y = x;
  2212. for (i = 0; i < pdfr->n; i++)
  2213. {
  2214. pdly = pdfr->pdlys[i];
  2215. y = DelayAllpass( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, y );
  2216. }
  2217. return y;
  2218. }
  2219. // batch version for performance
  2220. inline void DFR_GetNextN( dfr_t *pdfr, portable_samplepair_t *pbuffer, int SampleCount, int op )
  2221. {
  2222. int count = SampleCount;
  2223. portable_samplepair_t *pb = pbuffer;
  2224. switch (op)
  2225. {
  2226. default:
  2227. case OP_LEFT:
  2228. while (count--)
  2229. {
  2230. pb->left = DFR_GetNext( pdfr, pb->left );
  2231. pb++;
  2232. }
  2233. return;
  2234. case OP_RIGHT:
  2235. while (count--)
  2236. {
  2237. pb->right = DFR_GetNext( pdfr, pb->right );
  2238. pb++;
  2239. }
  2240. return;
  2241. case OP_LEFT_DUPLICATE:
  2242. while (count--)
  2243. {
  2244. pb->left = pb->right = DFR_GetNext( pdfr, pb->left );
  2245. pb++;
  2246. }
  2247. return;
  2248. }
  2249. }
  2250. #define DFR_BASEN 1 // base number of series allpass delays
  2251. // nominal diffusor delay and feedback values
  2252. float dfrdlys[] = {13, 19, 26, 21, 32, 36, 38, 16, 24, 28, 41, 35, 10, 46, 50, 27};
  2253. float dfrfbs[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
  2254. // diffusor parameter order
  2255. typedef enum
  2256. {
  2257. // parameter order
  2258. dfr_isize,
  2259. dfr_inumdelays,
  2260. dfr_ifeedback,
  2261. dfr_igain,
  2262. dfr_cparam // # of params
  2263. } dfr_e;
  2264. // diffusor parameter ranges
  2265. prm_rng_t dfr_rng[] = {
  2266. {dfr_cparam, 0, 0}, // first entry is # of parameters
  2267. {dfr_isize, 0.0, 1.0}, // 0-1.0 scales all delays
  2268. {dfr_inumdelays,0.0, 4.0}, // 0-4.0 controls # of series delays
  2269. {dfr_ifeedback, 0.0, 1.0}, // 0-1.0 scales all feedback parameters
  2270. {dfr_igain, 0.0, 10.0}, // 0-1.0 scales all feedback parameters
  2271. };
  2272. dfr_t * DFR_Params ( prc_t *pprc )
  2273. {
  2274. dfr_t *pdfr;
  2275. int i;
  2276. int s;
  2277. float size = pprc->prm[dfr_isize]; // 0-1.0 scales all delays
  2278. float numdelays = pprc->prm[dfr_inumdelays]; // 0-4.0 controls # of series delays
  2279. float feedback = pprc->prm[dfr_ifeedback]; // 0-1.0 scales all feedback parameters
  2280. float gain = pprc->prm[dfr_igain]; // 0-10.0 controls output gain
  2281. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  2282. // a array of reverb feedback parms for series delays (CRVB_S_DLYS)
  2283. // b gain of each reverb section
  2284. // n - number of series delays
  2285. int D[CDFR_DLYS];
  2286. int a[CDFR_DLYS];
  2287. int b[CDFR_DLYS];
  2288. int n;
  2289. if (gain == 0.0)
  2290. gain = 1.0;
  2291. // get # series diffusors
  2292. // limit m, n to half max number of delays
  2293. n = clamp (Float2Int(numdelays), DFR_BASEN, CDFR_DLYS/2);
  2294. // compute delays for diffusors
  2295. for (i = 0; i < n; i++)
  2296. {
  2297. s = (int)( dfrdlys[i] * size );
  2298. // delay of diffusor
  2299. D[i] = MSEC_TO_SAMPS(s);
  2300. // feedback and gain of diffusor
  2301. a[i] = min (0.999 * PMAX, (double)(dfrfbs[i] * PMAX * feedback));
  2302. b[i] = (int) ( (float)(gain * (float)PMAX) );
  2303. }
  2304. pdfr = DFR_Alloc ( D, a, b, n );
  2305. return pdfr;
  2306. }
  2307. inline void * DFR_VParams ( void *p )
  2308. {
  2309. PRC_CheckParams ((prc_t *)p, dfr_rng);
  2310. return (void *) DFR_Params ((prc_t *)p);
  2311. }
  2312. inline void DFR_Mod ( void *p, float v ) { return; }
  2313. //////////////////////
  2314. // LFO wav definitions
  2315. //////////////////////
  2316. #define CLFOSAMPS 512 // samples per wav table - single cycle only
  2317. #define LFOBITS 14 // bits of peak amplitude of lfo wav
  2318. #define LFOAMP ((1<<LFOBITS)-1) // peak amplitude of lfo wav
  2319. //types of lfo wavs
  2320. #define LFO_SIN 0 // sine wav
  2321. #define LFO_TRI 1 // triangle wav
  2322. #define LFO_SQR 2 // square wave, 50% duty cycle
  2323. #define LFO_SAW 3 // forward saw wav
  2324. #define LFO_RND 4 // random wav
  2325. #define LFO_LOG_IN 5 // logarithmic fade in
  2326. #define LFO_LOG_OUT 6 // logarithmic fade out
  2327. #define LFO_LIN_IN 7 // linear fade in
  2328. #define LFO_LIN_OUT 8 // linear fade out
  2329. #define LFO_MAX LFO_LIN_OUT
  2330. #define CLFOWAV 9 // number of LFO wav tables
  2331. struct lfowav_t // lfo or envelope wave table
  2332. {
  2333. int type; // lfo type
  2334. dly_t *pdly; // delay holds wav values and step pointers
  2335. };
  2336. lfowav_t lfowavs[CLFOWAV];
  2337. // deallocate lfo wave table. Called only when sound engine exits.
  2338. void LFOWAV_Free( lfowav_t *plw )
  2339. {
  2340. // free delay
  2341. if ( plw )
  2342. DLY_Free( plw->pdly );
  2343. Q_memset( plw, 0, sizeof (lfowav_t) );
  2344. }
  2345. // deallocate all lfo wave tables. Called only when sound engine exits.
  2346. void LFOWAV_FreeAll( void )
  2347. {
  2348. for ( int i = 0; i < CLFOWAV; i++ )
  2349. LFOWAV_Free( &lfowavs[i] );
  2350. }
  2351. // fill lfo array w with count samples of lfo type 'type'
  2352. // all lfo wavs except fade out, rnd, and log_out should start with 0 output
  2353. void LFOWAV_Fill( int *w, int count, int type )
  2354. {
  2355. int i,x;
  2356. switch (type)
  2357. {
  2358. default:
  2359. case LFO_SIN: // sine wav, all values 0 <= x <= LFOAMP, initial value = 0
  2360. for (i = 0; i < count; i++ )
  2361. {
  2362. x = ( int )( (float)(LFOAMP) * sinf( (2.0 * M_PI_F * (float)i / (float)count ) + (M_PI_F * 1.5) ) );
  2363. w[i] = (x + LFOAMP)/2;
  2364. }
  2365. break;
  2366. case LFO_TRI: // triangle wav, all values 0 <= x <= LFOAMP, initial value = 0
  2367. for (i = 0; i < count; i++)
  2368. {
  2369. w[i] = ( int ) ( (float)(2 * LFOAMP * i ) / (float)(count) );
  2370. if ( i > count / 2 )
  2371. w[i] = ( int ) ( (float) (2 * LFOAMP) - (float)( 2 * LFOAMP * i ) / (float)(count) );
  2372. }
  2373. break;
  2374. case LFO_SQR: // square wave, 50% duty cycle, all values 0 <= x <= LFOAMP, initial value = 0
  2375. for (i = 0; i < count; i++)
  2376. w[i] = i > count / 2 ? 0 : LFOAMP;
  2377. break;
  2378. case LFO_SAW: // forward saw wav, aall values 0 <= x <= LFOAMP, initial value = 0
  2379. for (i = 0; i < count; i++)
  2380. w[i] = ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
  2381. break;
  2382. case LFO_RND: // random wav, all values 0 <= x <= LFOAMP
  2383. for (i = 0; i < count; i++)
  2384. w[i] = ( int ) ( RandomInt(0, LFOAMP) );
  2385. break;
  2386. case LFO_LOG_IN: // logarithmic fade in, all values 0 <= x <= LFOAMP, initial value = 0
  2387. for (i = 0; i < count; i++)
  2388. w[i] = ( int ) ( (float)(LFOAMP) * powf( (float)i / (float)count, 2));
  2389. break;
  2390. case LFO_LOG_OUT: // logarithmic fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
  2391. for (i = 0; i < count; i++)
  2392. w[i] = ( int ) ( (float)(LFOAMP) * powf( 1.0 - ((float)i / (float)count), 2 ));
  2393. break;
  2394. case LFO_LIN_IN: // linear fade in, all values 0 <= x <= LFOAMP, initial value = 0
  2395. for (i = 0; i < count; i++)
  2396. w[i] = ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
  2397. break;
  2398. case LFO_LIN_OUT: // linear fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
  2399. for (i = 0; i < count; i++)
  2400. w[i] = LFOAMP - ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
  2401. break;
  2402. }
  2403. }
  2404. // allocate all lfo wave tables. Called only when sound engine loads.
  2405. void LFOWAV_InitAll()
  2406. {
  2407. int i;
  2408. dly_t *pdly;
  2409. Q_memset( lfowavs, 0, sizeof( lfowavs ) );
  2410. // alloc space for each lfo wav type
  2411. for (i = 0; i < CLFOWAV; i++)
  2412. {
  2413. pdly = DLY_Alloc( CLFOSAMPS, 0, 0 , DLY_PLAIN);
  2414. lfowavs[i].pdly = pdly;
  2415. lfowavs[i].type = i;
  2416. LFOWAV_Fill( pdly->w, CLFOSAMPS, i );
  2417. }
  2418. // if any dlys fail to alloc, free all
  2419. for (i = 0; i < CLFOWAV; i++)
  2420. {
  2421. if ( !lfowavs[i].pdly )
  2422. LFOWAV_FreeAll();
  2423. }
  2424. }
  2425. ////////////////////////////////////////
  2426. // LFO iterators - one shot and looping
  2427. ////////////////////////////////////////
  2428. #define CLFO 16 // max active lfos (this steals from active delays)
  2429. struct lfo_t
  2430. {
  2431. bool fused; // true if slot take
  2432. dly_t *pdly; // delay points to lfo wav within lfowav_t (don't free this)
  2433. int gain;
  2434. float f; // playback frequency in hz
  2435. pos_t pos; // current position within wav table, looping
  2436. pos_one_t pos1; // current position within wav table, one shot
  2437. int foneshot; // true - one shot only, don't repeat
  2438. };
  2439. lfo_t lfos[CLFO];
  2440. void LFO_Init( lfo_t *plfo ) { if ( plfo ) Q_memset( plfo, 0, sizeof (lfo_t) ); }
  2441. void LFO_InitAll( void ) { for (int i = 0; i < CLFO; i++) LFO_Init(&lfos[i]); }
  2442. void LFO_Free( lfo_t *plfo ) { if ( plfo ) Q_memset( plfo, 0, sizeof (lfo_t) ); }
  2443. void LFO_FreeAll( void ) { for (int i = 0; i < CLFO; i++) LFO_Free(&lfos[i]); }
  2444. // get step value given desired playback frequency
  2445. inline float LFO_HzToStep ( float freqHz )
  2446. {
  2447. float lfoHz;
  2448. // calculate integer and fractional step values,
  2449. // assume an update rate of SOUND_DMA_SPEED samples/sec
  2450. // 1 cycle/CLFOSAMPS * SOUND_DMA_SPEED samps/sec = cycles/sec = current lfo rate
  2451. //
  2452. // lforate * X = freqHz so X = freqHz/lforate = update rate
  2453. lfoHz = (float)(SOUND_DMA_SPEED) / (float)(CLFOSAMPS);
  2454. return freqHz / lfoHz;
  2455. }
  2456. // return pointer to new lfo
  2457. lfo_t * LFO_Alloc( int wtype, float freqHz, bool foneshot, float gain )
  2458. {
  2459. int i;
  2460. int type = min ( CLFOWAV - 1, wtype );
  2461. float lfostep;
  2462. for (i = 0; i < CLFO; i++)
  2463. if (!lfos[i].fused)
  2464. {
  2465. lfo_t *plfo = &lfos[i];
  2466. LFO_Init( plfo );
  2467. plfo->fused = true;
  2468. plfo->pdly = lfowavs[type].pdly; // pdly in lfo points to wav table data in lfowavs
  2469. plfo->f = freqHz;
  2470. plfo->foneshot = foneshot;
  2471. plfo->gain = gain * PMAX;
  2472. lfostep = LFO_HzToStep( freqHz );
  2473. // init positional pointer (ie: fixed point updater for controlling pitch of lfo)
  2474. if ( !foneshot )
  2475. POS_Init(&(plfo->pos), plfo->pdly->D, lfostep );
  2476. else
  2477. POS_ONE_Init(&(plfo->pos1), plfo->pdly->D,lfostep );
  2478. return plfo;
  2479. }
  2480. DevMsg ("DSP: Warning, failed to allocate LFO.\n" );
  2481. return NULL;
  2482. }
  2483. // get next lfo value
  2484. // Value returned is 0..LFOAMP. can be normalized by shifting right by LFOBITS
  2485. // To play back at correct passed in frequency, routien should be
  2486. // called once for every output sample (ie: at SOUND_DMA_SPEED)
  2487. // x is dummy param
  2488. inline int LFO_GetNext( lfo_t *plfo, int x )
  2489. {
  2490. int i;
  2491. // get current position
  2492. if ( !plfo->foneshot )
  2493. i = POS_GetNext( &plfo->pos );
  2494. else
  2495. i = POS_ONE_GetNext( &plfo->pos1 );
  2496. // return current sample
  2497. if (plfo->gain == PMAX)
  2498. return plfo->pdly->w[i];
  2499. else
  2500. return (plfo->pdly->w[i] * plfo->gain ) >> PBITS;
  2501. }
  2502. // batch version for performance
  2503. inline void LFO_GetNextN( lfo_t *plfo, portable_samplepair_t *pbuffer, int SampleCount, int op )
  2504. {
  2505. int count = SampleCount;
  2506. portable_samplepair_t *pb = pbuffer;
  2507. switch (op)
  2508. {
  2509. default:
  2510. case OP_LEFT:
  2511. while (count--)
  2512. {
  2513. pb->left = LFO_GetNext( plfo, pb->left );
  2514. pb++;
  2515. }
  2516. return;
  2517. case OP_RIGHT:
  2518. while (count--)
  2519. {
  2520. pb->right = LFO_GetNext( plfo, pb->right );
  2521. pb++;
  2522. }
  2523. return;
  2524. case OP_LEFT_DUPLICATE:
  2525. while (count--)
  2526. {
  2527. pb->left = pb->right = LFO_GetNext( plfo, pb->left );
  2528. pb++;
  2529. }
  2530. return;
  2531. }
  2532. }
  2533. // uses lfowav, rate, foneshot
  2534. typedef enum
  2535. {
  2536. // parameter order
  2537. lfo_iwav,
  2538. lfo_irate,
  2539. lfo_ifoneshot,
  2540. lfo_igain,
  2541. lfo_cparam // # of params
  2542. } lfo_e;
  2543. // parameter ranges
  2544. prm_rng_t lfo_rng[] = {
  2545. {lfo_cparam, 0, 0}, // first entry is # of parameters
  2546. {lfo_iwav, 0.0, LFO_MAX}, // lfo type to use (LFO_SIN, LFO_RND...)
  2547. {lfo_irate, 0.0, 16000.0}, // modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
  2548. {lfo_ifoneshot, 0.0, 1.0}, // 1.0 if lfo is oneshot
  2549. {lfo_igain, 0.0, 10.0}, // output gain
  2550. };
  2551. lfo_t * LFO_Params ( prc_t *pprc )
  2552. {
  2553. lfo_t *plfo;
  2554. bool foneshot = pprc->prm[lfo_ifoneshot] > 0 ? true : false;
  2555. float gain = pprc->prm[lfo_igain];
  2556. plfo = LFO_Alloc ( pprc->prm[lfo_iwav], pprc->prm[lfo_irate], foneshot, gain );
  2557. return plfo;
  2558. }
  2559. void LFO_ChangeVal ( lfo_t *plfo, float fhz )
  2560. {
  2561. float fstep = LFO_HzToStep( fhz );
  2562. // change lfo playback rate to new frequency fhz
  2563. if ( plfo->foneshot )
  2564. POS_ChangeVal( &plfo->pos, fstep );
  2565. else
  2566. POS_ChangeVal( &plfo->pos1.p, fstep );
  2567. }
  2568. inline void * LFO_VParams ( void *p )
  2569. {
  2570. PRC_CheckParams ( (prc_t *)p, lfo_rng );
  2571. return (void *) LFO_Params ((prc_t *)p);
  2572. }
  2573. // v is +/- 0-1.0
  2574. // v changes current lfo frequency up/down by +/- v%
  2575. inline void LFO_Mod ( lfo_t *plfo, float v )
  2576. {
  2577. float fhz;
  2578. float fhznew;
  2579. fhz = plfo->f;
  2580. fhznew = fhz * (1.0 + v);
  2581. LFO_ChangeVal ( plfo, fhznew );
  2582. return;
  2583. }
  2584. ////////////////////////////////////////
  2585. // Time Compress/expand with pitch shift
  2586. ////////////////////////////////////////
  2587. // realtime pitch shift - ie: pitch shift without change to playback rate
  2588. #define CPTCS 64
  2589. struct ptc_t
  2590. {
  2591. bool fused;
  2592. dly_t *pdly_in; // input buffer space
  2593. dly_t *pdly_out; // output buffer space
  2594. int *pin; // input buffer (pdly_in->w)
  2595. int *pout; // output buffer (pdly_out->w)
  2596. int cin; // # samples in input buffer
  2597. int cout; // # samples in output buffer
  2598. int cxfade; // # samples in crossfade segment
  2599. int ccut; // # samples to cut
  2600. int cduplicate; // # samples to duplicate (redundant - same as ccut)
  2601. int iin; // current index into input buffer (reading)
  2602. pos_one_t psn; // stepping index through output buffer
  2603. bool fdup; // true if duplicating, false if cutting
  2604. float fstep; // pitch shift & time compress/expand
  2605. };
  2606. ptc_t ptcs[CPTCS];
  2607. void PTC_Init( ptc_t *pptc ) { if (pptc) Q_memset( pptc, 0, sizeof (ptc_t) ); };
  2608. void PTC_Free( ptc_t *pptc )
  2609. {
  2610. if (pptc)
  2611. {
  2612. DLY_Free (pptc->pdly_in);
  2613. DLY_Free (pptc->pdly_out);
  2614. Q_memset( pptc, 0, sizeof (ptc_t) );
  2615. }
  2616. };
  2617. void PTC_InitAll() { for (int i = 0; i < CPTCS; i++) PTC_Init( &ptcs[i] ); };
  2618. void PTC_FreeAll() { for (int i = 0; i < CPTCS; i++) PTC_Free( &ptcs[i] ); };
  2619. // Time compressor/expander with pitch shift (ie: pitch changes, playback rate does not)
  2620. //
  2621. // Algorithm:
  2622. // 1) Duplicate or discard chunks of sound to provide tslice * fstep seconds of sound.
  2623. // (The user-selectable size of the buffer to process is tslice milliseconds in length)
  2624. // 2) Resample this compressed/expanded buffer at fstep to produce a pitch shifted
  2625. // output with the same duration as the input (ie: #samples out = # samples in, an
  2626. // obvious requirement for realtime inline processing).
  2627. // timeslice is size in milliseconds of full buffer to process.
  2628. // timeslice * fstep is the size of the expanded/compressed buffer
  2629. // timexfade is length in milliseconds of crossfade region between duplicated or cut sections
  2630. // fstep is % expanded/compressed sound normalized to 0.01-2.0 (1% - 200%)
  2631. // input buffer:
  2632. // iin-->
  2633. // [0... tslice ...D] input samples 0...D (D is NEWEST sample)
  2634. // [0... ...n][m... tseg ...D] region to be cut or duplicated m...D
  2635. // [0... [p..txf1..n][m... tseg ...D] fade in region 1 txf1 p...n
  2636. // [0... ...n][m..[q..txf2..D] fade out region 2 txf2 q...D
  2637. // pitch up: duplicate into output buffer: tdup = tseg
  2638. // [0... ...n][m... tdup ...D][m... tdup ...D] output buffer size with duplicate region
  2639. // [0... ...n][m..[p...xf1..n][m... tdup ...D] fade in p...n while fading out q...D
  2640. // [0... ...n][m..[q...xf2..D][m... tdup ...D]
  2641. // [0... ...n][m..[.XFADE...n][m... tdup ...D] final duplicated output buffer - resample at fstep
  2642. // pitch down: cut into output buffer: tcut = tseg
  2643. // [0... ...n][m... tcut ...D] input samples with cut region delineated m...D
  2644. // [0... ...n] output buffer size after cut
  2645. // [0... [q..txf2...D] fade in txf1 q...D while fade out txf2 p...n
  2646. // [0... [.XFADE ...D] final cut output buffer - resample at fstep
  2647. ptc_t * PTC_Alloc( float timeslice, float timexfade, float fstep )
  2648. {
  2649. int i;
  2650. ptc_t *pptc;
  2651. float tout;
  2652. int cin, cout;
  2653. float tslice = timeslice;
  2654. float txfade = timexfade;
  2655. float tcutdup;
  2656. // find time compressor slot
  2657. for ( i = 0; i < CPTCS; i++ )
  2658. {
  2659. if ( !ptcs[i].fused )
  2660. break;
  2661. }
  2662. if ( i == CPTCS )
  2663. {
  2664. DevMsg ("DSP: Warning, failed to allocate pitch shifter.\n" );
  2665. return NULL;
  2666. }
  2667. pptc = &ptcs[i];
  2668. PTC_Init ( pptc );
  2669. // get size of region to cut or duplicate
  2670. tcutdup = abs((fstep - 1.0) * timeslice);
  2671. // to prevent buffer overruns:
  2672. // make sure timeslice is greater than cut/dup time
  2673. tslice = max ( (double)tslice, 1.1 * tcutdup);
  2674. // make sure xfade time smaller than cut/dup time, and smaller than (timeslice-cutdup) time
  2675. txfade = min ( (double)txfade, 0.9 * tcutdup );
  2676. txfade = min ( (double)txfade, 0.9 * (tslice - tcutdup));
  2677. pptc->cxfade = MSEC_TO_SAMPS( txfade );
  2678. pptc->ccut = MSEC_TO_SAMPS( tcutdup );
  2679. pptc->cduplicate = MSEC_TO_SAMPS( tcutdup );
  2680. // alloc delay lines (buffers)
  2681. tout = tslice * fstep;
  2682. cin = MSEC_TO_SAMPS( tslice );
  2683. cout = MSEC_TO_SAMPS( tout );
  2684. pptc->pdly_in = DLY_Alloc( cin, 0, 1, DLY_LINEAR ); // alloc input buffer
  2685. pptc->pdly_out = DLY_Alloc( cout, 0, 1, DLY_LINEAR); // alloc output buffer
  2686. if ( !pptc->pdly_in || !pptc->pdly_out )
  2687. {
  2688. PTC_Free( pptc );
  2689. DevMsg ("DSP: Warning, failed to allocate delay for pitch shifter.\n" );
  2690. return NULL;
  2691. }
  2692. // buffer pointers
  2693. pptc->pin = pptc->pdly_in->w;
  2694. pptc->pout = pptc->pdly_out->w;
  2695. // input buffer index
  2696. pptc->iin = 0;
  2697. // output buffer index
  2698. POS_ONE_Init ( &pptc->psn, cout, fstep );
  2699. // if fstep > 1.0 we're pitching shifting up, so fdup = true
  2700. pptc->fdup = fstep > 1.0 ? true : false;
  2701. pptc->cin = cin;
  2702. pptc->cout = cout;
  2703. pptc->fstep = fstep;
  2704. pptc->fused = true;
  2705. return pptc;
  2706. }
  2707. // linear crossfader
  2708. // yfadein - instantaneous value fading in
  2709. // ydafeout -instantaneous value fading out
  2710. // nsamples - duration in #samples of fade
  2711. // isample - index in to fade 0...nsamples-1
  2712. inline int xfade ( int yfadein, int yfadeout, int nsamples, int isample )
  2713. {
  2714. int yout;
  2715. int m = (isample << PBITS ) / nsamples;
  2716. // yout = ((yfadein * m) >> PBITS) + ((yfadeout * (PMAX - m)) >> PBITS);
  2717. yout = (yfadeout + (yfadein - yfadeout) * m ) >> PBITS;
  2718. return yout;
  2719. }
  2720. // w - pointer to start of input buffer samples
  2721. // v - pointer to start of output buffer samples
  2722. // cin - # of input buffer samples
  2723. // cout = # of output buffer samples
  2724. // cxfade = # of crossfade samples
  2725. // cduplicate = # of samples in duplicate/cut segment
  2726. void TimeExpand( int *w, int *v, int cin, int cout, int cxfade, int cduplicate )
  2727. {
  2728. int i,j;
  2729. int m;
  2730. int p;
  2731. int q;
  2732. int D;
  2733. // input buffer
  2734. // xfade source duplicate
  2735. // [0...........][p.......n][m...........D]
  2736. // output buffer
  2737. // xfade region duplicate
  2738. // [0.....................n][m..[q.......D][m...........D]
  2739. // D - index of last sample in input buffer
  2740. // m - index of 1st sample in duplication region
  2741. // p - index of 1st sample of crossfade source
  2742. // q - index of 1st sample in crossfade region
  2743. D = cin - 1;
  2744. m = cin - cduplicate;
  2745. p = m - cxfade;
  2746. q = cin - cxfade;
  2747. // copy up to crossfade region
  2748. for (i = 0; i < q; i++)
  2749. v[i] = w[i];
  2750. // crossfade region
  2751. j = p;
  2752. for (i = q; i <= D; i++)
  2753. v[i] = xfade (w[j++], w[i], cxfade, i-q); // fade out p..n, fade in q..D
  2754. // duplicate region
  2755. j = D+1;
  2756. for (i = m; i <= D; i++)
  2757. v[j++] = w[i];
  2758. }
  2759. // cut ccut samples from end of input buffer, crossfade end of cut section
  2760. // with end of remaining section
  2761. // w - pointer to start of input buffer samples
  2762. // v - pointer to start of output buffer samples
  2763. // cin - # of input buffer samples
  2764. // cout = # of output buffer samples
  2765. // cxfade = # of crossfade samples
  2766. // ccut = # of samples in cut segment
  2767. void TimeCompress( int *w, int *v, int cin, int cout, int cxfade, int ccut )
  2768. {
  2769. int i,j;
  2770. int m;
  2771. int p;
  2772. int q;
  2773. int D;
  2774. // input buffer
  2775. // xfade source
  2776. // [0.....................n][m..[p.......D]
  2777. // xfade region cut
  2778. // [0...........][q.......n][m...........D]
  2779. // output buffer
  2780. // xfade to source
  2781. // [0...........][p.......D]
  2782. // D - index of last sample in input buffer
  2783. // m - index of 1st sample in cut region
  2784. // p - index of 1st sample of crossfade source
  2785. // q - index of 1st sample in crossfade region
  2786. D = cin - 1;
  2787. m = cin - ccut;
  2788. p = cin - cxfade;
  2789. q = m - cxfade;
  2790. // copy up to crossfade region
  2791. for (i = 0; i < q; i++)
  2792. v[i] = w[i];
  2793. // crossfade region
  2794. j = p;
  2795. for (i = q; i < m; i++)
  2796. v[i] = xfade (w[j++], w[i], cxfade, i-q); // fade out p..n, fade in q..D
  2797. // skip rest of input buffer
  2798. }
  2799. // get next sample
  2800. // put input sample into input (delay) buffer
  2801. // get output sample from output buffer, step by fstep %
  2802. // output buffer is time expanded or compressed version of previous input buffer
  2803. inline int PTC_GetNext( ptc_t *pptc, int x )
  2804. {
  2805. int iout, xout;
  2806. bool fhitend = false;
  2807. // write x into input buffer
  2808. Assert (pptc->iin < pptc->cin);
  2809. pptc->pin[pptc->iin] = x;
  2810. pptc->iin++;
  2811. // check for end of input buffer
  2812. if ( pptc->iin >= pptc->cin )
  2813. fhitend = true;
  2814. // read sample from output buffer, resampling at fstep
  2815. iout = POS_ONE_GetNext( &pptc->psn );
  2816. Assert (iout < pptc->cout);
  2817. xout = pptc->pout[iout];
  2818. if ( fhitend )
  2819. {
  2820. // if hit end of input buffer (ie: input buffer is full)
  2821. // reset input buffer pointer
  2822. // reset output buffer pointer
  2823. // rebuild entire output buffer (TimeCompress/TimeExpand)
  2824. pptc->iin = 0;
  2825. POS_ONE_Init( &pptc->psn, pptc->cout, pptc->fstep );
  2826. if ( pptc->fdup )
  2827. TimeExpand ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->cduplicate );
  2828. else
  2829. TimeCompress ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->ccut );
  2830. }
  2831. return xout;
  2832. }
  2833. // batch version for performance
  2834. inline void PTC_GetNextN( ptc_t *pptc, portable_samplepair_t *pbuffer, int SampleCount, int op )
  2835. {
  2836. int count = SampleCount;
  2837. portable_samplepair_t *pb = pbuffer;
  2838. switch (op)
  2839. {
  2840. default:
  2841. case OP_LEFT:
  2842. while (count--)
  2843. {
  2844. pb->left = PTC_GetNext( pptc, pb->left );
  2845. pb++;
  2846. }
  2847. return;
  2848. case OP_RIGHT:
  2849. while (count--)
  2850. {
  2851. pb->right = PTC_GetNext( pptc, pb->right );
  2852. pb++;
  2853. }
  2854. return;
  2855. case OP_LEFT_DUPLICATE:
  2856. while (count--)
  2857. {
  2858. pb->left = pb->right = PTC_GetNext( pptc, pb->left );
  2859. pb++;
  2860. }
  2861. return;
  2862. }
  2863. }
  2864. // change time compression to new value
  2865. // fstep is new value
  2866. // ramptime is how long change takes in seconds (ramps smoothly), 0 for no ramp
  2867. void PTC_ChangeVal( ptc_t *pptc, float fstep, float ramptime )
  2868. {
  2869. // UNDONE: ignored
  2870. // UNDONE: just realloc time compressor with new fstep
  2871. }
  2872. // uses pitch:
  2873. // 1.0 = playback normal rate
  2874. // 0.5 = cut 50% of sound (2x playback)
  2875. // 1.5 = add 50% sound (0.5x playback)
  2876. typedef enum
  2877. {
  2878. // parameter order
  2879. ptc_ipitch,
  2880. ptc_itimeslice,
  2881. ptc_ixfade,
  2882. ptc_cparam // # of params
  2883. } ptc_e;
  2884. // diffusor parameter ranges
  2885. prm_rng_t ptc_rng[] = {
  2886. {ptc_cparam, 0, 0}, // first entry is # of parameters
  2887. {ptc_ipitch, 0.1, 4.0}, // 0-n.0 where 1.0 = 1 octave up and 0.5 is one octave down
  2888. {ptc_itimeslice, 20.0, 300.0}, // in milliseconds - size of sound chunk to analyze and cut/duplicate - 100ms nominal
  2889. {ptc_ixfade, 1.0, 200.0}, // in milliseconds - size of crossfade region between spliced chunks - 20ms nominal
  2890. };
  2891. ptc_t * PTC_Params ( prc_t *pprc )
  2892. {
  2893. ptc_t *pptc;
  2894. float pitch = pprc->prm[ptc_ipitch];
  2895. float timeslice = pprc->prm[ptc_itimeslice];
  2896. float txfade = pprc->prm[ptc_ixfade];
  2897. pptc = PTC_Alloc( timeslice, txfade, pitch );
  2898. return pptc;
  2899. }
  2900. inline void * PTC_VParams ( void *p )
  2901. {
  2902. PRC_CheckParams ( (prc_t *)p, ptc_rng );
  2903. return (void *) PTC_Params ((prc_t *)p);
  2904. }
  2905. // change to new pitch value
  2906. // v is +/- 0-1.0
  2907. // v changes current pitch up/down by +/- v%
  2908. void PTC_Mod ( ptc_t *pptc, float v )
  2909. {
  2910. float fstep;
  2911. float fstepnew;
  2912. fstep = pptc->fstep;
  2913. fstepnew = fstep * (1.0 + v);
  2914. PTC_ChangeVal( pptc, fstepnew, 0.01 );
  2915. }
  2916. ////////////////////
  2917. // ADSR envelope
  2918. ////////////////////
  2919. #define CENVS 64 // max # of envelopes active
  2920. #define CENVRMPS 4 // A, D, S, R
  2921. #define ENV_LIN 0 // linear a,d,s,r
  2922. #define ENV_EXP 1 // exponential a,d,s,r
  2923. #define ENV_MAX ENV_EXP
  2924. #define ENV_BITS 14 // bits of resolution of ramp
  2925. struct env_t
  2926. {
  2927. bool fused;
  2928. bool fhitend; // true if done
  2929. bool fexp; // true if exponential ramps
  2930. int ienv; // current ramp
  2931. rmp_t rmps[CENVRMPS]; // ramps
  2932. };
  2933. env_t envs[CENVS];
  2934. void ENV_Init( env_t *penv ) { if (penv) Q_memset( penv, 0, sizeof (env_t) ); };
  2935. void ENV_Free( env_t *penv ) { if (penv) Q_memset( penv, 0, sizeof (env_t) ); };
  2936. void ENV_InitAll() { for (int i = 0; i < CENVS; i++) ENV_Init( &envs[i] ); };
  2937. void ENV_FreeAll() { for (int i = 0; i < CENVS; i++) ENV_Free( &envs[i] ); };
  2938. // allocate ADSR envelope
  2939. // all times are in seconds
  2940. // amp1 - attack amplitude multiplier 0-1.0
  2941. // amp2 - sustain amplitude multiplier 0-1.0
  2942. // amp3 - end of sustain amplitude multiplier 0-1.0
  2943. env_t *ENV_Alloc ( int type, float famp1, float famp2, float famp3, float attack, float decay, float sustain, float release, bool fexp)
  2944. {
  2945. int i;
  2946. env_t *penv;
  2947. for (i = 0; i < CENVS; i++)
  2948. {
  2949. if ( !envs[i].fused )
  2950. {
  2951. int amp1 = famp1 * (1 << ENV_BITS); // ramp resolution
  2952. int amp2 = famp2 * (1 << ENV_BITS);
  2953. int amp3 = famp3 * (1 << ENV_BITS);
  2954. penv = &envs[i];
  2955. ENV_Init (penv);
  2956. // UNDONE: ignoring type = ENV_EXP - use oneshot LFOS instead with sawtooth/exponential
  2957. // set up ramps
  2958. RMP_Init( &penv->rmps[0], attack, 0, amp1, true );
  2959. RMP_Init( &penv->rmps[1], decay, amp1, amp2, true );
  2960. RMP_Init( &penv->rmps[2], sustain, amp2, amp3, true );
  2961. RMP_Init( &penv->rmps[3], release, amp3, 0, true );
  2962. penv->ienv = 0;
  2963. penv->fused = true;
  2964. penv->fhitend = false;
  2965. penv->fexp = fexp;
  2966. return penv;
  2967. }
  2968. }
  2969. DevMsg ("DSP: Warning, failed to allocate envelope.\n" );
  2970. return NULL;
  2971. }
  2972. inline int ENV_GetNext( env_t *penv, int x )
  2973. {
  2974. if ( !penv->fhitend )
  2975. {
  2976. int i;
  2977. int y;
  2978. i = penv->ienv;
  2979. y = RMP_GetNext ( &penv->rmps[i] );
  2980. // check for next ramp
  2981. if ( penv->rmps[i].fhitend )
  2982. i++;
  2983. penv->ienv = i;
  2984. // check for end of all ramps
  2985. if ( i > 3)
  2986. penv->fhitend = true;
  2987. // multiply input signal by ramp
  2988. if (penv->fexp)
  2989. return (((x * y) >> ENV_BITS) * y) >> ENV_BITS;
  2990. else
  2991. return (x * y) >> ENV_BITS;
  2992. }
  2993. return 0;
  2994. }
  2995. // batch version for performance
  2996. inline void ENV_GetNextN( env_t *penv, portable_samplepair_t *pbuffer, int SampleCount, int op )
  2997. {
  2998. int count = SampleCount;
  2999. portable_samplepair_t *pb = pbuffer;
  3000. switch (op)
  3001. {
  3002. default:
  3003. case OP_LEFT:
  3004. while (count--)
  3005. {
  3006. pb->left = ENV_GetNext( penv, pb->left );
  3007. pb++;
  3008. }
  3009. return;
  3010. case OP_RIGHT:
  3011. while (count--)
  3012. {
  3013. pb->right = ENV_GetNext( penv, pb->right );
  3014. pb++;
  3015. }
  3016. return;
  3017. case OP_LEFT_DUPLICATE:
  3018. while (count--)
  3019. {
  3020. pb->left = pb->right = ENV_GetNext( penv, pb->left );
  3021. pb++;
  3022. }
  3023. return;
  3024. }
  3025. }
  3026. // uses lfowav, amp1, amp2, amp3, attack, decay, sustain, release
  3027. // lfowav is type, currently ignored - ie: LFO_LIN_IN, LFO_LOG_IN
  3028. // parameter order
  3029. typedef enum
  3030. {
  3031. env_itype,
  3032. env_iamp1,
  3033. env_iamp2,
  3034. env_iamp3,
  3035. env_iattack,
  3036. env_idecay,
  3037. env_isustain,
  3038. env_irelease,
  3039. env_ifexp,
  3040. env_cparam // # of params
  3041. } env_e;
  3042. // parameter ranges
  3043. prm_rng_t env_rng[] = {
  3044. {env_cparam, 0, 0}, // first entry is # of parameters
  3045. {env_itype, 0.0,ENV_MAX}, // ENV_LINEAR, ENV_LOG - currently ignored
  3046. {env_iamp1, 0.0, 1.0}, // attack peak amplitude 0-1.0
  3047. {env_iamp2, 0.0, 1.0}, // decay target amplitued 0-1.0
  3048. {env_iamp3, 0.0, 1.0}, // sustain target amplitude 0-1.0
  3049. {env_iattack, 0.0, 20000.0}, // attack time in milliseconds
  3050. {env_idecay, 0.0, 20000.0}, // envelope decay time in milliseconds
  3051. {env_isustain, 0.0, 20000.0}, // sustain time in milliseconds
  3052. {env_irelease, 0.0, 20000.0}, // release time in milliseconds
  3053. {env_ifexp, 0.0, 1.0}, // 1.0 if exponential ramps
  3054. };
  3055. env_t * ENV_Params ( prc_t *pprc )
  3056. {
  3057. env_t *penv;
  3058. float type = pprc->prm[env_itype];
  3059. float amp1 = pprc->prm[env_iamp1];
  3060. float amp2 = pprc->prm[env_iamp2];
  3061. float amp3 = pprc->prm[env_iamp3];
  3062. float attack = pprc->prm[env_iattack]/1000.0;
  3063. float decay = pprc->prm[env_idecay]/1000.0;
  3064. float sustain = pprc->prm[env_isustain]/1000.0;
  3065. float release = pprc->prm[env_irelease]/1000.0;
  3066. float fexp = pprc->prm[env_ifexp];
  3067. bool bexp;
  3068. bexp = fexp > 0.0 ? 1 : 0;
  3069. penv = ENV_Alloc ( type, amp1, amp2, amp3, attack, decay, sustain, release, bexp );
  3070. return penv;
  3071. }
  3072. inline void * ENV_VParams ( void *p )
  3073. {
  3074. PRC_CheckParams( (prc_t *)p, env_rng );
  3075. return (void *) ENV_Params ((prc_t *)p);
  3076. }
  3077. inline void ENV_Mod ( void *p, float v ) { return; }
  3078. //////////////////////////
  3079. // Gate & envelope follower
  3080. //////////////////////////
  3081. #define CEFOS 64 // max # of envelope followers active
  3082. struct efo_t
  3083. {
  3084. bool fused;
  3085. int xout; // current output value
  3086. // gate params
  3087. bool bgate; // if true, gate function is on
  3088. bool bgateon; // if true, gate is on
  3089. bool bexp; // if true, use exponential fade out
  3090. int thresh; // amplitude threshold for gate on
  3091. int thresh_off; // amplitidue threshold for gate off
  3092. float attack_time; // gate attack time in seconds
  3093. float decay_time; // gate decay time in seconds
  3094. rmp_t rmp_attack; // gate on ramp - attack
  3095. rmp_t rmp_decay; // gate off ramp - decay
  3096. };
  3097. efo_t efos[CEFOS];
  3098. void EFO_Init( efo_t *pefo ) { if (pefo) Q_memset( pefo, 0, sizeof (efo_t) ); };
  3099. void EFO_Free( efo_t *pefo ) { if (pefo) Q_memset( pefo, 0, sizeof (efo_t) ); };
  3100. void EFO_InitAll() { for (int i = 0; i < CEFOS; i++) EFO_Init( &efos[i] ); };
  3101. void EFO_FreeAll() { for (int i = 0; i < CEFOS; i++) EFO_Free( &efos[i] ); };
  3102. // return true when gate is off AND decay ramp has hit end
  3103. inline bool EFO_GateOff( efo_t *pefo )
  3104. {
  3105. return ( !pefo->bgateon && RMP_HitEnd( &pefo->rmp_decay ) );
  3106. }
  3107. // allocate enveloper follower
  3108. #define EFO_HYST_AMP 1000 // hysteresis amplitude
  3109. efo_t *EFO_Alloc ( float threshold, float attack_sec, float decay_sec, bool bexp )
  3110. {
  3111. int i;
  3112. efo_t *pefo;
  3113. for (i = 0; i < CEFOS; i++)
  3114. {
  3115. if ( !efos[i].fused )
  3116. {
  3117. pefo = &efos[i];
  3118. EFO_Init ( pefo );
  3119. pefo->xout = 0;
  3120. pefo->fused = true;
  3121. // init gate params
  3122. pefo->bgate = threshold > 0.0;
  3123. if (pefo->bgate)
  3124. {
  3125. pefo->attack_time = attack_sec;
  3126. pefo->decay_time = decay_sec;
  3127. RMP_Init( &pefo->rmp_attack, attack_sec, 0, PMAX, false);
  3128. RMP_Init( &pefo->rmp_decay, decay_sec, PMAX, 0, false);
  3129. RMP_SetEnd( &pefo->rmp_attack );
  3130. RMP_SetEnd( &pefo->rmp_decay );
  3131. pefo->thresh = threshold;
  3132. pefo->thresh_off = max(1.f, threshold - EFO_HYST_AMP);
  3133. pefo->bgateon = false;
  3134. pefo->bexp = bexp;
  3135. }
  3136. return pefo;
  3137. }
  3138. }
  3139. DevMsg ("DSP: Warning, failed to allocate envelope follower.\n" );
  3140. return NULL;
  3141. }
  3142. // values of L for CEFO_BITS_DIVIDE: L = (1 - 1/(1 << CEFO_BITS_DIVIDE))
  3143. // 1 L = 0.5
  3144. // 2 L = 0.75
  3145. // 3 L = 0.875
  3146. // 4 L = 0.9375
  3147. // 5 L = 0.96875
  3148. // 6 L = 0.984375
  3149. // 7 L = 0.9921875
  3150. // 8 L = 0.99609375
  3151. // 9 L = 0.998046875
  3152. // 10 L = 0.9990234375
  3153. // 11 L = 0.99951171875
  3154. // 12 L = 0.999755859375
  3155. // decay time constant for values of L, for E = 10^-3 = 60dB of attenuation
  3156. //
  3157. // Neff = Ln E / Ln L = -6.9077552 / Ln L
  3158. //
  3159. // 1 L = 0.5 Neff = 10 samples
  3160. // 2 L = 0.75 Neff = 24
  3161. // 3 L = 0.875 Neff = 51
  3162. // 4 L = 0.9375 Neff = 107
  3163. // 5 L = 0.96875 Neff = 217
  3164. // 6 L = 0.984375 Neff = 438
  3165. // 7 L = 0.9921875 Neff = 880
  3166. // 8 L = 0.99609375 Neff = 1764
  3167. // 9 L = 0.998046875 Neff = 3533
  3168. // 10 L = 0.9990234375 Neff = 7070
  3169. // 11 L = 0.99951171875 Neff = 14143
  3170. // 12 L = 0.999755859375 Neff = 28290
  3171. #define CEFO_BITS 11 // 14143 samples in gate window (3hz)
  3172. inline int EFO_GetNext( efo_t *pefo, int x )
  3173. {
  3174. int r;
  3175. int xa = abs(x);
  3176. int xdif;
  3177. // get envelope:
  3178. // Cn = L * Cn-1 + ( 1 - L ) * |x|
  3179. // which simplifies to:
  3180. // Cn = |x| + (Cn-1 - |x|) * L
  3181. // for 0 < L < 1
  3182. // increasing L increases time to rise or fall to a new input level
  3183. // so: increasing CEFO_BITS_DIVIDE increases rise/fall time
  3184. // where: L = (1 - 1/(1 << CEFO_BITS))
  3185. // xdif = Cn-1 - |x|
  3186. // so: xdif * L = xdif - xdif / (1 << CEFO_BITS) = ((xdif << CEFO_BITS) - xdif ) >> CEFO_BITS
  3187. xdif = pefo->xout - xa;
  3188. pefo->xout = xa + (((xdif << CEFO_BITS) - xdif) >> CEFO_BITS);
  3189. if ( pefo->bgate )
  3190. {
  3191. // gate
  3192. bool bgateon_prev = pefo->bgateon;
  3193. // gate hysteresis
  3194. if (bgateon_prev)
  3195. // gate was on - it's off only if amp drops below thresh_off
  3196. pefo->bgateon = ( pefo->xout >= pefo->thresh_off );
  3197. else
  3198. // gate was off - it's on only if amp > thresh
  3199. pefo->bgateon = ( pefo->xout >= pefo->thresh );
  3200. if ( pefo->bgateon )
  3201. {
  3202. // gate is on
  3203. if ( bgateon_prev && RMP_HitEnd( &pefo->rmp_attack ))
  3204. return x; // gate is fully on
  3205. if ( !bgateon_prev )
  3206. {
  3207. // gate just turned on, start ramp attack
  3208. // start attack from previous decay ramp if active
  3209. r = RMP_HitEnd( &pefo->rmp_decay ) ? 0 : RMP_GetNext( &pefo->rmp_decay );
  3210. RMP_SetEnd( &pefo->rmp_decay);
  3211. // DevMsg ("GATE ON \n");
  3212. RMP_Init( &pefo->rmp_attack, pefo->attack_time, r, PMAX, false);
  3213. return (x * r) >> PBITS;
  3214. }
  3215. if ( !RMP_HitEnd( &pefo->rmp_attack ) )
  3216. {
  3217. r = RMP_GetNext( &pefo->rmp_attack );
  3218. // gate is on and ramping up
  3219. return (x * r) >> PBITS;
  3220. }
  3221. }
  3222. else
  3223. {
  3224. // gate is fully off
  3225. if ( !bgateon_prev && RMP_HitEnd( &pefo->rmp_decay))
  3226. return 0;
  3227. if ( bgateon_prev )
  3228. {
  3229. // gate just turned off, start ramp decay
  3230. // start decay from previous attack ramp if active
  3231. r = RMP_HitEnd( &pefo->rmp_attack ) ? PMAX : RMP_GetNext( &pefo->rmp_attack );
  3232. RMP_SetEnd( &pefo->rmp_attack);
  3233. RMP_Init( &pefo->rmp_decay, pefo->decay_time, r, 0, false);
  3234. // DevMsg ("GATE OFF \n");
  3235. // if exponential set, gate has exponential ramp down. Otherwise linear ramp down.
  3236. if ( pefo->bexp )
  3237. return ( (((x * r) >> PBITS) * r ) >> PBITS );
  3238. else
  3239. return (x * r) >> PBITS;
  3240. }
  3241. else if ( !RMP_HitEnd( &pefo->rmp_decay ) )
  3242. {
  3243. // gate is off and ramping down
  3244. r = RMP_GetNext( &pefo->rmp_decay );
  3245. // if exponential set, gate has exponential ramp down. Otherwise linear ramp down.
  3246. if ( pefo->bexp )
  3247. return ( (((x * r) >> PBITS) * r ) >> PBITS );
  3248. else
  3249. return (x * r) >> PBITS;
  3250. }
  3251. }
  3252. return x;
  3253. }
  3254. return pefo->xout;
  3255. }
  3256. // batch version for performance
  3257. inline void EFO_GetNextN( efo_t *pefo, portable_samplepair_t *pbuffer, int SampleCount, int op )
  3258. {
  3259. int count = SampleCount;
  3260. portable_samplepair_t *pb = pbuffer;
  3261. switch (op)
  3262. {
  3263. default:
  3264. case OP_LEFT:
  3265. while (count--)
  3266. {
  3267. pb->left = EFO_GetNext( pefo, pb->left );
  3268. pb++;
  3269. }
  3270. return;
  3271. case OP_RIGHT:
  3272. while (count--)
  3273. {
  3274. pb->right = EFO_GetNext( pefo, pb->right );
  3275. pb++;
  3276. }
  3277. return;
  3278. case OP_LEFT_DUPLICATE:
  3279. while (count--)
  3280. {
  3281. pb->left = pb->right = EFO_GetNext( pefo, pb->left );
  3282. pb++;
  3283. }
  3284. return;
  3285. }
  3286. }
  3287. // parameter order
  3288. typedef enum
  3289. {
  3290. efo_ithreshold,
  3291. efo_iattack,
  3292. efo_idecay,
  3293. efo_iexp,
  3294. efo_cparam // # of params
  3295. } efo_e;
  3296. // parameter ranges
  3297. prm_rng_t efo_rng[] = {
  3298. {efo_cparam, 0, 0}, // first entry is # of parameters
  3299. {efo_ithreshold, -140.0, 0.0}, // gate threshold in db. if 0.0 then no gate.
  3300. {efo_iattack, 0.0, 20000.0}, // attack time in milliseconds
  3301. {efo_idecay, 0.0, 20000.0}, // envelope decay time in milliseconds
  3302. {efo_iexp, 0.0, 1.0}, // if 1, use exponential decay ramp (for more realistic reverb tail)
  3303. };
  3304. efo_t * EFO_Params ( prc_t *pprc )
  3305. {
  3306. efo_t *penv;
  3307. float threshold = Gain_To_Amplitude( dB_To_Gain(pprc->prm[efo_ithreshold]) );
  3308. float attack = pprc->prm[efo_iattack]/1000.0;
  3309. float decay = pprc->prm[efo_idecay]/1000.0;
  3310. float fexp = pprc->prm[efo_iexp];
  3311. bool bexp;
  3312. // check for no gate
  3313. if ( pprc->prm[efo_ithreshold] == 0.0 )
  3314. threshold = 0.0;
  3315. bexp = fexp > 0.0 ? 1 : 0;
  3316. penv = EFO_Alloc ( threshold, attack, decay, bexp );
  3317. return penv;
  3318. }
  3319. inline void * EFO_VParams ( void *p )
  3320. {
  3321. PRC_CheckParams( (prc_t *)p, efo_rng );
  3322. return (void *) EFO_Params ((prc_t *)p);
  3323. }
  3324. inline void EFO_Mod ( void *p, float v ) { return; }
  3325. ///////////////////////////////////////////
  3326. // Chorus - lfo modulated delay
  3327. ///////////////////////////////////////////
  3328. #define CCRSS 64 // max number chorus' active
  3329. struct crs_t
  3330. {
  3331. bool fused;
  3332. mdy_t *pmdy; // modulatable delay
  3333. lfo_t *plfo; // modulating lfo
  3334. int lfoprev; // previous modulator value from lfo
  3335. };
  3336. crs_t crss[CCRSS];
  3337. void CRS_Init( crs_t *pcrs ) { if (pcrs) Q_memset( pcrs, 0, sizeof (crs_t) ); };
  3338. void CRS_Free( crs_t *pcrs )
  3339. {
  3340. if (pcrs)
  3341. {
  3342. MDY_Free ( pcrs->pmdy );
  3343. LFO_Free ( pcrs->plfo );
  3344. Q_memset( pcrs, 0, sizeof (crs_t) );
  3345. }
  3346. }
  3347. void CRS_InitAll() { for (int i = 0; i < CCRSS; i++) CRS_Init( &crss[i] ); }
  3348. void CRS_FreeAll() { for (int i = 0; i < CCRSS; i++) CRS_Free( &crss[i] ); }
  3349. // fstep is base pitch shift, ie: floating point step value, where 1.0 = +1 octave, 0.5 = -1 octave
  3350. // lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  3351. // fHz is modulation frequency in Hz
  3352. // depth is modulation depth, 0-1.0
  3353. // mix is mix of chorus and clean signal
  3354. #define CRS_DELAYMAX 100 // max milliseconds of sweepable delay
  3355. #define CRS_RAMPTIME 5 // milliseconds to ramp between new delay values
  3356. crs_t * CRS_Alloc( int lfotype, float fHz, float fdepth, float mix )
  3357. {
  3358. int i;
  3359. crs_t *pcrs;
  3360. dly_t *pdly;
  3361. mdy_t *pmdy;
  3362. lfo_t *plfo;
  3363. float ramptime;
  3364. int D;
  3365. // find free chorus slot
  3366. for ( i = 0; i < CCRSS; i++ )
  3367. {
  3368. if ( !crss[i].fused )
  3369. break;
  3370. }
  3371. if ( i == CCRSS )
  3372. {
  3373. DevMsg ("DSP: Warning, failed to allocate chorus.\n" );
  3374. return NULL;
  3375. }
  3376. pcrs = &crss[i];
  3377. CRS_Init ( pcrs );
  3378. D = fdepth * MSEC_TO_SAMPS(CRS_DELAYMAX); // sweep from 0 - n milliseconds
  3379. ramptime = (float) CRS_RAMPTIME / 1000.0; // # milliseconds to ramp between new values
  3380. pdly = DLY_Alloc ( D, 0, 1, DLY_LINEAR );
  3381. pmdy = MDY_Alloc ( pdly, ramptime, 0.0, 0.0, mix );
  3382. plfo = LFO_Alloc ( lfotype, fHz, false, 1.0 );
  3383. if ( !plfo || !pmdy )
  3384. {
  3385. LFO_Free ( plfo );
  3386. MDY_Free ( pmdy );
  3387. DevMsg ("DSP: Warning, failed to allocate lfo or mdy for chorus.\n" );
  3388. return NULL;
  3389. }
  3390. pcrs->pmdy = pmdy;
  3391. pcrs->plfo = plfo;
  3392. pcrs->fused = true;
  3393. return pcrs;
  3394. }
  3395. // return next chorused sample (modulated delay) mixed with input sample
  3396. inline int CRS_GetNext( crs_t *pcrs, int x )
  3397. {
  3398. int l;
  3399. int y;
  3400. // get current mod delay value
  3401. y = MDY_GetNext ( pcrs->pmdy, x );
  3402. // get next lfo value for modulation
  3403. // note: lfo must return 0 as first value
  3404. l = LFO_GetNext ( pcrs->plfo, x );
  3405. // if modulator has changed, change mdy
  3406. if ( l != pcrs->lfoprev )
  3407. {
  3408. // calculate new tap starts at D)
  3409. int D = pcrs->pmdy->pdly->D0;
  3410. int tap;
  3411. // lfo should always output values 0 <= l <= LFOMAX
  3412. if (l < 0)
  3413. l = 0;
  3414. tap = D - ((l * D) >> LFOBITS);
  3415. MDY_ChangeVal ( pcrs->pmdy, tap );
  3416. pcrs->lfoprev = l;
  3417. }
  3418. return y;
  3419. }
  3420. // batch version for performance
  3421. inline void CRS_GetNextN( crs_t *pcrs, portable_samplepair_t *pbuffer, int SampleCount, int op )
  3422. {
  3423. int count = SampleCount;
  3424. portable_samplepair_t *pb = pbuffer;
  3425. switch (op)
  3426. {
  3427. default:
  3428. case OP_LEFT:
  3429. while (count--)
  3430. {
  3431. pb->left = CRS_GetNext( pcrs, pb->left );
  3432. pb++;
  3433. }
  3434. return;
  3435. case OP_RIGHT:
  3436. while (count--)
  3437. {
  3438. pb->right = CRS_GetNext( pcrs, pb->right );
  3439. pb++;
  3440. }
  3441. return;
  3442. case OP_LEFT_DUPLICATE:
  3443. while (count--)
  3444. {
  3445. pb->left = pb->right = CRS_GetNext( pcrs, pb->left );
  3446. pb++;
  3447. }
  3448. return;
  3449. }
  3450. }
  3451. // parameter order
  3452. typedef enum {
  3453. crs_ilfotype,
  3454. crs_irate,
  3455. crs_idepth,
  3456. crs_imix,
  3457. crs_cparam
  3458. } crs_e;
  3459. // parameter ranges
  3460. prm_rng_t crs_rng[] = {
  3461. {crs_cparam, 0, 0}, // first entry is # of parameters
  3462. {crs_ilfotype, 0, LFO_MAX}, // lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  3463. {crs_irate, 0.0, 1000.0}, // rate is modulation frequency in Hz
  3464. {crs_idepth, 0.0, 1.0}, // depth is modulation depth, 0-1.0
  3465. {crs_imix, 0.0, 1.0}, // mix is mix of chorus and clean signal
  3466. };
  3467. // uses pitch, lfowav, rate, depth
  3468. crs_t * CRS_Params ( prc_t *pprc )
  3469. {
  3470. crs_t *pcrs;
  3471. pcrs = CRS_Alloc ( pprc->prm[crs_ilfotype], pprc->prm[crs_irate], pprc->prm[crs_idepth], pprc->prm[crs_imix] );
  3472. return pcrs;
  3473. }
  3474. inline void * CRS_VParams ( void *p )
  3475. {
  3476. PRC_CheckParams ( (prc_t *)p, crs_rng );
  3477. return (void *) CRS_Params ((prc_t *)p);
  3478. }
  3479. inline void CRS_Mod ( void *p, float v ) { return; }
  3480. ////////////////////////////////////////////////////
  3481. // amplifier - modulatable gain, distortion
  3482. ////////////////////////////////////////////////////
  3483. #define CAMPS 64 // max number amps active
  3484. #define AMPSLEW 10 // milliseconds of slew time between gain changes
  3485. struct amp_t
  3486. {
  3487. bool fused;
  3488. int gain; // amplification 0-6.0 * PMAX
  3489. int gain_max; // original gain setting
  3490. int distmix; // 0-1.0 mix of distortion with clean * PMAX
  3491. int vfeed; // 0-1.0 feedback with distortion * PMAX
  3492. int vthresh; // amplitude of clipping threshold 0..32768
  3493. bool fchanging; // true if modulating to new amp value
  3494. float ramptime; // ramp 'glide' time - time in seconds to change between values
  3495. int mtime; // time in samples between amp changes. 0 implies no self-modulating
  3496. int mtimecur; // current time in samples until next amp change
  3497. int depth; // modulate amp from A to A - (A*depth) depth 0-1.0
  3498. bool brand; // if true, use random modulation otherwise alternate btwn max/min
  3499. rmp_t rmp_interp; // interpolation ramp 0...PMAX
  3500. };
  3501. amp_t amps[CAMPS];
  3502. void AMP_Init( amp_t *pamp ) { if (pamp) Q_memset( pamp, 0, sizeof (amp_t) ); };
  3503. void AMP_Free( amp_t *pamp )
  3504. {
  3505. if (pamp)
  3506. {
  3507. Q_memset( pamp, 0, sizeof (amp_t) );
  3508. }
  3509. }
  3510. void AMP_InitAll() { for (int i = 0; i < CAMPS; i++) AMP_Init( &amps[i] ); }
  3511. void AMP_FreeAll() { for (int i = 0; i < CAMPS; i++) AMP_Free( &amps[i] ); }
  3512. amp_t * AMP_Alloc( float gain, float vthresh, float distmix, float vfeed, float ramptime, float modtime, float depth, bool brand )
  3513. {
  3514. int i;
  3515. amp_t *pamp;
  3516. // find free amp slot
  3517. for ( i = 0; i < CAMPS; i++ )
  3518. {
  3519. if ( !amps[i].fused )
  3520. break;
  3521. }
  3522. if ( i == CAMPS )
  3523. {
  3524. DevMsg ("DSP: Warning, failed to allocate amp.\n" );
  3525. return NULL;
  3526. }
  3527. pamp = &amps[i];
  3528. AMP_Init ( pamp );
  3529. pamp->fused = true;
  3530. pamp->gain = gain * PMAX;
  3531. pamp->gain_max = gain * PMAX;
  3532. pamp->distmix = distmix * PMAX;
  3533. pamp->vfeed = vfeed * PMAX;
  3534. pamp->vthresh = vthresh * 32767.0;
  3535. // modrate, 0.01, 200.0}, // frequency at which amplitude values change to new random value. 0 is no self-modulation
  3536. // moddepth, 0.0, 1.0}, // how much amplitude changes (decreases) from current value (0-1.0)
  3537. // modglide, 0.01, 100.0}, // glide time between mapcur and ampnew in milliseconds
  3538. pamp->ramptime = ramptime;
  3539. pamp->mtime = SEC_TO_SAMPS(modtime);
  3540. pamp->mtimecur = pamp->mtime;
  3541. pamp->depth = depth * PMAX;
  3542. pamp->brand = brand;
  3543. return pamp;
  3544. }
  3545. // return next amplified sample
  3546. inline int AMP_GetNext( amp_t *pamp, int x )
  3547. {
  3548. int y = x;
  3549. int d;
  3550. // if distortion is on, add distortion, feedback
  3551. if ( pamp->vthresh < PMAX && pamp->distmix )
  3552. {
  3553. int vthresh = pamp->vthresh;
  3554. /* if ( pamp->vfeed > 0.0 )
  3555. {
  3556. // UNDONE: feedback
  3557. }
  3558. */
  3559. // clip distort
  3560. d = ( y > vthresh ? vthresh : ( y < -vthresh ? -vthresh : y));
  3561. // mix distorted with clean (1.0 = full distortion)
  3562. if ( pamp->distmix < PMAX )
  3563. y = y + (((d - y) * pamp->distmix ) >> PBITS);
  3564. else
  3565. y = d;
  3566. }
  3567. // get output for current gain value
  3568. int xout = (y * pamp->gain) >> PBITS;
  3569. if ( !pamp->fchanging && !pamp->mtime )
  3570. {
  3571. // if not modulating and not self modulating, return right away
  3572. return xout;
  3573. }
  3574. if (pamp->fchanging)
  3575. {
  3576. // modulating...
  3577. // get next gain value
  3578. pamp->gain = RMP_GetNext( &pamp->rmp_interp ); // 0...next gain
  3579. if ( RMP_HitEnd( &pamp->rmp_interp ) )
  3580. {
  3581. // done.
  3582. pamp->fchanging = false;
  3583. }
  3584. }
  3585. // if self-modulating and timer has expired, get next change
  3586. if ( pamp->mtime && !pamp->mtimecur-- )
  3587. {
  3588. pamp->mtimecur = pamp->mtime;
  3589. int gain_new;
  3590. int G1;
  3591. int G2 = pamp->gain_max;
  3592. // modulate between 0 and 100% of gain_max
  3593. G1 = pamp->gain_max - ((pamp->gain_max * pamp->depth) >> PBITS);
  3594. if (pamp->brand)
  3595. {
  3596. gain_new = RandomInt( min(G1,G2), max(G1,G2) );
  3597. }
  3598. else
  3599. {
  3600. // alternate between min & max
  3601. gain_new = (pamp->gain == G1 ? G2 : G1);
  3602. }
  3603. // set up modulation to new value
  3604. pamp->fchanging = true;
  3605. // init gain ramp - always hit target
  3606. RMP_Init ( &pamp->rmp_interp, pamp->ramptime, pamp->gain, gain_new, false );
  3607. }
  3608. return xout;
  3609. }
  3610. // batch version for performance
  3611. inline void AMP_GetNextN( amp_t *pamp, portable_samplepair_t *pbuffer, int SampleCount, int op )
  3612. {
  3613. int count = SampleCount;
  3614. portable_samplepair_t *pb = pbuffer;
  3615. switch (op)
  3616. {
  3617. default:
  3618. case OP_LEFT:
  3619. while (count--)
  3620. {
  3621. pb->left = AMP_GetNext( pamp, pb->left );
  3622. pb++;
  3623. }
  3624. return;
  3625. case OP_RIGHT:
  3626. while (count--)
  3627. {
  3628. pb->right = AMP_GetNext( pamp, pb->right );
  3629. pb++;
  3630. }
  3631. return;
  3632. case OP_LEFT_DUPLICATE:
  3633. while (count--)
  3634. {
  3635. pb->left = pb->right = AMP_GetNext( pamp, pb->left );
  3636. pb++;
  3637. }
  3638. return;
  3639. }
  3640. }
  3641. inline void AMP_Mod( amp_t *pamp, float v )
  3642. {
  3643. }
  3644. // parameter order
  3645. typedef enum {
  3646. amp_gain,
  3647. amp_vthresh,
  3648. amp_distmix,
  3649. amp_vfeed,
  3650. amp_imodrate,
  3651. amp_imoddepth,
  3652. amp_imodglide,
  3653. amp_irand,
  3654. amp_cparam
  3655. } amp_e;
  3656. // parameter ranges
  3657. prm_rng_t amp_rng[] = {
  3658. {amp_cparam, 0, 0}, // first entry is # of parameters
  3659. {amp_gain, 0.0, 1000.0}, // amplification
  3660. {amp_vthresh, 0.0, 1.0}, // threshold for distortion (1.0 = no distortion)
  3661. {amp_distmix, 0.0, 1.0}, // mix of clean and distortion (1.0 = full distortion, 0.0 = full clean)
  3662. {amp_vfeed, 0.0, 1.0}, // distortion feedback
  3663. {amp_imodrate, 0.0, 200.0}, // frequency at which amplitude values change to new random value. 0 is no self-modulation
  3664. {amp_imoddepth, 0.0, 1.0}, // how much amplitude changes (decreases) from current value (0-1.0)
  3665. {amp_imodglide, 0.01, 100.0}, // glide time between mapcur and ampnew in milliseconds
  3666. {amp_irand, 0.0, 1.0}, // if 1, use random modulation otherwise alternate from max-min-max
  3667. };
  3668. amp_t * AMP_Params ( prc_t *pprc )
  3669. {
  3670. amp_t *pamp;
  3671. float ramptime = 0.0;
  3672. float modtime = 0.0;
  3673. float depth = 0.0;
  3674. float rand = pprc->prm[amp_irand];
  3675. bool brand;
  3676. if (pprc->prm[amp_imodrate] > 0.0)
  3677. {
  3678. ramptime = pprc->prm[amp_imodglide] / 1000.0; // get ramp time in seconds
  3679. modtime = 1.0 / max((double)pprc->prm[amp_imodrate], 0.01); // time between modulations in seconds
  3680. depth = pprc->prm[amp_imoddepth]; // depth of modulations 0-1.0
  3681. }
  3682. brand = rand > 0.0 ? 1 : 0;
  3683. pamp = AMP_Alloc ( pprc->prm[amp_gain], pprc->prm[amp_vthresh], pprc->prm[amp_distmix], pprc->prm[amp_vfeed],
  3684. ramptime, modtime, depth, brand );
  3685. return pamp;
  3686. }
  3687. inline void * AMP_VParams ( void *p )
  3688. {
  3689. PRC_CheckParams ( (prc_t *)p, amp_rng );
  3690. return (void *) AMP_Params ((prc_t *)p);
  3691. }
  3692. /////////////////
  3693. // NULL processor
  3694. /////////////////
  3695. struct nul_t
  3696. {
  3697. int type;
  3698. };
  3699. nul_t nuls[] = {{0}};
  3700. void NULL_Init ( nul_t *pnul ) { }
  3701. void NULL_InitAll( ) { }
  3702. void NULL_Free ( nul_t *pnul ) { }
  3703. void NULL_FreeAll ( ) { }
  3704. nul_t *NULL_Alloc ( ) { return &nuls[0]; }
  3705. inline int NULL_GetNext ( void *p, int x) { return x; }
  3706. inline void NULL_GetNextN( nul_t *pnul, portable_samplepair_t *pbuffer, int SampleCount, int op ) { return; }
  3707. inline void NULL_Mod ( void *p, float v ) { return; }
  3708. inline void * NULL_VParams ( void *p ) { return (void *) (&nuls[0]); }
  3709. //////////////////////////
  3710. // DSP processors presets - see dsp_presets.txt
  3711. //////////////////////////
  3712. // init array of processors - first store pfnParam, pfnGetNext and pfnFree functions for type,
  3713. // then call the pfnParam function to initialize each processor
  3714. // prcs - an array of prc structures, all with initialized params
  3715. // count - number of elements in the array
  3716. // returns false if failed to init one or more processors
  3717. bool PRC_InitAll( prc_t *prcs, int count )
  3718. {
  3719. int i;
  3720. prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
  3721. prc_GetNext_t pfnGetNext; // get next function
  3722. prc_GetNextN_t pfnGetNextN; // get next function, batch version
  3723. prc_Free_t pfnFree;
  3724. prc_Mod_t pfnMod;
  3725. bool fok = true;;
  3726. if ( count == 0 )
  3727. count = 1;
  3728. // set up pointers to XXX_Free, XXX_GetNext and XXX_Params functions
  3729. for (i = 0; i < count; i++)
  3730. {
  3731. switch (prcs[i].type)
  3732. {
  3733. default:
  3734. case PRC_NULL:
  3735. pfnFree = (prc_Free_t)NULL_Free;
  3736. pfnGetNext = (prc_GetNext_t)NULL_GetNext;
  3737. pfnGetNextN = (prc_GetNextN_t)NULL_GetNextN;
  3738. pfnParam = NULL_VParams;
  3739. pfnMod = (prc_Mod_t)NULL_Mod;
  3740. break;
  3741. case PRC_DLY:
  3742. pfnFree = (prc_Free_t)DLY_Free;
  3743. pfnGetNext = (prc_GetNext_t)DLY_GetNext;
  3744. pfnGetNextN = (prc_GetNextN_t)DLY_GetNextN;
  3745. pfnParam = DLY_VParams;
  3746. pfnMod = (prc_Mod_t)DLY_Mod;
  3747. break;
  3748. case PRC_RVA:
  3749. pfnFree = (prc_Free_t)RVA_Free;
  3750. pfnGetNext = (prc_GetNext_t)RVA_GetNext;
  3751. pfnGetNextN = (prc_GetNextN_t)RVA_GetNextN;
  3752. pfnParam = RVA_VParams;
  3753. pfnMod = (prc_Mod_t)RVA_Mod;
  3754. break;
  3755. case PRC_FLT:
  3756. pfnFree = (prc_Free_t)FLT_Free;
  3757. pfnGetNext = (prc_GetNext_t)FLT_GetNext;
  3758. pfnGetNextN = (prc_GetNextN_t)FLT_GetNextN;
  3759. pfnParam = FLT_VParams;
  3760. pfnMod = (prc_Mod_t)FLT_Mod;
  3761. break;
  3762. case PRC_CRS:
  3763. pfnFree = (prc_Free_t)CRS_Free;
  3764. pfnGetNext = (prc_GetNext_t)CRS_GetNext;
  3765. pfnGetNextN = (prc_GetNextN_t)CRS_GetNextN;
  3766. pfnParam = CRS_VParams;
  3767. pfnMod = (prc_Mod_t)CRS_Mod;
  3768. break;
  3769. case PRC_PTC:
  3770. pfnFree = (prc_Free_t)PTC_Free;
  3771. pfnGetNext = (prc_GetNext_t)PTC_GetNext;
  3772. pfnGetNextN = (prc_GetNextN_t)PTC_GetNextN;
  3773. pfnParam = PTC_VParams;
  3774. pfnMod = (prc_Mod_t)PTC_Mod;
  3775. break;
  3776. case PRC_ENV:
  3777. pfnFree = (prc_Free_t)ENV_Free;
  3778. pfnGetNext = (prc_GetNext_t)ENV_GetNext;
  3779. pfnGetNextN = (prc_GetNextN_t)ENV_GetNextN;
  3780. pfnParam = ENV_VParams;
  3781. pfnMod = (prc_Mod_t)ENV_Mod;
  3782. break;
  3783. case PRC_LFO:
  3784. pfnFree = (prc_Free_t)LFO_Free;
  3785. pfnGetNext = (prc_GetNext_t)LFO_GetNext;
  3786. pfnGetNextN = (prc_GetNextN_t)LFO_GetNextN;
  3787. pfnParam = LFO_VParams;
  3788. pfnMod = (prc_Mod_t)LFO_Mod;
  3789. break;
  3790. case PRC_EFO:
  3791. pfnFree = (prc_Free_t)EFO_Free;
  3792. pfnGetNext = (prc_GetNext_t)EFO_GetNext;
  3793. pfnGetNextN = (prc_GetNextN_t)EFO_GetNextN;
  3794. pfnParam = EFO_VParams;
  3795. pfnMod = (prc_Mod_t)EFO_Mod;
  3796. break;
  3797. case PRC_MDY:
  3798. pfnFree = (prc_Free_t)MDY_Free;
  3799. pfnGetNext = (prc_GetNext_t)MDY_GetNext;
  3800. pfnGetNextN = (prc_GetNextN_t)MDY_GetNextN;
  3801. pfnParam = MDY_VParams;
  3802. pfnMod = (prc_Mod_t)MDY_Mod;
  3803. break;
  3804. case PRC_DFR:
  3805. pfnFree = (prc_Free_t)DFR_Free;
  3806. pfnGetNext = (prc_GetNext_t)DFR_GetNext;
  3807. pfnGetNextN = (prc_GetNextN_t)DFR_GetNextN;
  3808. pfnParam = DFR_VParams;
  3809. pfnMod = (prc_Mod_t)DFR_Mod;
  3810. break;
  3811. case PRC_AMP:
  3812. pfnFree = (prc_Free_t)AMP_Free;
  3813. pfnGetNext = (prc_GetNext_t)AMP_GetNext;
  3814. pfnGetNextN = (prc_GetNextN_t)AMP_GetNextN;
  3815. pfnParam = AMP_VParams;
  3816. pfnMod = (prc_Mod_t)AMP_Mod;
  3817. break;
  3818. }
  3819. // set up function pointers
  3820. prcs[i].pfnParam = pfnParam;
  3821. prcs[i].pfnGetNext = pfnGetNext;
  3822. prcs[i].pfnGetNextN = pfnGetNextN;
  3823. prcs[i].pfnFree = pfnFree;
  3824. prcs[i].pfnMod = pfnMod;
  3825. // call param function, store pdata for the processor type
  3826. prcs[i].pdata = pfnParam ( (void *) (&prcs[i]) );
  3827. if ( !prcs[i].pdata )
  3828. fok = false;
  3829. }
  3830. return fok;
  3831. }
  3832. // free individual processor's data
  3833. void PRC_Free ( prc_t *pprc )
  3834. {
  3835. if ( pprc->pfnFree && pprc->pdata )
  3836. pprc->pfnFree ( pprc->pdata );
  3837. }
  3838. // free all processors for supplied array
  3839. // prcs - array of processors
  3840. // count - elements in array
  3841. void PRC_FreeAll ( prc_t *prcs, int count )
  3842. {
  3843. for (int i = 0; i < count; i++)
  3844. PRC_Free( &prcs[i] );
  3845. }
  3846. // get next value for processor - (usually called directly by PSET_GetNext)
  3847. inline int PRC_GetNext ( prc_t *pprc, int x )
  3848. {
  3849. return pprc->pfnGetNext ( pprc->pdata, x );
  3850. }
  3851. // automatic parameter range limiting
  3852. // force parameters between specified min/max in param_rng
  3853. void PRC_CheckParams ( prc_t *pprc, prm_rng_t *prng )
  3854. {
  3855. // first entry in param_rng is # of parameters
  3856. int cprm = prng[0].iprm;
  3857. for (int i = 0; i < cprm; i++)
  3858. {
  3859. // if parameter is 0.0, always allow it (this is 'off' for most params)
  3860. if ( pprc->prm[i] != 0.0 && (pprc->prm[i] > prng[i+1].hi || pprc->prm[i] < prng[i+1].lo) )
  3861. {
  3862. DevMsg ("DSP: Warning, clamping out of range parameter.\n" );
  3863. pprc->prm[i] = clamp (pprc->prm[i], prng[i+1].lo, prng[i+1].hi);
  3864. }
  3865. }
  3866. }
  3867. // DSP presets
  3868. // A dsp preset comprises one or more dsp processors in linear, parallel or feedback configuration
  3869. // preset configurations
  3870. //
  3871. #define PSET_SIMPLE 0
  3872. // x(n)--->P(0)--->y(n)
  3873. #define PSET_LINEAR 1
  3874. // x(n)--->P(0)-->P(1)-->...P(m)--->y(n)
  3875. #define PSET_PARALLEL2 5
  3876. // x(n)--->P(0)-->(+)-->y(n)
  3877. // ^
  3878. // |
  3879. // x(n)--->P(1)-----
  3880. #define PSET_PARALLEL4 6
  3881. // x(n)--->P(0)-->P(1)-->(+)-->y(n)
  3882. // ^
  3883. // |
  3884. // x(n)--->P(2)-->P(3)-----
  3885. #define PSET_PARALLEL5 7
  3886. // x(n)--->P(0)-->P(1)-->(+)-->P(4)-->y(n)
  3887. // ^
  3888. // |
  3889. // x(n)--->P(2)-->P(3)-----
  3890. #define PSET_FEEDBACK 8
  3891. // x(n)-P(0)--(+)-->P(1)-->P(2)---->y(n)
  3892. // ^ |
  3893. // | v
  3894. // -----P(4)<--P(3)--
  3895. #define PSET_FEEDBACK3 9
  3896. // x(n)---(+)-->P(0)--------->y(n)
  3897. // ^ |
  3898. // | v
  3899. // -----P(2)<--P(1)--
  3900. #define PSET_FEEDBACK4 10
  3901. // x(n)---(+)-->P(0)-------->P(3)--->y(n)
  3902. // ^ |
  3903. // | v
  3904. // ---P(2)<--P(1)--
  3905. #define PSET_MOD 11
  3906. //
  3907. // x(n)------>P(1)--P(2)--P(3)--->y(n)
  3908. // ^
  3909. // x(n)------>P(0)....:
  3910. #define PSET_MOD2 12
  3911. //
  3912. // x(n)-------P(1)-->y(n)
  3913. // ^
  3914. // x(n)-->P(0)..:
  3915. #define PSET_MOD3 13
  3916. //
  3917. // x(n)-------P(1)-->P(2)-->y(n)
  3918. // ^
  3919. // x(n)-->P(0)..:
  3920. #define CPSETS 64 // max number of presets simultaneously active
  3921. #define CPSET_PRCS 5 // max # of processors per dsp preset
  3922. #define CPSET_STATES (CPSET_PRCS+3) // # of internal states
  3923. // NOTE: do not reorder members of pset_t - g_psettemplates relies on it!!!
  3924. struct pset_t
  3925. {
  3926. int type; // preset configuration type
  3927. int cprcs; // number of processors for this preset
  3928. prc_t prcs[CPSET_PRCS]; // processor preset data
  3929. float mix_min; // min dsp mix at close range
  3930. float mix_max; // max dsp mix at long range
  3931. float db_min; // if sndlvl of a new sound is < db_min, reduce mix_min/max by db_mixdrop
  3932. float db_mixdrop; // reduce mix_min/max by n% if sndlvl of new sound less than db_min
  3933. float duration; // if > 0, duration of preset in seconds (duration 0 = infinite)
  3934. float fade; // fade out time, exponential fade
  3935. int csamp_duration; // duration counter # samples
  3936. int w[CPSET_STATES]; // internal states
  3937. int fused;
  3938. };
  3939. pset_t psets[CPSETS];
  3940. pset_t *g_psettemplates = NULL;
  3941. int g_cpsettemplates = 0;
  3942. // returns true if preset will expire after duration
  3943. bool PSET_IsOneShot( pset_t *ppset )
  3944. {
  3945. return ppset->duration > 0.0;
  3946. }
  3947. // return true if preset is no longer active - duration has expired
  3948. bool PSET_HasExpired( pset_t *ppset )
  3949. {
  3950. if (!PSET_IsOneShot( ppset ))
  3951. return false;
  3952. return ppset->csamp_duration <= 0;
  3953. }
  3954. // if preset is oneshot, update duration counter by SampleCount samples
  3955. void PSET_UpdateDuration( pset_t *ppset, int SampleCount )
  3956. {
  3957. if ( PSET_IsOneShot( ppset ) )
  3958. {
  3959. // if oneshot preset and not expired, decrement sample count
  3960. if (ppset->csamp_duration > 0)
  3961. ppset->csamp_duration -= SampleCount;
  3962. }
  3963. }
  3964. // A dsp processor (prc) performs a single-sample function, such as pitch shift, delay, reverb, filter
  3965. // init a preset - just clear state array
  3966. void PSET_Init( pset_t *ppset )
  3967. {
  3968. // clear state array
  3969. if (ppset)
  3970. Q_memset( ppset->w, 0, sizeof (int) * (CPSET_STATES) );
  3971. }
  3972. // clear runtime slots
  3973. void PSET_InitAll( void )
  3974. {
  3975. for (int i = 0; i < CPSETS; i++)
  3976. Q_memset( &psets[i], 0, sizeof(pset_t));
  3977. }
  3978. // free the preset - free all processors
  3979. void PSET_Free( pset_t *ppset )
  3980. {
  3981. if (ppset)
  3982. {
  3983. // free processors
  3984. PRC_FreeAll ( ppset->prcs, ppset->cprcs );
  3985. // clear
  3986. Q_memset( ppset, 0, sizeof (pset_t));
  3987. }
  3988. }
  3989. void PSET_FreeAll() { for (int i = 0; i < CPSETS; i++) PSET_Free( &psets[i] ); };
  3990. // return preset struct, given index into preset template array
  3991. // NOTE: should not ever be more than 2 or 3 of these active simultaneously
  3992. pset_t * PSET_Alloc ( int ipsettemplate )
  3993. {
  3994. pset_t *ppset;
  3995. bool fok;
  3996. // don't excede array bounds
  3997. if ( ipsettemplate >= g_cpsettemplates)
  3998. ipsettemplate = 0;
  3999. // find free slot
  4000. int i = 0;
  4001. for (i = 0; i < CPSETS; i++)
  4002. {
  4003. if ( !psets[i].fused )
  4004. break;
  4005. }
  4006. if ( i == CPSETS )
  4007. return NULL;
  4008. if (das_debug.GetInt())
  4009. {
  4010. int nSlots = 0;
  4011. for ( int j = 0; j < CPSETS; j++)
  4012. {
  4013. if ( psets[j].fused )
  4014. nSlots++;
  4015. }
  4016. DevMsg("total preset slots used: %d \n", nSlots );
  4017. }
  4018. ppset = &psets[i];
  4019. // clear preset
  4020. Q_memset(ppset, 0, sizeof(pset_t));
  4021. // copy template into preset
  4022. *ppset = g_psettemplates[ipsettemplate];
  4023. ppset->fused = true;
  4024. // clear state array
  4025. PSET_Init ( ppset );
  4026. // init all processors, set up processor function pointers
  4027. fok = PRC_InitAll( ppset->prcs, ppset->cprcs );
  4028. if ( !fok )
  4029. {
  4030. // failed to init one or more processors
  4031. Warning( "Sound DSP: preset failed to init.\n");
  4032. PRC_FreeAll ( ppset->prcs, ppset->cprcs );
  4033. return NULL;
  4034. }
  4035. // if preset has duration, setup duration sample counter
  4036. if ( PSET_IsOneShot( ppset ) )
  4037. {
  4038. ppset->csamp_duration = SEC_TO_SAMPS( ppset->duration );
  4039. }
  4040. return ppset;
  4041. }
  4042. // batch version of PSET_GetNext for linear array of processors. For performance.
  4043. // ppset - preset array
  4044. // pbuffer - input sample data
  4045. // SampleCount - size of input buffer
  4046. // OP: OP_LEFT - process left channel in place
  4047. // OP_RIGHT - process right channel in place
  4048. // OP_LEFT_DUPLICATe - process left channel, duplicate into right
  4049. inline void PSET_GetNextN( pset_t *ppset, portable_samplepair_t *pbuffer, int SampleCount, int op )
  4050. {
  4051. portable_samplepair_t *pbf = pbuffer;
  4052. prc_t *pprc;
  4053. int count = ppset->cprcs;
  4054. switch ( ppset->type )
  4055. {
  4056. default:
  4057. case PSET_SIMPLE:
  4058. {
  4059. // x(n)--->P(0)--->y(n)
  4060. ppset->prcs[0].pfnGetNextN (ppset->prcs[0].pdata, pbf, SampleCount, op);
  4061. return;
  4062. }
  4063. case PSET_LINEAR:
  4064. {
  4065. // w0 w1 w2
  4066. // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
  4067. // w0 w1 w2 w3 w4 w5
  4068. // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
  4069. // call batch processors in sequence - no internal state for batch processing
  4070. // point to first processor
  4071. pprc = &ppset->prcs[0];
  4072. for (int i = 0; i < count; i++)
  4073. {
  4074. pprc->pfnGetNextN (pprc->pdata, pbf, SampleCount, op);
  4075. pprc++;
  4076. }
  4077. return;
  4078. }
  4079. }
  4080. }
  4081. // Get next sample from this preset. called once for every sample in buffer
  4082. // ppset is pointer to preset
  4083. // x is input sample
  4084. inline int PSET_GetNext ( pset_t *ppset, int x )
  4085. {
  4086. // pset_simple and pset_linear have no internal state:
  4087. // this is REQUIRED for all presets that have a batch getnextN equivalent!
  4088. if ( ppset->type == PSET_SIMPLE )
  4089. {
  4090. // x(n)--->P(0)--->y(n)
  4091. return ppset->prcs[0].pfnGetNext (ppset->prcs[0].pdata, x);
  4092. }
  4093. prc_t *pprc;
  4094. int count = ppset->cprcs;
  4095. if ( ppset->type == PSET_LINEAR )
  4096. {
  4097. int y = x;
  4098. // w0 w1 w2
  4099. // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
  4100. // w0 w1 w2 w3 w4 w5
  4101. // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
  4102. // call processors in reverse order, from count to 1
  4103. //for (int i = count; i > 0; i--, pprc--)
  4104. // w[i] = pprc->pfnGetNext (pprc->pdata, w[i-1]);
  4105. // return w[count];
  4106. // point to first processor, update sequentially, no state preserved
  4107. pprc = &ppset->prcs[0];
  4108. switch (count)
  4109. {
  4110. default:
  4111. case 5:
  4112. y = pprc->pfnGetNext (pprc->pdata, y);
  4113. pprc++;
  4114. case 4:
  4115. y = pprc->pfnGetNext (pprc->pdata, y);
  4116. pprc++;
  4117. case 3:
  4118. y = pprc->pfnGetNext (pprc->pdata, y);
  4119. pprc++;
  4120. case 2:
  4121. y = pprc->pfnGetNext (pprc->pdata, y);
  4122. pprc++;
  4123. case 1:
  4124. case 0:
  4125. y = pprc->pfnGetNext (pprc->pdata, y);
  4126. }
  4127. return y;
  4128. }
  4129. // all other preset types have internal state:
  4130. // initialize 0'th element of state array
  4131. int *w = ppset->w;
  4132. w[0] = x;
  4133. switch ( ppset->type )
  4134. {
  4135. default:
  4136. case PSET_PARALLEL2:
  4137. { // w0 w1 w3
  4138. // x(n)--->P(0)-->(+)-->y(n)
  4139. // ^
  4140. // w0 w2 |
  4141. // x(n)--->P(1)-----
  4142. pprc = &ppset->prcs[0];
  4143. w[3] = w[1] + w[2];
  4144. w[1] = pprc->pfnGetNext( pprc->pdata, w[0] );
  4145. pprc++;
  4146. w[2] = pprc->pfnGetNext( pprc->pdata, w[0] );
  4147. return w[3];
  4148. }
  4149. case PSET_PARALLEL4:
  4150. { // w0 w1 w2 w5
  4151. // x(n)--->P(0)-->P(1)-->(+)-->y(n)
  4152. // ^
  4153. // w0 w3 w4 |
  4154. // x(n)--->P(2)-->P(3)-----
  4155. pprc = &ppset->prcs[0];
  4156. w[5] = w[2] + w[4];
  4157. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  4158. w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  4159. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  4160. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
  4161. return w[5];
  4162. }
  4163. case PSET_PARALLEL5:
  4164. { // w0 w1 w2 w5 w6
  4165. // x(n)--->P(0)-->P(1)-->(+)--P(4)-->y(n)
  4166. // ^
  4167. // w0 w3 w4 |
  4168. // x(n)--->P(2)-->P(3)-----
  4169. pprc = &ppset->prcs[0];
  4170. w[5] = w[2] + w[4];
  4171. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  4172. w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  4173. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  4174. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
  4175. return pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
  4176. }
  4177. case PSET_FEEDBACK:
  4178. {
  4179. // w0 w1 w2 w3 w4 w7
  4180. // x(n)-P(0)--(+)-->P(1)-->P(2)-->---->y(n)
  4181. // ^ |
  4182. // | w6 w5 v
  4183. // -----P(4)<--P(3)--
  4184. pprc = &ppset->prcs[0];
  4185. // start with adders
  4186. w[2] = w[1] + w[6];
  4187. // evaluate in reverse order
  4188. w[6] = pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
  4189. w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[4] );
  4190. w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  4191. w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  4192. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  4193. return w[4];
  4194. }
  4195. case PSET_FEEDBACK3:
  4196. {
  4197. // w0 w1 w2
  4198. // x(n)---(+)-->P(0)--------->y(n)
  4199. // ^ |
  4200. // | w4 w3 v
  4201. // -----P(2)<--P(1)--
  4202. pprc = &ppset->prcs[0];
  4203. // start with adders
  4204. w[1] = w[0] + w[4];
  4205. // evaluate in reverse order
  4206. w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  4207. w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  4208. w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
  4209. return w[2];
  4210. }
  4211. case PSET_FEEDBACK4:
  4212. {
  4213. // w0 w1 w2 w5
  4214. // x(n)---(+)-->P(0)-------->P(3)--->y(n)
  4215. // ^ |
  4216. // | w4 w3 v
  4217. // ---P(2)<--P(1)--
  4218. pprc = &ppset->prcs[0];
  4219. // start with adders
  4220. w[1] = w[0] + w[4];
  4221. // evaluate in reverse order
  4222. w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[2] );
  4223. w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  4224. w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  4225. w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
  4226. return w[2];
  4227. }
  4228. case PSET_MOD:
  4229. {
  4230. // w0 w1 w3 w4
  4231. // x(n)------>P(1)--P(2)--P(3)--->y(n)
  4232. // w0 w2 ^
  4233. // x(n)------>P(0)....:
  4234. pprc = &ppset->prcs[0];
  4235. w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  4236. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[1] );
  4237. // modulate processor 2
  4238. pprc[2].pfnMod( pprc[2].pdata, ((float)w[2] / (float)PMAX));
  4239. // get modulator output
  4240. w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  4241. w[1] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  4242. return w[4];
  4243. }
  4244. case PSET_MOD2:
  4245. {
  4246. // w0 w2
  4247. // x(n)---------P(1)-->y(n)
  4248. // w0 w1 ^
  4249. // x(n)-->P(0)....:
  4250. pprc = &ppset->prcs[0];
  4251. // modulate processor 1
  4252. pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
  4253. // get modulator output
  4254. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  4255. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  4256. return w[2];
  4257. }
  4258. case PSET_MOD3:
  4259. {
  4260. // w0 w2 w3
  4261. // x(n)----------P(1)-->P(2)-->y(n)
  4262. // w0 w1 ^
  4263. // x(n)-->P(0).....:
  4264. pprc = &ppset->prcs[0];
  4265. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[2] );
  4266. // modulate processor 1
  4267. pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
  4268. // get modulator output
  4269. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  4270. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  4271. return w[2];
  4272. }
  4273. }
  4274. }
  4275. /////////////
  4276. // DSP system
  4277. /////////////
  4278. // Main interface
  4279. // Whenever the preset # changes on any of these processors, the old processor is faded out, new is faded in.
  4280. // dsp_chan is optionally set when a sound is played - a preset is sent with the start_static/dynamic sound.
  4281. //
  4282. // sound1---->dsp_chan--> -------------(+)---->dsp_water--->dsp_player--->out
  4283. // sound2---->dsp_chan--> | |
  4284. // sound3---------------> ----dsp_room---
  4285. // | |
  4286. // --dsp_indirect-
  4287. // dsp_room - set this cvar to a preset # to change the room dsp. room fx are more prevalent farther from player.
  4288. // use: when player moves into a new room, all sounds played in room take on its reverberant character
  4289. // dsp_water - set this cvar (once) to a preset # for serial underwater sound.
  4290. // use: when player goes under water, all sounds pass through this dsp (such as low pass filter)
  4291. // dsp_player - set this cvar to a preset # to cause all sounds to run through the effect (serial, in-line).
  4292. // use: player is deafened, player fires special weapon, player is hit by special weapon.
  4293. // dsp_facingaway- set this cvar to a preset # appropriate for sounds which are played facing away from player (weapon,voice)
  4294. //
  4295. // dsp_spatial - set by system to create modulated spatial delays for left/right/front/back ears - delay value
  4296. // modulates by distance to nearest l/r surface in world
  4297. // Dsp presets
  4298. ConVar dsp_room ("dsp_room", "0", FCVAR_DEMO ); // room dsp preset - sounds more distant from player (1ch)
  4299. ConVar dsp_water ("dsp_water", "14", FCVAR_DEMO ); // "14" underwater dsp preset - sound when underwater (1-2ch)
  4300. ConVar dsp_player ("dsp_player", "0", FCVAR_DEMO | FCVAR_SERVER_CAN_EXECUTE ); // dsp on player - sound when player hit by special device (1-2ch)
  4301. ConVar dsp_facingaway ("dsp_facingaway", "0", FCVAR_DEMO ); // "30" sounds that face away from player (weapons, voice) (1-4ch)
  4302. ConVar dsp_speaker ("dsp_speaker", "50", FCVAR_DEMO ); // "50" small distorted speaker sound (1ch)
  4303. ConVar dsp_spatial ("dsp_spatial", "40", FCVAR_DEMO ); // spatial delays for l/r front/rear ears
  4304. ConVar dsp_automatic ("dsp_automatic", "0", FCVAR_DEMO ); // automatic room type detection. if non zero, replaces dsp_room
  4305. int ipset_room_prev;
  4306. int ipset_water_prev;
  4307. int ipset_player_prev;
  4308. int ipset_facingaway_prev;
  4309. int ipset_speaker_prev;
  4310. int ipset_spatial_prev;
  4311. int ipset_automatic_prev;
  4312. // legacy room_type support
  4313. ConVar dsp_room_type ( "room_type", "0", FCVAR_DEMO );
  4314. int ipset_room_typeprev;
  4315. // DSP processors
  4316. int idsp_room;
  4317. int idsp_water;
  4318. int idsp_player;
  4319. int idsp_facingaway;
  4320. int idsp_speaker;
  4321. int idsp_spatial;
  4322. int idsp_automatic;
  4323. ConVar dsp_off ("dsp_off", "0", FCVAR_CHEAT | FCVAR_ALLOWED_IN_COMPETITIVE ); // set to 1 to disable all dsp processing
  4324. ConVar dsp_slow_cpu ("dsp_slow_cpu", "0", FCVAR_ARCHIVE|FCVAR_DEMO ); // set to 1 if cpu bound - ie: does not process dsp_room fx
  4325. ConVar snd_profile ("snd_profile", "0", FCVAR_DEMO ); // 1 - profile dsp, 2 - mix, 3 - load sound, 4 - all sound
  4326. ConVar dsp_volume ("dsp_volume", "1.0", FCVAR_ARCHIVE|FCVAR_DEMO ); // 0.0 - 2.0; master dsp volume control
  4327. ConVar dsp_vol_5ch ("dsp_vol_5ch", "0.5", FCVAR_DEMO ); // 0.0 - 1.0; attenuate master dsp volume for 5ch surround
  4328. ConVar dsp_vol_4ch ("dsp_vol_4ch", "0.5", FCVAR_DEMO ); // 0.0 - 1.0; attenuate master dsp volume for 4ch surround
  4329. ConVar dsp_vol_2ch ("dsp_vol_2ch", "1.0", FCVAR_DEMO ); // 0.0 - 1.0; attenuate master dsp volume for 2ch surround
  4330. ConVar dsp_enhance_stereo("dsp_enhance_stereo", "0", FCVAR_ARCHIVE ); // 1) use dsp_spatial delays on all reverb channels
  4331. // DSP preset executor
  4332. #define CDSPS 32 // max number dsp executors active
  4333. #define DSPCHANMAX 5 // max number of channels dsp can process (allocs a separte processor for each chan)
  4334. struct dsp_t
  4335. {
  4336. bool fused;
  4337. int cchan; // 1-5 channels, ie: mono, FrontLeft, FrontRight, RearLeft, RearRight, FrontCenter
  4338. pset_t *ppset[DSPCHANMAX]; // current preset (1-5 channels)
  4339. int ipset; // current ipreset
  4340. pset_t *ppsetprev[DSPCHANMAX]; // previous preset (1-5 channels)
  4341. int ipsetprev; // previous ipreset
  4342. float xfade; // crossfade time between previous preset and new
  4343. float xfade_default; // default xfade value, set in DSP_Alloc
  4344. bool bexpfade; // true if exponential crossfade
  4345. int ipsetsav_oneshot; // previous preset before one-shot preset was set
  4346. rmp_t xramp; // crossfade ramp
  4347. };
  4348. dsp_t dsps[CDSPS];
  4349. void DSP_Init( int idsp )
  4350. {
  4351. dsp_t *pdsp;
  4352. Assert( idsp < CDSPS );
  4353. if (idsp < 0 || idsp >= CDSPS)
  4354. return;
  4355. pdsp = &dsps[idsp];
  4356. Q_memset( pdsp, 0, sizeof (dsp_t) );
  4357. }
  4358. void DSP_Free( int idsp )
  4359. {
  4360. dsp_t *pdsp;
  4361. Assert( idsp < CDSPS );
  4362. if (idsp < 0 || idsp >= CDSPS)
  4363. return;
  4364. pdsp = &dsps[idsp];
  4365. for (int i = 0; i < pdsp->cchan; i++)
  4366. {
  4367. if ( pdsp->ppset[i] )
  4368. PSET_Free( pdsp->ppset[i] );
  4369. if ( pdsp->ppsetprev[i] )
  4370. PSET_Free( pdsp->ppsetprev[i] );
  4371. }
  4372. Q_memset( pdsp, 0, sizeof (dsp_t) );
  4373. }
  4374. // Init all dsp processors - called once, during engine startup
  4375. void DSP_InitAll ( bool bLoadPresetFile )
  4376. {
  4377. // only load template file on engine startup
  4378. if ( bLoadPresetFile )
  4379. DSP_LoadPresetFile();
  4380. // order is important, don't rearange.
  4381. FLT_InitAll();
  4382. DLY_InitAll();
  4383. RVA_InitAll();
  4384. LFOWAV_InitAll();
  4385. LFO_InitAll();
  4386. CRS_InitAll();
  4387. PTC_InitAll();
  4388. ENV_InitAll();
  4389. EFO_InitAll();
  4390. MDY_InitAll();
  4391. AMP_InitAll();
  4392. PSET_InitAll();
  4393. for (int idsp = 0; idsp < CDSPS; idsp++)
  4394. DSP_Init( idsp );
  4395. }
  4396. // free all resources associated with dsp - called once, during engine shutdown
  4397. void DSP_FreeAll (void)
  4398. {
  4399. // order is important, don't rearange.
  4400. for (int idsp = 0; idsp < CDSPS; idsp++)
  4401. DSP_Free( idsp );
  4402. AMP_FreeAll();
  4403. MDY_FreeAll();
  4404. EFO_FreeAll();
  4405. ENV_FreeAll();
  4406. PTC_FreeAll();
  4407. CRS_FreeAll();
  4408. LFO_FreeAll();
  4409. LFOWAV_FreeAll();
  4410. RVA_FreeAll();
  4411. DLY_FreeAll();
  4412. FLT_FreeAll();
  4413. }
  4414. // allocate a new dsp processor chain, kill the old processor. Called during dsp init only.
  4415. // ipset is new preset
  4416. // xfade is crossfade time when switching between presets (milliseconds)
  4417. // cchan is how many simultaneous preset channels to allocate (1-4)
  4418. // return index to new dsp
  4419. int DSP_Alloc( int ipset, float xfade, int cchan )
  4420. {
  4421. dsp_t *pdsp;
  4422. int i;
  4423. int idsp;
  4424. int cchans = clamp( cchan, 1, DSPCHANMAX);
  4425. // find free slot
  4426. for ( idsp = 0; idsp < CDSPS; idsp++ )
  4427. {
  4428. if ( !dsps[idsp].fused )
  4429. break;
  4430. }
  4431. if ( idsp >= CDSPS )
  4432. return -1;
  4433. pdsp = &dsps[idsp];
  4434. DSP_Init ( idsp );
  4435. pdsp->fused = true;
  4436. pdsp->cchan = cchans;
  4437. // allocate a preset processor for each channel
  4438. pdsp->ipset = ipset;
  4439. pdsp->ipsetprev = 0;
  4440. pdsp->ipsetsav_oneshot = 0;
  4441. for (i = 0; i < pdsp->cchan; i++)
  4442. {
  4443. pdsp->ppset[i] = PSET_Alloc ( ipset );
  4444. pdsp->ppsetprev[i] = NULL;
  4445. }
  4446. // set up crossfade time in seconds
  4447. pdsp->xfade = xfade / 1000.0;
  4448. pdsp->xfade_default = pdsp->xfade;
  4449. RMP_SetEnd(&pdsp->xramp);
  4450. return idsp;
  4451. }
  4452. // call modulation function of specified processor within dsp preset
  4453. // idsp - dsp preset
  4454. // channel - channel 1-5 (l,r,rl,rr,fc)
  4455. // iproc - which processor to change (normally 0)
  4456. // value - new parameter value for processor
  4457. // NOTE: routine returns with no result or error if any parameter is invalid.
  4458. void DSP_ChangePresetValue( int idsp, int channel, int iproc, float value )
  4459. {
  4460. dsp_t *pdsp;
  4461. pset_t *ppset; // preset
  4462. prc_Mod_t pfnMod; // modulation function
  4463. if (idsp < 0 || idsp >= CDSPS)
  4464. return;
  4465. if (channel >= DSPCHANMAX)
  4466. return;
  4467. if (iproc >= CPSET_PRCS)
  4468. return;
  4469. // get ptr to processor preset
  4470. pdsp = &dsps[idsp];
  4471. // assert that this dsp processor has enough separate channels
  4472. Assert(channel <= pdsp->cchan);
  4473. ppset = pdsp->ppset[channel];
  4474. if (!ppset)
  4475. return;
  4476. // get ptr to modulation function
  4477. pfnMod = ppset->prcs[iproc].pfnMod;
  4478. if (!pfnMod)
  4479. return;
  4480. // call modulation function with new value
  4481. pfnMod (ppset->prcs[iproc].pdata, value);
  4482. }
  4483. #define DSP_AUTOMATIC 1 // corresponds to Generic preset
  4484. // if dsp_room == DSP_AUTOMATIC, then use dsp_automatic value for dsp
  4485. // any subsequent reset of dsp_room will disable automatic room detection.
  4486. // return true if automatic room detection is enabled
  4487. bool DSP_CheckDspAutoEnabled( void )
  4488. {
  4489. return (dsp_room.GetInt() == DSP_AUTOMATIC);
  4490. }
  4491. // set dsp_automatic preset, used in place of dsp_room when automatic room detection enabled
  4492. void DSP_SetDspAuto( int dsp_preset )
  4493. {
  4494. // set dsp_preset into dsp_automatic
  4495. dsp_automatic.SetValue( dsp_preset );
  4496. }
  4497. // wrapper on dsp_room GetInt so that dsp_automatic can override
  4498. int dsp_room_GetInt ( void )
  4499. {
  4500. // if dsp_automatic is not enabled, get room
  4501. if (! DSP_CheckDspAutoEnabled())
  4502. return dsp_room.GetInt();
  4503. // automatic room detection is on, get dsp_automatic instead of dsp_room
  4504. return dsp_automatic.GetInt();
  4505. }
  4506. // wrapper on idsp_room preset so that idsp_automatic can override
  4507. int Get_idsp_room ( void )
  4508. {
  4509. // if dsp_automatic is not enabled, get room
  4510. if ( !DSP_CheckDspAutoEnabled())
  4511. return idsp_room;
  4512. // automatic room detection is on, return dsp_automatic preset instead of dsp_room preset
  4513. return idsp_automatic;
  4514. }
  4515. // free previous preset if not 0
  4516. inline void DSP_FreePrevPreset( dsp_t *pdsp )
  4517. {
  4518. // free previous presets if non-null - ie: rapid change of preset just kills old without xfade
  4519. if ( pdsp->ipsetprev )
  4520. {
  4521. for (int i = 0; i < pdsp->cchan; i++)
  4522. {
  4523. if ( pdsp->ppsetprev[i] )
  4524. {
  4525. PSET_Free( pdsp->ppsetprev[i] );
  4526. pdsp->ppsetprev[i] = NULL;
  4527. }
  4528. }
  4529. pdsp->ipsetprev = 0;
  4530. }
  4531. }
  4532. extern ConVar dsp_mix_min;
  4533. extern ConVar dsp_mix_max;
  4534. extern ConVar dsp_db_min;
  4535. extern ConVar dsp_db_mixdrop;
  4536. // alloc new preset if different from current
  4537. // xfade from prev to new preset
  4538. // free previous preset, copy current into previous, set up xfade from previous to new
  4539. void DSP_SetPreset( int idsp, int ipsetnew)
  4540. {
  4541. dsp_t *pdsp;
  4542. pset_t *ppsetnew[DSPCHANMAX];
  4543. Assert (idsp >= 0 && idsp < CDSPS);
  4544. pdsp = &dsps[idsp];
  4545. // validate new preset range
  4546. if ( ipsetnew >= g_cpsettemplates || ipsetnew < 0 )
  4547. return;
  4548. // ignore if new preset is same as current preset
  4549. if ( ipsetnew == pdsp->ipset )
  4550. return;
  4551. // alloc new presets (each channel is a duplicate preset)
  4552. Assert (pdsp->cchan <= DSPCHANMAX);
  4553. for (int i = 0; i < pdsp->cchan; i++)
  4554. {
  4555. ppsetnew[i] = PSET_Alloc ( ipsetnew );
  4556. if ( !ppsetnew[i] )
  4557. {
  4558. DevMsg("WARNING: DSP preset failed to allocate.\n");
  4559. return;
  4560. }
  4561. }
  4562. Assert (pdsp);
  4563. // free PREVIOUS previous preset if not 0
  4564. DSP_FreePrevPreset( pdsp );
  4565. for (int i = 0; i < pdsp->cchan; i++)
  4566. {
  4567. // current becomes previous
  4568. pdsp->ppsetprev[i] = pdsp->ppset[i];
  4569. // new becomes current
  4570. pdsp->ppset[i] = ppsetnew[i];
  4571. }
  4572. pdsp->ipsetprev = pdsp->ipset;
  4573. pdsp->ipset = ipsetnew;
  4574. if ( idsp == idsp_room || idsp == idsp_automatic )
  4575. {
  4576. // set up new dsp mix min & max, db_min & db_drop params so that new channels get new mix values
  4577. // NOTE: only new sounds will get the new mix min/max values set in their dspmix param
  4578. // NOTE: so - no crossfade is needed between dspmix and dspmix prev, but this also means
  4579. // NOTE: that currently playing ambients will not see changes to dspmix at all.
  4580. float mix_min = pdsp->ppset[0]->mix_min;
  4581. float mix_max = pdsp->ppset[0]->mix_max;
  4582. float db_min = pdsp->ppset[0]->db_min;
  4583. float db_mixdrop = pdsp->ppset[0]->db_mixdrop;
  4584. dsp_mix_min.SetValue( mix_min );
  4585. dsp_mix_max.SetValue( mix_max );
  4586. dsp_db_min.SetValue( db_min );
  4587. dsp_db_mixdrop.SetValue( db_mixdrop );
  4588. }
  4589. RMP_SetEnd( &pdsp->xramp );
  4590. // make sure previous dsp preset has data
  4591. Assert (pdsp->ppsetprev[0]);
  4592. // shouldn't be crossfading if current dsp preset == previous dsp preset
  4593. Assert (pdsp->ipset != pdsp->ipsetprev);
  4594. // if new preset is one-shot, keep previous preset to restore when one-shot times out
  4595. // but: don't restore previous one-shots!
  4596. pdsp->ipsetsav_oneshot = 0;
  4597. if ( PSET_IsOneShot( pdsp->ppset[0] ) && !PSET_IsOneShot( pdsp->ppsetprev[0] ) )
  4598. pdsp->ipsetsav_oneshot = pdsp->ipsetprev;
  4599. // get new xfade time from previous preset (ie: fade out time). if 0 use default. if < 0, use exponential xfade
  4600. if ( fabs(pdsp->ppsetprev[0]->fade) > 0.0 )
  4601. {
  4602. pdsp->xfade = fabs(pdsp->ppsetprev[0]->fade);
  4603. pdsp->bexpfade = pdsp->ppsetprev[0]->fade < 0 ? 1 : 0;
  4604. }
  4605. else
  4606. {
  4607. // no previous preset - use defauts, set in DSP_Alloc
  4608. pdsp->xfade = pdsp->xfade_default;
  4609. pdsp->bexpfade = false;
  4610. }
  4611. RMP_Init( &(pdsp->xramp), pdsp->xfade, 0, PMAX, false );
  4612. }
  4613. #define DSP_AUTO_BASE 60 // presets 60-100 in g_psettemplates are reserved as autocreated presets
  4614. #define DSP_CAUTO_PRESETS 40 // must be same as DAS_CNODES!!!
  4615. // construct a dsp preset based on provided parameters,
  4616. // preset is constructed within g_psettemplates[] array.
  4617. // return preset #
  4618. // parameter batch
  4619. struct auto_params_t
  4620. {
  4621. // passed in params
  4622. bool bskyabove; // true if sky is mostly above player
  4623. int width; // max width of room in inches
  4624. int length; // max length of room in inches (length always > width)
  4625. int height; // max height of room in inches
  4626. float fdiffusion; // diffusion of room 0..1.0
  4627. float freflectivity; // average reflectivity of all surfaces in room 0..1.0
  4628. float surface_refl[6]; // reflectivity for left,right,front,back,ceiling,floor surfaces 0.0 for open surface (sky or no hit)
  4629. // derived params
  4630. int shape; // ADSP_ROOM, etc 0...4
  4631. int size; // ADSP_SIZE_SMALL, etc 0...3
  4632. int len; // ADSP_LENGTH_SHORT, etc 0...3
  4633. int wid; // ADSP_WIDTH_NARROW, etc 0...3
  4634. int ht; // ADSP_HEIGHT_LOW, etc 0...3
  4635. int reflectivity; // ADSP_DULL, etc 0..3
  4636. int diffusion; // ADSP_EMPTY, etc 0...3
  4637. };
  4638. // select type 1..5 based on params
  4639. // 1:simple reverb
  4640. // 2:diffusor + reverb
  4641. // 3:diffusor + delay + reverb
  4642. // 4:simple delay
  4643. // 5:diffusor + delay
  4644. #define AROOM_SMALL (10.0 * 12.0) // small room
  4645. #define AROOM_MEDIUM (20.0 * 12.0) // medium room
  4646. #define AROOM_LARGE (40.0 * 12.0) // large room
  4647. #define AROOM_HUGE (100.0 * 12.0) // huge room
  4648. #define AROOM_GIGANTIC (200.0 * 12.0) // gigantic room
  4649. #define AROOM_DUCT_WIDTH (4.0 * 12.0) // max width for duct
  4650. #define AROOM_DUCT_HEIGHT (6.0 * 12.0)
  4651. #define AROOM_HALL_WIDTH (8.0 * 12.0) // max width for hall
  4652. #define AROOM_HALL_HEIGHT (16.0 * 12.0) // max height for hall
  4653. #define AROOM_TUNNEL_WIDTH (20.0 * 12.0) // max width for tunnel
  4654. #define AROOM_TUNNEL_HEIGHT (30.0 * 12.0) // max height for tunnel
  4655. #define AROOM_STREET_WIDTH (12.0 * 12.0) // min width for street
  4656. #define AROOM_SHORT_LENGTH (12.0 * 12.0) // max length for short hall
  4657. #define AROOM_MEDIUM_LENGTH (24.0 * 12.0) // min length for medium hall
  4658. #define AROOM_LONG_LENGTH (48.0 * 12.0) // min length for long hall
  4659. #define AROOM_VLONG_LENGTH (96.0 * 12.0) // min length for very long hall
  4660. #define AROOM_XLONG_LENGTH (192.0 * 12.0) // min length for huge hall
  4661. #define AROOM_LOW_HEIGHT (4.0 * 12.0) // short ceiling
  4662. #define AROOM_MEDIUM_HEIGHT (128) // medium ceiling
  4663. #define AROOM_TALL_HEIGHT (18.0 * 12.0) // tall ceiling
  4664. #define AROOM_VTALL_HEIGHT (32.0 * 12.0) // very tall ceiling
  4665. #define AROOM_XTALL_HEIGHT (64.0 * 12.0) // huge tall ceiling
  4666. #define AROOM_NARROW_WIDTH (6.0 * 12.0) // narrow width
  4667. #define AROOM_MEDIUM_WIDTH (12.0 * 12.0) // medium width
  4668. #define AROOM_WIDE_WIDTH (24.0 * 12.0) // wide width
  4669. #define AROOM_VWIDE_WIDTH (48.0 * 12.0) // very wide
  4670. #define AROOM_XWIDE_WIDTH (96.0 * 12.0) // huge width
  4671. #define BETWEEN(a,b,c) ( ((a) > (b)) && ((a) <= (c)) )
  4672. #define ADSP_IsShaft(pa) (pa->height > (3.0 * pa->length))
  4673. #define ADSP_IsRoom(pa) (pa->length <= (2.5 * pa->width))
  4674. #define ADSP_IsHall(pa) ((pa->length > (2.5 * pa->width)) && (BETWEEN(pa->width, AROOM_DUCT_WIDTH, AROOM_HALL_WIDTH)))
  4675. #define ADSP_IsTunnel(pa) ((pa->length > (4.0 * pa->width)) && (pa->width > AROOM_HALL_WIDTH))
  4676. #define ADSP_IsDuct(pa) ((pa->length > (4.0 * pa->width)) && (pa->width <= AROOM_DUCT_WIDTH))
  4677. #define ADSP_IsCourtyard(pa) (pa->length <= (2.5 * pa->width))
  4678. #define ADSP_IsAlley(pa) ((pa->length > (2.5 * pa->width)) && (pa->width <= AROOM_STREET_WIDTH))
  4679. #define ADSP_IsStreet(pa) ((pa->length > (2.5 * pa->width)) && (pa->width > AROOM_STREET_WIDTH))
  4680. #define ADSP_IsSmallRoom(pa) (pa->length <= AROOM_SMALL)
  4681. #define ADSP_IsMediumRoom(pa) ((BETWEEN(pa->length, AROOM_SMALL, AROOM_MEDIUM)) ) // && (BETWEEN(pa->width, AROOM_SMALL, AROOM_MEDIUM)))
  4682. #define ADSP_IsLargeRoom(pa) (BETWEEN(pa->length, AROOM_MEDIUM, AROOM_LARGE) ) // && BETWEEN(pa->width, AROOM_MEDIUM, AROOM_LARGE))
  4683. #define ADSP_IsHugeRoom(pa) (BETWEEN(pa->length, AROOM_LARGE, AROOM_HUGE) ) // && BETWEEN(pa->width, AROOM_LARGE, AROOM_HUGE))
  4684. #define ADSP_IsGiganticRoom(pa) ((pa->length > AROOM_HUGE) ) // && (pa->width > AROOM_HUGE))
  4685. #define ADSP_IsShortLength(pa) (pa->length <= AROOM_SHORT_LENGTH)
  4686. #define ADSP_IsMediumLength(pa) (BETWEEN(pa->length, AROOM_SHORT_LENGTH, AROOM_MEDIUM_LENGTH))
  4687. #define ADSP_IsLongLength(pa) (BETWEEN(pa->length, AROOM_MEDIUM_LENGTH, AROOM_LONG_LENGTH))
  4688. #define ADSP_IsVLongLength(pa) (BETWEEN(pa->length, AROOM_LONG_LENGTH, AROOM_VLONG_LENGTH))
  4689. #define ADSP_IsXLongLength(pa) (pa->length > AROOM_VLONG_LENGTH)
  4690. #define ADSP_IsLowHeight(pa) (pa->height <= AROOM_LOW_HEIGHT)
  4691. #define ADSP_IsMediumHeight(pa) (BETWEEN(pa->height, AROOM_LOW_HEIGHT, AROOM_MEDIUM_HEIGHT))
  4692. #define ADSP_IsTallHeight(pa) (BETWEEN(pa->height, AROOM_MEDIUM_HEIGHT, AROOM_TALL_HEIGHT))
  4693. #define ADSP_IsVTallHeight(pa) (BETWEEN(pa->height, AROOM_TALL_HEIGHT, AROOM_VTALL_HEIGHT))
  4694. #define ADSP_IsXTallHeight(pa) (pa->height > AROOM_VTALL_HEIGHT)
  4695. #define ADSP_IsNarrowWidth(pa) (pa->width <= AROOM_NARROW_WIDTH)
  4696. #define ADSP_IsMediumWidth(pa) (BETWEEN(pa->width, AROOM_NARROW_WIDTH, AROOM_MEDIUM_WIDTH))
  4697. #define ADSP_IsWideWidth(pa) (BETWEEN(pa->width, AROOM_MEDIUM_WIDTH, AROOM_WIDE_WIDTH))
  4698. #define ADSP_IsVWideWidth(pa) (BETWEEN(pa->width, AROOM_WIDE_WIDTH, AROOM_VWIDE_WIDTH))
  4699. #define ADSP_IsXWideWidth(pa) (pa->width > AROOM_VWIDE_WIDTH)
  4700. #define ADSP_IsInside(pa) (!(pa->bskyabove))
  4701. // room diffusion
  4702. #define ADSP_EMPTY 0
  4703. #define ADSP_SPARSE 1
  4704. #define ADSP_CLUTTERED 2
  4705. #define ADSP_FULL 3
  4706. #define ADSP_DIFFUSION_MAX 4
  4707. #define AROOM_DIF_EMPTY 0.01 // 1% of space by volume is other objects
  4708. #define AROOM_DIF_SPARSE 0.1 // 10% "
  4709. #define AROOM_DIF_CLUTTERED 0.3 // 30% "
  4710. #define AROOM_DIF_FULL 0.5 // 50% "
  4711. #define ADSP_IsEmpty(pa) (pa->fdiffusion <= AROOM_DIF_EMPTY)
  4712. #define ADSP_IsSparse(pa) (BETWEEN(pa->fdiffusion, AROOM_DIF_EMPTY, AROOM_DIF_SPARSE))
  4713. #define ADSP_IsCluttered(pa) (BETWEEN(pa->fdiffusion, AROOM_DIF_SPARSE, AROOM_DIF_CLUTTERED))
  4714. #define ADSP_IsFull(pa) (pa->fdiffusion > AROOM_DIF_CLUTTERED)
  4715. #define ADSP_IsDiffuse(pa) (pa->diffusion > ADSP_SPARSE)
  4716. // room acoustic reflectivity
  4717. // tile 0.3 * 3.3 = 0.99
  4718. // metal 0.25 * 3.3 = 0.83
  4719. // concrete,rock,brick,glass,gravel 0.2 * 3.3 = 0.66
  4720. // metal panel/vent, wood, water 0.1 * 3.3 = 0.33
  4721. // carpet,sand,snow,dirt 0.01 * 3.3 = 0.03
  4722. #define ADSP_DULL 0
  4723. #define ADSP_FLAT 1
  4724. #define ADSP_REFLECTIVE 2
  4725. #define ADSP_BRIGHT 3
  4726. #define ADSP_REFLECTIVITY_MAX 4
  4727. #define AROOM_REF_DULL 0.04
  4728. #define AROOM_REF_FLAT 0.50
  4729. #define AROOM_REF_REFLECTIVE 0.80
  4730. #define AROOM_REF_BRIGHT 0.99
  4731. #define ADSP_IsDull(pa) (pa->freflectivity <= AROOM_REF_DULL)
  4732. #define ADSP_IsFlat(pa) (BETWEEN(pa->freflectivity, AROOM_REF_DULL, AROOM_REF_FLAT))
  4733. #define ADSP_IsReflective(pa) (BETWEEN(pa->freflectivity, AROOM_REF_FLAT, AROOM_REF_REFLECTIVE))
  4734. #define ADSP_IsBright(pa) (pa->freflectivity > AROOM_REF_REFLECTIVE)
  4735. #define ADSP_IsRefl(pa) (pa->reflectivity > ADSP_FLAT)
  4736. // room shapes
  4737. #define ADSP_ROOM 0
  4738. #define ADSP_DUCT 1
  4739. #define ADSP_HALL 2
  4740. #define ADSP_TUNNEL 3
  4741. #define ADSP_STREET 4
  4742. #define ADSP_ALLEY 5
  4743. #define ADSP_COURTYARD 6
  4744. #define ADSP_OPEN_SPACE 7 // NOTE: 7..10 must remain in order !!!
  4745. #define ADSP_OPEN_WALL 8
  4746. #define ADSP_OPEN_STREET 9
  4747. #define ADSP_OPEN_COURTYARD 10
  4748. // room sizes
  4749. #define ADSP_SIZE_SMALL 0 // NOTE: must remain 0..4!!!
  4750. #define ADSP_SIZE_MEDIUM 1
  4751. #define ADSP_SIZE_LARGE 2
  4752. #define ADSP_SIZE_HUGE 3
  4753. #define ADSP_SIZE_GIGANTIC 4
  4754. #define ADSP_SIZE_MAX 5
  4755. #define ADSP_LENGTH_SHORT 0
  4756. #define ADSP_LENGTH_MEDIUM 1
  4757. #define ADSP_LENGTH_LONG 2
  4758. #define ADSP_LENGTH_VLONG 3
  4759. #define ADSP_LENGTH_XLONG 4
  4760. #define ADSP_LENGTH_MAX 5
  4761. #define ADSP_WIDTH_NARROW 0
  4762. #define ADSP_WIDTH_MEDIUM 1
  4763. #define ADSP_WIDTH_WIDE 2
  4764. #define ADSP_WIDTH_VWIDE 3
  4765. #define ADSP_WIDTH_XWIDE 4
  4766. #define ADSP_WIDTH_MAX 5
  4767. #define ADSP_HEIGHT_LOW 0
  4768. #define ADSP_HEIGTH_MEDIUM 1
  4769. #define ADSP_HEIGHT_TALL 2
  4770. #define ADSP_HEIGHT_VTALL 3
  4771. #define ADSP_HEIGHT_XTALL 4
  4772. #define ADSP_HEIGHT_MAX 5
  4773. // convert numeric size params to #defined size params
  4774. void ADSP_GetSize( auto_params_t *pa )
  4775. {
  4776. pa->size = ((ADSP_IsSmallRoom(pa) ? 1 : 0) * ADSP_SIZE_SMALL) +
  4777. ((ADSP_IsMediumRoom(pa) ? 1 : 0) * ADSP_SIZE_MEDIUM) +
  4778. ((ADSP_IsLargeRoom(pa) ? 1 : 0) * ADSP_SIZE_LARGE) +
  4779. ((ADSP_IsHugeRoom(pa) ? 1 : 0) * ADSP_SIZE_HUGE) +
  4780. ((ADSP_IsGiganticRoom(pa) ? 1 : 0) * ADSP_SIZE_GIGANTIC);
  4781. pa->len = ((ADSP_IsShortLength(pa) ? 1 : 0) * ADSP_LENGTH_SHORT) +
  4782. ((ADSP_IsMediumLength(pa) ? 1 : 0) * ADSP_LENGTH_MEDIUM) +
  4783. ((ADSP_IsLongLength(pa) ? 1 : 0) * ADSP_LENGTH_LONG) +
  4784. ((ADSP_IsVLongLength(pa) ? 1 : 0) * ADSP_LENGTH_VLONG) +
  4785. ((ADSP_IsXLongLength(pa) ? 1 : 0) * ADSP_LENGTH_XLONG);
  4786. pa->wid = ((ADSP_IsNarrowWidth(pa) ? 1 : 0) * ADSP_WIDTH_NARROW) +
  4787. ((ADSP_IsMediumWidth(pa) ? 1 : 0) * ADSP_WIDTH_MEDIUM) +
  4788. ((ADSP_IsWideWidth(pa) ? 1 : 0) * ADSP_WIDTH_WIDE) +
  4789. ((ADSP_IsVWideWidth(pa) ? 1 : 0) * ADSP_WIDTH_VWIDE) +
  4790. ((ADSP_IsXWideWidth(pa) ? 1 : 0) * ADSP_WIDTH_XWIDE);
  4791. pa->ht = ((ADSP_IsLowHeight(pa) ? 1 : 0) * ADSP_HEIGHT_LOW) +
  4792. ((ADSP_IsMediumHeight(pa) ? 1 : 0) * ADSP_HEIGTH_MEDIUM) +
  4793. ((ADSP_IsTallHeight(pa) ? 1 : 0) * ADSP_HEIGHT_TALL) +
  4794. ((ADSP_IsVTallHeight(pa) ? 1 : 0) * ADSP_HEIGHT_VTALL) +
  4795. ((ADSP_IsXTallHeight(pa) ? 1 : 0) * ADSP_HEIGHT_XTALL);
  4796. pa->reflectivity =
  4797. ((ADSP_IsDull(pa) ? 1 : 0) * ADSP_DULL) +
  4798. ((ADSP_IsFlat(pa) ? 1 : 0) * ADSP_FLAT) +
  4799. ((ADSP_IsReflective(pa) ? 1 : 0) * ADSP_REFLECTIVE) +
  4800. ((ADSP_IsBright(pa) ? 1 : 0) * ADSP_BRIGHT);
  4801. pa->diffusion =
  4802. ((ADSP_IsEmpty(pa) ? 1 : 0) * ADSP_EMPTY) +
  4803. ((ADSP_IsSparse(pa) ? 1 : 0) * ADSP_SPARSE) +
  4804. ((ADSP_IsCluttered(pa) ? 1 : 0) * ADSP_CLUTTERED) +
  4805. ((ADSP_IsFull(pa) ? 1 : 0) * ADSP_FULL);
  4806. Assert(pa->size < ADSP_SIZE_MAX);
  4807. Assert(pa->len < ADSP_LENGTH_MAX);
  4808. Assert(pa->wid < ADSP_WIDTH_MAX);
  4809. Assert(pa->ht < ADSP_HEIGHT_MAX);
  4810. Assert(pa->reflectivity < ADSP_REFLECTIVITY_MAX);
  4811. Assert(pa->diffusion < ADSP_DIFFUSION_MAX);
  4812. if ( pa->shape != ADSP_COURTYARD && pa->shape != ADSP_OPEN_COURTYARD )
  4813. {
  4814. // fix up size for streets, alleys, halls, ducts, tunnelsy
  4815. if (pa->shape == ADSP_STREET || pa->shape == ADSP_ALLEY )
  4816. pa->size = pa->wid;
  4817. else
  4818. pa->size = (pa->len + pa->wid) / 2;
  4819. }
  4820. }
  4821. void ADSP_GetOutsideSize( auto_params_t *pa )
  4822. {
  4823. ADSP_GetSize( pa );
  4824. }
  4825. // return # of sides that had max length or sky hits (out of 6 sides).
  4826. int ADSP_COpenSides( auto_params_t *pa )
  4827. {
  4828. int count = 0;
  4829. // only look at left,right,front,back walls - ignore floor, ceiling
  4830. for (int i = 0; i < 4; i++)
  4831. {
  4832. if (pa->surface_refl[i] == 0.0)
  4833. count++;
  4834. }
  4835. return count;
  4836. }
  4837. // given auto params, return shape and size of room
  4838. void ADSP_GetAutoShape( auto_params_t *pa )
  4839. {
  4840. // INSIDE:
  4841. // shapes: duct, hall, tunnel, shaft (vertical duct, hall or tunnel)
  4842. // sizes: short->long, narrow->wide, low->tall
  4843. // shapes: room
  4844. // sizes: small->large, low->tall
  4845. // OUTSIDE:
  4846. // shapes: street, alley
  4847. // sizes: short->long, narrow->wide
  4848. // shapes: courtyard
  4849. // sizes: small->large
  4850. // shapes: open_space, wall, open_street, open_corner, open_courtyard
  4851. // sizes: open, narrow->wide
  4852. bool bshaft = false;
  4853. int t;
  4854. if (ADSP_IsInside(pa))
  4855. {
  4856. if (ADSP_IsShaft(pa))
  4857. {
  4858. // temp swap height and length
  4859. bshaft = true;
  4860. t = pa->height;
  4861. pa->height = pa->length;
  4862. pa->length = t;
  4863. if (das_debug.GetInt() > 1)
  4864. DevMsg("VERTICAL SHAFT Detected \n");
  4865. }
  4866. // get shape
  4867. if (ADSP_IsDuct(pa))
  4868. {
  4869. pa->shape = ADSP_DUCT;
  4870. ADSP_GetSize( pa );
  4871. if (das_debug.GetInt() > 1)
  4872. DevMsg("DUCT Detected \n");
  4873. goto autoshape_exit;
  4874. }
  4875. if (ADSP_IsHall(pa))
  4876. {
  4877. // get size
  4878. pa->shape = ADSP_HALL;
  4879. ADSP_GetSize( pa );
  4880. if (das_debug.GetInt() > 1)
  4881. DevMsg("HALL Detected \n");
  4882. goto autoshape_exit;
  4883. }
  4884. if (ADSP_IsTunnel(pa))
  4885. {
  4886. // get size
  4887. pa->shape = ADSP_TUNNEL;
  4888. ADSP_GetSize( pa );
  4889. if (das_debug.GetInt() > 1)
  4890. DevMsg("TUNNEL Detected \n");
  4891. goto autoshape_exit;
  4892. }
  4893. // default
  4894. // (ADSP_IsRoom(pa))
  4895. {
  4896. // get size
  4897. pa->shape = ADSP_ROOM;
  4898. ADSP_GetSize( pa );
  4899. if (das_debug.GetInt() > 1)
  4900. DevMsg("ROOM Detected \n");
  4901. goto autoshape_exit;
  4902. }
  4903. }
  4904. // outside:
  4905. if (ADSP_COpenSides(pa) > 0) // side hit sky, or side has max length
  4906. {
  4907. // get shape - courtyard, street, wall or open space
  4908. // 10..7
  4909. pa->shape = ADSP_OPEN_COURTYARD - (ADSP_COpenSides(pa) - 1);
  4910. ADSP_GetOutsideSize( pa );
  4911. if (das_debug.GetInt() > 1)
  4912. DevMsg("OPEN SIDED OUTDOOR AREA Detected \n");
  4913. goto autoshape_exit;
  4914. }
  4915. // all sides closed:
  4916. // get shape - closed street or alley or courtyard
  4917. if (ADSP_IsCourtyard(pa))
  4918. {
  4919. pa->shape = ADSP_COURTYARD;
  4920. ADSP_GetOutsideSize( pa );
  4921. if (das_debug.GetInt() > 1)
  4922. DevMsg("OUTSIDE COURTYARD Detected \n");
  4923. goto autoshape_exit;
  4924. }
  4925. if (ADSP_IsAlley(pa))
  4926. {
  4927. pa->shape = ADSP_ALLEY;
  4928. ADSP_GetOutsideSize( pa );
  4929. if (das_debug.GetInt() > 1)
  4930. DevMsg("OUTSIDE ALLEY Detected \n");
  4931. goto autoshape_exit;
  4932. }
  4933. // default to 'street' if sides are closed
  4934. // if (ADSP_IsStreet(pa))
  4935. {
  4936. pa->shape = ADSP_STREET;
  4937. ADSP_GetOutsideSize( pa );
  4938. if (das_debug.GetInt() > 1)
  4939. DevMsg("OUTSIDE STREET Detected \n");
  4940. goto autoshape_exit;
  4941. }
  4942. autoshape_exit:
  4943. // swap height & length if needed
  4944. if (bshaft)
  4945. {
  4946. t = pa->height;
  4947. pa->height = pa->length;
  4948. pa->length = t;
  4949. }
  4950. }
  4951. int MapReflectivityToDLYCutoff[] =
  4952. {
  4953. 1000, // DULL
  4954. 2000, // FLAT
  4955. 4000, // REFLECTIVE
  4956. 6000 // BRIGHT
  4957. };
  4958. float MapSizeToDLYFeedback[] =
  4959. {
  4960. 0.9, // 0.6, // SMALL
  4961. 0.8, // 0.5, // MEDIUM
  4962. 0.7, // 0.4, // LARGE
  4963. 0.6, // 0.3, // HUGE
  4964. 0.5, // 0.2, // GIGANTIC
  4965. };
  4966. void ADSP_SetupAutoDelay( prc_t *pprc_dly, auto_params_t *pa )
  4967. {
  4968. // shapes:
  4969. // inside: duct, long hall, long tunnel, large room
  4970. // outside: open courtyard, street wall, space
  4971. // outside: closed courtyard, alley, street
  4972. // size 0..4
  4973. // len 0..3
  4974. // wid 0..3
  4975. // reflectivity: 0..3
  4976. // diffusion 0..3
  4977. // dtype: delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  4978. // delay: delay in milliseconds (room max size in feet)
  4979. // feedback: feedback 0-1.0
  4980. // gain: final gain of output stage, 0-1.0
  4981. int size = pa->length * 2.0;
  4982. if (pa->shape == ADSP_ALLEY || pa->shape == ADSP_STREET || pa->shape == ADSP_OPEN_STREET)
  4983. size = pa->width * 2.0;
  4984. pprc_dly->type = PRC_DLY;
  4985. pprc_dly->prm[dly_idtype] = DLY_LOWPASS; // delay with feedback
  4986. pprc_dly->prm[dly_idelay] = clamp((size / 12.0), 5.0, 500.0);
  4987. pprc_dly->prm[dly_ifeedback] = MapSizeToDLYFeedback[pa->len];
  4988. // reduce gain based on distance reflection travels
  4989. // float g = 1.0 - ( clamp(pprc_dly->prm[dly_idelay], 10.0, 1000.0) / (1000.0 - 10.0) );
  4990. // pprc_dly->prm[dly_igain] = g;
  4991. pprc_dly->prm[dly_iftype] = FLT_LP;
  4992. if (ADSP_IsInside(pa))
  4993. pprc_dly->prm[dly_icutoff] = MapReflectivityToDLYCutoff[pa->reflectivity];
  4994. else
  4995. pprc_dly->prm[dly_icutoff] = (int)((float)(MapReflectivityToDLYCutoff[pa->reflectivity]) * 0.75);
  4996. pprc_dly->prm[dly_iqwidth] = 0;
  4997. pprc_dly->prm[dly_iquality] = QUA_LO;
  4998. float l = clamp((pa->length * 2.0 / 12.0), 14.0, 500.0);
  4999. float w = clamp((pa->width * 2.0 / 12.0), 14.0, 500.0);
  5000. // convert to multitap delay
  5001. pprc_dly->prm[dly_idtype] = DLY_LOWPASS_4TAP;
  5002. pprc_dly->prm[dly_idelay] = l;
  5003. pprc_dly->prm[dly_itap1] = w;
  5004. pprc_dly->prm[dly_itap2] = l; // max(7, l * 0.7 );
  5005. pprc_dly->prm[dly_itap3] = l; // max(7, w * 0.7 );
  5006. pprc_dly->prm[dly_igain] = 1.0;
  5007. }
  5008. int MapReflectivityToRVACutoff[] =
  5009. {
  5010. 1000, // DULL
  5011. 2000, // FLAT
  5012. 4000, // REFLECTIVE
  5013. 6000 // BRIGHT
  5014. };
  5015. float MapSizeToRVANumDelays[] =
  5016. {
  5017. 3, // SMALL 3 reverbs
  5018. 6, // MEDIUM 6 reverbs
  5019. 6, // LARGE 6 reverbs
  5020. 9, // HUGE 9 reverbs
  5021. 12, // GIGANTIC 12 reverbs
  5022. };
  5023. float MapSizeToRVAFeedback[] =
  5024. {
  5025. 0.75, // SMALL
  5026. 0.8, // MEDIUM
  5027. 0.9, // LARGE
  5028. 0.95, // HUGE
  5029. 0.98, // GIGANTIC
  5030. };
  5031. void ADSP_SetupAutoReverb( prc_t *pprc_rva, auto_params_t *pa )
  5032. {
  5033. // shape: hall, tunnel or room
  5034. // size 0..4
  5035. // reflectivity: 0..3
  5036. // diffusion 0..3
  5037. // size: 0-2.0 scales nominal delay parameters (18 to 47 ms * scale = delay)
  5038. // numdelays: 0-12 controls # of parallel or series delays
  5039. // decay: 0-2.0 scales feedback parameters (.7 to .9 * scale/2.0 = feedback)
  5040. // fparallel: if true, filters are built into delays, otherwise filter output only
  5041. // fmoddly: if true, all delays are modulating delays
  5042. float gain = 1.0;
  5043. pprc_rva->type = PRC_RVA;
  5044. pprc_rva->prm[rva_size_max] = 50.0;
  5045. pprc_rva->prm[rva_size_min] = 30.0;
  5046. if (ADSP_IsRoom(pa))
  5047. pprc_rva->prm[rva_inumdelays] = MapSizeToRVANumDelays[pa->size];
  5048. else
  5049. pprc_rva->prm[rva_inumdelays] = MapSizeToRVANumDelays[pa->len];
  5050. pprc_rva->prm[rva_ifeedback] = 0.9;
  5051. pprc_rva->prm[rva_icutoff] = MapReflectivityToRVACutoff[pa->reflectivity];
  5052. pprc_rva->prm[rva_ifparallel] = 1;
  5053. pprc_rva->prm[rva_imoddly] = ADSP_IsEmpty(pa) ? 0 : 4;
  5054. pprc_rva->prm[rva_imodrate] = 3.48;
  5055. pprc_rva->prm[rva_iftaps] = 0; // 0.1 // use extra delay taps to increase density
  5056. pprc_rva->prm[rva_width] = clamp( ((float)(pa->width) / 12.0), 6.0, 500.0); // in feet
  5057. pprc_rva->prm[rva_depth] = clamp( ((float)(pa->length) / 12.0), 6.0, 500.0);
  5058. pprc_rva->prm[rva_height] = clamp( ((float)(pa->height) / 12.0), 6.0, 500.0);
  5059. // room
  5060. pprc_rva->prm[rva_fbwidth] = 0.9; // MapSizeToRVAFeedback[pa->size]; // larger size = more feedback
  5061. pprc_rva->prm[rva_fbdepth] = 0.9; // MapSizeToRVAFeedback[pa->size];
  5062. pprc_rva->prm[rva_fbheight] = 0.5; // MapSizeToRVAFeedback[pa->size];
  5063. // feedback is based on size of room:
  5064. if (ADSP_IsInside(pa))
  5065. {
  5066. if (pa->shape == ADSP_HALL)
  5067. {
  5068. pprc_rva->prm[rva_fbwidth] = 0.7; //MapSizeToRVAFeedback[pa->wid];
  5069. pprc_rva->prm[rva_fbdepth] = -0.5; //MapSizeToRVAFeedback[pa->len];
  5070. pprc_rva->prm[rva_fbheight] = 0.3; //MapSizeToRVAFeedback[pa->ht];
  5071. }
  5072. if (pa->shape == ADSP_TUNNEL)
  5073. {
  5074. pprc_rva->prm[rva_fbwidth] = 0.9;
  5075. pprc_rva->prm[rva_fbdepth] = -0.8; // fixed pre-delay, no feedback
  5076. pprc_rva->prm[rva_fbheight] = 0.3;
  5077. }
  5078. }
  5079. else
  5080. {
  5081. if (pa->shape == ADSP_ALLEY)
  5082. {
  5083. pprc_rva->prm[rva_fbwidth] = 0.9;
  5084. pprc_rva->prm[rva_fbdepth] = -0.8; // fixed pre-delay, no feedback
  5085. pprc_rva->prm[rva_fbheight] = 0.0;
  5086. }
  5087. }
  5088. if (!ADSP_IsInside(pa))
  5089. pprc_rva->prm[rva_fbheight] = 0.0;
  5090. pprc_rva->prm[rva_igain] = gain;
  5091. }
  5092. // diffusor templates for auto create
  5093. // size: 0-1.0 scales all delays (13ms to 41ms * scale = delay)
  5094. // numdelays: 0-4.0 controls # of series delays
  5095. // decay: 0-1.0 scales all feedback parameters
  5096. // prctype size #dly feedback
  5097. #if 0
  5098. #define PRC_DFRA_S {PRC_DFR, {0.5, 2, 0.10}, NULL,NULL,NULL,NULL,NULL} // S room
  5099. #define PRC_DFRA_M {PRC_DFR, {0.75, 2, 0.12}, NULL,NULL,NULL,NULL,NULL} // M room
  5100. #define PRC_DFRA_L {PRC_DFR, {1.0, 3, 0.13}, NULL,NULL,NULL,NULL,NULL} // L room
  5101. #define PRC_DFRA_VL {PRC_DFR, {1.0, 3, 0.15}, NULL,NULL,NULL,NULL,NULL} // VL room
  5102. prc_t g_prc_dfr_auto[] = {PRC_DFRA_S, PRC_DFRA_M, PRC_DFRA_L, PRC_DFRA_VL, PRC_DFRA_VL};
  5103. //$BUGBUGBUG: I think this should be sizeof(prc_t), not sizeof(pset_t)...
  5104. #define CDFRTEMPLATES (sizeof(g_prc_dfr_auto)/sizeof(pset_t)) // number of diffusor templates
  5105. // copy diffusor template from preset list, based on room size
  5106. void ADSP_SetupAutoDiffusor( prc_t *pprc_dfr, auto_params_t *pa )
  5107. {
  5108. int i = clamp(pa->size, 0, (int)CDFRTEMPLATES - 1);
  5109. // copy diffusor preset based on size
  5110. *pprc_dfr = g_prc_dfr_auto[i];
  5111. }
  5112. #endif
  5113. // return index to processor given processor type and preset
  5114. // skips N processors of similar type
  5115. // returns -1 if type not found
  5116. int ADSP_FindProc( pset_t *ppset, int proc_type, int skip )
  5117. {
  5118. int skipcount = skip;
  5119. for (int i = 0; i < ppset->cprcs; i++)
  5120. {
  5121. // look for match on processor type
  5122. if ( ppset->prcs[i].type == proc_type )
  5123. {
  5124. // skip first N procs of similar type,
  5125. // return index to processor
  5126. if (!skipcount)
  5127. return i;
  5128. skipcount--;
  5129. }
  5130. }
  5131. return -1;
  5132. }
  5133. // interpolate parameter:
  5134. // pnew - target preset
  5135. // pmin - preset with parameter with min value
  5136. // pmax - preset with parameter with max value
  5137. // proc_type - type of processor to look for ie: PRC_RVA or PRC_DLY
  5138. // skipprocs - skip n processors of type
  5139. // iparam - which parameter within processor to interpolate
  5140. // index -
  5141. // index_max: use index/index_max as interpolater between pmin param and pmax param
  5142. // if bexp is true, interpolate exponentially as (index/index_max)^2
  5143. // NOTE: returns with no result if processor type is not found in all presets.
  5144. void ADSP_InterpParam( pset_t *pnew, pset_t *pmin, pset_t *pmax, int proc_type, int skipprocs, int iparam, int index, int index_max, bool bexp )
  5145. {
  5146. // find processor index in pnew
  5147. int iproc_new = ADSP_FindProc( pnew, proc_type, skipprocs);
  5148. int iproc_min = ADSP_FindProc( pmin, proc_type, skipprocs);
  5149. int iproc_max = ADSP_FindProc( pmax, proc_type, skipprocs);
  5150. // make sure processor type found in all presets
  5151. if ( iproc_new < 0 || iproc_min < 0 || iproc_max < 0 )
  5152. return;
  5153. float findex = (float)index/(float)index_max;
  5154. float vmin = pmin->prcs[iproc_min].prm[iparam];
  5155. float vmax = pmax->prcs[iproc_max].prm[iparam];
  5156. float vinterp;
  5157. // interpolate
  5158. if (!bexp)
  5159. vinterp = vmin + (vmax - vmin) * findex;
  5160. else
  5161. vinterp = vmin + (vmax - vmin) * findex * findex;
  5162. pnew->prcs[iproc_new].prm[iparam] = vinterp;
  5163. return;
  5164. }
  5165. // directly set parameter
  5166. void ADSP_SetParam( pset_t *pnew, int proc_type, int skipprocs, int iparam, float value )
  5167. {
  5168. int iproc_new = ADSP_FindProc( pnew, proc_type, skipprocs);
  5169. if (iproc_new >= 0)
  5170. pnew->prcs[iproc_new].prm[iparam] = value;
  5171. }
  5172. // directly set parameter if min or max is negative
  5173. void ADSP_SetParamIfNegative( pset_t *pnew, pset_t *pmin, pset_t *pmax, int proc_type, int skipprocs, int iparam, int index, int index_max, bool bexp, float value )
  5174. {
  5175. // find processor index in pnew
  5176. int iproc_new = ADSP_FindProc( pnew, proc_type, skipprocs);
  5177. int iproc_min = ADSP_FindProc( pmin, proc_type, skipprocs);
  5178. int iproc_max = ADSP_FindProc( pmax, proc_type, skipprocs);
  5179. // make sure processor type found in all presets
  5180. if ( iproc_new < 0 || iproc_min < 0 || iproc_max < 0 )
  5181. return;
  5182. float vmin = pmin->prcs[iproc_min].prm[iparam];
  5183. float vmax = pmax->prcs[iproc_max].prm[iparam];
  5184. if ( vmin < 0.0 || vmax < 0.0 )
  5185. ADSP_SetParam( pnew, proc_type, skipprocs, iparam, value );
  5186. else
  5187. ADSP_InterpParam( pnew, pmin, pmax, proc_type, skipprocs, iparam, index, index_max, bexp);
  5188. return;
  5189. }
  5190. // given min and max preset and auto parameters, create new preset
  5191. // NOTE: the # and type of processors making up pmin and pmax presets must be identical!
  5192. void ADSP_InterpolatePreset( pset_t *pnew, pset_t *pmin, pset_t *pmax, auto_params_t *pa, int iskip )
  5193. {
  5194. int i;
  5195. // if size > mid size, then copy basic processors from MAX preset,
  5196. // otherwise, copy from MIN preset
  5197. if ( !iskip )
  5198. {
  5199. // only copy on 1st call
  5200. if ( pa->size > ADSP_SIZE_MEDIUM )
  5201. {
  5202. *pnew = *pmax;
  5203. }
  5204. else
  5205. {
  5206. *pnew = *pmin;
  5207. }
  5208. }
  5209. // DFR
  5210. // interpolate all DFR params on size
  5211. for (i = 0; i < dfr_cparam; i++)
  5212. ADSP_InterpParam( pnew, pmin, pmax, PRC_DFR, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5213. // RVA
  5214. // interpolate size_max, size_min, feedback, #delays, moddly, imodrate, based on ap size
  5215. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_ifeedback, pa->size, ADSP_SIZE_MAX, 0);
  5216. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_size_min, pa->size, ADSP_SIZE_MAX, 1);
  5217. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_size_max, pa->size, ADSP_SIZE_MAX, 1);
  5218. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_igain, pa->size, ADSP_SIZE_MAX, 0);
  5219. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_inumdelays, pa->size, ADSP_SIZE_MAX , 0);
  5220. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_imoddly, pa->size, ADSP_SIZE_MAX , 0);
  5221. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_imodrate, pa->size, ADSP_SIZE_MAX , 0);
  5222. // interpolate width,depth,height based on ap width length & height - exponential interpolation
  5223. // if pmin or pmax parameters are < 0, directly set value from w/l/h
  5224. float w = clamp( ((float)(pa->width) / 12.0), 6.0, 500.0); // in feet
  5225. float l = clamp( ((float)(pa->length) / 12.0), 6.0, 500.0);
  5226. float h = clamp( ((float)(pa->height) / 12.0), 6.0, 500.0);
  5227. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_RVA, iskip, rva_width, pa->wid, ADSP_WIDTH_MAX, 1, w);
  5228. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_RVA, iskip, rva_depth, pa->len, ADSP_LENGTH_MAX, 1, l);
  5229. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_RVA, iskip, rva_height, pa->ht, ADSP_HEIGHT_MAX, 1, h);
  5230. // interpolate w/d/h feedback based on ap w/d/f
  5231. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_fbwidth, pa->wid, ADSP_WIDTH_MAX , 0);
  5232. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_fbdepth, pa->len, ADSP_LENGTH_MAX , 0);
  5233. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_fbheight, pa->ht, ADSP_HEIGHT_MAX , 0);
  5234. // interpolate cutoff based on ap reflectivity
  5235. // NOTE: cutoff goes from max to min! ie: small bright - large dull
  5236. ADSP_InterpParam( pnew, pmax, pmin, PRC_RVA, iskip, rva_icutoff, pa->reflectivity, ADSP_REFLECTIVITY_MAX , 0);
  5237. // don't interpolate: fparallel, ftaps
  5238. // DLY
  5239. // directly set delay value from pa->length if pmin or pmax value is < 0
  5240. l = clamp((pa->length * 2.0 / 12.0), 14.0, 500.0);
  5241. w = clamp((pa->width * 2.0 / 12.0), 14.0, 500.0);
  5242. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_idelay, pa->len, ADSP_LENGTH_MAX, 1, l);
  5243. // interpolate feedback, gain, based on max size (length)
  5244. ADSP_InterpParam( pnew, pmin, pmax, PRC_DLY, iskip, dly_ifeedback, pa->len, ADSP_LENGTH_MAX , 0);
  5245. ADSP_InterpParam( pnew, pmin, pmax, PRC_DLY, iskip, dly_igain, pa->len, ADSP_LENGTH_MAX , 0);
  5246. // directly set tap value from pa->width if pmin or pmax value is < 0
  5247. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_itap1, pa->len, ADSP_LENGTH_MAX, 1, w);
  5248. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_itap2, pa->len, ADSP_LENGTH_MAX, 1, l);
  5249. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_itap3, pa->len, ADSP_LENGTH_MAX, 1, l);
  5250. // interpolate cutoff and qwidth based on reflectivity NOTE: this can affect gain!
  5251. // NOTE: cutoff goes from max to min! ie: small bright - large dull
  5252. ADSP_InterpParam( pnew, pmax, pmin, PRC_DLY, iskip, dly_icutoff, pa->len, ADSP_LENGTH_MAX , 0);
  5253. ADSP_InterpParam( pnew, pmax, pmin, PRC_DLY, iskip, dly_iqwidth, pa->len, ADSP_LENGTH_MAX , 0);
  5254. // interpolate all other parameters for all other processor types based on size
  5255. // PRC_MDY, PRC_AMP, PRC_FLT, PTC, CRS, ENV, EFO, LFO
  5256. for (i = 0; i < mdy_cparam; i++)
  5257. ADSP_InterpParam( pnew, pmin, pmax, PRC_MDY, iskip, i, pa->len, ADSP_LENGTH_MAX , 0);
  5258. for (i = 0; i < amp_cparam; i++)
  5259. ADSP_InterpParam( pnew, pmin, pmax, PRC_AMP, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5260. for (i = 0; i < flt_cparam; i++)
  5261. ADSP_InterpParam( pnew, pmin, pmax, PRC_FLT, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5262. for (i = 0; i < ptc_cparam; i++)
  5263. ADSP_InterpParam( pnew, pmin, pmax, PRC_PTC, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5264. for (i = 0; i < crs_cparam; i++)
  5265. ADSP_InterpParam( pnew, pmin, pmax, PRC_CRS, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5266. for (i = 0; i < env_cparam; i++)
  5267. ADSP_InterpParam( pnew, pmin, pmax, PRC_ENV, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5268. for (i = 0; i < efo_cparam; i++)
  5269. ADSP_InterpParam( pnew, pmin, pmax, PRC_EFO, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5270. for (i = 0; i < lfo_cparam; i++)
  5271. ADSP_InterpParam( pnew, pmin, pmax, PRC_LFO, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  5272. }
  5273. // these convars store the index to the first preset for each shape type in dsp_presets.txt
  5274. ConVar adsp_room_min ("adsp_room_min", "102");
  5275. ConVar adsp_duct_min ("adsp_duct_min", "106");
  5276. ConVar adsp_hall_min ("adsp_hall_min", "110");
  5277. ConVar adsp_tunnel_min ("adsp_tunnel_min", "114");
  5278. ConVar adsp_street_min ("adsp_street_min", "118");
  5279. ConVar adsp_alley_min ("adsp_alley_min", "122");
  5280. ConVar adsp_courtyard_min ("adsp_courtyard_min", "126");
  5281. ConVar adsp_openspace_min ("adsp_openspace_min", "130");
  5282. ConVar adsp_openwall_min ("adsp_openwall_min", "130");
  5283. ConVar adsp_openstreet_min ("adsp_openstreet_min", "118");
  5284. ConVar adsp_opencourtyard_min ("adsp_opencourtyard_min", "126");
  5285. // given room parameters, construct and return a dsp preset representing the room.
  5286. // bskyabove, width, length, height, fdiffusion, freflectivity are all passed-in room parameters
  5287. // psurf_refl is a passed-in array of reflectivity values for 6 surfaces
  5288. // inode is the location within g_psettemplates[] that the dsp preset will be constructed (inode = dsp preset#)
  5289. // cnode should always = DSP_CAUTO_PRESETS
  5290. // returns idsp preset.
  5291. int DSP_ConstructPreset( bool bskyabove, int width, int length, int height, float fdiffusion, float freflectivity, float *psurf_refl, int inode, int cnodes )
  5292. {
  5293. auto_params_t ap;
  5294. auto_params_t *pa;
  5295. pset_t new_pset; // preset
  5296. pset_t pset_min;
  5297. pset_t pset_max;
  5298. int ipreset;
  5299. int ipset_min;
  5300. int ipset_max;
  5301. if (inode >= DSP_CAUTO_PRESETS)
  5302. {
  5303. Assert(false); // check DAS_CNODES == DSP_CAUTO_PRESETS!!!
  5304. return 0;
  5305. }
  5306. // fill parameter struct
  5307. ap.bskyabove = bskyabove;
  5308. ap.width = width;
  5309. ap.length = length;
  5310. ap.height = height;
  5311. ap.fdiffusion = fdiffusion;
  5312. ap.freflectivity = freflectivity;
  5313. for (int i = 0; i < 6; i++)
  5314. ap.surface_refl[i] = psurf_refl[i];
  5315. if (ap.bskyabove)
  5316. ap.surface_refl[4] = 0.0;
  5317. // select shape, size based on params
  5318. ADSP_GetAutoShape( &ap );
  5319. // set up min/max presets based on shape
  5320. switch ( ap.shape )
  5321. {
  5322. default:
  5323. case ADSP_ROOM: ipset_min = adsp_room_min.GetInt(); break;
  5324. case ADSP_DUCT: ipset_min = adsp_duct_min.GetInt(); break;
  5325. case ADSP_HALL: ipset_min = adsp_hall_min.GetInt(); break;
  5326. case ADSP_TUNNEL: ipset_min = adsp_tunnel_min.GetInt(); break;
  5327. case ADSP_STREET: ipset_min = adsp_street_min.GetInt(); break;
  5328. case ADSP_ALLEY: ipset_min = adsp_alley_min.GetInt(); break;
  5329. case ADSP_COURTYARD: ipset_min = adsp_courtyard_min.GetInt(); break;
  5330. case ADSP_OPEN_SPACE: ipset_min = adsp_openspace_min.GetInt(); break;
  5331. case ADSP_OPEN_WALL: ipset_min = adsp_openwall_min.GetInt(); break;
  5332. case ADSP_OPEN_STREET: ipset_min = adsp_openstreet_min.GetInt(); break;
  5333. case ADSP_OPEN_COURTYARD: ipset_min = adsp_opencourtyard_min.GetInt(); break;
  5334. }
  5335. // presets in dsp_presets.txt are ordered as:
  5336. // <shape><empty><min>
  5337. // <shape><empty><max>
  5338. // <shape><diffuse><min>
  5339. // <shape><diffuse><max>
  5340. pa = &ap;
  5341. if ( ADSP_IsDiffuse(pa) )
  5342. ipset_min += 2;
  5343. ipset_max = ipset_min + 1;
  5344. pset_min = g_psettemplates[ipset_min];
  5345. pset_max = g_psettemplates[ipset_max];
  5346. // given min and max preset and auto parameters, create new preset
  5347. // interpolate between 1st instances of each processor type (ie: PRC_DLY) appearing in preset
  5348. ADSP_InterpolatePreset( &new_pset, &pset_min, &pset_max, &ap, 0 );
  5349. // interpolate between 2nd instances of each processor type (ie: PRC_DLY) appearing in preset
  5350. ADSP_InterpolatePreset( &new_pset, &pset_min, &pset_max, &ap, 1 );
  5351. // copy constructed preset back into node's template location
  5352. ipreset = DSP_AUTO_BASE + inode;
  5353. g_psettemplates[ipreset] = new_pset;
  5354. return ipreset;
  5355. }
  5356. ///////////////////////////////////////
  5357. // Helpers: called only from DSP_Process
  5358. ///////////////////////////////////////
  5359. // return true if batch processing version of preset exists
  5360. inline bool FBatchPreset( pset_t *ppset )
  5361. {
  5362. switch (ppset->type)
  5363. {
  5364. case PSET_LINEAR:
  5365. return true;
  5366. case PSET_SIMPLE:
  5367. return true;
  5368. default:
  5369. return false;
  5370. }
  5371. }
  5372. // Helper: called only from DSP_Process
  5373. // mix front stereo buffer to mono buffer, apply dsp fx
  5374. inline void DSP_ProcessStereoToMono(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  5375. {
  5376. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  5377. int count = sampleCount;
  5378. int av;
  5379. int x;
  5380. if ( !bcrossfading )
  5381. {
  5382. if ( !pdsp->ipset )
  5383. return;
  5384. if ( FBatchPreset(pdsp->ppset[0]))
  5385. {
  5386. // convert Stereo to Mono in place, then batch process fx: perf KDB
  5387. // front->left + front->right / 2 into front->left, front->right duplicated.
  5388. while ( count-- )
  5389. {
  5390. pbf->left = (pbf->left + pbf->right) >> 1;
  5391. pbf++;
  5392. }
  5393. // process left (mono), duplicate output into right
  5394. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  5395. }
  5396. else
  5397. {
  5398. // avg left and right -> mono fx -> duplcate out left and right
  5399. while ( count-- )
  5400. {
  5401. av = ( ( pbf->left + pbf->right ) >> 1 );
  5402. x = PSET_GetNext( pdsp->ppset[0], av );
  5403. x = CLIP_DSP( x );
  5404. pbf->left = pbf->right = x;
  5405. pbf++;
  5406. }
  5407. }
  5408. return;
  5409. }
  5410. // crossfading to current preset from previous preset
  5411. if ( bcrossfading )
  5412. {
  5413. int r;
  5414. int fl;
  5415. int fr;
  5416. int flp;
  5417. int frp;
  5418. int xf_fl;
  5419. int xf_fr;
  5420. bool bexp = pdsp->bexpfade;
  5421. bool bfadetostereo = (pdsp->ipset == 0);
  5422. bool bfadefromstereo = (pdsp->ipsetprev == 0);
  5423. Assert ( !(bfadetostereo && bfadefromstereo) ); // don't call if ipset & ipsetprev both 0!
  5424. if ( bfadetostereo || bfadefromstereo )
  5425. {
  5426. // special case if fading to or from preset 0, stereo passthrough
  5427. while ( count-- )
  5428. {
  5429. av = ( ( pbf->left + pbf->right ) >> 1 );
  5430. // get current preset values
  5431. if ( pdsp->ipset )
  5432. {
  5433. fl = fr = PSET_GetNext( pdsp->ppset[0], av );
  5434. }
  5435. else
  5436. {
  5437. fl = pbf->left;
  5438. fr = pbf->right;
  5439. }
  5440. // get previous preset values
  5441. if ( pdsp->ipsetprev )
  5442. {
  5443. frp = flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  5444. }
  5445. else
  5446. {
  5447. flp = pbf->left;
  5448. frp = pbf->right;
  5449. }
  5450. fl = CLIP_DSP(fl);
  5451. fr = CLIP_DSP(fr);
  5452. flp = CLIP_DSP(flp);
  5453. frp = CLIP_DSP(frp);
  5454. // get current ramp value
  5455. r = RMP_GetNext( &pdsp->xramp );
  5456. // crossfade from previous to current preset
  5457. if (!bexp)
  5458. {
  5459. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5460. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  5461. }
  5462. else
  5463. {
  5464. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5465. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  5466. }
  5467. pbf->left = xf_fl; // crossfaded front left, duplicate in right channel
  5468. pbf->right = xf_fr;
  5469. pbf++;
  5470. }
  5471. return;
  5472. }
  5473. // crossfade mono to mono preset
  5474. while ( count-- )
  5475. {
  5476. av = ( ( pbf->left + pbf->right ) >> 1 );
  5477. // get current preset values
  5478. fl = PSET_GetNext( pdsp->ppset[0], av );
  5479. // get previous preset values
  5480. flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  5481. fl = CLIP_DSP(fl);
  5482. flp = CLIP_DSP(flp);
  5483. // get current ramp value
  5484. r = RMP_GetNext( &pdsp->xramp );
  5485. // crossfade from previous to current preset
  5486. if (!bexp)
  5487. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5488. else
  5489. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5490. pbf->left = xf_fl; // crossfaded front left, duplicate in right channel
  5491. pbf->right = xf_fl;
  5492. pbf++;
  5493. }
  5494. }
  5495. }
  5496. // Helper: called only from DSP_Process
  5497. // DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
  5498. inline void DSP_ProcessStereoToStereo(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  5499. {
  5500. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  5501. int count = sampleCount;
  5502. int fl, fr;
  5503. if ( !bcrossfading )
  5504. {
  5505. if ( !pdsp->ipset )
  5506. return;
  5507. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) )
  5508. {
  5509. // process left & right
  5510. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT );
  5511. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  5512. }
  5513. else
  5514. {
  5515. // left -> left fx, right -> right fx
  5516. while ( count-- )
  5517. {
  5518. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  5519. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  5520. fl = CLIP_DSP( fl );
  5521. fr = CLIP_DSP( fr );
  5522. pbf->left = fl;
  5523. pbf->right = fr;
  5524. pbf++;
  5525. }
  5526. }
  5527. return;
  5528. }
  5529. // crossfading to current preset from previous preset
  5530. if ( bcrossfading )
  5531. {
  5532. int r;
  5533. int flp, frp;
  5534. int xf_fl, xf_fr;
  5535. bool bexp = pdsp->bexpfade;
  5536. while ( count-- )
  5537. {
  5538. // get current preset values
  5539. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  5540. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  5541. // get previous preset values
  5542. flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  5543. frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  5544. // get current ramp value
  5545. r = RMP_GetNext( &pdsp->xramp );
  5546. fl = CLIP_DSP( fl );
  5547. fr = CLIP_DSP( fr );
  5548. flp = CLIP_DSP( flp );
  5549. frp = CLIP_DSP( frp );
  5550. // crossfade from previous to current preset
  5551. if (!bexp)
  5552. {
  5553. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5554. xf_fr = XFADE(fr, frp, r);
  5555. }
  5556. else
  5557. {
  5558. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5559. xf_fr = XFADE_EXP(fr, frp, r);
  5560. }
  5561. pbf->left = xf_fl; // crossfaded front left
  5562. pbf->right = xf_fr;
  5563. pbf++;
  5564. }
  5565. }
  5566. }
  5567. // Helper: called only from DSP_Process
  5568. // DSP_Process quad in to mono out (front left = front right)
  5569. inline void DSP_ProcessQuadToMono(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  5570. {
  5571. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  5572. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  5573. int count = sampleCount;
  5574. int x;
  5575. int av;
  5576. if ( !bcrossfading )
  5577. {
  5578. if ( !pdsp->ipset )
  5579. return;
  5580. if ( FBatchPreset(pdsp->ppset[0]) )
  5581. {
  5582. // convert Quad to Mono in place, then batch process fx: perf KDB
  5583. // left front + rear -> left, right front + rear -> right
  5584. while ( count-- )
  5585. {
  5586. pbf->left = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  5587. pbf++;
  5588. pbr++;
  5589. }
  5590. // process left (mono), duplicate into right
  5591. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  5592. // copy processed front to rear
  5593. count = sampleCount;
  5594. pbf = pbfront;
  5595. pbr = pbrear;
  5596. while ( count-- )
  5597. {
  5598. pbr->left = pbf->left;
  5599. pbr->right = pbf->right;
  5600. pbf++;
  5601. pbr++;
  5602. }
  5603. }
  5604. else
  5605. {
  5606. // avg fl,fr,rl,rr into mono fx, duplicate on all channels
  5607. while ( count-- )
  5608. {
  5609. av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  5610. x = PSET_GetNext( pdsp->ppset[0], av );
  5611. x = CLIP_DSP( x );
  5612. pbr->left = pbr->right = pbf->left = pbf->right = x;
  5613. pbf++;
  5614. pbr++;
  5615. }
  5616. }
  5617. return;
  5618. }
  5619. if ( bcrossfading )
  5620. {
  5621. int r;
  5622. int fl, fr, rl, rr;
  5623. int flp, frp, rlp, rrp;
  5624. int xf_fl, xf_fr, xf_rl, xf_rr;
  5625. bool bexp = pdsp->bexpfade;
  5626. bool bfadetoquad = (pdsp->ipset == 0);
  5627. bool bfadefromquad = (pdsp->ipsetprev == 0);
  5628. if ( bfadetoquad || bfadefromquad )
  5629. {
  5630. // special case if previous or current preset is 0 (quad passthrough)
  5631. while ( count-- )
  5632. {
  5633. av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  5634. // get current preset values
  5635. // current preset is 0, which implies fading to passthrough quad output
  5636. // need to fade from mono to quad
  5637. if ( pdsp->ipset )
  5638. {
  5639. rl = rr = fl = fr = PSET_GetNext( pdsp->ppset[0], av );
  5640. }
  5641. else
  5642. {
  5643. fl = pbf->left;
  5644. fr = pbf->right;
  5645. rl = pbr->left;
  5646. rr = pbr->right;
  5647. }
  5648. // get previous preset values
  5649. if ( pdsp->ipsetprev )
  5650. {
  5651. rrp = rlp = frp = flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  5652. }
  5653. else
  5654. {
  5655. flp = pbf->left;
  5656. frp = pbf->right;
  5657. rlp = pbr->left;
  5658. rrp = pbr->right;
  5659. }
  5660. fl = CLIP_DSP(fl);
  5661. fr = CLIP_DSP(fr);
  5662. flp = CLIP_DSP(flp);
  5663. frp = CLIP_DSP(frp);
  5664. rl = CLIP_DSP(rl);
  5665. rr = CLIP_DSP(rr);
  5666. rlp = CLIP_DSP(rlp);
  5667. rrp = CLIP_DSP(rrp);
  5668. // get current ramp value
  5669. r = RMP_GetNext( &pdsp->xramp );
  5670. // crossfade from previous to current preset
  5671. if (!bexp)
  5672. {
  5673. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5674. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  5675. xf_rl = XFADE(rl, rlp, r); // crossfade front left previous to front left
  5676. xf_rr = XFADE(rr, rrp, r); // crossfade front left previous to front left
  5677. }
  5678. else
  5679. {
  5680. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5681. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  5682. xf_rl = XFADE_EXP(rl, rlp, r); // crossfade front left previous to front left
  5683. xf_rr = XFADE_EXP(rr, rrp, r); // crossfade front left previous to front left
  5684. }
  5685. pbf->left = xf_fl;
  5686. pbf->right = xf_fr;
  5687. pbr->left = xf_rl;
  5688. pbr->right = xf_rr;
  5689. pbf++;
  5690. pbr++;
  5691. }
  5692. return;
  5693. }
  5694. while ( count-- )
  5695. {
  5696. av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  5697. // get current preset values
  5698. fl = PSET_GetNext( pdsp->ppset[0], av );
  5699. // get previous preset values
  5700. flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  5701. // get current ramp value
  5702. r = RMP_GetNext( &pdsp->xramp );
  5703. fl = CLIP_DSP( fl );
  5704. flp = CLIP_DSP( flp );
  5705. // crossfade from previous to current preset
  5706. if (!bexp)
  5707. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5708. else
  5709. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5710. pbf->left = xf_fl; // crossfaded front left, duplicated to all channels
  5711. pbf->right = xf_fl;
  5712. pbr->left = xf_fl;
  5713. pbr->right = xf_fl;
  5714. pbf++;
  5715. pbr++;
  5716. }
  5717. }
  5718. }
  5719. // Helper: called only from DSP_Process
  5720. // DSP_Process quad in to stereo out (preserve stereo spatialization, throw away front/rear)
  5721. inline void DSP_ProcessQuadToStereo(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  5722. {
  5723. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  5724. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  5725. int count = sampleCount;
  5726. int fl, fr;
  5727. if ( !bcrossfading )
  5728. {
  5729. if ( !pdsp->ipset )
  5730. return;
  5731. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) )
  5732. {
  5733. // convert Quad to Stereo in place, then batch process fx: perf KDB
  5734. // left front + rear -> left, right front + rear -> right
  5735. while ( count-- )
  5736. {
  5737. pbf->left = (pbf->left + pbr->left) >> 1;
  5738. pbf->right = (pbf->right + pbr->right) >> 1;
  5739. pbf++;
  5740. pbr++;
  5741. }
  5742. // process left & right
  5743. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT);
  5744. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  5745. // copy processed front to rear
  5746. count = sampleCount;
  5747. pbf = pbfront;
  5748. pbr = pbrear;
  5749. while ( count-- )
  5750. {
  5751. pbr->left = pbf->left;
  5752. pbr->right = pbf->right;
  5753. pbf++;
  5754. pbr++;
  5755. }
  5756. }
  5757. else
  5758. {
  5759. // left front + rear -> left fx, right front + rear -> right fx
  5760. while ( count-- )
  5761. {
  5762. fl = PSET_GetNext( pdsp->ppset[0], (pbf->left + pbr->left) >> 1);
  5763. fr = PSET_GetNext( pdsp->ppset[1], (pbf->right + pbr->right) >> 1);
  5764. fl = CLIP_DSP( fl );
  5765. fr = CLIP_DSP( fr );
  5766. pbr->left = pbf->left = fl;
  5767. pbr->right = pbf->right = fr;
  5768. pbf++;
  5769. pbr++;
  5770. }
  5771. }
  5772. return;
  5773. }
  5774. // crossfading to current preset from previous preset
  5775. if ( bcrossfading )
  5776. {
  5777. int r;
  5778. int rl, rr;
  5779. int flp, frp, rlp, rrp;
  5780. int xf_fl, xf_fr, xf_rl, xf_rr;
  5781. int avl, avr;
  5782. bool bexp = pdsp->bexpfade;
  5783. bool bfadetoquad = (pdsp->ipset == 0);
  5784. bool bfadefromquad = (pdsp->ipsetprev == 0);
  5785. if ( bfadetoquad || bfadefromquad )
  5786. {
  5787. // special case if previous or current preset is 0 (quad passthrough)
  5788. while ( count-- )
  5789. {
  5790. avl = (pbf->left + pbr->left) >> 1;
  5791. avr = (pbf->right + pbr->right) >> 1;
  5792. // get current preset values
  5793. // current preset is 0, which implies fading to passthrough quad output
  5794. // need to fade from stereo to quad
  5795. if ( pdsp->ipset )
  5796. {
  5797. rl = fl = PSET_GetNext( pdsp->ppset[0], avl );
  5798. rr = fr = PSET_GetNext( pdsp->ppset[0], avr );
  5799. }
  5800. else
  5801. {
  5802. fl = pbf->left;
  5803. fr = pbf->right;
  5804. rl = pbr->left;
  5805. rr = pbr->right;
  5806. }
  5807. // get previous preset values
  5808. if ( pdsp->ipsetprev )
  5809. {
  5810. rlp = flp = PSET_GetNext( pdsp->ppsetprev[0], avl );
  5811. rrp = frp = PSET_GetNext( pdsp->ppsetprev[0], avr );
  5812. }
  5813. else
  5814. {
  5815. flp = pbf->left;
  5816. frp = pbf->right;
  5817. rlp = pbr->left;
  5818. rrp = pbr->right;
  5819. }
  5820. fl = CLIP_DSP(fl);
  5821. fr = CLIP_DSP(fr);
  5822. flp = CLIP_DSP(flp);
  5823. frp = CLIP_DSP(frp);
  5824. rl = CLIP_DSP(rl);
  5825. rr = CLIP_DSP(rr);
  5826. rlp = CLIP_DSP(rlp);
  5827. rrp = CLIP_DSP(rrp);
  5828. // get current ramp value
  5829. r = RMP_GetNext( &pdsp->xramp );
  5830. // crossfade from previous to current preset
  5831. if (!bexp)
  5832. {
  5833. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5834. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  5835. xf_rl = XFADE(rl, rlp, r); // crossfade front left previous to front left
  5836. xf_rr = XFADE(rr, rrp, r); // crossfade front left previous to front left
  5837. }
  5838. else
  5839. {
  5840. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5841. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  5842. xf_rl = XFADE_EXP(rl, rlp, r); // crossfade front left previous to front left
  5843. xf_rr = XFADE_EXP(rr, rrp, r); // crossfade front left previous to front left
  5844. }
  5845. pbf->left = xf_fl;
  5846. pbf->right = xf_fr;
  5847. pbr->left = xf_rl;
  5848. pbr->right = xf_rr;
  5849. pbf++;
  5850. pbr++;
  5851. }
  5852. return;
  5853. }
  5854. while ( count-- )
  5855. {
  5856. avl = (pbf->left + pbr->left) >> 1;
  5857. avr = (pbf->right + pbr->right) >> 1;
  5858. // get current preset values
  5859. fl = PSET_GetNext( pdsp->ppset[0], avl );
  5860. fr = PSET_GetNext( pdsp->ppset[1], avr );
  5861. // get previous preset values
  5862. flp = PSET_GetNext( pdsp->ppsetprev[0], avl );
  5863. frp = PSET_GetNext( pdsp->ppsetprev[1], avr );
  5864. fl = CLIP_DSP( fl );
  5865. fr = CLIP_DSP( fr );
  5866. // get previous preset values
  5867. flp = CLIP_DSP( flp );
  5868. frp = CLIP_DSP( frp );
  5869. // get current ramp value
  5870. r = RMP_GetNext( &pdsp->xramp );
  5871. // crossfade from previous to current preset
  5872. if (!bexp)
  5873. {
  5874. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5875. xf_fr = XFADE(fr, frp, r);
  5876. }
  5877. else
  5878. {
  5879. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5880. xf_fr = XFADE_EXP(fr, frp, r);
  5881. }
  5882. pbf->left = xf_fl; // crossfaded front left
  5883. pbf->right = xf_fr;
  5884. pbr->left = xf_fl; // duplicate front channel to rear channel
  5885. pbr->right = xf_fr;
  5886. pbf++;
  5887. pbr++;
  5888. }
  5889. }
  5890. }
  5891. // Helper: called only from DSP_Process
  5892. // DSP_Process quad in to quad out
  5893. inline void DSP_ProcessQuadToQuad(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  5894. {
  5895. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  5896. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  5897. int count = sampleCount;
  5898. int fl, fr, rl, rr;
  5899. if ( !bcrossfading )
  5900. {
  5901. if ( !pdsp->ipset )
  5902. return;
  5903. // each channel gets its own processor
  5904. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) && FBatchPreset(pdsp->ppset[2]) && FBatchPreset(pdsp->ppset[3]))
  5905. {
  5906. // batch process fx front & rear, left & right: perf KDB
  5907. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT);
  5908. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  5909. PSET_GetNextN( pdsp->ppset[2], pbrear, sampleCount, OP_LEFT );
  5910. PSET_GetNextN( pdsp->ppset[3], pbrear, sampleCount, OP_RIGHT );
  5911. }
  5912. else
  5913. {
  5914. while ( count-- )
  5915. {
  5916. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  5917. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  5918. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  5919. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  5920. pbf->left = CLIP_DSP( fl );
  5921. pbf->right = CLIP_DSP( fr );
  5922. pbr->left = CLIP_DSP( rl );
  5923. pbr->right = CLIP_DSP( rr );
  5924. pbf++;
  5925. pbr++;
  5926. }
  5927. }
  5928. return;
  5929. }
  5930. // crossfading to current preset from previous preset
  5931. if ( bcrossfading )
  5932. {
  5933. int r;
  5934. int flp, frp, rlp, rrp;
  5935. int xf_fl, xf_fr, xf_rl, xf_rr;
  5936. bool bexp = pdsp->bexpfade;
  5937. while ( count-- )
  5938. {
  5939. // get current preset values
  5940. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  5941. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  5942. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  5943. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  5944. // get previous preset values
  5945. flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  5946. frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  5947. rlp = PSET_GetNext( pdsp->ppsetprev[2], pbr->left );
  5948. rrp = PSET_GetNext( pdsp->ppsetprev[3], pbr->right );
  5949. // get current ramp value
  5950. r = RMP_GetNext( &pdsp->xramp );
  5951. // crossfade from previous to current preset
  5952. if (!bexp)
  5953. {
  5954. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  5955. xf_fr = XFADE(fr, frp, r);
  5956. xf_rl = XFADE(rl, rlp, r);
  5957. xf_rr = XFADE(rr, rrp, r);
  5958. }
  5959. else
  5960. {
  5961. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  5962. xf_fr = XFADE_EXP(fr, frp, r);
  5963. xf_rl = XFADE_EXP(rl, rlp, r);
  5964. xf_rr = XFADE_EXP(rr, rrp, r);
  5965. }
  5966. pbf->left = CLIP_DSP(xf_fl); // crossfaded front left
  5967. pbf->right = CLIP_DSP(xf_fr);
  5968. pbr->left = CLIP_DSP(xf_rl);
  5969. pbr->right = CLIP_DSP(xf_rr);
  5970. pbf++;
  5971. pbr++;
  5972. }
  5973. }
  5974. }
  5975. // Helper: called only from DSP_Process
  5976. // DSP_Process quad + center in to mono out (front left = front right)
  5977. inline void DSP_Process5To1(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, portable_samplepair_t *pbcenter, int sampleCount, bool bcrossfading )
  5978. {
  5979. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  5980. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  5981. portable_samplepair_t *pbc = pbcenter; // pointer to buffer of center mono samples to process
  5982. int count = sampleCount;
  5983. int x;
  5984. int av;
  5985. if ( !bcrossfading )
  5986. {
  5987. if ( !pdsp->ipset )
  5988. return;
  5989. if ( FBatchPreset(pdsp->ppset[0]) )
  5990. {
  5991. // convert Quad + Center to Mono in place, then batch process fx: perf KDB
  5992. // left front + rear -> left, right front + rear -> right
  5993. while ( count-- )
  5994. {
  5995. // pbf->left = ((pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) / 5);
  5996. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  5997. av >>= 8;
  5998. pbf->left = av;
  5999. pbf++;
  6000. pbr++;
  6001. pbc++;
  6002. }
  6003. // process left (mono), duplicate into right
  6004. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  6005. // copy processed front to rear & center
  6006. count = sampleCount;
  6007. pbf = pbfront;
  6008. pbr = pbrear;
  6009. pbc = pbcenter;
  6010. while ( count-- )
  6011. {
  6012. pbr->left = pbf->left;
  6013. pbr->right = pbf->right;
  6014. pbc->left = pbf->left;
  6015. pbf++;
  6016. pbr++;
  6017. pbc++;
  6018. }
  6019. }
  6020. else
  6021. {
  6022. // avg fl,fr,rl,rr,fc into mono fx, duplicate on all channels
  6023. while ( count-- )
  6024. {
  6025. // av = ((pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) / 5);
  6026. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  6027. av >>= 8;
  6028. x = PSET_GetNext( pdsp->ppset[0], av );
  6029. x = CLIP_DSP( x );
  6030. pbr->left = pbr->right = pbf->left = pbf->right = pbc->left = x;
  6031. pbf++;
  6032. pbr++;
  6033. pbc++;
  6034. }
  6035. }
  6036. return;
  6037. }
  6038. if ( bcrossfading )
  6039. {
  6040. int r;
  6041. int fl, fr, rl, rr, fc;
  6042. int flp, frp, rlp, rrp, fcp;
  6043. int xf_fl, xf_fr, xf_rl, xf_rr, xf_fc;
  6044. bool bexp = pdsp->bexpfade;
  6045. bool bfadetoquad = (pdsp->ipset == 0);
  6046. bool bfadefromquad = (pdsp->ipsetprev == 0);
  6047. if ( bfadetoquad || bfadefromquad )
  6048. {
  6049. // special case if previous or current preset is 0 (quad passthrough)
  6050. while ( count-- )
  6051. {
  6052. // av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  6053. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  6054. av >>= 8;
  6055. // get current preset values
  6056. // current preset is 0, which implies fading to passthrough quad output
  6057. // need to fade from mono to quad
  6058. if ( pdsp->ipset )
  6059. {
  6060. fc = rl = rr = fl = fr = PSET_GetNext( pdsp->ppset[0], av );
  6061. }
  6062. else
  6063. {
  6064. fl = pbf->left;
  6065. fr = pbf->right;
  6066. rl = pbr->left;
  6067. rr = pbr->right;
  6068. fc = pbc->left;
  6069. }
  6070. // get previous preset values
  6071. if ( pdsp->ipsetprev )
  6072. {
  6073. fcp = rrp = rlp = frp = flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  6074. }
  6075. else
  6076. {
  6077. flp = pbf->left;
  6078. frp = pbf->right;
  6079. rlp = pbr->left;
  6080. rrp = pbr->right;
  6081. fcp = pbc->left;
  6082. }
  6083. fl = CLIP_DSP(fl);
  6084. fr = CLIP_DSP(fr);
  6085. flp = CLIP_DSP(flp);
  6086. frp = CLIP_DSP(frp);
  6087. rl = CLIP_DSP(rl);
  6088. rr = CLIP_DSP(rr);
  6089. rlp = CLIP_DSP(rlp);
  6090. rrp = CLIP_DSP(rrp);
  6091. fc = CLIP_DSP(fc);
  6092. fcp = CLIP_DSP(fcp);
  6093. // get current ramp value
  6094. r = RMP_GetNext( &pdsp->xramp );
  6095. // crossfade from previous to current preset
  6096. if (!bexp)
  6097. {
  6098. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  6099. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  6100. xf_rl = XFADE(rl, rlp, r); // crossfade front left previous to front left
  6101. xf_rr = XFADE(rr, rrp, r); // crossfade front left previous to front left
  6102. xf_fc = XFADE(fc, fcp, r); // crossfade front left previous to front left
  6103. }
  6104. else
  6105. {
  6106. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  6107. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  6108. xf_rl = XFADE_EXP(rl, rlp, r); // crossfade front left previous to front left
  6109. xf_rr = XFADE_EXP(rr, rrp, r); // crossfade front left previous to front left
  6110. xf_fc = XFADE_EXP(fc, fcp, r); // crossfade front left previous to front left
  6111. }
  6112. pbf->left = xf_fl;
  6113. pbf->right = xf_fr;
  6114. pbr->left = xf_rl;
  6115. pbr->right = xf_rr;
  6116. pbc->left = xf_fc;
  6117. pbf++;
  6118. pbr++;
  6119. pbc++;
  6120. }
  6121. return;
  6122. }
  6123. while ( count-- )
  6124. {
  6125. // av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  6126. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  6127. av >>= 8;
  6128. // get current preset values
  6129. fl = PSET_GetNext( pdsp->ppset[0], av );
  6130. // get previous preset values
  6131. flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  6132. // get current ramp value
  6133. r = RMP_GetNext( &pdsp->xramp );
  6134. fl = CLIP_DSP( fl );
  6135. flp = CLIP_DSP( flp );
  6136. // crossfade from previous to current preset
  6137. if (!bexp)
  6138. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  6139. else
  6140. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  6141. pbf->left = xf_fl; // crossfaded front left, duplicated to all channels
  6142. pbf->right = xf_fl;
  6143. pbr->left = xf_fl;
  6144. pbr->right = xf_fl;
  6145. pbc->left = xf_fl;
  6146. pbf++;
  6147. pbr++;
  6148. pbc++;
  6149. }
  6150. }
  6151. }
  6152. // Helper: called only from DSP_Process
  6153. // DSP_Process quad + center in to quad + center out
  6154. inline void DSP_Process5To5(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, portable_samplepair_t *pbcenter, int sampleCount, bool bcrossfading )
  6155. {
  6156. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  6157. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  6158. portable_samplepair_t *pbc = pbcenter; // pointer to buffer of center mono samples to process
  6159. int count = sampleCount;
  6160. int fl, fr, rl, rr, fc;
  6161. if ( !bcrossfading )
  6162. {
  6163. if ( !pdsp->ipset )
  6164. return;
  6165. // each channel gets its own processor
  6166. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) && FBatchPreset(pdsp->ppset[2]) && FBatchPreset(pdsp->ppset[3]))
  6167. {
  6168. // batch process fx front & rear, left & right: perf KDB
  6169. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT);
  6170. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  6171. PSET_GetNextN( pdsp->ppset[2], pbrear, sampleCount, OP_LEFT );
  6172. PSET_GetNextN( pdsp->ppset[3], pbrear, sampleCount, OP_RIGHT );
  6173. PSET_GetNextN( pdsp->ppset[4], pbcenter, sampleCount, OP_LEFT );
  6174. }
  6175. else
  6176. {
  6177. while ( count-- )
  6178. {
  6179. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  6180. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  6181. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  6182. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  6183. fc = PSET_GetNext( pdsp->ppset[4], pbc->left );
  6184. pbf->left = CLIP_DSP( fl );
  6185. pbf->right = CLIP_DSP( fr );
  6186. pbr->left = CLIP_DSP( rl );
  6187. pbr->right = CLIP_DSP( rr );
  6188. pbc->left = CLIP_DSP( fc );
  6189. pbf++;
  6190. pbr++;
  6191. pbc++;
  6192. }
  6193. }
  6194. return;
  6195. }
  6196. // crossfading to current preset from previous preset
  6197. if ( bcrossfading )
  6198. {
  6199. int r;
  6200. int flp, frp, rlp, rrp, fcp;
  6201. int xf_fl, xf_fr, xf_rl, xf_rr, xf_fc;
  6202. bool bexp = pdsp->bexpfade;
  6203. while ( count-- )
  6204. {
  6205. // get current preset values
  6206. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  6207. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  6208. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  6209. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  6210. fc = PSET_GetNext( pdsp->ppset[4], pbc->left );
  6211. // get previous preset values
  6212. flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  6213. frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  6214. rlp = PSET_GetNext( pdsp->ppsetprev[2], pbr->left );
  6215. rrp = PSET_GetNext( pdsp->ppsetprev[3], pbr->right );
  6216. fcp = PSET_GetNext( pdsp->ppsetprev[4], pbc->left );
  6217. // get current ramp value
  6218. r = RMP_GetNext( &pdsp->xramp );
  6219. // crossfade from previous to current preset
  6220. if (!bexp)
  6221. {
  6222. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  6223. xf_fr = XFADE(fr, frp, r);
  6224. xf_rl = XFADE(rl, rlp, r);
  6225. xf_rr = XFADE(rr, rrp, r);
  6226. xf_fc = XFADE(fc, fcp, r);
  6227. }
  6228. else
  6229. {
  6230. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  6231. xf_fr = XFADE_EXP(fr, frp, r);
  6232. xf_rl = XFADE_EXP(rl, rlp, r);
  6233. xf_rr = XFADE_EXP(rr, rrp, r);
  6234. xf_fc = XFADE_EXP(fc, fcp, r);
  6235. }
  6236. pbf->left = CLIP_DSP(xf_fl); // crossfaded front left
  6237. pbf->right = CLIP_DSP(xf_fr);
  6238. pbr->left = CLIP_DSP(xf_rl);
  6239. pbr->right = CLIP_DSP(xf_rr);
  6240. pbc->left = CLIP_DSP(xf_fc);
  6241. pbf++;
  6242. pbr++;
  6243. pbc++;
  6244. }
  6245. }
  6246. }
  6247. // This is an evil hack, but we need to restore the old presets after letting the sound system update for a few frames, so we just
  6248. // "defer" the restore until the top of the next call to CheckNewDspPresets. I put in a bit of warning in case we ever have code
  6249. // outside of this time period modifying any of the dsp convars. It doesn't seem to be an issue just save/loading between levels
  6250. static bool g_bNeedPresetRestore = false;
  6251. //-----------------------------------------------------------------------------
  6252. // Purpose:
  6253. //-----------------------------------------------------------------------------
  6254. struct PreserveDSP_t
  6255. {
  6256. ConVar *cvar;
  6257. float oldvalue;
  6258. };
  6259. static PreserveDSP_t g_PreserveDSP[] =
  6260. {
  6261. { &dsp_room },
  6262. { &dsp_water },
  6263. { &dsp_player },
  6264. { &dsp_facingaway },
  6265. { &dsp_speaker },
  6266. { &dsp_spatial },
  6267. { &dsp_automatic }
  6268. };
  6269. //-----------------------------------------------------------------------------
  6270. // Purpose: Called at the top of CheckNewDspPresets to restore ConVars to real values
  6271. //-----------------------------------------------------------------------------
  6272. void DSP_CheckRestorePresets()
  6273. {
  6274. if ( !g_bNeedPresetRestore )
  6275. return;
  6276. g_bNeedPresetRestore = false;
  6277. int i;
  6278. int c = ARRAYSIZE( g_PreserveDSP );
  6279. // Restore
  6280. for ( i = 0 ; i < c; ++i )
  6281. {
  6282. PreserveDSP_t& slot = g_PreserveDSP[ i ];
  6283. ConVar *cv = slot.cvar;
  6284. Assert( cv );
  6285. if ( cv->GetFloat() != 0.0f )
  6286. {
  6287. // NOTE: dsp_speaker is being (correctly) save/restored by maps, which would trigger this warning
  6288. //Warning( "DSP_CheckRestorePresets: Value of %s was changed between DSP_ClearState and CheckNewDspPresets, not restoring to old value\n", cv->GetName() );
  6289. continue;
  6290. }
  6291. cv->SetValue( slot.oldvalue );
  6292. }
  6293. // reinit all dsp processors (only load preset file on engine init, however)
  6294. AllocDsps( false );
  6295. // flush dsp automatic nodes
  6296. g_bdas_init_nodes = 0;
  6297. g_bdas_room_init = 0;
  6298. }
  6299. //-----------------------------------------------------------------------------
  6300. // Purpose:
  6301. //-----------------------------------------------------------------------------
  6302. void DSP_ClearState()
  6303. {
  6304. // if we already cleared dsp state, and a restore is pending,
  6305. // don't clear again
  6306. if ( g_bNeedPresetRestore )
  6307. return;
  6308. // always save a cleared dsp automatic value to force reset of all adsp code
  6309. dsp_automatic.SetValue(0);
  6310. // Tracker 7155: YWB: This is a pretty ugly hack to zero out all of the dsp convars and bootstrap the dsp system into using them for a few frames
  6311. int i;
  6312. int c = ARRAYSIZE( g_PreserveDSP );
  6313. for ( i = 0 ; i < c; ++i )
  6314. {
  6315. PreserveDSP_t& slot = g_PreserveDSP[ i ];
  6316. ConVar *cv = slot.cvar;
  6317. Assert( cv );
  6318. slot.oldvalue = cv->GetFloat();
  6319. cv->SetValue( 0 );
  6320. }
  6321. // force all dsp presets to end crossfades, end one-shot presets, & release and reset all resources
  6322. // immediately.
  6323. FreeDsps( false ); // free all dsp states, but don't discard preset templates
  6324. // This forces the ConVars which we set to zero above to be reloaded to their old values at the time we issue the CheckNewDspPresets
  6325. // command. This seems to happen early enough in level changes were we don't appear to be trying to stomp real settings...
  6326. g_bNeedPresetRestore = true;
  6327. }
  6328. // return true if dsp's preset is one-shot and it has expired
  6329. bool DSP_HasExpired( int idsp )
  6330. {
  6331. dsp_t *pdsp;
  6332. Assert( idsp < CDSPS );
  6333. if (idsp < 0 || idsp >= CDSPS)
  6334. return false;
  6335. pdsp = &dsps[idsp];
  6336. // if first preset has expired, dsp has expired
  6337. if ( PSET_IsOneShot( pdsp->ppset[0] ) )
  6338. return PSET_HasExpired( pdsp->ppset[0] );
  6339. else
  6340. return false;
  6341. }
  6342. // returns true if dsp is crossfading from previous dsp preset
  6343. bool DSP_IsCrossfading( int idsp )
  6344. {
  6345. dsp_t *pdsp;
  6346. Assert( idsp < CDSPS );
  6347. if (idsp < 0 || idsp >= CDSPS)
  6348. return false;
  6349. pdsp = &dsps[idsp];
  6350. return !RMP_HitEnd( &pdsp->xramp );
  6351. }
  6352. // returns previous preset # before oneshot preset was set
  6353. int DSP_OneShotPrevious( int idsp )
  6354. {
  6355. dsp_t *pdsp;
  6356. int idsp_prev;
  6357. Assert( idsp < CDSPS );
  6358. if (idsp < 0 || idsp >= CDSPS)
  6359. return 0;
  6360. pdsp = &dsps[idsp];
  6361. idsp_prev = pdsp->ipsetsav_oneshot;
  6362. return idsp_prev;
  6363. }
  6364. // given idsp (processor index), return true if
  6365. // both current and previous presets are 0 for this processor
  6366. bool DSP_PresetIsOff( int idsp )
  6367. {
  6368. dsp_t *pdsp;
  6369. if (idsp < 0 || idsp >= CDSPS)
  6370. return true;
  6371. Assert ( idsp < CDSPS ); // make sure idsp is valid
  6372. pdsp = &dsps[idsp];
  6373. // if current and previous preset 0, return - preset 0 is 'off'
  6374. return ( !pdsp->ipset && !pdsp->ipsetprev );
  6375. }
  6376. // returns true if dsp is off for room effects
  6377. bool DSP_RoomDSPIsOff()
  6378. {
  6379. return DSP_PresetIsOff( Get_idsp_room() );
  6380. }
  6381. // Main DSP processing routine:
  6382. // process samples in buffers using pdsp processor
  6383. // continue crossfade between 2 dsp processors if crossfading on switch
  6384. // pfront - front stereo buffer to process
  6385. // prear - rear stereo buffer to process (may be NULL)
  6386. // pcenter - front center mono buffer (may be NULL)
  6387. // sampleCount - number of samples in pbuf to process
  6388. // This routine also maps the # processing channels in the pdsp to the number of channels
  6389. // supplied. ie: if the pdsp has 4 channels and pbfront and pbrear are both non-null, the channels
  6390. // map 1:1 through the processors.
  6391. void DSP_Process( int idsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, portable_samplepair_t *pbcenter, int sampleCount )
  6392. {
  6393. bool bcrossfading;
  6394. int cchan_in; // input channels (2,4 or 5)
  6395. int cprocs; // output cannels (1, 2 or 4)
  6396. dsp_t *pdsp;
  6397. if (idsp < 0 || idsp >= CDSPS)
  6398. return;
  6399. // Don't pull dsp data in if player is not connected (during load/level change)
  6400. if ( !g_pSoundServices->IsConnected() )
  6401. return;
  6402. Assert ( idsp < CDSPS ); // make sure idsp is valid
  6403. pdsp = &dsps[idsp];
  6404. Assert (pbfront);
  6405. // return right away if fx processing is turned off
  6406. if ( dsp_off.GetInt() )
  6407. return;
  6408. // if current and previous preset 0, return - preset 0 is 'off'
  6409. if ( !pdsp->ipset && !pdsp->ipsetprev )
  6410. return;
  6411. if ( sampleCount < 0 )
  6412. return;
  6413. bcrossfading = !RMP_HitEnd( &pdsp->xramp );
  6414. // if not crossfading, and previous channel is not null, free previous
  6415. if ( !bcrossfading )
  6416. DSP_FreePrevPreset( pdsp );
  6417. // if current and previous preset 0 (ie: just freed previous), return - preset 0 is 'off'
  6418. if ( !pdsp->ipset && !pdsp->ipsetprev )
  6419. return;
  6420. cchan_in = (pbrear ? 4 : 2) + (pbcenter ? 1 : 0);
  6421. cprocs = pdsp->cchan;
  6422. Assert(cchan_in == 2 || cchan_in == 4 || cchan_in == 5 );
  6423. // if oneshot preset, update the duration counter (only update front left counter)
  6424. PSET_UpdateDuration( pdsp->ppset[0], sampleCount );
  6425. // NOTE: when mixing between different channel sizes,
  6426. // always AVERAGE down to fewer channels and DUPLICATE up more channels.
  6427. // The following routines always process cchan_in channels.
  6428. // ie: QuadToMono still updates 4 values in buffer
  6429. // DSP_Process stereo in to mono out (ie: left and right are averaged)
  6430. if ( cchan_in == 2 && cprocs == 1)
  6431. {
  6432. DSP_ProcessStereoToMono( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  6433. return;
  6434. }
  6435. // DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
  6436. if ( cchan_in == 2 && cprocs >= 2)
  6437. {
  6438. DSP_ProcessStereoToStereo( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  6439. return;
  6440. }
  6441. // DSP_Process quad in to mono out
  6442. if ( cchan_in == 4 && cprocs == 1)
  6443. {
  6444. DSP_ProcessQuadToMono( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  6445. return;
  6446. }
  6447. // DSP_Process quad in to stereo out (preserve stereo spatialization, loose front/rear)
  6448. if ( cchan_in == 4 && cprocs == 2)
  6449. {
  6450. DSP_ProcessQuadToStereo( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  6451. return;
  6452. }
  6453. // DSP_Process quad in to quad out
  6454. if ( cchan_in == 4 && cprocs == 4)
  6455. {
  6456. DSP_ProcessQuadToQuad( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  6457. return;
  6458. }
  6459. // DSP_Process quad + center in to mono out
  6460. if ( cchan_in == 5 && cprocs == 1)
  6461. {
  6462. DSP_Process5To1( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  6463. return;
  6464. }
  6465. if ( cchan_in == 5 && cprocs == 2)
  6466. {
  6467. // undone: not used in AllocDsps
  6468. Assert(false);
  6469. //DSP_Process5to2( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  6470. return;
  6471. }
  6472. if ( cchan_in == 5 && cprocs == 4)
  6473. {
  6474. // undone: not used in AllocDsps
  6475. Assert(false);
  6476. //DSP_Process5to4( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  6477. return;
  6478. }
  6479. // DSP_Process quad + center in to quad + center out
  6480. if ( cchan_in == 5 && cprocs == 5)
  6481. {
  6482. DSP_Process5To5( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  6483. return;
  6484. }
  6485. }
  6486. // DSP helpers
  6487. // free all dsp processors
  6488. void FreeDsps( bool bReleaseTemplateMemory )
  6489. {
  6490. DSP_Free(idsp_room);
  6491. DSP_Free(idsp_water);
  6492. DSP_Free(idsp_player);
  6493. DSP_Free(idsp_facingaway);
  6494. DSP_Free(idsp_speaker);
  6495. DSP_Free(idsp_spatial);
  6496. DSP_Free(idsp_automatic);
  6497. idsp_room = 0;
  6498. idsp_water = 0;
  6499. idsp_player = 0;
  6500. idsp_facingaway = 0;
  6501. idsp_speaker = 0;
  6502. idsp_spatial = 0;
  6503. idsp_automatic = 0;
  6504. for ( int i = SOUND_BUFFER_SPECIAL_START; i < g_paintBuffers.Count(); ++i )
  6505. {
  6506. paintbuffer_t *pSpecialBuffer = MIX_GetPPaintFromIPaint( i );
  6507. if ( pSpecialBuffer->nSpecialDSP != 0 )
  6508. {
  6509. DSP_Free( pSpecialBuffer->idsp_specialdsp );
  6510. pSpecialBuffer->idsp_specialdsp = 0;
  6511. pSpecialBuffer->nPrevSpecialDSP = 0;
  6512. pSpecialBuffer->nSpecialDSP = 0;
  6513. }
  6514. }
  6515. DSP_FreeAll();
  6516. // only unlock and free psettemplate memory on engine shutdown
  6517. if ( bReleaseTemplateMemory )
  6518. DSP_ReleaseMemory();
  6519. }
  6520. // alloc dsp processors, load dsp preset array from file on engine init only
  6521. bool AllocDsps( bool bLoadPresetFile )
  6522. {
  6523. int csurround = (g_AudioDevice->IsSurround() ? 2: 0); // surround channels to allocate
  6524. int ccenter = (g_AudioDevice->IsSurroundCenter() ? 1 : 0); // center channels to allocate
  6525. DSP_InitAll( bLoadPresetFile );
  6526. idsp_room = -1;
  6527. idsp_water = -1;
  6528. idsp_player = -1;
  6529. idsp_facingaway = -1;
  6530. idsp_speaker = -1;
  6531. idsp_spatial = -1;
  6532. idsp_automatic = -1;
  6533. // alloc dsp room channel (mono, stereo if dsp_stereo is 1)
  6534. // dsp room is mono, 300ms default fade time
  6535. idsp_room = DSP_Alloc( dsp_room.GetInt(), 200, 1 );
  6536. // dsp automatic overrides dsp_room, if dsp_room set to DSP_AUTOMATIC (1)
  6537. idsp_automatic = DSP_Alloc( dsp_automatic.GetInt(), 200, 1 ) ;
  6538. // alloc stereo or quad series processors for player or water
  6539. // water and player presets are mono
  6540. idsp_water = DSP_Alloc( dsp_water.GetInt(), 100, 1 );
  6541. idsp_player = DSP_Alloc( dsp_player.GetInt(), 100, 1 );
  6542. // alloc facing away filters (stereo, quad or 5ch)
  6543. idsp_facingaway = DSP_Alloc( dsp_facingaway.GetInt(), 100, 2 + csurround + ccenter );
  6544. // alloc speaker preset (mono)
  6545. idsp_speaker = DSP_Alloc( dsp_speaker.GetInt(), 300, 1 );
  6546. // alloc spatial preset (2-5 chan)
  6547. idsp_spatial = DSP_Alloc( dsp_spatial.GetInt(), 300, 2 + csurround + ccenter );
  6548. // init prev values
  6549. ipset_room_prev = dsp_room.GetInt();
  6550. ipset_water_prev = dsp_water.GetInt();
  6551. ipset_player_prev = dsp_player.GetInt();
  6552. ipset_facingaway_prev = dsp_facingaway.GetInt();
  6553. ipset_room_typeprev = dsp_room_type.GetInt();
  6554. ipset_speaker_prev = dsp_speaker.GetInt();
  6555. ipset_spatial_prev = dsp_spatial.GetInt();
  6556. ipset_automatic_prev = dsp_automatic.GetInt();
  6557. if (idsp_room < 0 || idsp_water < 0 || idsp_player < 0 || idsp_facingaway < 0 || idsp_speaker < 0 || idsp_spatial < 0 || idsp_automatic < 0)
  6558. {
  6559. DevMsg ("WARNING: DSP processor failed to initialize! \n" );
  6560. FreeDsps( true );
  6561. return false;
  6562. }
  6563. return true;
  6564. }
  6565. // count number of dsp presets specified in preset file
  6566. // counts outer {} pairs, ignoring inner {} pairs.
  6567. int DSP_CountFilePresets( const char *pstart )
  6568. {
  6569. int cpresets = 0;
  6570. bool binpreset = false;
  6571. bool blookleft = false;
  6572. while ( 1 )
  6573. {
  6574. pstart = COM_Parse( pstart );
  6575. if ( strlen(com_token) <= 0)
  6576. break;
  6577. if ( com_token[0] == '{' ) // left paren
  6578. {
  6579. if (!binpreset)
  6580. {
  6581. cpresets++; // found preset:
  6582. blookleft = true; // look for another left
  6583. binpreset = true;
  6584. }
  6585. else
  6586. {
  6587. blookleft = false; // inside preset: next, look for matching right paren
  6588. }
  6589. continue;
  6590. }
  6591. if ( com_token[0] == '}' ) // right paren
  6592. {
  6593. if (binpreset)
  6594. {
  6595. if (!blookleft) // looking for right paren
  6596. {
  6597. blookleft = true; // found it, now look for another left
  6598. }
  6599. else
  6600. {
  6601. // expected inner left paren, found outer right - end of preset definition
  6602. binpreset = false;
  6603. blookleft = true;
  6604. }
  6605. }
  6606. else
  6607. {
  6608. // error - unexpected } paren
  6609. DevMsg("PARSE ERROR!!! dsp_presets.txt: unexpected '}' \n");
  6610. continue;
  6611. }
  6612. }
  6613. }
  6614. return cpresets;
  6615. }
  6616. struct dsp_stringmap_t
  6617. {
  6618. char sz[33];
  6619. int i;
  6620. };
  6621. // token map for dsp_preset.txt
  6622. dsp_stringmap_t gdsp_stringmap[] =
  6623. {
  6624. // PROCESSOR TYPE:
  6625. {"NULL", PRC_NULL},
  6626. {"DLY", PRC_DLY},
  6627. {"RVA", PRC_RVA},
  6628. {"FLT", PRC_FLT},
  6629. {"CRS", PRC_CRS},
  6630. {"PTC", PRC_PTC},
  6631. {"ENV", PRC_ENV},
  6632. {"LFO", PRC_LFO},
  6633. {"EFO", PRC_EFO},
  6634. {"MDY", PRC_MDY},
  6635. {"DFR", PRC_DFR},
  6636. {"AMP", PRC_AMP},
  6637. // FILTER TYPE:
  6638. {"LP", FLT_LP},
  6639. {"HP", FLT_HP},
  6640. {"BP", FLT_BP},
  6641. // FILTER QUALITY:
  6642. {"LO", QUA_LO},
  6643. {"MED", QUA_MED},
  6644. {"HI", QUA_HI},
  6645. {"VHI", QUA_VHI},
  6646. // DELAY TYPE:
  6647. {"PLAIN", DLY_PLAIN},
  6648. {"ALLPASS", DLY_ALLPASS},
  6649. {"LOWPASS", DLY_LOWPASS},
  6650. {"DLINEAR", DLY_LINEAR},
  6651. {"FLINEAR", DLY_FLINEAR},
  6652. {"LOWPASS_4TAP",DLY_LOWPASS_4TAP},
  6653. {"PLAIN_4TAP", DLY_PLAIN_4TAP},
  6654. // LFO TYPE:
  6655. {"SIN", LFO_SIN},
  6656. {"TRI", LFO_TRI},
  6657. {"SQR", LFO_SQR},
  6658. {"SAW", LFO_SAW},
  6659. {"RND", LFO_RND},
  6660. {"LOG_IN", LFO_LOG_IN},
  6661. {"LOG_OUT", LFO_LOG_OUT},
  6662. {"LIN_IN", LFO_LIN_IN},
  6663. {"LIN_OUT", LFO_LIN_OUT},
  6664. // ENVELOPE TYPE:
  6665. {"LIN", ENV_LIN},
  6666. {"EXP", ENV_EXP},
  6667. // PRESET CONFIGURATION TYPE:
  6668. {"SIMPLE", PSET_SIMPLE},
  6669. {"LINEAR", PSET_LINEAR},
  6670. {"PARALLEL2", PSET_PARALLEL2},
  6671. {"PARALLEL4", PSET_PARALLEL4},
  6672. {"PARALLEL5", PSET_PARALLEL5},
  6673. {"FEEDBACK", PSET_FEEDBACK},
  6674. {"FEEDBACK3", PSET_FEEDBACK3},
  6675. {"FEEDBACK4", PSET_FEEDBACK4},
  6676. {"MOD1", PSET_MOD},
  6677. {"MOD2", PSET_MOD2},
  6678. {"MOD3", PSET_MOD3}
  6679. };
  6680. int gcdsp_stringmap = sizeof(gdsp_stringmap) / sizeof (dsp_stringmap_t);
  6681. #define isnumber(c) (c == '+' || c == '-' || c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7'|| c == '8' || c == '9')\
  6682. // given ptr to null term. string, return integer or float value from g_dsp_stringmap
  6683. float DSP_LookupStringToken( char *psz, int ipset )
  6684. {
  6685. int i;
  6686. float fipset = (float)ipset;
  6687. if (isnumber(psz[0]))
  6688. return atof(psz);
  6689. for (i = 0; i < gcdsp_stringmap; i++)
  6690. {
  6691. if (!strcmpi(gdsp_stringmap[i].sz, psz))
  6692. return gdsp_stringmap[i].i;
  6693. }
  6694. // not found
  6695. DevMsg("DSP PARSE ERROR! token not found in dsp_presets.txt. Preset: %3.0f \n", fipset );
  6696. return 0;
  6697. }
  6698. // load dsp preset file, parse presets into g_psettemplate array
  6699. // format for each preset:
  6700. // { <preset #> <preset type> <#processors> <gain> { <processor type> <param0>...<param15> } {...} {...} }
  6701. #define CHAR_LEFT_PAREN '{'
  6702. #define CHAR_RIGHT_PAREN '}'
  6703. // free preset template memory
  6704. void DSP_ReleaseMemory( void )
  6705. {
  6706. if (g_psettemplates)
  6707. {
  6708. delete[] g_psettemplates;
  6709. g_psettemplates = NULL;
  6710. }
  6711. }
  6712. bool DSP_LoadPresetFile( void )
  6713. {
  6714. char szFile[ MAX_OSPATH ];
  6715. char *pbuffer;
  6716. const char *pstart;
  6717. bool bResult = false;
  6718. int cpresets;
  6719. int ipreset;
  6720. int itype;
  6721. int cproc;
  6722. float mix_min;
  6723. float mix_max;
  6724. float db_min;
  6725. float db_mixdrop;
  6726. int j;
  6727. bool fdone;
  6728. float duration;
  6729. float fadeout;
  6730. Q_snprintf( szFile, sizeof( szFile ), "scripts/dsp_presets.txt" );
  6731. MEM_ALLOC_CREDIT();
  6732. CUtlBuffer buf;
  6733. if ( !g_pFullFileSystem->ReadFile( szFile, "GAME", buf ) )
  6734. {
  6735. Error( "DSP_LoadPresetFile: unable to open '%s'\n", szFile );
  6736. return bResult;
  6737. }
  6738. pbuffer = (char *)buf.PeekGet(); // Use malloc - free at end of this routine
  6739. pstart = pbuffer;
  6740. // figure out how many presets we're loading - count outer parens.
  6741. cpresets = DSP_CountFilePresets( pstart );
  6742. g_cpsettemplates = cpresets;
  6743. g_psettemplates = new pset_t[cpresets];
  6744. if (!g_psettemplates)
  6745. {
  6746. Warning( "DSP Preset Loader: Out of memory.\n");
  6747. goto load_exit;
  6748. }
  6749. memset (g_psettemplates, 0, cpresets * sizeof(pset_t));
  6750. // parse presets into g_psettemplates array
  6751. pstart = pbuffer;
  6752. // for each preset...
  6753. for ( j = 0; j < cpresets; j++)
  6754. {
  6755. // check for end of file or next CHAR_LEFT_PAREN
  6756. while (1)
  6757. {
  6758. pstart = COM_Parse( pstart );
  6759. if ( strlen(com_token) <= 0)
  6760. break;
  6761. if ( com_token[0] != CHAR_LEFT_PAREN )
  6762. continue;
  6763. break;
  6764. }
  6765. // found start of a new preset definition
  6766. // get preset #, type, cprocessors, gain
  6767. pstart = COM_Parse( pstart );
  6768. ipreset = atoi( com_token );
  6769. pstart = COM_Parse( pstart );
  6770. itype = (int)DSP_LookupStringToken( com_token , ipreset);
  6771. pstart = COM_Parse( pstart );
  6772. mix_min = atof( com_token );
  6773. pstart = COM_Parse( pstart );
  6774. mix_max = atof( com_token );
  6775. pstart = COM_Parse( pstart );
  6776. duration = atof( com_token );
  6777. pstart = COM_Parse( pstart );
  6778. fadeout = atof( com_token );
  6779. pstart = COM_Parse( pstart );
  6780. db_min = atof( com_token );
  6781. pstart = COM_Parse( pstart );
  6782. db_mixdrop = atof( com_token );
  6783. g_psettemplates[ipreset].fused = true;
  6784. g_psettemplates[ipreset].mix_min = mix_min;
  6785. g_psettemplates[ipreset].mix_max = mix_max;
  6786. g_psettemplates[ipreset].duration = duration;
  6787. g_psettemplates[ipreset].fade = fadeout;
  6788. g_psettemplates[ipreset].db_min = db_min;
  6789. g_psettemplates[ipreset].db_mixdrop = db_mixdrop;
  6790. // parse each processor for this preset
  6791. fdone = false;
  6792. cproc = 0;
  6793. while (1)
  6794. {
  6795. // find CHAR_LEFT_PAREN - start of new processor
  6796. while (1)
  6797. {
  6798. pstart = COM_Parse( pstart );
  6799. if ( strlen(com_token) <= 0)
  6800. break;
  6801. if (com_token[0] == CHAR_LEFT_PAREN)
  6802. break;
  6803. if (com_token[0] == CHAR_RIGHT_PAREN)
  6804. {
  6805. // if found right paren, no more processors: done with this preset
  6806. fdone = true;
  6807. break;
  6808. }
  6809. }
  6810. if ( fdone )
  6811. break;
  6812. // get processor type
  6813. pstart = COM_Parse( pstart );
  6814. g_psettemplates[ipreset].prcs[cproc].type = (int)DSP_LookupStringToken( com_token, ipreset );
  6815. // get param 0..n or stop when hit closing CHAR_RIGHT_PAREN
  6816. int ip = 0;
  6817. while (1)
  6818. {
  6819. pstart = COM_Parse( pstart );
  6820. if ( strlen(com_token) <= 0)
  6821. break;
  6822. if ( com_token[0] == CHAR_RIGHT_PAREN )
  6823. break;
  6824. g_psettemplates[ipreset].prcs[cproc].prm[ip++] = DSP_LookupStringToken( com_token, ipreset );
  6825. // cap at max params
  6826. ip = min(ip, CPRCPARAMS);
  6827. }
  6828. cproc++;
  6829. if (cproc > CPSET_PRCS)
  6830. DevMsg("DSP PARSE ERROR!!! dsp_presets.txt: missing } or too many processors in preset #: %d \n", ipreset);
  6831. cproc = min(cproc, CPSET_PRCS); // don't overflow # procs
  6832. }
  6833. // if cproc == 1, type is always SIMPLE
  6834. if ( cproc == 1)
  6835. itype = PSET_SIMPLE;
  6836. g_psettemplates[ipreset].type = itype;
  6837. g_psettemplates[ipreset].cprcs = cproc;
  6838. }
  6839. bResult = true;
  6840. load_exit:
  6841. return bResult;
  6842. }
  6843. //-----------------------------------------------------------------------------
  6844. // Purpose: Called by client on level shutdown to clear ear ringing dsp effects
  6845. // could be extended to other stuff
  6846. //-----------------------------------------------------------------------------
  6847. void DSP_FastReset( int dspType )
  6848. {
  6849. int c = ARRAYSIZE( g_PreserveDSP );
  6850. // Restore
  6851. for ( int i = 0 ; i < c; ++i )
  6852. {
  6853. PreserveDSP_t& slot = g_PreserveDSP[ i ];
  6854. if ( slot.cvar == &dsp_player )
  6855. {
  6856. slot.oldvalue = dspType;
  6857. return;
  6858. }
  6859. }
  6860. }
  6861. // Helper to check for change in preset of any of 4 processors
  6862. // if switching to a new preset, alloc new preset, simulate both presets in DSP_Process & xfade,
  6863. // called a few times per frame.
  6864. void CheckNewDspPresets( void )
  6865. {
  6866. bool b_slow_cpu = dsp_slow_cpu.GetInt() == 0 ? false : true;
  6867. DSP_CheckRestorePresets();
  6868. // room fx are on only if cpu is not slow
  6869. int iroom = b_slow_cpu ? 0 : dsp_room.GetInt() ;
  6870. int ifacingaway = b_slow_cpu ? 0 : dsp_facingaway.GetInt();
  6871. int iroomtype = b_slow_cpu ? 0 : dsp_room_type.GetInt();
  6872. int ispatial = b_slow_cpu ? 0 : dsp_spatial.GetInt();
  6873. int iautomatic = b_slow_cpu ? 0 : dsp_automatic.GetInt();
  6874. // always use dsp to process these
  6875. int iwater = dsp_water.GetInt();
  6876. int iplayer = dsp_player.GetInt();
  6877. int ispeaker = dsp_speaker.GetInt();
  6878. // check for expired one-shot presets on player and room.
  6879. // Only check if a) no new preset has been set and b) not crossfading from previous preset (ie; previous is null)
  6880. if ( iplayer == ipset_player_prev && !DSP_IsCrossfading( idsp_player ) )
  6881. {
  6882. if ( DSP_HasExpired ( idsp_player ) )
  6883. {
  6884. iplayer = DSP_OneShotPrevious( idsp_player); // preset has expired - revert to previous preset before one-shot
  6885. dsp_player.SetValue(iplayer);
  6886. }
  6887. }
  6888. if ( iroom == ipset_room_prev && !DSP_IsCrossfading( idsp_room ) )
  6889. {
  6890. if ( DSP_HasExpired ( idsp_room ) )
  6891. {
  6892. iroom = DSP_OneShotPrevious( idsp_room ); // preset has expired - revert to previous preset before one-shot
  6893. dsp_room.SetValue(iroom);
  6894. }
  6895. }
  6896. // legacy code support for "room_type" Cvar
  6897. if ( iroomtype != ipset_room_typeprev )
  6898. {
  6899. // force dsp_room = room_type
  6900. ipset_room_typeprev = iroomtype;
  6901. dsp_room.SetValue(iroomtype);
  6902. }
  6903. // NOTE: don't change presets if currently crossfading from a previous preset
  6904. if ( iroom != ipset_room_prev && !DSP_IsCrossfading( idsp_room) )
  6905. {
  6906. DSP_SetPreset( idsp_room, iroom );
  6907. ipset_room_prev = iroom;
  6908. // force room_type = dsp_room
  6909. dsp_room_type.SetValue(iroom);
  6910. ipset_room_typeprev = iroom;
  6911. }
  6912. if ( iwater != ipset_water_prev && !DSP_IsCrossfading( idsp_water) )
  6913. {
  6914. DSP_SetPreset( idsp_water, iwater );
  6915. ipset_water_prev = iwater;
  6916. }
  6917. if ( iplayer != ipset_player_prev && !DSP_IsCrossfading( idsp_player))
  6918. {
  6919. DSP_SetPreset( idsp_player, iplayer );
  6920. ipset_player_prev = iplayer;
  6921. }
  6922. if ( ifacingaway != ipset_facingaway_prev && !DSP_IsCrossfading( idsp_facingaway) )
  6923. {
  6924. DSP_SetPreset( idsp_facingaway, ifacingaway );
  6925. ipset_facingaway_prev = ifacingaway;
  6926. }
  6927. if ( ispeaker != ipset_speaker_prev && !DSP_IsCrossfading( idsp_speaker) )
  6928. {
  6929. DSP_SetPreset( idsp_speaker, ispeaker );
  6930. ipset_speaker_prev = ispeaker;
  6931. }
  6932. if ( ispatial != ipset_spatial_prev && !DSP_IsCrossfading( idsp_spatial) )
  6933. {
  6934. DSP_SetPreset( idsp_spatial, ispatial );
  6935. ipset_spatial_prev = ispatial;
  6936. }
  6937. if ( iautomatic != ipset_automatic_prev && !DSP_IsCrossfading( idsp_automatic) )
  6938. {
  6939. DSP_SetPreset( idsp_automatic, iautomatic );
  6940. ipset_automatic_prev = iautomatic;
  6941. }
  6942. for ( int i = SOUND_BUFFER_SPECIAL_START; i < g_paintBuffers.Count(); ++i )
  6943. {
  6944. paintbuffer_t *pSpecialBuffer = MIX_GetPPaintFromIPaint( i );
  6945. if ( pSpecialBuffer->nSpecialDSP != pSpecialBuffer->nPrevSpecialDSP && !DSP_IsCrossfading( pSpecialBuffer->idsp_specialdsp ) )
  6946. {
  6947. DSP_SetPreset( pSpecialBuffer->idsp_specialdsp, pSpecialBuffer->nSpecialDSP );
  6948. pSpecialBuffer->nPrevSpecialDSP = pSpecialBuffer->nSpecialDSP;
  6949. }
  6950. }
  6951. }
  6952. // create idsp_room preset from set of values, reload the preset.
  6953. // modifies psettemplates in place.
  6954. // ipreset is the preset # ie: 40
  6955. // iproc is the processor to modify within the preset (typically 0)
  6956. // pvalues is an array of floating point parameters
  6957. // cparams is the # of elements in pvalues
  6958. // USED FOR DEBUG ONLY.
  6959. void DSP_DEBUGSetParams(int ipreset, int iproc, float *pvalues, int cparams)
  6960. {
  6961. pset_t new_pset; // preset
  6962. int cparam = clamp (cparams, 0, CPRCPARAMS);
  6963. prc_t *pprct;
  6964. // copy template preset from template array
  6965. new_pset = g_psettemplates[ipreset];
  6966. // get iproc processor
  6967. pprct = &(new_pset.prcs[iproc]);
  6968. // copy parameters in to processor
  6969. for (int i = 0; i < cparam; i++)
  6970. {
  6971. pprct->prm[i] = pvalues[i];
  6972. }
  6973. // copy constructed preset back into template location
  6974. g_psettemplates[ipreset] = new_pset;
  6975. // setup new preset
  6976. dsp_room.SetValue( 0 );
  6977. CheckNewDspPresets();
  6978. dsp_room.SetValue( ipreset );
  6979. CheckNewDspPresets();
  6980. }
  6981. // reload entire preset file, reset all current dsp presets
  6982. // NOTE: this is debug code only. It doesn't do all mem free work correctly!
  6983. void DSP_DEBUGReloadPresetFile( void )
  6984. {
  6985. int iroom = dsp_room.GetInt();
  6986. int iwater = dsp_water.GetInt();
  6987. int iplayer = dsp_player.GetInt();
  6988. // int ifacingaway = dsp_facingaway.GetInt();
  6989. // int iroomtype = dsp_room_type.GetInt();
  6990. int ispeaker = dsp_speaker.GetInt();
  6991. int ispatial = dsp_spatial.GetInt();
  6992. // int iautomatic = dsp_automatic.GetInt();
  6993. // reload template array
  6994. DSP_ReleaseMemory();
  6995. DSP_LoadPresetFile();
  6996. // force presets to reload
  6997. dsp_room.SetValue( 0 );
  6998. dsp_water.SetValue( 0 );
  6999. dsp_player.SetValue( 0 );
  7000. //dsp_facingaway.SetValue( 0 );
  7001. //dsp_room_type.SetValue( 0 );
  7002. dsp_speaker.SetValue( 0 );
  7003. dsp_spatial.SetValue( 0 );
  7004. //dsp_automatic.SetValue( 0 );
  7005. CUtlVector< int > specialDSPs;
  7006. for ( int i = SOUND_BUFFER_SPECIAL_START; i < g_paintBuffers.Count(); ++i )
  7007. {
  7008. paintbuffer_t *pSpecialBuffer = MIX_GetPPaintFromIPaint( i );
  7009. specialDSPs.AddToTail( pSpecialBuffer->nSpecialDSP );
  7010. pSpecialBuffer->nSpecialDSP = 0;
  7011. }
  7012. CheckNewDspPresets();
  7013. dsp_room.SetValue( iroom );
  7014. dsp_water.SetValue( iwater );
  7015. dsp_player.SetValue( iplayer );
  7016. //dsp_facingaway.SetValue( ifacingaway );
  7017. //dsp_room_type.SetValue( iroomtype );
  7018. dsp_speaker.SetValue( ispeaker );
  7019. dsp_spatial.SetValue( ispatial );
  7020. //dsp_automatic.SetValue( iautomatic );
  7021. int nSpecialDSPNum = 0;
  7022. for ( int i = SOUND_BUFFER_SPECIAL_START; i < g_paintBuffers.Count(); ++i )
  7023. {
  7024. paintbuffer_t *pSpecialBuffer = MIX_GetPPaintFromIPaint( i );
  7025. pSpecialBuffer->nSpecialDSP = specialDSPs[ nSpecialDSPNum ];
  7026. nSpecialDSPNum++;
  7027. }
  7028. CheckNewDspPresets();
  7029. // flush dsp automatic nodes
  7030. g_bdas_init_nodes = 0;
  7031. g_bdas_room_init = 0;
  7032. }
  7033. // UNDONE: stock reverb presets:
  7034. // carpet hallway
  7035. // tile hallway
  7036. // wood hallway
  7037. // metal hallway
  7038. // train tunnel
  7039. // sewer main tunnel
  7040. // concrete access tunnel
  7041. // cave tunnel
  7042. // sand floor cave tunnel
  7043. // metal duct shaft
  7044. // elevator shaft
  7045. // large elevator shaft
  7046. // parking garage
  7047. // aircraft hangar
  7048. // cathedral
  7049. // train station
  7050. // small cavern
  7051. // large cavern
  7052. // huge cavern
  7053. // watery cavern
  7054. // long, low cavern
  7055. // wood warehouse
  7056. // metal warehouse
  7057. // concrete warehouse
  7058. // small closet room
  7059. // medium drywall room
  7060. // medium wood room
  7061. // medium metal room
  7062. // elevator
  7063. // small metal room
  7064. // medium metal room
  7065. // large metal room
  7066. // huge metal room
  7067. // small metal room dense
  7068. // medium metal room dense
  7069. // large metal room dense
  7070. // huge metal room dense
  7071. // small concrete room
  7072. // medium concrete room
  7073. // large concrete room
  7074. // huge concrete room
  7075. // small concrete room dense
  7076. // medium concrete room dense
  7077. // large concrete room dense
  7078. // huge concrete room dense
  7079. // soundproof room
  7080. // carpet lobby
  7081. // swimming pool
  7082. // open park
  7083. // open courtyard
  7084. // wide parkinglot
  7085. // narrow street
  7086. // wide street, short buildings
  7087. // wide street, tall buildings
  7088. // narrow canyon
  7089. // wide canyon
  7090. // huge canyon
  7091. // small valley
  7092. // wide valley
  7093. // wreckage & rubble
  7094. // small building cluster
  7095. // wide open plain
  7096. // high vista
  7097. // alien interior small
  7098. // alien interior medium
  7099. // alien interior large
  7100. // alien interior huge
  7101. // special fx presets:
  7102. // alien citadel
  7103. // teleport aftershock (these presets all ADSR timeout and reset the dsp_* to 0)
  7104. // on target teleport
  7105. // off target teleport
  7106. // death fade
  7107. // beam stasis
  7108. // scatterbrain
  7109. // pulse only
  7110. // slomo
  7111. // hypersensitive
  7112. // supershocker
  7113. // physwhacked
  7114. // forcefieldfry
  7115. // juiced
  7116. // zoomed in
  7117. // crabbed
  7118. // barnacle gut
  7119. // bad transmission
  7120. ////////////////////////
  7121. // Dynamics processing
  7122. ////////////////////////
  7123. // compressor defines
  7124. #define COMP_MAX_AMP 32767 // abs max amplitude
  7125. #define COMP_THRESH 20000 // start compressing at this threshold
  7126. // compress input value - smoothly limit output y to -32767 <= y <= 32767
  7127. // UNDONE: not tested or used
  7128. inline int S_Compress( int xin )
  7129. {
  7130. return CLIP( xin >> 2 ); // DEBUG - disabled
  7131. float Yn, Xn, Cn, Fn;
  7132. float C0 = 20000; // threshold
  7133. float p = .3; // compression ratio
  7134. float g = 1; // gain after compression
  7135. Xn = (float)xin;
  7136. // Compressor formula:
  7137. // Cn = l*Cn-1 + (1-l)*|Xn| // peak detector with memory
  7138. // f(Cn) = (Cn/C0)^(p-1) for Cn > C0 // gain function above threshold
  7139. // f(Cn) = 1 for C <= C0 // unity gain below threshold
  7140. // Yn = f(Cn) * Xn // compressor output
  7141. // UNDONE: curves discontinuous at threshold, causes distortion, try catmul-rom
  7142. //float l = .5; // compressor memory
  7143. //Cn = l * (*pCnPrev) + (1 - l) * fabs((float)xin);
  7144. //*pCnPrev = Cn;
  7145. Cn = fabs((float)xin);
  7146. if (Cn < C0)
  7147. Fn = 1;
  7148. else
  7149. Fn = powf((Cn / C0),(p - 1));
  7150. Yn = Fn * Xn * g;
  7151. //if (Cn > 0)
  7152. // Msg("%d -> %d\n", xin, (int)Yn); // DEBUG
  7153. //if (fabs(Yn) > 32767)
  7154. // Yn = Yn; // DEBUG
  7155. return (CLIP((int)Yn));
  7156. }