Counter Strike : Global Offensive Source Code
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.

12358 lines
336 KiB

  1. //========= Copyright 1996-2005, 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 "iprediction.h"
  11. #include "../../common.h" // for parsing routines
  12. #include "vstdlib/random.h"
  13. #include "tier0/cache_hints.h"
  14. #include "sound.h"
  15. #include "client.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. #define SIGN(d) ((d)<0?-1:1)
  19. #define ABS(a) abs(a)
  20. #define MSEC_TO_SAMPS(a) (((a)*SOUND_DMA_SPEED) / 1000) // convert milliseconds to # samples in equivalent time
  21. #define SEC_TO_SAMPS(a) ((a)*SOUND_DMA_SPEED) // convert seconds to # samples in equivalent time
  22. #define SAMPS_TO_SEC(a) ((a)/SOUND_DMA_SPEED) // convert seconds to # samples in equivalent time
  23. #define CLIP_DSP(x) (x)
  24. extern ConVar das_debug;
  25. #define SOUND_MS_PER_FT 1 // sound travels approx 1 foot per millisecond
  26. #define ROOM_MAX_SIZE 1000 // max size in feet of room simulation for dsp
  27. void DSP_ReleaseMemory( void );
  28. bool DSP_LoadPresetFile( void );
  29. extern float Gain_To_dB ( float gain );
  30. extern float dB_To_Gain ( float dB );
  31. extern float Gain_To_Amplitude ( float gain );
  32. extern float Amplitude_To_Gain ( float amplitude );
  33. extern bool g_bdas_room_init;
  34. extern bool g_bdas_init_nodes;
  35. ConVar snd_dsp_optimization( "snd_dsp_optimization", "0", FCVAR_NONE, "Turns optimization on for DSP effects if set to 1 (default). 0 to turn the optimization off." );
  36. ConVar snd_dsp_spew_changes( "snd_dsp_spew_changes", "0", FCVAR_NONE, "Spews major changes to the dsp or presets if set to 1. 0 to turn the spew off (default)." );
  37. ConVar snd_dsp_cancel_old_preset_after_N_milliseconds( "snd_dsp_cancel_old_preset_after_N_milliseconds", "1000", FCVAR_NONE, "Number of milliseconds after an unused previous preset is not considered valid for the start of a cross-fade.");
  38. ConVar snd_spew_dsp_process( "snd_spew_dsp_process", "0", FCVAR_NONE, "Spews text every time a DSP effect is applied if set to 1. 0 to turn the spew off (default)." );
  39. ConVar snd_dsp_test1( "snd_dsp_test1", "1.0", FCVAR_NONE );
  40. ConVar snd_dsp_test2( "snd_dsp_test2", "1.0", FCVAR_NONE );
  41. // Use short to save some memory and L2 cache misses on X360 and PS3. Except in some cases, it does not seem that we need to use int for the samples.
  42. // For the moment we enable it on all platforms to detect issues earlier, but later we may only use it for PS3.
  43. typedef int LocalOutputSample_t;
  44. typedef int CircularBufferSample_t;
  45. //===============================================================================
  46. //
  47. // Digital Signal Processing algorithms for audio FX.
  48. //
  49. // KellyB 2/18/03
  50. //===============================================================================
  51. // Performance notes:
  52. // DSP processing should take no more than 3ms total time per frame to remain on par with hl1
  53. // Assume a min frame rate of 24fps = 42ms per frame
  54. // at 24fps, to maintain 44.1khz output rate, we must process about 1840 mono samples per frame.
  55. // So we must process 1840 samples in 3ms.
  56. // on a 1Ghz CPU (mid-low end CPU) 3ms provides roughly 3,000,000 cycles.
  57. // Thus we have 3e6 / 1840 = 1630 cycles per sample.
  58. #define PBITS 12 // parameter bits
  59. #define PMAX ((1 << PBITS)) // parameter max
  60. // crossfade from y2 to y1 at point r (0 < r < PMAX)
  61. #define XFADE(y1,y2,r) ((y2) + ( ( ((y1) - (y2)) * (r) ) >> PBITS) )
  62. // exponential crossfade from y2 to y1 at point r (0 < r < PMAX)
  63. #define XFADE_EXP(y1, y2, r) ((y2) + ((((((y1) - (y2)) * (r) ) >> PBITS) * (r)) >> PBITS) )
  64. // In debug, we are going to compare the old code and the new code and make sure we get the exact same output
  65. // As it has to clone all the filters, delays, modulated delays, rvas, samples, etc... The code is also initially checking
  66. // that the clone works correctly with the original algorithm (so we separate issues related to incorrect cloning from incorrect optimization).
  67. #if _DEBUG
  68. #define CHECK_VALUES_AFTER_REFACTORING 1
  69. #else
  70. #define CHECK_VALUES_AFTER_REFACTORING 0
  71. #endif
  72. const int SAMPLES_BEFORE = 64;
  73. const int SAMPLES_AFTER = 64;
  74. const unsigned char FILL_PATTERN = 0xA5;
  75. // To make sure we have the same results, duplicate everything
  76. // Add some markers before and after to detect if we write outside of the range.
  77. portable_samplepair_t * DuplicateSamplePairs(portable_samplepair_t * pInputBuffer, int nSampleCount)
  78. {
  79. if ( nSampleCount == 1 )
  80. {
  81. // There is a bug in some PC Asm code where it assumes that we have at least 2 samples
  82. // Set the value to 2, so the FILL_PATTERN is handled correctly.
  83. nSampleCount = 2;
  84. }
  85. portable_samplepair_t * pSamePairs = (portable_samplepair_t *)MemAlloc_AllocAligned( sizeof( portable_samplepair_t ) * ( SAMPLES_BEFORE + nSampleCount + SAMPLES_AFTER ), 16 );
  86. // Because we are allocating a big size, we have a 16 bytes alignment on allocation
  87. Assert( ( (intp)pSamePairs & 0xf ) == 0 );
  88. memset( pSamePairs, FILL_PATTERN, SAMPLES_BEFORE * sizeof( portable_samplepair_t ) );
  89. pSamePairs += SAMPLES_BEFORE;
  90. memcpy( pSamePairs, pInputBuffer, nSampleCount * sizeof( portable_samplepair_t ) );
  91. memset( pSamePairs + nSampleCount, FILL_PATTERN, SAMPLES_AFTER * sizeof( portable_samplepair_t ) );
  92. return pSamePairs;
  93. }
  94. void FreeDuplicatedSamplePairs( portable_samplepair_t * pInputBuffer, int nSampleCount )
  95. {
  96. Assert( ( (intp)pInputBuffer & 0xf ) == 0 );
  97. if ( nSampleCount == 1 )
  98. {
  99. // There is a bug in some PC Asm code where it assumes that we have at least 2 samples
  100. // Set the value to 2, so the FILL_PATTERN is handled correctly.
  101. nSampleCount = 2;
  102. }
  103. unsigned char * pAfterBuffer;
  104. pAfterBuffer = (unsigned char *)( pInputBuffer + nSampleCount );
  105. const int nAfterSize = SAMPLES_AFTER * sizeof( portable_samplepair_t );
  106. for ( int i = 0 ; i < nAfterSize ; ++i )
  107. {
  108. Assert( pAfterBuffer[i] == FILL_PATTERN );
  109. }
  110. pInputBuffer -= SAMPLES_BEFORE;
  111. const int nBeforeSize = SAMPLES_BEFORE * sizeof( portable_samplepair_t );
  112. unsigned char * pBeforeBuffer;
  113. pBeforeBuffer = (unsigned char *)( pInputBuffer );
  114. for ( int i = 0 ; i < nBeforeSize ; ++i )
  115. {
  116. Assert( pBeforeBuffer[i] == FILL_PATTERN );
  117. }
  118. MemAlloc_FreeAligned( pInputBuffer );
  119. }
  120. const char * GetIndentationText( int nIndentation )
  121. {
  122. const int MAX_INDENTATION_SIZE = 32;
  123. static char sIndentationBuffer[MAX_INDENTATION_SIZE + 1];
  124. static bool sFirstTime = true;
  125. if ( sFirstTime )
  126. {
  127. memset( sIndentationBuffer, '\t', MAX_INDENTATION_SIZE );
  128. sIndentationBuffer[MAX_INDENTATION_SIZE] = '\0';
  129. sFirstTime = false;
  130. }
  131. if ( nIndentation > MAX_INDENTATION_SIZE )
  132. {
  133. nIndentation = MAX_INDENTATION_SIZE;
  134. }
  135. // nIndentation corresponds to the number of tabs returned in the string
  136. return sIndentationBuffer + MAX_INDENTATION_SIZE - nIndentation;
  137. }
  138. #if CHECK_VALUES_AFTER_REFACTORING
  139. void LocalRandomSeed( )
  140. {
  141. // Do nothing...
  142. }
  143. // For the comparison test always return the same value... (some filters are using RandomInt() in some cases making the comparison impossible).
  144. // Setting the seed before the test is not enough as another thread could call Random() and we would still have an indeterministic result.
  145. // TODO: Improve this by creating a proper random stream...
  146. int LocalRandomInt( int min, int max )
  147. {
  148. return ( min + max ) / 2;
  149. }
  150. #else
  151. inline
  152. int LocalRandomInt( int min, int max )
  153. {
  154. return RandomInt( min, max );
  155. }
  156. #endif
  157. template <typename T>
  158. bool CheckPointers( T * p1, T * p2 )
  159. {
  160. if ( p1 != NULL )
  161. {
  162. Assert( p2 != NULL );
  163. // When pointers are not NULL, we want to make sure that they don't point to the same object (after all they are completely cloned).
  164. Assert( p1 != p2 );
  165. return true;
  166. }
  167. else
  168. {
  169. Assert( p2 == NULL );
  170. return false;
  171. }
  172. }
  173. /////////////////////
  174. // dsp helpers
  175. /////////////////////
  176. // reverse delay pointer
  177. inline void DlyPtrReverse (int dlysize, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp)
  178. {
  179. // when *ppsamp = psamps - 1, it wraps around to *ppsamp = psamps + dlysize
  180. if ( *ppsamp < psamps )
  181. *ppsamp += dlysize + 1;
  182. }
  183. // advance delay pointer
  184. inline void DlyPtrForward (int dlysize, int *psamps, int **ppsamp)
  185. {
  186. // when *ppsamp = psamps + dlysize + 1, it wraps around to *ppsamp = psamps
  187. if ( *ppsamp > psamps + dlysize )
  188. *ppsamp -= dlysize + 1;
  189. }
  190. // Infinite Impulse Response (feedback) filter, cannonical form
  191. // returns single sample 'out' for current input value 'in'
  192. // in: input sample
  193. // psamp: internal state array, dimension max(cdenom,cnumer) + 1
  194. // cnumer,cdenom: numerator and denominator filter orders
  195. // denom,numer: cdenom+1 dimensional arrays of filter params
  196. //
  197. // for cdenom = 4:
  198. //
  199. // 1 psamp0(n) numer0
  200. // in(n)--->(+)--(*)---.------(*)---->(+)---> out(n)
  201. // ^ | ^
  202. // | [Delay d] |
  203. // | | |
  204. // | -denom1 |psamp1 numer1 |
  205. // ----(*)---.------(*)-------
  206. // ^ | ^
  207. // | [Delay d] |
  208. // | | |
  209. // | -denom2 |psamp2 numer2 |
  210. // ----(*)---.------(*)-------
  211. // ^ | ^
  212. // | [Delay d] |
  213. // | | |
  214. // | -denom3 |psamp3 numer3 |
  215. // ----(*)---.------(*)-------
  216. // ^ | ^
  217. // | [Delay d] |
  218. // | | |
  219. // | -denom4 |psamp4 numer4 |
  220. // ----(*)---.------(*)-------
  221. //
  222. // for each input sample in:
  223. // psamp0 = in - denom1*psamp1 - denom2*psamp2 - ...
  224. // out = numer0*psamp0 + numer1*psamp1 + ...
  225. // psampi = psampi-1, i = cmax, cmax-1, ..., 1
  226. inline int IIRFilter_Update_OrderN ( int cdenom, int *denom, int cnumer, int *numer, int *psamp, int in )
  227. {
  228. int cmax, i;
  229. int out;
  230. int in0;
  231. out = 0;
  232. in0 = in;
  233. cmax = MAX ( cdenom, cnumer );
  234. // add input values
  235. // for (i = 1; i <= cdenom; i++)
  236. // psamp[0] -= ( denom[i] * psamp[i] ) >> PBITS;
  237. switch (cdenom)
  238. {
  239. case 12: in0 -= ( denom[12] * psamp[12] ) >> PBITS;
  240. case 11: in0 -= ( denom[11] * psamp[11] ) >> PBITS;
  241. case 10: in0 -= ( denom[10] * psamp[10] ) >> PBITS;
  242. case 9: in0 -= ( denom[9] * psamp[9] ) >> PBITS;
  243. case 8: in0 -= ( denom[8] * psamp[8] ) >> PBITS;
  244. case 7: in0 -= ( denom[7] * psamp[7] ) >> PBITS;
  245. case 6: in0 -= ( denom[6] * psamp[6] ) >> PBITS;
  246. case 5: in0 -= ( denom[5] * psamp[5] ) >> PBITS;
  247. case 4: in0 -= ( denom[4] * psamp[4] ) >> PBITS;
  248. case 3: in0 -= ( denom[3] * psamp[3] ) >> PBITS;
  249. case 2: in0 -= ( denom[2] * psamp[2] ) >> PBITS;
  250. default:
  251. case 1: in0 -= ( denom[1] * psamp[1] ) >> PBITS;
  252. }
  253. psamp[0] = in0;
  254. // add output values
  255. //for (i = 0; i <= cnumer; i++)
  256. // out += ( numer[i] * psamp[i] ) >> PBITS;
  257. switch (cnumer)
  258. {
  259. case 12: out += ( numer[12] * psamp[12] ) >> PBITS;
  260. case 11: out += ( numer[11] * psamp[11] ) >> PBITS;
  261. case 10: out += ( numer[10] * psamp[10] ) >> PBITS;
  262. case 9: out += ( numer[9] * psamp[9] ) >> PBITS;
  263. case 8: out += ( numer[8] * psamp[8] ) >> PBITS;
  264. case 7: out += ( numer[7] * psamp[7] ) >> PBITS;
  265. case 6: out += ( numer[6] * psamp[6] ) >> PBITS;
  266. case 5: out += ( numer[5] * psamp[5] ) >> PBITS;
  267. case 4: out += ( numer[4] * psamp[4] ) >> PBITS;
  268. case 3: out += ( numer[3] * psamp[3] ) >> PBITS;
  269. case 2: out += ( numer[2] * psamp[2] ) >> PBITS;
  270. default:
  271. case 1: out += ( numer[1] * psamp[1] ) >> PBITS;
  272. case 0: out += ( numer[0] * psamp[0] ) >> PBITS;
  273. }
  274. // update internal state (reverse order)
  275. for (i = cmax; i >= 1; i--)
  276. psamp[i] = psamp[i-1];
  277. // return current output sample
  278. return out;
  279. }
  280. // 1st order filter - faster version
  281. inline int IIRFilter_Update_Order1 ( int *denom, int cnumer, int *numer, int *psamp, int in )
  282. {
  283. int out;
  284. if (!psamp[0] && !psamp[1] && !in)
  285. return 0;
  286. psamp[0] = in - (( denom[1] * psamp[1] ) >> PBITS);
  287. out = ( ( numer[1] * psamp[1] ) + ( numer[0] * psamp[0] ) ) >> PBITS;
  288. psamp[1] = psamp[0];
  289. return out;
  290. }
  291. // return 'tdelay' delayed sample from delay buffer
  292. // dlysize: delay samples
  293. // psamps: head of delay buffer psamps[0...dlysize]
  294. // psamp: current data pointer
  295. // sdly: 0...dlysize
  296. inline int GetDly ( int dlysize, CircularBufferSample_t *psamps, CircularBufferSample_t *psamp, int tdelay )
  297. {
  298. CircularBufferSample_t *pout;
  299. pout = psamp + tdelay;
  300. if ( pout <= (psamps + dlysize))
  301. return *pout;
  302. else
  303. return *(pout - dlysize - 1);
  304. }
  305. // update the delay buffer pointer
  306. // dlysize: delay samples
  307. // psamps: head of delay buffer psamps[0...dlysize]
  308. // ppsamp: data pointer
  309. inline void DlyUpdate ( int dlysize, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp )
  310. {
  311. // decrement pointer and fix up on buffer boundary
  312. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  313. (*ppsamp)--;
  314. DlyPtrReverse ( dlysize, psamps, ppsamp );
  315. }
  316. // simple delay with feedback, no filter in feedback line.
  317. // delaysize: delay line size in samples
  318. // tdelay: tap from this location - <= delaysize
  319. // psamps: delay line buffer pointer of dimension delaysize+1
  320. // ppsamp: circular pointer, must be init to &psamps[0] before first call
  321. // fbgain: feedback value, 0-PMAX (normalized to 0.0-1.0)
  322. // outgain: gain
  323. // in: input sample
  324. // psamps0(n) outgain
  325. // in(n)--->(+)--------.-----(*)-> out(n)
  326. // ^ |
  327. // | [Delay d]
  328. // | |
  329. // | fbgain |Wd(n)
  330. // ----(*)---.
  331. inline int ReverbSimple ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int in )
  332. {
  333. int out, sD;
  334. // get current delay output
  335. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  336. // calculate output + delay * gain
  337. out = in + (( fbgain * sD ) >> PBITS);
  338. // write to delay
  339. **ppsamp = out;
  340. // advance internal delay pointers
  341. DlyUpdate ( delaysize, psamps, ppsamp );
  342. return ( (out * outgain) >> PBITS );
  343. }
  344. inline void ReverbSimple_Opt ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int * pIn, LocalOutputSample_t * pOut, int nCount )
  345. {
  346. while ( nCount-- > 0 )
  347. {
  348. *pOut++ += ReverbSimple( delaysize, tdelay, psamps, ppsamp, fbgain, outgain, *pIn );
  349. pIn += 2; // Because pIn has both left AND right (but we read only one).
  350. }
  351. }
  352. inline int ReverbSimple_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int in )
  353. {
  354. int out, sD;
  355. int sDnew;
  356. // crossfade from tdelay to tdelaynew samples. xfade is 0..PMAX
  357. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  358. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  359. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  360. out = in + (( fbgain * sD ) >> PBITS);
  361. **ppsamp = out;
  362. DlyUpdate ( delaysize, psamps, ppsamp );
  363. return ( (out * outgain) >> PBITS );
  364. }
  365. // multitap simple reverb
  366. // NOTE: tdelay3 > tdelay2 > tdelay1 > t0
  367. // NOTE: fbgain * 4 < 1!
  368. inline int ReverbSimple_multitap ( int delaysize, int tdelay0, int tdelay1, int tdelay2, int tdelay3, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int in )
  369. {
  370. int s1, s2, s3, s4, sum;
  371. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  372. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  373. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  374. s4 = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  375. sum = s1 + s2 + s3 + s4;
  376. // write to delay
  377. **ppsamp = in + ((s4 * fbgain) >> PBITS);
  378. // update delay pointers
  379. DlyUpdate ( delaysize, psamps, ppsamp );
  380. return ( ((sum + in) * outgain ) >> PBITS );
  381. }
  382. inline void ReverbSimple_multitap_Opt ( int delaysize, int tdelay0, int tdelay1, int tdelay2, int tdelay3, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int * pIn, LocalOutputSample_t * pOut, int nCount )
  383. {
  384. while ( nCount-- > 0 )
  385. {
  386. *pOut++ += ReverbSimple_multitap( delaysize, tdelay0, tdelay1, tdelay2, tdelay3, psamps, ppsamp, fbgain, outgain, *pIn );
  387. pIn += 2; // Because pIn has both left AND right (but we read only one).
  388. }
  389. }
  390. // modulate smallest tap delay only
  391. inline int ReverbSimple_multitap_xfade ( int delaysize, int tdelay0, int tdelaynew, int xf, int tdelay1, int tdelay2, int tdelay3, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int in )
  392. {
  393. int s1, s2, s3, s4, sum;
  394. int sD, sDnew;
  395. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  396. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  397. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  398. s4 = sD + (((sDnew - sD) * xf) >> PBITS);
  399. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  400. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  401. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  402. sum = s1 + s2 + s3 + s4;
  403. // write to delay
  404. **ppsamp = in + ((s4 * fbgain) >> PBITS);
  405. // update delay pointers
  406. DlyUpdate ( delaysize, psamps, ppsamp );
  407. return ( ((sum + in) * outgain ) >> PBITS );
  408. }
  409. // straight delay, no feedback
  410. //
  411. // delaysize: delay line size in samples
  412. // tdelay: tap from this location - <= delaysize
  413. // psamps: delay line buffer pointer of dimension delaysize+1
  414. // ppsamp: circular pointer, must be init to &psamps[0] before first call
  415. // in: input sample
  416. //
  417. // in(n)--->[Delay d]---> out(n)
  418. //
  419. inline int DelayLinear ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int in )
  420. {
  421. int out;
  422. out = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  423. **ppsamp = in;
  424. DlyUpdate ( delaysize, psamps, ppsamp );
  425. return ( out );
  426. }
  427. inline void DelayLinear_Opt ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int * pIn, LocalOutputSample_t * pOut, int nCount )
  428. {
  429. while ( nCount-- > 0 )
  430. {
  431. *pOut++ += DelayLinear( delaysize, tdelay, psamps, ppsamp, *pIn );
  432. pIn += 2; // Because pIn has both left AND right (but we read only one).
  433. }
  434. }
  435. // crossfade delay values from tdelay to tdelaynew, with xfade1 for tdelay and xfade2 for tdelaynew. xfade = 0...PMAX
  436. inline int DelayLinear_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int in )
  437. {
  438. int out;
  439. int outnew;
  440. out = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  441. outnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  442. out = out + (((outnew - out) * xf) >> PBITS);
  443. **ppsamp = in;
  444. DlyUpdate ( delaysize, psamps, ppsamp );
  445. return ( out );
  446. }
  447. // lowpass reverberator, replace feedback multiplier 'fbgain' in
  448. // reverberator with a low pass filter
  449. // delaysize: delay line size in samples
  450. // tdelay: tap from this location - <= delaysize
  451. // psamps: delay line buffer pointer of dimension delaysize+1
  452. // ppsamp: circular pointer, must be init to &w[0] before first call
  453. // fbgain: feedback gain (built into filter gain)
  454. // outgain: output gain
  455. // cnumer: filter order
  456. // numer: filter numerator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  457. // denom: filter denominator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  458. // pfsamps: filter state, cnumer+1 dimensional
  459. // in: input sample
  460. // psamps0(n) outgain
  461. // in(n)--->(+)--------------.----(*)--> out(n)
  462. // ^ |
  463. // | [Delay d]
  464. // | |
  465. // | fbgain |Wd(n)
  466. // --(*)--[Filter])-
  467. inline int DelayLowPass ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  468. {
  469. int out, sD;
  470. // delay output is filter input
  471. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  472. // filter output, with feedback 'fbgain' baked into filter params
  473. out = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  474. // write to delay
  475. **ppsamp = out;
  476. // update delay pointers
  477. DlyUpdate ( delaysize, psamps, ppsamp );
  478. // output with gain
  479. return ( (out * outgain) >> PBITS );
  480. }
  481. inline void DelayLowPass_Opt ( const int nDelaySize, const int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, const int fbgain, const int outgain, int *denom, const int Ll, int *numer, int *pfsamps, int * pIn, int * pOut, int nCount )
  482. {
  483. while ( nCount-- > 0 )
  484. {
  485. *pOut++ += DelayLowPass( nDelaySize, tdelay, psamps, ppsamp, fbgain, outgain, denom, Ll, numer, pfsamps, *pIn );
  486. pIn += 2;
  487. }
  488. }
  489. void DelayLowPass_Opt2 ( const int nDelaySize, const int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, const int fbgain, const int outgain, int *denom, const int Ll, int *numer, int *pfsamps, int * pIn, LocalOutputSample_t * pOut, int nCount )
  490. {
  491. // int pfsamps0 = pfsamps[0]; // pfsamps0 is not needed as it is overridden during the filtering
  492. int pfsamps1 = pfsamps[1];
  493. int numer0 = numer[0];
  494. int numer1 = numer[1];
  495. int denom1 = denom[1];
  496. CircularBufferSample_t * pDelaySample = *ppsamp;
  497. // Code path with no tests
  498. // TODO: We could improve a bit further by calculating how many samples we can calculate without having to loop around
  499. // This would reduce some of the overhead with the branch-less test (save a couple of cycles).
  500. // TODO: Consider unrolling this, don't know how much we would really save though. And would make the code much less maintainable (esp. if we do the same for all filters).
  501. CircularBufferSample_t * pSampsPDelaySize = psamps + nDelaySize;
  502. const int nDelaySizeP1 = nDelaySize + 1;
  503. while ( nCount-- > 0 )
  504. {
  505. // delay output is filter input
  506. CircularBufferSample_t *pInputSampleDelay = pDelaySample + tdelay;
  507. #if 1
  508. // 4 ops instead of 1 op + 1 branch (and potentially one more op).
  509. // Re-use our own version of isel() as there is an optimization we can do
  510. int nMask1 = (pSampsPDelaySize - pInputSampleDelay) >> 31; // 0xffffffff if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  511. nMask1 &= nDelaySizeP1; // nDelaySizeP1 if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  512. pInputSampleDelay -= nMask1;
  513. #else
  514. if ( pInputSampleDelay > pSampsPDelaySize)
  515. {
  516. pInputSampleDelay -= nDelaySizeP1;
  517. }
  518. #endif
  519. int sD = *pInputSampleDelay;
  520. // filter output, with feedback 'fbgain' baked into filter params
  521. // IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  522. int pfsamps0 = sD - (( denom1 * pfsamps1 ) >> PBITS);
  523. int nFilteredOutput = ( ( numer1 * pfsamps1 ) + ( numer0 * pfsamps0 ) ) >> PBITS;
  524. pfsamps1 = pfsamps0;
  525. int out = *pIn + nFilteredOutput;
  526. pIn += 2; // Because pIn has both left AND right (but we read only one).
  527. // write to delay
  528. *pDelaySample = out;
  529. // update delay pointers, decrement pointer and fix up on buffer boundary
  530. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  531. --pDelaySample;
  532. #if 1
  533. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  534. int nMask2 = (pDelaySample - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  535. nMask2 &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  536. pDelaySample += nMask2;
  537. #else
  538. if ( pDelaySample < psamps )
  539. {
  540. pDelaySample += nDelaySizeP1;
  541. }
  542. #endif
  543. // output with gain
  544. *pOut++ += ( (out * outgain) >> PBITS );
  545. if ( ( nCount % (CACHE_LINE_SIZE / sizeof(portable_samplepair_t) ) ) == 0)
  546. {
  547. // Prefetch the next input samples (output samples are already in cache anyway)
  548. // Do conservative prefetching to reduce cache usage and in case the memory was virtual and would prefetch memory outside the buffer.
  549. const int nBytesLeft = nCount * sizeof(portable_samplepair_t);
  550. if ( nBytesLeft >= 3 * CACHE_LINE_SIZE )
  551. {
  552. PREFETCH_128( pIn, 4 * CACHE_LINE_SIZE );
  553. }
  554. const int OFFSET = CACHE_LINE_SIZE / sizeof( *pDelaySample );
  555. if ( pDelaySample - OFFSET >= psamps )
  556. {
  557. PREFETCH_128( pDelaySample, -2 * CACHE_LINE_SIZE ); // We often read the delay sample just before the one that we are writing
  558. // Thus one prefetch will handle gracefully both delay accesses
  559. }
  560. }
  561. }
  562. *ppsamp = pDelaySample;
  563. pfsamps[0] = pfsamps1; // The [0] and [1] are the same after the filtering
  564. pfsamps[1] = pfsamps1;
  565. }
  566. // By adding few constraints on the data and accepting some slight error in the calculation we could make the code much faster.
  567. // Currently we can't SIMD this code the way it is but if we were calculating 4 samples at a time (completely independently), then we could make this loop 4-10 times faster.
  568. // But the first thing would be to make the code work with floats.
  569. void DelayLowPass_Opt3 ( const int nDelaySize, const int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, const int fbgain, const int outgain, int *denom, const int Ll, int *numer, int *pfsamps, int * pIn, LocalOutputSample_t * pOut, int nCount )
  570. {
  571. if ( nDelaySize != tdelay )
  572. {
  573. // Use less optimized code path if conditions are not right.
  574. DelayLowPass_Opt2( nDelaySize, tdelay, psamps, ppsamp, fbgain, outgain, denom, Ll, numer, pfsamps, pIn, pOut, nCount );
  575. return;
  576. }
  577. // Here it means that the read delay buffer is always just after the write delay buffer (have to account the wrap around obviously).
  578. // int pfsamps0 = pfsamps[0]; // pfsamps0 is not needed as it is overridden during the filtering
  579. int pfsamps1 = pfsamps[1];
  580. int numer0 = numer[0];
  581. int numer1 = numer[1];
  582. int denom1 = denom[1];
  583. CircularBufferSample_t * pDelaySample = *ppsamp;
  584. // Code path with no tests
  585. // TODO: We could improve a bit further by calculating how many samples we can calculate without having to loop around
  586. // This would reduce some of the overhead with the branch-less test (save a couple of cycles).
  587. // TODO: Consider unrolling this, don't know how much we would really save though. And would make the code much less maintainable (esp. if we do the same for all filters).
  588. CircularBufferSample_t * pSampsPDelaySize = psamps + nDelaySize;
  589. const int nDelaySizeP1 = nDelaySize + 1;
  590. // First the final 3 samples (so nCount is aligned on 4 after this loop)
  591. while ( (nCount & 3 ) != 0 )
  592. {
  593. --nCount;
  594. // delay output is filter input
  595. CircularBufferSample_t *pInputDelaySample = pDelaySample + nDelaySize;
  596. int nMask1 = (pSampsPDelaySize - pInputDelaySample) >> 31; // 0xffffffff if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  597. nMask1 &= nDelaySizeP1; // nDelaySizeP1 if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  598. pInputDelaySample -= nMask1;
  599. int sD = *pInputDelaySample;
  600. // filter output, with feedback 'fbgain' baked into filter params
  601. // IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  602. int pfsamps0 = sD - (( denom1 * pfsamps1 ) >> PBITS);
  603. int nFilteredOutput = ( ( numer1 * pfsamps1 ) + ( numer0 * pfsamps0 ) ) >> PBITS;
  604. pfsamps1 = pfsamps0;
  605. int out = *pIn + nFilteredOutput;
  606. pIn += 2; // Because pIn has both left AND right (but we read only one).
  607. // write to delay
  608. *pDelaySample = out;
  609. // update delay pointers, decrement pointer and fix up on buffer boundary
  610. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  611. --pDelaySample;
  612. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  613. int nMask2 = (pDelaySample - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  614. nMask2 &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  615. pDelaySample += nMask2;
  616. // output with gain
  617. *pOut++ += ( (out * outgain) >> PBITS );
  618. }
  619. CircularBufferSample_t * RESTRICT pDelaySampleA = pDelaySample;
  620. CircularBufferSample_t * RESTRICT pDelaySampleB = pDelaySample - 1;
  621. CircularBufferSample_t * RESTRICT pDelaySampleC = pDelaySample - 2;
  622. CircularBufferSample_t * RESTRICT pDelaySampleD = pDelaySample - 3;
  623. // pDelaySampleA is already in the correct range
  624. int nMask2B = (pDelaySampleB - psamps) >> 31;
  625. nMask2B &= nDelaySizeP1;
  626. pDelaySampleB += nMask2B;
  627. int nMask2C = (pDelaySampleC - psamps) >> 31;
  628. nMask2C &= nDelaySizeP1;
  629. pDelaySampleC += nMask2C;
  630. int nMask2D = (pDelaySampleD - psamps) >> 31;
  631. nMask2D &= nDelaySizeP1;
  632. pDelaySampleD += nMask2D;
  633. // pDelaySampleD is the lowest address used, that's going to be the first one to cross the wrap-around
  634. // We could have a more optimized path by getting rid of the wrap around when we are inside the safe zone.
  635. // It would make the code more complicated though (safe zone, then unsafe for up to 2*4 samples, safe zone again...
  636. while ( nCount >= 4 )
  637. {
  638. nCount -= 4;
  639. // delay output is filter input
  640. // Here is the trick, pDelaySampleA, B, C and D are all offseted by 4. Because read and write are only separated by one sample,
  641. // What we read with A, we will write it with B, B to C, C to D. So we can avoid wrap-around for A, B and C as the values are already known.
  642. // Only D will have to be calculated (the smaller value of the set of 4, not yet calculated).
  643. CircularBufferSample_t *pInputDelaySampleD = pDelaySampleD + nDelaySize;
  644. int nMask1D = (pSampsPDelaySize - pInputDelaySampleD) >> 31;
  645. nMask1D &= nDelaySizeP1;
  646. pInputDelaySampleD -= nMask1D;
  647. int sDA = *pDelaySampleB; // Read A (from written position B)
  648. int sDB = *pDelaySampleC; // Read B (from written position C)
  649. int sDC = *pDelaySampleD; // Read C (from written position D)
  650. int sDD = *pInputDelaySampleD;
  651. // filter output, with feedback 'fbgain' baked into filter params
  652. // IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  653. int pfsamps0A = sDA - (( denom1 * pfsamps1 ) >> PBITS);
  654. int nFilteredOutputA = ( ( numer1 * pfsamps1 ) + ( numer0 * pfsamps0A ) ) >> PBITS;
  655. int pfsamps0B = sDB - (( denom1 * pfsamps0A ) >> PBITS);
  656. int nFilteredOutputB = ( ( numer1 * pfsamps0A ) + ( numer0 * pfsamps0B ) ) >> PBITS;
  657. int pfsamps0C = sDC - (( denom1 * pfsamps0B ) >> PBITS);
  658. int nFilteredOutputC = ( ( numer1 * pfsamps0B ) + ( numer0 * pfsamps0C ) ) >> PBITS;
  659. int pfsamps0D = sDD - (( denom1 * pfsamps0C ) >> PBITS);
  660. int nFilteredOutputD = ( ( numer1 * pfsamps0C ) + ( numer0 * pfsamps0D ) ) >> PBITS;
  661. pfsamps1 = pfsamps0D;
  662. // Assuming that the addresses were aligned, on PS3 we could load this on VMX
  663. // Add the filter normally on an integer VMX base. And store the delay in an aligned manner.
  664. int outA = *pIn + nFilteredOutputA;
  665. int outB = *(pIn + 2) + nFilteredOutputB;
  666. int outC = *(pIn + 4) + nFilteredOutputC;
  667. int outD = *(pIn + 6) + nFilteredOutputD;
  668. pIn += 8; // Because pIn has both left AND right (but we read only one).
  669. // write to delay
  670. *pDelaySampleA = outA;
  671. *pDelaySampleB = outB;
  672. *pDelaySampleC = outC;
  673. *pDelaySampleD = outD;
  674. // update delay pointers, decrement pointer and fix up on buffer boundary
  675. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  676. pDelaySampleA -= 4;
  677. pDelaySampleB -= 4;
  678. pDelaySampleC -= 4;
  679. pDelaySampleD -= 4;
  680. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  681. int nMask2A = (pDelaySampleA - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  682. nMask2A &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  683. pDelaySampleA += nMask2A;
  684. nMask2B = (pDelaySampleB - psamps) >> 31;
  685. nMask2B &= nDelaySizeP1;
  686. pDelaySampleB += nMask2B;
  687. nMask2C = (pDelaySampleC - psamps) >> 31;
  688. nMask2C &= nDelaySizeP1;
  689. pDelaySampleC += nMask2C;
  690. nMask2D = (pDelaySampleD - psamps) >> 31;
  691. nMask2D &= nDelaySizeP1;
  692. pDelaySampleD += nMask2D;
  693. // output with gain
  694. *pOut += ( (outA * outgain) >> PBITS );
  695. *(pOut + 1) += ( (outB * outgain) >> PBITS );
  696. *(pOut + 2) += ( (outC * outgain) >> PBITS );
  697. *(pOut + 3) += ( (outD * outgain) >> PBITS );
  698. pOut += 4;
  699. if ( ( nCount % ( CACHE_LINE_SIZE / ( 4 * sizeof(portable_samplepair_t) ) ) ) == 0 )
  700. {
  701. // Prefetch the next input samples (output samples are already in cache anyway)
  702. // Remove the conservative prefetching to make the loop a bit faster
  703. PREFETCH_128( pIn, 4 * CACHE_LINE_SIZE );
  704. if ( ( nCount % ( CACHE_LINE_SIZE / ( 4 * sizeof(*pDelaySampleD) ) ) ) == 0 )
  705. {
  706. // Delay sample is not prefetched as often.
  707. PREFETCH_128( pDelaySampleD, -2 * CACHE_LINE_SIZE ); // We often read the delay sample just before the one that we are writing
  708. }
  709. }
  710. }
  711. *ppsamp = pDelaySampleA;
  712. pfsamps[0] = pfsamps1; // The [0] and [1] are the same after the filtering
  713. pfsamps[1] = pfsamps1;
  714. }
  715. inline int DelayLowpass_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  716. {
  717. int out, sD;
  718. int sDnew;
  719. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  720. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  721. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  722. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  723. // filter output with feedback 'fbgain' baked into filter params
  724. out = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  725. // write to delay
  726. **ppsamp = out;
  727. // update delay ptrs
  728. DlyUpdate ( delaysize, psamps, ppsamp );
  729. // output with gain
  730. return ( (out * outgain) >> PBITS );
  731. }
  732. // delay is multitap tdelay0,tdelay1,tdelay2,tdelay3
  733. // NOTE: tdelay3 > tdelay2 > tdelay1 > tdelay0
  734. // NOTE: fbgain * 4 < 1!
  735. inline int DelayLowpass_multitap ( int delaysize, int tdelay0, int tdelay1, int tdelay2, int tdelay3, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  736. {
  737. int s0, s1, s2, s3, s4, sum;
  738. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  739. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  740. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  741. s4 = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  742. sum = s1 + s2 + s3 + s4;
  743. s0 = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, s4 );
  744. // write to delay
  745. **ppsamp = s0;
  746. // update delay ptrs
  747. DlyUpdate ( delaysize, psamps, ppsamp );
  748. return ( ((sum + in) * outgain ) >> PBITS );
  749. }
  750. inline void DelayLowpass_multitap_Opt ( int delaysize, int tdelay0, int tdelay1, int tdelay2, int tdelay3, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int * pIn, LocalOutputSample_t *pOut, int nCount )
  751. {
  752. while ( nCount-- > 0 )
  753. {
  754. *pOut++ += DelayLowpass_multitap( delaysize, tdelay0, tdelay1, tdelay2, tdelay3, psamps, ppsamp, fbgain, outgain, denom, Ll, numer, pfsamps, *pIn );
  755. pIn += 2; // Because pIn has both left AND right (but we read only one).
  756. }
  757. }
  758. inline int DelayLowpass_multitap_xfade ( int delaysize, int tdelay0, int tdelaynew, int xf, int tdelay1, int tdelay2, int tdelay3, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int Ll, int *numer, int *pfsamps, int in )
  759. {
  760. int s0, s1, s2, s3, s4, sum;
  761. int sD, sDnew;
  762. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  763. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay3 );
  764. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  765. s4 = sD + (((sDnew - sD) * xf) >> PBITS);
  766. s1 = GetDly ( delaysize, psamps, *ppsamp, tdelay0 );
  767. s2 = GetDly ( delaysize, psamps, *ppsamp, tdelay1 );
  768. s3 = GetDly ( delaysize, psamps, *ppsamp, tdelay2 );
  769. sum = s1 + s2 + s3 + s4;
  770. s0 = in + IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, s4 );
  771. **ppsamp = s0;
  772. DlyUpdate ( delaysize, psamps, ppsamp );
  773. return ( ((sum + in) * outgain ) >> PBITS );
  774. }
  775. // linear delay with lowpass filter on delay output and gain stage
  776. // delaysize: delay line size in samples
  777. // tdelay: delay tap from this location - <= delaysize
  778. // psamps: delay line buffer pointer of dimension delaysize+1
  779. // ppsamp: circular pointer, must init &psamps[0] before first call
  780. // fbgain: feedback gain (ignored)
  781. // outgain: output gain
  782. // cnumer: filter order
  783. // numer: filter numerator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  784. // denom: filter denominator, 0-PMAX (normalized to 0.0-1.0), cnumer+1 dimensional
  785. // pfsamps: filter state, cnumer+1 dimensional
  786. // in: input sample
  787. // in(n)--->[Delay d]--->[Filter]-->(*outgain)---> out(n)
  788. inline int DelayLinearLowPass ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int cnumer, int *numer, int *pfsamps, int in )
  789. {
  790. int out, sD;
  791. // delay output is filter input
  792. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  793. // calc filter output
  794. out = IIRFilter_Update_Order1 ( denom, cnumer, numer, pfsamps, sD );
  795. // input sample to delay input
  796. **ppsamp = in;
  797. // update delay pointers
  798. DlyUpdate ( delaysize, psamps, ppsamp );
  799. // output with gain
  800. return ( (out * outgain) >> PBITS );
  801. }
  802. inline void DelayLinearLowPass_Opt ( const int nDelaySize, const int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, const int fbgain, const int outgain, int *denom, const int Ll, int *numer, int *pfsamps, int * pIn, int * pOut, int nCount )
  803. {
  804. while ( nCount-- > 0 )
  805. {
  806. *pOut++ += DelayLinearLowPass( nDelaySize, tdelay, psamps, ppsamp, fbgain, outgain, denom, Ll, numer, pfsamps, *pIn );
  807. pIn += 2;
  808. }
  809. }
  810. void DelayLinearLowPass_Opt2 ( const int nDelaySize, const int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, const int fbgain, const int outgain, int *denom, const int Ll, int *numer, int *pfsamps, int * pIn, LocalOutputSample_t * pOut, int nCount )
  811. {
  812. // int pfsamps0 = pfsamps[0]; // pfsamps0 is not needed as it is overridden during the filtering
  813. int pfsamps1 = pfsamps[1];
  814. int numer0 = numer[0];
  815. int numer1 = numer[1];
  816. int denom1 = denom[1];
  817. CircularBufferSample_t * pDelaySample = *ppsamp;
  818. // Code path with no tests
  819. // TODO: We could improve a bit further by calculating how many samples we can calculate without having to loop around
  820. // This would reduce some of the overhead with the branch-less test (save a couple of cycles).
  821. // TODO: Consider unrolling this, don't know how much we would really save though.
  822. CircularBufferSample_t * pSampsPDelaySize = psamps + nDelaySize;
  823. const int nDelaySizeP1 = nDelaySize + 1;
  824. while ( nCount-- > 0 )
  825. {
  826. // delay output is filter input
  827. CircularBufferSample_t *pInputSampleDelay = pDelaySample + tdelay;
  828. #if 1
  829. // 4 ops instead of 1 op + 1 branch (and potentially one more op).
  830. // Re-use our own version of isel() as there is an optimization we can do
  831. int nMask1 = (pSampsPDelaySize - pInputSampleDelay) >> 31; // 0xffffffff if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  832. nMask1 &= nDelaySizeP1; // nDelaySizeP1 if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  833. pInputSampleDelay -= nMask1;
  834. #else
  835. if ( pInputSampleDelay > pSampsPDelaySize)
  836. {
  837. pInputSampleDelay -= nDelaySizeP1;
  838. }
  839. #endif
  840. int sD = *pInputSampleDelay;
  841. // filter output, with feedback 'fbgain' baked into filter params
  842. // IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  843. int pfsamps0 = sD - (( denom1 * pfsamps1 ) >> PBITS);
  844. int nFilteredOutput = ( ( numer1 * pfsamps1 ) + ( numer0 * pfsamps0 ) ) >> PBITS;
  845. pfsamps1 = pfsamps0;
  846. // write to delay
  847. *pDelaySample = *pIn;
  848. pIn += 2; // Because pIn has both left AND right (but we read only one).
  849. // update delay pointers, decrement pointer and fix up on buffer boundary
  850. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  851. --pDelaySample;
  852. #if 1
  853. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  854. int nMask2 = (pDelaySample - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  855. nMask2 &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  856. pDelaySample += nMask2;
  857. #else
  858. if ( pDelaySample < psamps )
  859. {
  860. pDelaySample += nDelaySizeP1;
  861. }
  862. #endif
  863. // output with gain
  864. *pOut++ += ( (nFilteredOutput * outgain) >> PBITS );
  865. if ( ( nCount % (CACHE_LINE_SIZE / sizeof(portable_samplepair_t) ) ) == 0)
  866. {
  867. // Prefetch the next input samples (output samples are already in cache anyway)
  868. // Do conservative prefetching to reduce cache usage and in case the memory was virtual and would prefetch memory outside the buffer.
  869. const int nBytesLeft = nCount * sizeof(portable_samplepair_t);
  870. if ( nBytesLeft >= 3 * CACHE_LINE_SIZE )
  871. {
  872. PREFETCH_128( pIn, 4 * CACHE_LINE_SIZE );
  873. }
  874. const int OFFSET = CACHE_LINE_SIZE / sizeof( *pDelaySample );
  875. if ( pDelaySample - OFFSET >= psamps )
  876. {
  877. PREFETCH_128( pDelaySample, -2 * CACHE_LINE_SIZE ); // We often read the delay sample just before the one that we are writing
  878. // Thus one prefetch will handle gracefully both delay accesses
  879. }
  880. }
  881. }
  882. *ppsamp = pDelaySample;
  883. pfsamps[0] = pfsamps1; // The [0] and [1] are the same after the filtering
  884. pfsamps[1] = pfsamps1;
  885. }
  886. void DelayLinearLowPass_Opt3 ( const int nDelaySize, const int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, const int fbgain, const int outgain, int *denom, const int Ll, int *numer, int *pfsamps, int * pIn, LocalOutputSample_t * pOut, int nCount )
  887. {
  888. if ( nDelaySize != tdelay )
  889. {
  890. // Use less optimized code path if conditions are not right.
  891. DelayLinearLowPass_Opt2( nDelaySize, tdelay, psamps, ppsamp, fbgain, outgain, denom, Ll, numer, pfsamps, pIn, pOut, nCount );
  892. return;
  893. }
  894. // Here it means that the read delay buffer is always just after the write delay buffer (have to account the wrap around obviously).
  895. // int pfsamps0 = pfsamps[0]; // pfsamps0 is not needed as it is overridden during the filtering
  896. int pfsamps1 = pfsamps[1];
  897. int numer0 = numer[0];
  898. int numer1 = numer[1];
  899. int denom1 = denom[1];
  900. CircularBufferSample_t * pDelaySample = *ppsamp;
  901. // Code path with no tests
  902. // TODO: We could improve a bit further by calculating how many samples we can calculate without having to loop around
  903. // This would reduce some of the overhead with the branch-less test (save a couple of cycles).
  904. // TODO: Consider unrolling this, don't know how much we would really save though. And would make the code much less maintainable (esp. if we do the same for all filters).
  905. CircularBufferSample_t * pSampsPDelaySize = psamps + nDelaySize;
  906. const int nDelaySizeP1 = nDelaySize + 1;
  907. // First the final 3 samples (so nCount is aligned on 4 after this loop)
  908. while ( (nCount & 3 ) != 0 )
  909. {
  910. --nCount;
  911. // delay output is filter input
  912. CircularBufferSample_t *pInputDelaySample = pDelaySample + nDelaySize;
  913. int nMask1 = (pSampsPDelaySize - pInputDelaySample) >> 31; // 0xffffffff if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  914. nMask1 &= nDelaySizeP1; // nDelaySizeP1 if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  915. pInputDelaySample -= nMask1;
  916. int sD = *pInputDelaySample;
  917. // filter output, with feedback 'fbgain' baked into filter params
  918. // IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  919. int pfsamps0 = sD - (( denom1 * pfsamps1 ) >> PBITS);
  920. int nFilteredOutput = ( ( numer1 * pfsamps1 ) + ( numer0 * pfsamps0 ) ) >> PBITS;
  921. pfsamps1 = pfsamps0;
  922. // write to delay
  923. *pDelaySample = *pIn;
  924. pIn += 2; // Because pIn has both left AND right (but we read only one).
  925. // update delay pointers, decrement pointer and fix up on buffer boundary
  926. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  927. --pDelaySample;
  928. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  929. int nMask2 = (pDelaySample - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  930. nMask2 &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  931. pDelaySample += nMask2;
  932. // output with gain
  933. *pOut++ += ( (nFilteredOutput * outgain) >> PBITS );
  934. }
  935. CircularBufferSample_t * RESTRICT pDelaySampleA = pDelaySample;
  936. CircularBufferSample_t * RESTRICT pDelaySampleB = pDelaySample - 1;
  937. CircularBufferSample_t * RESTRICT pDelaySampleC = pDelaySample - 2;
  938. CircularBufferSample_t * RESTRICT pDelaySampleD = pDelaySample - 3;
  939. // pDelaySampleA is already in the correct range
  940. int nMask2B = (pDelaySampleB - psamps) >> 31;
  941. nMask2B &= nDelaySizeP1;
  942. pDelaySampleB += nMask2B;
  943. int nMask2C = (pDelaySampleC - psamps) >> 31;
  944. nMask2C &= nDelaySizeP1;
  945. pDelaySampleC += nMask2C;
  946. int nMask2D = (pDelaySampleD - psamps) >> 31;
  947. nMask2D &= nDelaySizeP1;
  948. pDelaySampleD += nMask2D;
  949. // pDelaySampleD is the lowest address used, that's going to be the first one to cross the wrap-around
  950. // We could have a more optimized path by getting rid of the wrap around when we are inside the safe zone.
  951. // It would make the code more complicated though (safe zone, then unsafe for up to 2*4 samples, safe zone again...
  952. while ( nCount >= 4 )
  953. {
  954. nCount -= 4;
  955. // delay output is filter input
  956. // Here is the trick, pDelaySampleA, B, C and D are all offseted by 4. Because read and write are only separated by one sample,
  957. // What we read with A, we will write it with B, B to C, C to D. So we can avoid wrap-around for A, B and C as the values are already known.
  958. // Only D will have to be calculated (the smaller value of the set of 4, not yet calculated).
  959. CircularBufferSample_t *pInputDelaySampleD = pDelaySampleD + nDelaySize;
  960. int nMask1D = (pSampsPDelaySize - pInputDelaySampleD) >> 31;
  961. nMask1D &= nDelaySizeP1;
  962. pInputDelaySampleD -= nMask1D;
  963. int sDA = *pDelaySampleB; // Read A (from written position B)
  964. int sDB = *pDelaySampleC; // Read B (from written position C)
  965. int sDC = *pDelaySampleD; // Read C (from written position D)
  966. int sDD = *pInputDelaySampleD;
  967. // filter output, with feedback 'fbgain' baked into filter params
  968. // IIRFilter_Update_Order1 ( denom, Ll, numer, pfsamps, sD );
  969. int pfsamps0A = sDA - (( denom1 * pfsamps1 ) >> PBITS);
  970. int nFilteredOutputA = ( ( numer1 * pfsamps1 ) + ( numer0 * pfsamps0A ) ) >> PBITS;
  971. int pfsamps0B = sDB - (( denom1 * pfsamps0A ) >> PBITS);
  972. int nFilteredOutputB = ( ( numer1 * pfsamps0A ) + ( numer0 * pfsamps0B ) ) >> PBITS;
  973. int pfsamps0C = sDC - (( denom1 * pfsamps0B ) >> PBITS);
  974. int nFilteredOutputC = ( ( numer1 * pfsamps0B ) + ( numer0 * pfsamps0C ) ) >> PBITS;
  975. int pfsamps0D = sDD - (( denom1 * pfsamps0C ) >> PBITS);
  976. int nFilteredOutputD = ( ( numer1 * pfsamps0C ) + ( numer0 * pfsamps0D ) ) >> PBITS;
  977. pfsamps1 = pfsamps0D;
  978. // write to delay
  979. *pDelaySampleA = *pIn;
  980. *pDelaySampleB = *(pIn + 2);
  981. *pDelaySampleC = *(pIn + 4);
  982. *pDelaySampleD = *(pIn + 6);
  983. pIn += 8; // Because pIn has both left AND right (but we read only one).
  984. // update delay pointers, decrement pointer and fix up on buffer boundary
  985. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  986. pDelaySampleA -= 4;
  987. pDelaySampleB -= 4;
  988. pDelaySampleC -= 4;
  989. pDelaySampleD -= 4;
  990. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  991. int nMask2A = (pDelaySampleA - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  992. nMask2A &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  993. pDelaySampleA += nMask2A;
  994. nMask2B = (pDelaySampleB - psamps) >> 31;
  995. nMask2B &= nDelaySizeP1;
  996. pDelaySampleB += nMask2B;
  997. nMask2C = (pDelaySampleC - psamps) >> 31;
  998. nMask2C &= nDelaySizeP1;
  999. pDelaySampleC += nMask2C;
  1000. nMask2D = (pDelaySampleD - psamps) >> 31;
  1001. nMask2D &= nDelaySizeP1;
  1002. pDelaySampleD += nMask2D;
  1003. // output with gain
  1004. *pOut += ( (nFilteredOutputA * outgain) >> PBITS );
  1005. *(pOut + 1) += ( (nFilteredOutputB * outgain) >> PBITS );
  1006. *(pOut + 2) += ( (nFilteredOutputC * outgain) >> PBITS );
  1007. *(pOut + 3) += ( (nFilteredOutputD * outgain) >> PBITS );
  1008. pOut += 4;
  1009. if ( ( nCount % (CACHE_LINE_SIZE / (4 * sizeof(portable_samplepair_t) ) ) ) == 0)
  1010. {
  1011. // Prefetch the next input samples (output samples are already in cache anyway)
  1012. // Remove the conservative prefetching to make the loop a bit faster
  1013. PREFETCH_128( pIn, 4 * CACHE_LINE_SIZE );
  1014. if ( ( nCount % ( CACHE_LINE_SIZE / ( 4 * sizeof(*pDelaySampleD) ) ) ) == 0 )
  1015. {
  1016. PREFETCH_128( pDelaySampleD, -2 * CACHE_LINE_SIZE ); // We often read the delay sample just before the one that we are writing
  1017. }
  1018. }
  1019. }
  1020. *ppsamp = pDelaySampleA;
  1021. pfsamps[0] = pfsamps1; // The [0] and [1] are the same after the filtering
  1022. pfsamps[1] = pfsamps1;
  1023. }
  1024. inline int DelayLinear_lowpass_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int *denom, int cnumer, int *numer, int *pfsamps, int in )
  1025. {
  1026. int out, sD;
  1027. int sDnew;
  1028. // crossfade from tdelay to tdelaynew tap. xfade is 0..PMAX
  1029. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  1030. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  1031. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  1032. out = IIRFilter_Update_Order1 ( denom, cnumer, numer, pfsamps, sD );
  1033. **ppsamp = in;
  1034. DlyUpdate ( delaysize, psamps, ppsamp );
  1035. return ( (out * outgain) >> PBITS );
  1036. }
  1037. // classic allpass reverb
  1038. // delaysize: delay line size in samples
  1039. // tdelay: tap from this location - <= D
  1040. // psamps: delay line buffer pointer of dimension delaysize+1
  1041. // ppsamp: circular pointer, must be init to &psamps[0] before first call
  1042. // fbgain: feedback value, 0-PMAX (normalized to 0.0-1.0)
  1043. // outgain: gain
  1044. // psamps0(n) -fbgain outgain
  1045. // in(n)--->(+)--------.-----(*)-->(+)--(*)-> out(n)
  1046. // ^ | ^
  1047. // | [Delay d] |
  1048. // | | |
  1049. // | fbgain |psampsd(n) |
  1050. // ----(*)---.-------------
  1051. //
  1052. // for each input sample 'in':
  1053. // psamps0 = in + fbgain * psampsd
  1054. // y = -fbgain * psamps0 + psampsd
  1055. // delay (d, psamps) - psamps is the delay buffer array
  1056. //
  1057. // or, using circular delay, for each input sample 'in':
  1058. //
  1059. // Sd = GetDly (delaysize,psamps,ppsamp,delaysize)
  1060. // S0 = in + fbgain*Sd
  1061. // y = -fbgain*S0 + Sd
  1062. // *ppsamp = S0
  1063. // DlyUpdate(delaysize, psamps, &ppsamp)
  1064. inline int DelayAllpass ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int in )
  1065. {
  1066. int out, s0, sD;
  1067. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  1068. s0 = in + (( fbgain * sD ) >> PBITS);
  1069. out = ( ( -fbgain * s0 ) >> PBITS ) + sD;
  1070. **ppsamp = s0;
  1071. DlyUpdate ( delaysize, psamps, ppsamp );
  1072. return ( (out * outgain) >> PBITS );
  1073. }
  1074. enum MixMode
  1075. {
  1076. MM_ADD,
  1077. MM_REPLACE,
  1078. };
  1079. template <int SOURCE_INCREMENT, MixMode MODE>
  1080. inline void DelayAllpass_Opt ( int delaysize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int * pIn, LocalOutputSample_t * pOut, int nCount )
  1081. {
  1082. while ( nCount-- > 0 )
  1083. {
  1084. int nValue = DelayAllpass( delaysize, tdelay, psamps, ppsamp, fbgain, outgain, *pIn );
  1085. if ( MODE == MM_ADD )
  1086. {
  1087. *pOut++ += nValue;
  1088. }
  1089. else
  1090. {
  1091. Assert( MODE == MM_REPLACE );
  1092. *pOut++ = nValue;
  1093. }
  1094. pIn += SOURCE_INCREMENT; // Because pIn has both left AND right (but we read only one).
  1095. }
  1096. }
  1097. template <int SOURCE_INCREMENT, MixMode MODE>
  1098. inline void DelayAllpass_Opt2 ( int nDelaySize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int * pIn, LocalOutputSample_t * pOut, int nCount )
  1099. {
  1100. CircularBufferSample_t * pDelaySample = *ppsamp;
  1101. // Code path with no tests
  1102. // TODO: We could improve a bit further by calculating how many samples we can calculate without having to loop around
  1103. // This would reduce some of the overhead with the branch-less test (save a couple of cycles).
  1104. // TODO: Consider unrolling this, don't know how much we would really save though. And would make the code much less maintainable (esp. if we do the same for all filters).
  1105. CircularBufferSample_t * pSampsPDelaySize = psamps + nDelaySize;
  1106. const int nDelaySizeP1 = nDelaySize + 1;
  1107. while ( nCount-- > 0 )
  1108. {
  1109. // delay output is filter input
  1110. CircularBufferSample_t *pInputDelaySample = pDelaySample + tdelay;
  1111. #if 1
  1112. // 4 ops instead of 1 op + 1 branch (and potentially one more op).
  1113. // Re-use our own version of isel() as there is an optimization we can do
  1114. int nMask1 = (pSampsPDelaySize - pInputDelaySample) >> 31; // 0xffffffff if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  1115. nMask1 &= nDelaySizeP1; // nDelaySizeP1 if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  1116. pInputDelaySample -= nMask1;
  1117. #else
  1118. if ( pInputDelaySample > pSampsPDelaySize)
  1119. {
  1120. pInputDelaySample -= nDelaySizeP1;
  1121. }
  1122. #endif
  1123. int sD = *pInputDelaySample;
  1124. int s0 = *pIn + (( fbgain * sD ) >> PBITS);
  1125. // write to delay
  1126. *pDelaySample = s0;
  1127. int out = ( ( -fbgain * s0 ) >> PBITS ) + sD;
  1128. pIn += SOURCE_INCREMENT; // Because pIn has both left AND right (but we read only one).
  1129. // update delay pointers, decrement pointer and fix up on buffer boundary
  1130. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  1131. --pDelaySample;
  1132. #if 1
  1133. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  1134. int nMask2 = (pDelaySample - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  1135. nMask2 &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  1136. pDelaySample += nMask2;
  1137. #else
  1138. if ( pDelaySample < psamps )
  1139. {
  1140. pDelaySample += nDelaySizeP1;
  1141. }
  1142. #endif
  1143. // output with gain
  1144. int nValue = ( (out * outgain) >> PBITS );
  1145. if ( MODE == MM_ADD )
  1146. {
  1147. *pOut++ += nValue;
  1148. }
  1149. else
  1150. {
  1151. Assert( MODE == MM_REPLACE );
  1152. *pOut++ = nValue;
  1153. }
  1154. if ( ( nCount % (CACHE_LINE_SIZE / sizeof(portable_samplepair_t) ) ) == 0)
  1155. {
  1156. // Prefetch the next input samples (output samples are already in cache anyway)
  1157. // Do conservative prefetching to reduce cache usage and in case the memory was virtual and would prefetch memory outside the buffer.
  1158. const int nBytesLeft = nCount * sizeof(portable_samplepair_t);
  1159. if ( nBytesLeft >= 3 * CACHE_LINE_SIZE )
  1160. {
  1161. PREFETCH_128( pIn, 4 * CACHE_LINE_SIZE );
  1162. }
  1163. const int OFFSET = CACHE_LINE_SIZE / sizeof( *pDelaySample );
  1164. if ( pDelaySample - OFFSET >= psamps )
  1165. {
  1166. PREFETCH_128( pDelaySample, -2 * CACHE_LINE_SIZE ); // We often read the delay sample just before the one that we are writing
  1167. // Thus one prefetch will handle gracefully both delay accesses
  1168. }
  1169. }
  1170. }
  1171. *ppsamp = pDelaySample;
  1172. }
  1173. template <int SOURCE_INCREMENT, MixMode MODE>
  1174. inline void DelayAllpass_Opt3 ( int nDelaySize, int tdelay, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int * pIn, LocalOutputSample_t * pOut, int nCount )
  1175. {
  1176. if ( nDelaySize != tdelay )
  1177. {
  1178. DelayAllpass_Opt2<SOURCE_INCREMENT, MODE>( nDelaySize, tdelay, psamps, ppsamp, fbgain, outgain, pIn, pOut, nCount );
  1179. return;
  1180. }
  1181. // Here it means that the read delay buffer is always just after the write delay buffer (have to account the wrap around obviously).
  1182. CircularBufferSample_t * pDelaySample = *ppsamp;
  1183. // Code path with no tests
  1184. // TODO: We could improve a bit further by calculating how many samples we can calculate without having to loop around
  1185. // This would reduce some of the overhead with the branch-less test (save a couple of cycles).
  1186. // TODO: Consider unrolling this, don't know how much we would really save though. And would make the code much less maintainable (esp. if we do the same for all filters).
  1187. CircularBufferSample_t * pSampsPDelaySize = psamps + nDelaySize;
  1188. const int nDelaySizeP1 = nDelaySize + 1;
  1189. // First the final 3 samples (so nCount is aligned on 4 after this loop)
  1190. while ( (nCount & 3 ) != 0 )
  1191. {
  1192. --nCount;
  1193. // delay output is filter input
  1194. CircularBufferSample_t *pInputDelaySample = pDelaySample + nDelaySize;
  1195. int nMask1 = (pSampsPDelaySize - pInputDelaySample) >> 31; // 0xffffffff if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  1196. nMask1 &= nDelaySizeP1; // nDelaySizeP1 if pInputSampleDelay > pSampsPDelaySize, 0 otherwise
  1197. pInputDelaySample -= nMask1;
  1198. int sD = *pInputDelaySample;
  1199. int s0 = *pIn + (( fbgain * sD ) >> PBITS);
  1200. // write to delay
  1201. *pDelaySample = s0;
  1202. int out = ( ( -fbgain * s0 ) >> PBITS ) + sD;
  1203. pIn += SOURCE_INCREMENT; // Because pIn has both left AND right (but we read only one).
  1204. // update delay pointers, decrement pointer and fix up on buffer boundary
  1205. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  1206. --pDelaySample;
  1207. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  1208. int nMask2 = (pDelaySample - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  1209. nMask2 &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  1210. pDelaySample += nMask2;
  1211. // output with gain
  1212. int nValue = ( (out * outgain) >> PBITS );
  1213. if ( MODE == MM_ADD )
  1214. {
  1215. *pOut++ += nValue;
  1216. }
  1217. else
  1218. {
  1219. Assert( MODE == MM_REPLACE );
  1220. *pOut++ = nValue;
  1221. }
  1222. }
  1223. CircularBufferSample_t * RESTRICT pDelaySampleA = pDelaySample;
  1224. CircularBufferSample_t * RESTRICT pDelaySampleB = pDelaySample - 1;
  1225. CircularBufferSample_t * RESTRICT pDelaySampleC = pDelaySample - 2;
  1226. CircularBufferSample_t * RESTRICT pDelaySampleD = pDelaySample - 3;
  1227. // pDelaySampleA is already in the correct range
  1228. int nMask2B = (pDelaySampleB - psamps) >> 31;
  1229. nMask2B &= nDelaySizeP1;
  1230. pDelaySampleB += nMask2B;
  1231. int nMask2C = (pDelaySampleC - psamps) >> 31;
  1232. nMask2C &= nDelaySizeP1;
  1233. pDelaySampleC += nMask2C;
  1234. int nMask2D = (pDelaySampleD - psamps) >> 31;
  1235. nMask2D &= nDelaySizeP1;
  1236. pDelaySampleD += nMask2D;
  1237. // pDelaySampleD is the lowest address used, that's going to be the first one to cross the wrap-around
  1238. // We could have a more optimized path by getting rid of the wrap around when we are inside the safe zone.
  1239. // It would make the code more complicated though (safe zone, then unsafe for up to 2*4 samples, safe zone again...
  1240. while ( nCount >= 4 )
  1241. {
  1242. nCount -= 4;
  1243. // delay output is filter input
  1244. // Here is the trick, pDelaySampleA, B, C and D are all offseted by 4. Because read and write are only separated by one sample,
  1245. // What we read with A, we will write it with B, B to C, C to D. So we can avoid wrap-around for A, B and C as the values are already known.
  1246. // Only D will have to be calculated (the smaller value of the set of 4, not yet calculated).
  1247. CircularBufferSample_t *pInputDelaySampleD = pDelaySampleD + nDelaySize;
  1248. int nMask1D = (pSampsPDelaySize - pInputDelaySampleD) >> 31;
  1249. nMask1D &= nDelaySizeP1;
  1250. pInputDelaySampleD -= nMask1D;
  1251. int sDA = *pDelaySampleB; // Read A (from written position B)
  1252. int sDB = *pDelaySampleC; // Read B (from written position C)
  1253. int sDC = *pDelaySampleD; // Read C (from written position D)
  1254. int sDD = *pInputDelaySampleD;
  1255. int s0A = *pIn + (( fbgain * sDA ) >> PBITS);
  1256. int s0B = *(pIn + SOURCE_INCREMENT) + (( fbgain * sDB ) >> PBITS);
  1257. int s0C = *(pIn + 2 * SOURCE_INCREMENT) + (( fbgain * sDC ) >> PBITS);
  1258. int s0D = *(pIn + 3 * SOURCE_INCREMENT) + (( fbgain * sDD ) >> PBITS);
  1259. // write to delay
  1260. *pDelaySampleA = s0A;
  1261. *pDelaySampleB = s0B;
  1262. *pDelaySampleC = s0C;
  1263. *pDelaySampleD = s0D;
  1264. // Assuming that the addresses were aligned, on PS3 we could load this on VMX
  1265. // Add the filter normally on an integer VMX base. And store the delay in an aligned manner.
  1266. int outA = ( ( -fbgain * s0A ) >> PBITS ) + sDA;
  1267. int outB = ( ( -fbgain * s0B ) >> PBITS ) + sDB;
  1268. int outC = ( ( -fbgain * s0C ) >> PBITS ) + sDC;
  1269. int outD = ( ( -fbgain * s0D ) >> PBITS ) + sDD;
  1270. pIn += 4 * SOURCE_INCREMENT; // Because pIn has both left AND right (but we read only one).
  1271. // update delay pointers, decrement pointer and fix up on buffer boundary
  1272. // when *ppsamp = psamps-1, it wraps around to *ppsamp = psamps+dlysize
  1273. pDelaySampleA -= 4;
  1274. pDelaySampleB -= 4;
  1275. pDelaySampleC -= 4;
  1276. pDelaySampleD -= 4;
  1277. // 4 ops instead of 1 op + 1 branch (and potentially one more op)
  1278. int nMask2A = (pDelaySampleA - psamps) >> 31; // 0xffffffff if pDelaySample < psamps, 0 otherwise
  1279. nMask2A &= nDelaySizeP1; // nDelaySizeP1 if pDelaySample < psamps, 0 otherwise
  1280. pDelaySampleA += nMask2A;
  1281. nMask2B = (pDelaySampleB - psamps) >> 31;
  1282. nMask2B &= nDelaySizeP1;
  1283. pDelaySampleB += nMask2B;
  1284. nMask2C = (pDelaySampleC - psamps) >> 31;
  1285. nMask2C &= nDelaySizeP1;
  1286. pDelaySampleC += nMask2C;
  1287. nMask2D = (pDelaySampleD - psamps) >> 31;
  1288. nMask2D &= nDelaySizeP1;
  1289. pDelaySampleD += nMask2D;
  1290. // output with gain
  1291. int nValueA = ( (outA * outgain) >> PBITS );
  1292. int nValueB = ( (outB * outgain) >> PBITS );
  1293. int nValueC = ( (outC * outgain) >> PBITS );
  1294. int nValueD = ( (outD * outgain) >> PBITS );
  1295. if ( MODE == MM_ADD )
  1296. {
  1297. *pOut += nValueA;
  1298. *(pOut + 1) += nValueB;
  1299. *(pOut + 2) += nValueC;
  1300. *(pOut + 3) += nValueD;
  1301. }
  1302. else
  1303. {
  1304. Assert( MODE == MM_REPLACE );
  1305. *pOut = nValueA;
  1306. *(pOut + 1) = nValueB;
  1307. *(pOut + 2) = nValueC;
  1308. *(pOut + 3) = nValueD;
  1309. }
  1310. pOut += 4;
  1311. if ( ( nCount % ( CACHE_LINE_SIZE / ( 4 * sizeof(portable_samplepair_t) ) ) ) == 0 )
  1312. {
  1313. // Prefetch the next input samples (output samples are already in cache anyway)
  1314. // Remove the conservative prefetching to make the loop a bit faster
  1315. PREFETCH_128( pIn, 4 * CACHE_LINE_SIZE );
  1316. if ( ( nCount % ( CACHE_LINE_SIZE / ( 4 * sizeof(*pDelaySampleD) ) ) ) == 0 )
  1317. {
  1318. // Delay sample is not prefetched as often.
  1319. PREFETCH_128( pDelaySampleD, -2 * CACHE_LINE_SIZE ); // We often read the delay sample just before the one that we are writing
  1320. }
  1321. }
  1322. }
  1323. *ppsamp = pDelaySampleA;
  1324. }
  1325. inline int DelayAllpass_xfade ( int delaysize, int tdelay, int tdelaynew, int xf, CircularBufferSample_t *psamps, CircularBufferSample_t **ppsamp, int fbgain, int outgain, int in )
  1326. {
  1327. int out, s0, sD;
  1328. int sDnew;
  1329. // crossfade from t to tnew tap. xfade is 0..PMAX
  1330. sD = GetDly ( delaysize, psamps, *ppsamp, tdelay );
  1331. sDnew = GetDly ( delaysize, psamps, *ppsamp, tdelaynew );
  1332. sD = sD + (((sDnew - sD) * xf) >> PBITS);
  1333. s0 = in + (( fbgain * sD ) >> PBITS);
  1334. out = ( ( -fbgain * s0 ) >> PBITS ) + sD;
  1335. **ppsamp = s0;
  1336. DlyUpdate ( delaysize, psamps, ppsamp );
  1337. return ( (out * outgain) >> PBITS );
  1338. }
  1339. ///////////////////////////////////////////////////////////////////////////////////
  1340. // fixed point math for real-time wave table traversing, pitch shifting, resampling
  1341. ///////////////////////////////////////////////////////////////////////////////////
  1342. #define FIX20_BITS 20 // 20 bits of fractional part
  1343. #define FIX20_SCALE (1 << FIX20_BITS)
  1344. #define FIX20_INTMAX ((1 << (32 - FIX20_BITS))-1) // maximum step integer
  1345. #define FLOAT_TO_FIX20(a) ((int)((a) * (float)FIX20_SCALE)) // convert float to fixed point
  1346. #define INT_TO_FIX20(a) (((int)(a)) << FIX20_BITS) // convert int to fixed point
  1347. #define FIX20_TO_FLOAT(a) ((float)(a) / (float)FIX20_SCALE) // convert fix20 to float
  1348. #define FIX20_INTPART(a) (((int)(a)) >> FIX20_BITS) // get integer part of fixed point
  1349. #define FIX20_FRACPART(a) ((a) - (((a) >> FIX20_BITS) << FIX20_BITS)) // get fractional part of fixed point
  1350. #define FIX20_FRACTION(a,b) (FIX(a)/(b)) // convert int a to fixed point, divide by b
  1351. typedef int fix20int;
  1352. /////////////////////////////////
  1353. // DSP processor parameter block
  1354. /////////////////////////////////
  1355. // NOTE: these prototypes must match the XXX_Params ( prc_t *pprc ) and XXX_GetNext ( XXX_t *p, int x ) functions
  1356. typedef void * (*prc_Param_t)( void *pprc ); // individual processor allocation functions
  1357. typedef int (*prc_GetNext_t) ( void *pdata, int x ); // get next function for processor
  1358. typedef int (*prc_GetNextN_t) ( void *pdata, portable_samplepair_t *pbuffer, int SampleCount, int op); // batch version of getnext
  1359. typedef void (*prc_Free_t) ( void *pdata ); // free function for processor
  1360. typedef void (*prc_Mod_t) (void *pdata, float v); // modulation function for processor
  1361. #define OP_LEFT 0 // batch process left channel in place
  1362. #define OP_RIGHT 1 // batch process right channel in place
  1363. #define OP_LEFT_DUPLICATE 2 // batch process left channel in place, duplicate to right channel
  1364. #define PRC_NULL 0 // pass through - must be 0
  1365. #define PRC_DLY 1 // simple feedback reverb
  1366. #define PRC_RVA 2 // parallel reverbs
  1367. #define PRC_FLT 3 // lowpass or highpass filter
  1368. #define PRC_CRS 4 // chorus
  1369. #define PRC_PTC 5 // pitch shifter
  1370. #define PRC_ENV 6 // adsr envelope
  1371. #define PRC_LFO 7 // lfo
  1372. #define PRC_EFO 8 // envelope follower
  1373. #define PRC_MDY 9 // mod delay
  1374. #define PRC_DFR 10 // diffusor - n series allpass delays
  1375. #define PRC_AMP 11 // amplifier with distortion
  1376. #define QUA_LO 0 // quality of filter or reverb. Must be 0,1,2,3.
  1377. #define QUA_MED 1
  1378. #define QUA_HI 2
  1379. #define QUA_VHI 3
  1380. #define QUA_MAX QUA_VHI
  1381. #define CPRCPARAMS 16 // up to 16 floating point params for each processor type
  1382. // processor definition - one for each running instance of a dsp processor
  1383. struct prc_t
  1384. {
  1385. int type; // PRC type
  1386. float prm[CPRCPARAMS]; // dsp processor parameters - array of floats
  1387. prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
  1388. prc_GetNext_t pfnGetNext; // get next function
  1389. prc_GetNextN_t pfnGetNextN; // batch version of get next
  1390. prc_Free_t pfnFree; // free function
  1391. prc_Mod_t pfnMod; // modulation function
  1392. void *pdata; // processor state data - ie: pdly, pflt etc.
  1393. };
  1394. // processor parameter ranges - for validating parameters during allocation of new processor
  1395. typedef struct prm_rng_t
  1396. {
  1397. int iprm; // parameter index
  1398. float lo; // min value of parameter
  1399. float hi; // max value of parameter
  1400. } prm_rng_s;
  1401. void PRC_CheckParams ( prc_t *pprc, prm_rng_t *prng );
  1402. ///////////
  1403. // Filters
  1404. ///////////
  1405. #if CHECK_VALUES_AFTER_REFACTORING
  1406. #define CFLTS 128 // max number of filters simultaneously active
  1407. #else
  1408. #define CFLTS 64 // max number of filters simultaneously active
  1409. #endif
  1410. #define FLT_M 12 // max order of any filter
  1411. #define FLT_LP 0 // lowpass filter
  1412. #define FLT_HP 1 // highpass filter
  1413. #define FLT_BP 2 // bandpass filter
  1414. #define FTR_MAX FLT_BP
  1415. // flt parameters
  1416. struct flt_t
  1417. {
  1418. bool fused; // true if slot in use
  1419. int b[FLT_M+1]; // filter numerator parameters (convert 0.0-1.0 to 0-PMAX representation)
  1420. int a[FLT_M+1]; // filter denominator parameters (convert 0.0-1.0 to 0-PMAX representation)
  1421. int w[FLT_M+1]; // filter state - samples (dimension of max (M, L))
  1422. int L; // filter order numerator (dimension of a[M+1])
  1423. int M; // filter order denominator (dimension of b[L+1])
  1424. int N; // # of series sections - 1 (0 = 1 section, 1 = 2 sections etc)
  1425. flt_t *pf1; // series cascaded versions of filter
  1426. flt_t *pf2;
  1427. flt_t *pf3;
  1428. };
  1429. // flt flts
  1430. flt_t flts[CFLTS];
  1431. void FLT_Init ( flt_t *pf ) { if ( pf ) Q_memset ( pf, 0, sizeof (flt_t) ); }
  1432. void FLT_InitAll ( void ) { for ( int i = 0 ; i < CFLTS; i++ ) FLT_Init ( &flts[i] ); }
  1433. void FLT_Free ( flt_t *pf )
  1434. {
  1435. if ( pf )
  1436. {
  1437. if (pf->pf1)
  1438. Q_memset ( pf->pf1, 0, sizeof (flt_t) );
  1439. if (pf->pf2)
  1440. Q_memset ( pf->pf2, 0, sizeof (flt_t) );
  1441. if (pf->pf3)
  1442. Q_memset ( pf->pf3, 0, sizeof (flt_t) );
  1443. Q_memset ( pf, 0, sizeof (flt_t) );
  1444. }
  1445. }
  1446. void FLT_FreeAll ( void ) { for (int i = 0 ; i < CFLTS; i++) FLT_Free ( &flts[i] ); }
  1447. // find a free filter from the filter pool
  1448. // initialize filter numerator, denominator b[0..M], a[0..L]
  1449. // gain scales filter numerator
  1450. // N is # of series sections - 1
  1451. flt_t * FLT_Alloc ( int N, int M, int L, int *a, int *b, float gain )
  1452. {
  1453. int i, j;
  1454. flt_t *pf = NULL;
  1455. for (i = 0; i < CFLTS; i++)
  1456. {
  1457. if ( !flts[i].fused )
  1458. {
  1459. pf = &flts[i];
  1460. // transfer filter params into filter struct
  1461. pf->M = M;
  1462. pf->L = L;
  1463. pf->N = N;
  1464. for (j = 0; j <= M; j++)
  1465. pf->a[j] = a[j];
  1466. for (j = 0; j <= L; j++)
  1467. pf->b[j] = (int)((float)(b[j]) * gain);
  1468. pf->pf1 = NULL;
  1469. pf->pf2 = NULL;
  1470. pf->pf3 = NULL;
  1471. pf->fused = true;
  1472. break;
  1473. }
  1474. }
  1475. Assert(pf); // make sure we're not trying to alloc more than CFLTS flts
  1476. return pf;
  1477. }
  1478. void FLT_Print( const flt_t & filter, int nIndentation )
  1479. {
  1480. const char * pIndent = GetIndentationText( nIndentation );
  1481. DevMsg( "%sFilter: %p [Addr]\n", pIndent, &filter );
  1482. DevMsg( "%sb[] = ", pIndent );
  1483. for ( int i = 0 ; i < FLT_M + 1 ; ++i )
  1484. {
  1485. DevMsg( "%d ", filter.b[i] );
  1486. }
  1487. DevMsg( "\n" );
  1488. DevMsg( "%sa[] = ", pIndent );
  1489. for ( int i = 0 ; i < FLT_M + 1 ; ++i )
  1490. {
  1491. DevMsg( "%d ", filter.a[i] );
  1492. }
  1493. DevMsg( "\n" );
  1494. DevMsg( "%sw[] = ", pIndent );
  1495. for ( int i = 0 ; i < FLT_M + 1 ; ++i )
  1496. {
  1497. DevMsg( "%d ", filter.w[i] );
  1498. }
  1499. DevMsg( "\n" );
  1500. DevMsg( "%sL: %d\n", pIndent, filter.L );
  1501. DevMsg( "%sM: %d\n", pIndent, filter.M );
  1502. DevMsg( "%sN: %d\n", pIndent, filter.N );
  1503. DevMsg( "%spf1:", pIndent );
  1504. if ( filter.pf1 != NULL )
  1505. {
  1506. FLT_Print( *filter.pf1, nIndentation + 1 );
  1507. }
  1508. else
  1509. {
  1510. DevMsg( "NULL\n" );
  1511. }
  1512. DevMsg( "%spf2:", pIndent );
  1513. if ( filter.pf2 != NULL )
  1514. {
  1515. FLT_Print( *filter.pf2, nIndentation + 1 );
  1516. }
  1517. else
  1518. {
  1519. DevMsg( "NULL\n" );
  1520. }
  1521. DevMsg( "%spf3:", pIndent );
  1522. if ( filter.pf3 != NULL )
  1523. {
  1524. FLT_Print( *filter.pf3, nIndentation + 1 );
  1525. }
  1526. else
  1527. {
  1528. DevMsg( "NULL\n" );
  1529. }
  1530. }
  1531. #if CHECK_VALUES_AFTER_REFACTORING
  1532. flt_t * FLT_Clone( flt_t * pOldFilter )
  1533. {
  1534. if ( pOldFilter == NULL )
  1535. {
  1536. return NULL;
  1537. }
  1538. // Use a gain of 1.0 to make sure we keep the same data.
  1539. flt_t * pNewFilter = FLT_Alloc( pOldFilter->N, pOldFilter->M, pOldFilter->L, pOldFilter->a, pOldFilter->b, 1.0f );
  1540. // Copy w
  1541. for ( int i = 0 ; i < FLT_M+1 ; ++i )
  1542. {
  1543. pNewFilter->w[i] = pOldFilter->w[i];
  1544. }
  1545. // Recursive deep-copy
  1546. pNewFilter->pf1 = FLT_Clone( pOldFilter->pf1 );
  1547. pNewFilter->pf2 = FLT_Clone( pOldFilter->pf2 );
  1548. pNewFilter->pf3 = FLT_Clone( pOldFilter->pf3 );
  1549. return pNewFilter;
  1550. }
  1551. void FLT_Compare( const flt_t & leftFilter, const flt_t & rightFilter )
  1552. {
  1553. Assert ( &leftFilter != &rightFilter );
  1554. for ( int i = 0 ; i < FLT_M + 1 ; ++i )
  1555. {
  1556. Assert( leftFilter.b[i] == rightFilter.b[i] );
  1557. }
  1558. for ( int i = 0 ; i < FLT_M + 1 ; ++i )
  1559. {
  1560. Assert( leftFilter.a[i] == rightFilter.a[i] );
  1561. }
  1562. for ( int i = 0 ; i < FLT_M + 1 ; ++i )
  1563. {
  1564. Assert( leftFilter.w[i] == rightFilter.w[i] );
  1565. }
  1566. Assert( leftFilter.L == rightFilter.L );
  1567. Assert( leftFilter.M == rightFilter.M );
  1568. Assert( leftFilter.N == rightFilter.N );
  1569. if ( CheckPointers( leftFilter.pf1, rightFilter.pf1 ) )
  1570. {
  1571. FLT_Compare( *leftFilter.pf1, *rightFilter.pf1 );
  1572. }
  1573. if ( CheckPointers( leftFilter.pf2, rightFilter.pf2 ) )
  1574. {
  1575. FLT_Compare( *leftFilter.pf2, *rightFilter.pf2 );
  1576. }
  1577. if ( CheckPointers( leftFilter.pf3, rightFilter.pf3 ) )
  1578. {
  1579. FLT_Compare( *leftFilter.pf3, *rightFilter.pf3 );
  1580. }
  1581. }
  1582. #endif
  1583. // convert filter params cutoff and type into
  1584. // iir transfer function params M, L, a[], b[]
  1585. // iir filter, 1st order, transfer function is H(z) = b0 + b1 Z^-1 / a0 + a1 Z^-1
  1586. // or H(z) = b0 - b1 Z^-1 / a0 + a1 Z^-1 for lowpass
  1587. // design cutoff filter at 3db (.5 gain) p579
  1588. void FLT_Design_3db_IIR ( float cutoff, float ftype, int *pM, int *pL, int *a, int *b )
  1589. {
  1590. // ftype: FLT_LP, FLT_HP, FLT_BP
  1591. double Wc = 2.0 * M_PI * cutoff / SOUND_DMA_SPEED; // radians per sample
  1592. double Oc;
  1593. double fa;
  1594. double fb;
  1595. // calculations:
  1596. // Wc = 2pi * fc/44100 convert to radians
  1597. // Oc = tan (Wc/2) * Gc / sqt ( 1 - Gc^2) get analog version, low pass
  1598. // Oc = tan (Wc/2) * (sqt (1 - Gc^2)) / Gc analog version, high pass
  1599. // Gc = 10 ^ (-Ac/20) gain at cutoff. Ac = 3db, so Gc^2 = 0.5
  1600. // a = ( 1 - Oc ) / ( 1 + Oc )
  1601. // b = ( 1 - a ) / 2
  1602. Oc = tan ( Wc / 2.0 );
  1603. fa = ( 1.0 - Oc ) / ( 1.0 + Oc );
  1604. fb = ( 1.0 - fa ) / 2.0;
  1605. if ( ftype == FLT_HP )
  1606. fb = ( 1.0 + fa ) / 2.0;
  1607. a[0] = 0; // a0 always ignored
  1608. a[1] = (int)( -fa * PMAX ); // quantize params down to 0-PMAX >> PBITS
  1609. b[0] = (int)( fb * PMAX );
  1610. b[1] = b[0];
  1611. if ( ftype == FLT_HP )
  1612. b[1] = -b[1];
  1613. *pM = *pL = 1;
  1614. return;
  1615. }
  1616. // filter parameter order
  1617. typedef enum
  1618. {
  1619. flt_iftype,
  1620. flt_icutoff,
  1621. flt_iqwidth,
  1622. flt_iquality,
  1623. flt_igain,
  1624. flt_cparam // # of params
  1625. } flt_e;
  1626. // filter parameter ranges
  1627. prm_rng_t flt_rng[] = {
  1628. {flt_cparam, 0, 0}, // first entry is # of parameters
  1629. {flt_iftype, 0, FTR_MAX}, // filter type FLT_LP, FLT_HP, FLT_BP
  1630. {flt_icutoff, 10, 22050}, // cutoff frequency in hz at -3db gain
  1631. {flt_iqwidth, 0, 11025}, // width of BP (cut in starts at cutoff)
  1632. {flt_iquality, 0, QUA_MAX}, // QUA_LO, _MED, _HI, _VHI = # of series sections
  1633. {flt_igain, 0.0, 10.0}, // output gain 0-10.0
  1634. };
  1635. // convert prc float params to iir filter params, alloc filter and return ptr to it
  1636. // filter quality set by prc quality - 0,1,2
  1637. flt_t * FLT_Params ( prc_t *pprc )
  1638. {
  1639. float qual = pprc->prm[flt_iquality];
  1640. float cutoff = pprc->prm[flt_icutoff];
  1641. float ftype = pprc->prm[flt_iftype];
  1642. float qwidth = pprc->prm[flt_iqwidth];
  1643. float gain = pprc->prm[flt_igain];
  1644. int L = 0; // numerator order
  1645. int M = 0; // denominator order
  1646. int b[FLT_M+1]; // numerator params 0..PMAX
  1647. int b_scaled[FLT_M+1]; // gain scaled numerator
  1648. int a[FLT_M+1]; // denominator params 0..PMAX
  1649. int L_bp = 0; // bandpass numerator order
  1650. int M_bp = 0; // bandpass denominator order
  1651. int b_bp[FLT_M+1]; // bandpass numerator params 0..PMAX
  1652. int b_bp_scaled[FLT_M+1]; // gain scaled numerator
  1653. int a_bp[FLT_M+1]; // bandpass denominator params 0..PMAX
  1654. int N; // # of series sections
  1655. bool bpass = false;
  1656. // if qwidth > 0 then alloc bandpass filter (pf is lowpass)
  1657. if ( qwidth > 0.0 )
  1658. bpass = true;
  1659. if (bpass)
  1660. {
  1661. ftype = FLT_LP;
  1662. }
  1663. // low pass and highpass filter design
  1664. // 1st order IIR filter, 3db cutoff at fc
  1665. if ( bpass )
  1666. {
  1667. // highpass section
  1668. FLT_Design_3db_IIR ( cutoff, FLT_HP, &M_bp, &L_bp, a_bp, b_bp );
  1669. M_bp = iclamp (M_bp, 1, FLT_M);
  1670. L_bp = iclamp (L_bp, 1, FLT_M);
  1671. cutoff += qwidth;
  1672. }
  1673. // lowpass section
  1674. FLT_Design_3db_IIR ( cutoff, (int)ftype, &M, &L, a, b );
  1675. M = iclamp (M, 1, FLT_M);
  1676. L = iclamp (L, 1, FLT_M);
  1677. // quality = # of series sections - 1
  1678. N = iclamp ((int)qual, 0, 3);
  1679. // make sure we alloc at least 2 filters
  1680. if (bpass)
  1681. N = MAX(N, 1);
  1682. flt_t *pf0 = NULL;
  1683. flt_t *pf1 = NULL;
  1684. flt_t *pf2 = NULL;
  1685. flt_t *pf3 = NULL;
  1686. // scale b numerators with gain - only scale for first filter if series filters
  1687. for (int i = 0; i < FLT_M; i++)
  1688. {
  1689. b_bp_scaled[i] = (int)((float)(b_bp[i]) * gain );
  1690. b_scaled[i] = (int)((float)(b[i]) * gain );
  1691. }
  1692. if (bpass)
  1693. {
  1694. // 1st filter is lowpass
  1695. pf0 = FLT_Alloc ( N, M_bp, L_bp, a_bp, b_bp_scaled, 1.0 );
  1696. }
  1697. else
  1698. {
  1699. pf0 = FLT_Alloc ( N, M, L, a, b_scaled, 1.0 );
  1700. }
  1701. // allocate series filters
  1702. if (pf0)
  1703. {
  1704. switch (N)
  1705. {
  1706. case 3:
  1707. // alloc last filter as lowpass also if FLT_BP
  1708. if (bpass)
  1709. pf3 = FLT_Alloc ( 0, M_bp, L_bp, a_bp, b_bp, 1.0 );
  1710. else
  1711. pf3 = FLT_Alloc ( 0, M, L, a, b, 1.0 );
  1712. case 2:
  1713. pf2 = FLT_Alloc ( 0, M, L, a, b, 1.0 );
  1714. case 1:
  1715. pf1 = FLT_Alloc ( 0, M, L, a, b, 1.0 );
  1716. case 0:
  1717. break;
  1718. }
  1719. pf0->pf1 = pf1;
  1720. pf0->pf2 = pf2;
  1721. pf0->pf3 = pf3;
  1722. }
  1723. return pf0;
  1724. }
  1725. inline void * FLT_VParams ( void *p )
  1726. {
  1727. PRC_CheckParams( (prc_t *)p, flt_rng);
  1728. return (void *) FLT_Params ((prc_t *)p);
  1729. }
  1730. inline void FLT_Mod ( void *p, float v ) { return; }
  1731. // get next filter value for filter pf and input x
  1732. inline int FLT_GetNext ( flt_t *pf, int x )
  1733. {
  1734. flt_t *pf1;
  1735. flt_t *pf2;
  1736. flt_t *pf3;
  1737. int y;
  1738. switch( pf->N )
  1739. {
  1740. default:
  1741. case 0:
  1742. return IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  1743. case 1:
  1744. pf1 = pf->pf1;
  1745. y = IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  1746. return IIRFilter_Update_Order1(pf1->a, pf1->L, pf1->b, pf1->w, y);
  1747. case 2:
  1748. pf1 = pf->pf1;
  1749. pf2 = pf->pf2;
  1750. y = IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  1751. y = IIRFilter_Update_Order1(pf1->a, pf1->L, pf1->b, pf1->w, y);
  1752. return IIRFilter_Update_Order1(pf2->a, pf2->L, pf2->b, pf2->w, y);
  1753. case 3:
  1754. pf1 = pf->pf1;
  1755. pf2 = pf->pf2;
  1756. pf3 = pf->pf3;
  1757. y = IIRFilter_Update_Order1(pf->a, pf->L, pf->b, pf->w, x);
  1758. y = IIRFilter_Update_Order1(pf1->a, pf1->L, pf1->b, pf1->w, y);
  1759. y = IIRFilter_Update_Order1(pf2->a, pf2->L, pf2->b, pf2->w, y);
  1760. return IIRFilter_Update_Order1(pf3->a, pf3->L, pf3->b, pf3->w, y);
  1761. }
  1762. }
  1763. // batch version for performance
  1764. inline void FLT_GetNextN( flt_t *pflt, portable_samplepair_t *pbuffer, int SampleCount, int op )
  1765. {
  1766. int count = SampleCount;
  1767. portable_samplepair_t *pb = pbuffer;
  1768. switch (op)
  1769. {
  1770. default:
  1771. case OP_LEFT:
  1772. while (count--)
  1773. {
  1774. pb->left = FLT_GetNext( pflt, pb->left );
  1775. pb++;
  1776. }
  1777. return;
  1778. case OP_RIGHT:
  1779. while (count--)
  1780. {
  1781. pb->right = FLT_GetNext( pflt, pb->right );
  1782. pb++;
  1783. }
  1784. return;
  1785. case OP_LEFT_DUPLICATE:
  1786. while (count--)
  1787. {
  1788. pb->left = pb->right = FLT_GetNext( pflt, pb->left );
  1789. pb++;
  1790. }
  1791. return;
  1792. }
  1793. }
  1794. ///////////////////////////////////////////////////////////////////////////
  1795. // Positional updaters for pitch shift etc
  1796. ///////////////////////////////////////////////////////////////////////////
  1797. // looping position within a wav, with integer and fractional parts
  1798. // used for pitch shifting, upsampling/downsampling
  1799. // 20 bits of fraction, 8+ bits of integer
  1800. struct pos_t
  1801. {
  1802. fix20int step; // wave table whole and fractional step value
  1803. fix20int cstep; // current cumulative step value
  1804. int pos; // current position within wav table
  1805. int D; // max dimension of array w[0...D] ie: # of samples = D+1
  1806. };
  1807. // circular wrap of pointer p, relative to array w
  1808. // D max buffer index w[0...D] (count of samples in buffer is D+1)
  1809. // i circular index
  1810. inline void POS_Wrap ( int D, int *i )
  1811. {
  1812. if ( *i > D )
  1813. *i -= D + 1; // when *pi = D + 1, it wraps around to *pi = 0
  1814. if ( *i < 0 )
  1815. *i += D + 1; // when *pi = - 1, it wraps around to *pi = D
  1816. }
  1817. // set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
  1818. // D is array max dimension w[0...D] (ie: size D+1)
  1819. // w is ptr to array
  1820. // p is ptr to pos_t to initialize
  1821. inline void POS_Init( pos_t *p, int D, float fstep )
  1822. {
  1823. float step = fstep;
  1824. // make sure int part of step is capped at fix20_intmax
  1825. if ((int)step > FIX20_INTMAX)
  1826. step = (step - (int)step) + FIX20_INTMAX;
  1827. p->step = FLOAT_TO_FIX20(step); // convert fstep to fixed point
  1828. p->cstep = 0;
  1829. p->pos = 0; // current update value
  1830. p->D = D; // always init to end value, in case we're stepping backwards
  1831. }
  1832. // change step value - this is an instantaneous change, not smoothed.
  1833. inline void POS_ChangeVal( pos_t *p, float fstepnew )
  1834. {
  1835. p->step = FLOAT_TO_FIX20( fstepnew ); // convert fstep to fixed point
  1836. }
  1837. // return current integer position, then update internal position value
  1838. inline int POS_GetNext ( pos_t *p )
  1839. {
  1840. //float f = FIX20_TO_FLOAT(p->cstep);
  1841. //int i1 = FIX20_INTPART(p->cstep);
  1842. //float f1 = FIX20_TO_FLOAT(FIX20_FRACPART(p->cstep));
  1843. //float f2 = FIX20_TO_FLOAT(p->step);
  1844. p->cstep += p->step; // update accumulated fraction step value (fixed point)
  1845. p->pos += FIX20_INTPART( p->cstep ); // update pos with integer part of accumulated step
  1846. p->cstep = FIX20_FRACPART( p->cstep ); // throw away the integer part of accumulated step
  1847. // wrap pos around either end of buffer if needed
  1848. POS_Wrap(p->D, &(p->pos));
  1849. // make sure returned position is within array bounds
  1850. Assert (p->pos <= p->D);
  1851. return p->pos;
  1852. }
  1853. void POS_Print( const pos_t & pos, int nIndentation )
  1854. {
  1855. const char * pIndent = GetIndentationText( nIndentation);
  1856. DevMsg( "%sPos: %p [Addr]\n", pIndent, &pos );
  1857. DevMsg( "%sstep: %d\n", pIndent, pos.step );
  1858. DevMsg( "%scstep: %d\n", pIndent, pos.cstep );
  1859. DevMsg( "%spos: %d\n", pIndent, pos.pos );
  1860. DevMsg( "%sD: %d\n", pIndent, pos.D );
  1861. }
  1862. #if CHECK_VALUES_AFTER_REFACTORING
  1863. void POS_Compare( const pos_t & leftPos, const pos_t & rightPos )
  1864. {
  1865. Assert ( &leftPos != &rightPos );
  1866. Assert( leftPos.step == rightPos.step );
  1867. Assert( leftPos.cstep == rightPos.cstep );
  1868. Assert( leftPos.pos == rightPos.pos );
  1869. Assert( leftPos.D == rightPos.D );
  1870. }
  1871. #endif
  1872. // oneshot position within wav
  1873. struct pos_one_t
  1874. {
  1875. pos_t p; // pos_t
  1876. bool fhitend; // flag indicating we hit end of oneshot wav
  1877. };
  1878. // set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
  1879. // one shot position - play only once, don't wrap, when hit end of buffer, return last position
  1880. inline void POS_ONE_Init( pos_one_t *p1, int D, float fstep )
  1881. {
  1882. POS_Init( &p1->p, D, fstep ) ;
  1883. p1->fhitend = false;
  1884. }
  1885. // return current integer position, then update internal position value
  1886. inline int POS_ONE_GetNext ( pos_one_t *p1 )
  1887. {
  1888. int pos;
  1889. pos_t *p0;
  1890. pos = p1->p.pos; // return current position
  1891. if (p1->fhitend)
  1892. return pos;
  1893. p0 = &(p1->p);
  1894. p0->cstep += p0->step; // update accumulated fraction step value (fixed point)
  1895. p0->pos += FIX20_INTPART( p0->cstep ); // update pos with integer part of accumulated step
  1896. //p0->cstep = SIGN(p0->cstep) * FIX20_FRACPART( p0->cstep );
  1897. p0->cstep = FIX20_FRACPART( p0->cstep ); // throw away the integer part of accumulated step
  1898. // if we wrapped, stop updating, always return last position
  1899. // if step value is 0, return hit end
  1900. if (!p0->step || p0->pos < 0 || p0->pos >= p0->D )
  1901. p1->fhitend = true;
  1902. else
  1903. pos = p0->pos;
  1904. // make sure returned value is within array bounds
  1905. Assert ( pos <= p0->D );
  1906. return pos;
  1907. }
  1908. void POS_ONE_Print( const pos_one_t & posOne, int nIndentation )
  1909. {
  1910. const char * pIndent = GetIndentationText( nIndentation );
  1911. DevMsg( "%sPosOne: %p [Addr]\n", pIndent, &posOne );
  1912. POS_Print( posOne.p, nIndentation + 1 );
  1913. DevMsg( "%sfhitend: %d\n", pIndent, posOne.fhitend );
  1914. }
  1915. #if CHECK_VALUES_AFTER_REFACTORING
  1916. void POS_ONE_Compare( const pos_one_t & leftPosOne, const pos_one_t & rightPosOne )
  1917. {
  1918. Assert ( &leftPosOne != &rightPosOne );
  1919. POS_Compare( leftPosOne.p, rightPosOne.p );
  1920. Assert( leftPosOne.fhitend == rightPosOne.fhitend );
  1921. }
  1922. #endif
  1923. /////////////////////
  1924. // Reverbs and delays
  1925. /////////////////////
  1926. #if CHECK_VALUES_AFTER_REFACTORING
  1927. #define CDLYS 256 // max delay lines active. Also used for lfos. Need more of them when cloning all the buffers for consistency checking.
  1928. #else
  1929. #define CDLYS 128 // max delay lines active. Also used for lfos.
  1930. #endif
  1931. #define DLY_PLAIN 0 // single feedback loop
  1932. #define DLY_ALLPASS 1 // feedback and feedforward loop - flat frequency response (diffusor)
  1933. #define DLY_LOWPASS 2 // lowpass filter in feedback loop
  1934. #define DLY_LINEAR 3 // linear delay, no feedback, unity gain
  1935. #define DLY_FLINEAR 4 // linear delay with lowpass filter and output gain
  1936. #define DLY_LOWPASS_4TAP 5 // lowpass filter in feedback loop, 4 delay taps
  1937. #define DLY_PLAIN_4TAP 6 // single feedback loop, 4 delay taps
  1938. #define DLY_MAX DLY_PLAIN_4TAP
  1939. #define DLY_HAS_MULTITAP(a) ((a) == DLY_LOWPASS_4TAP || (a) == DLY_PLAIN_4TAP)
  1940. #define DLY_HAS_FILTER(a) ((a) == DLY_FLINEAR || (a) == DLY_LOWPASS || (a) == DLY_LOWPASS_4TAP)
  1941. #define DLY_TAP_FEEDBACK_GAIN 0.25 // drop multitap feedback to compensate for sum of taps in dly_*multitap()
  1942. #define DLY_NORMALIZING_REDUCTION_MAX 0.25 // don't reduce gain (due to feedback) below N% of original gain
  1943. // delay line
  1944. struct dly_t
  1945. {
  1946. bool fused; // true if dly is in use
  1947. int type; // delay type
  1948. int D; // delay size, in samples
  1949. int t; // current tap, <= D
  1950. int tnew; // crossfading to tnew
  1951. int xf; // crossfade value of t (0..PMAX)
  1952. int t1,t2,t3; // additional taps for multi-tap delays
  1953. int a1,a2,a3; // feedback values for taps
  1954. int D0; // original delay size (only relevant if calling DLY_ChangeVal)
  1955. CircularBufferSample_t *p; // circular buffer pointer
  1956. CircularBufferSample_t *w; // array of samples
  1957. int a; // feedback value 0..PMAX,normalized to 0-1.0
  1958. int b; // gain value 0..PMAX, normalized to 0-1.0
  1959. flt_t *pflt; // pointer to filter, if type DLY_LOWPASS
  1960. };
  1961. dly_t dlys[CDLYS]; // delay lines
  1962. void DLY_Init ( dly_t *pdly ) { if ( pdly ) Q_memset( pdly, 0, sizeof (dly_t)); }
  1963. void DLY_InitAll ( void ) { for (int i = 0 ; i < CDLYS; i++) DLY_Init ( &dlys[i] ); }
  1964. void DLY_Free ( dly_t *pdly )
  1965. {
  1966. // free memory buffer
  1967. if ( pdly )
  1968. {
  1969. FLT_Free ( pdly->pflt );
  1970. if ( pdly->w )
  1971. {
  1972. delete[] pdly->w;
  1973. }
  1974. // free dly slot
  1975. Q_memset ( pdly, 0, sizeof (dly_t) );
  1976. }
  1977. }
  1978. void DLY_FreeAll ( void ) { for (int i = 0; i < CDLYS; i++ ) DLY_Free ( &dlys[i] ); }
  1979. // return adjusted feedback value for given dly
  1980. // such that decay time is same as that for dmin and fbmin
  1981. // dmin - minimum delay
  1982. // fbmin - minimum feedback
  1983. // dly - delay to match decay to dmin, fbmin
  1984. float DLY_NormalizeFeedback ( int dmin, float fbmin, int dly )
  1985. {
  1986. // minimum decay time T to -60db for a simple reverb is:
  1987. // Tmin = (ln 10^-3 / Ln fbmin) * (Dmin / fs)
  1988. // where fs = sample frequency
  1989. // similarly,
  1990. // Tdly = (ln 10^-3 / Ln fb) * (D / fs)
  1991. // setting Tdly = Tmin and solving for fb gives:
  1992. // D / Dmin = ln fb / ln fbmin
  1993. // since y^x = z gives x = ln z / ln y
  1994. // fb = fbmin ^ (D/Dmin)
  1995. float fb = powf (fbmin, (float)dly / (float) dmin);
  1996. return fb;
  1997. }
  1998. // set up 'b' gain parameter of feedback delay to
  1999. // compensate for gain caused by feedback 'fb'.
  2000. void DLY_SetNormalizingGain ( dly_t *pdly, int feedback )
  2001. {
  2002. // compute normalized gain, set as output gain
  2003. // calculate gain of delay line with feedback, and use it to
  2004. // reduce output. ie: force delay line with feedback to unity gain
  2005. // for constant input x with feedback fb:
  2006. // out = x + x*fb + x * fb^2 + x * fb^3...
  2007. // gain = out/x
  2008. // so gain = 1 + fb + fb^2 + fb^3...
  2009. // which, by the miracle of geometric series, equates to 1/1-fb
  2010. // thus, gain = 1/(1-fb)
  2011. float fgain = 0;
  2012. float gain;
  2013. int b;
  2014. float fb = (float)feedback;
  2015. fb = fb / (float)PMAX;
  2016. fb = fpmin(fb, 0.999f);
  2017. // if b is 0, set b to PMAX (1)
  2018. b = pdly->b ? pdly->b : PMAX;
  2019. fgain = 1.0 / (1.0 - fb);
  2020. // compensating gain - multiply rva output by gain then >> PBITS
  2021. gain = (int)((1.0 / fgain) * PMAX);
  2022. gain = gain * 4; // compensate for fact that gain calculation is for +/- 32767 amplitude wavs
  2023. // ie: ok to allow a bit more gain because most wavs are not at theoretical peak amplitude at all times
  2024. // limit gain reduction to N% PMAX
  2025. gain = iclamp (gain, (PMAX * DLY_NORMALIZING_REDUCTION_MAX), PMAX);
  2026. gain = ((float)b/(float)PMAX) * gain; // scale final gain by pdly->b.
  2027. pdly->b = (int)gain;
  2028. }
  2029. void DLY_ChangeTaps ( dly_t *pdly, int t0, int t1, int t2, int t3 );
  2030. // allocate a new delay line
  2031. // D number of samples to delay
  2032. // a feedback value (0-PMAX normalized to 0.0-1.0)
  2033. // b gain value (0-PMAX normalized to 0.0-1.0) - this is folded into the filter fb params
  2034. // if DLY_LOWPASS or DLY_FLINEAR:
  2035. // L - numerator order of filter
  2036. // M - denominator order of filter
  2037. // fb - numerator params, M+1
  2038. // fa - denominator params, L+1
  2039. dly_t * DLY_AllocLP ( int D, int a, int b, int type, int M, int L, int *fa, int *fb )
  2040. {
  2041. CircularBufferSample_t *w;
  2042. int i;
  2043. dly_t *pdly = NULL;
  2044. int feedback;
  2045. // find open slot
  2046. for (i = 0; i < CDLYS; i++)
  2047. {
  2048. if (!dlys[i].fused)
  2049. {
  2050. pdly = &dlys[i];
  2051. DLY_Init( pdly );
  2052. break;
  2053. }
  2054. }
  2055. if ( i == CDLYS )
  2056. {
  2057. DevMsg ("DSP: Warning, failed to allocate delay line.\n" );
  2058. return NULL; // all delay lines in use
  2059. }
  2060. // save original feedback value
  2061. feedback = a;
  2062. // adjust feedback a, gain b if delay is multitap unit
  2063. if ( DLY_HAS_MULTITAP(type) )
  2064. {
  2065. // split output gain over 4 taps
  2066. b = (int)((float)(b) * DLY_TAP_FEEDBACK_GAIN);
  2067. }
  2068. if ( DLY_HAS_FILTER(type) )
  2069. {
  2070. // alloc lowpass iir_filter
  2071. // delay feedback gain is built into filter gain
  2072. float gain = (float)a / (float)(PMAX);
  2073. pdly->pflt = FLT_Alloc( 0, M, L, fa, fb, gain );
  2074. if ( !pdly->pflt )
  2075. {
  2076. DevMsg ("DSP: Warning, failed to allocate filter for delay line.\n" );
  2077. return NULL;
  2078. }
  2079. }
  2080. // alloc delay memory
  2081. w = new CircularBufferSample_t[D+1];
  2082. if ( !w )
  2083. {
  2084. Warning( "Sound DSP: Failed to lock.\n");
  2085. FLT_Free ( pdly->pflt );
  2086. return NULL;
  2087. }
  2088. // clear delay array
  2089. Q_memset (w, 0, sizeof(CircularBufferSample_t) * (D+1));
  2090. // init values
  2091. pdly->type = type;
  2092. pdly->D = D;
  2093. pdly->t = D; // set delay tap to full delay
  2094. pdly->tnew = D;
  2095. pdly->xf = 0;
  2096. pdly->D0 = D;
  2097. pdly->p = w; // init circular pointer to head of buffer
  2098. pdly->w = w;
  2099. pdly->a = MIN( a, PMAX - 1 ); // do not allow 100% feedback
  2100. pdly->b = b;
  2101. pdly->fused = true;
  2102. if ( type == DLY_LINEAR || type == DLY_FLINEAR )
  2103. {
  2104. // linear delay has no feedback and unity gain
  2105. pdly->a = 0;
  2106. pdly->b = PMAX;
  2107. }
  2108. else
  2109. {
  2110. // adjust b to compensate for feedback gain of steady state max input
  2111. DLY_SetNormalizingGain( pdly, feedback );
  2112. }
  2113. if ( DLY_HAS_MULTITAP(type) )
  2114. {
  2115. // initially set up all taps to same value - caller uses DLY_ChangeTaps to change values
  2116. DLY_ChangeTaps( pdly, D, D, D, D );
  2117. }
  2118. return (pdly);
  2119. }
  2120. // allocate lowpass or allpass delay
  2121. dly_t * DLY_Alloc( int D, int a, int b, int type )
  2122. {
  2123. return DLY_AllocLP( D, a, b, type, 0, 0, 0, 0 );
  2124. }
  2125. void DLY_Print( const dly_t & delay, int nIndentation )
  2126. {
  2127. const char * pIndent = GetIndentationText( nIndentation );
  2128. DevMsg( "%sDelay: %p [Addr]\n", pIndent, &delay );
  2129. DevMsg( "%sfused: %d\n", pIndent, delay.fused );
  2130. DevMsg( "%stype: %d\n", pIndent, delay.type );
  2131. DevMsg( "%sD: %d\n", pIndent, delay.D );
  2132. DevMsg( "%st: %d\n", pIndent, delay.t );
  2133. DevMsg( "%stnew: %d\n", pIndent, delay.tnew );
  2134. DevMsg( "%sxf: %d\n", pIndent, delay.xf );
  2135. DevMsg( "%st1: %d - t2: %d - t3: %d\n", pIndent, delay.t1, delay.t2, delay.t3 );
  2136. DevMsg( "%sa1: %d - a2: %d - a3: %d\n", pIndent, delay.a1, delay.a2, delay.a3 );
  2137. DevMsg( "%sD0: %d\n", pIndent, delay.D0 );
  2138. DevMsg( "%sw: %d\n", pIndent, delay.p - delay.w ); // Put the index and not the address
  2139. // See if we can reduce the output if possible
  2140. CircularBufferSample_t nFirstValue = delay.w[0];
  2141. bool bAllSame = true;
  2142. for ( int i = 1 ; i < delay.D + 1 ; ++i )
  2143. {
  2144. if ( delay.w[i] != nFirstValue )
  2145. {
  2146. bAllSame = false;
  2147. }
  2148. }
  2149. if ( bAllSame )
  2150. {
  2151. DevMsg( "%sAll %d values are equal to %d.\n", pIndent, delay.D + 1, nFirstValue );
  2152. }
  2153. else
  2154. {
  2155. // Values are different, list them
  2156. int nValues = delay.D + 1;
  2157. const int MAX_SAMPLES_DISPLAYED = 256;
  2158. if ( nValues > MAX_SAMPLES_DISPLAYED )
  2159. {
  2160. nValues = MAX_SAMPLES_DISPLAYED;
  2161. DevMsg( "%sDisplay only the first %d samples.\n", pIndent, nValues );
  2162. }
  2163. for ( int i = 0 ; i < nValues ; ++i )
  2164. {
  2165. if ( ( i % 64 ) == 0 )
  2166. {
  2167. DevMsg( "\n%s ", pIndent );
  2168. }
  2169. DevMsg( "%d ", delay.w[i] );
  2170. }
  2171. DevMsg( "\n" );
  2172. }
  2173. DevMsg( "%sa: %d\n", pIndent, delay.a );
  2174. DevMsg( "%sb: %d\n", pIndent, delay.b );
  2175. DevMsg( "%spflt: ", pIndent );
  2176. if (delay.pflt != NULL)
  2177. {
  2178. FLT_Print( *delay.pflt, nIndentation + 1 );
  2179. }
  2180. else
  2181. {
  2182. DevMsg( "NULL\n" );
  2183. }
  2184. }
  2185. #if CHECK_VALUES_AFTER_REFACTORING
  2186. dly_t * DLY_Clone(dly_t * pOldDelay)
  2187. {
  2188. flt_t * pFilter = pOldDelay->pflt;
  2189. dly_t * pNewDelay;
  2190. if ( pFilter != NULL )
  2191. {
  2192. pNewDelay = DLY_AllocLP(pOldDelay->D, pOldDelay->a, pOldDelay->b, pOldDelay->type, pFilter->M, pFilter->L, pFilter->a, pFilter->b);
  2193. }
  2194. else
  2195. {
  2196. pNewDelay = DLY_Alloc(pOldDelay->D, pOldDelay->a, pOldDelay->b, pOldDelay->type);
  2197. }
  2198. // Copy the samples
  2199. for (int i = 0 ; i < pOldDelay->D + 1 ; ++i)
  2200. {
  2201. pNewDelay->w[i] = pOldDelay->w[i];
  2202. }
  2203. // Update the offset
  2204. pNewDelay->p += ( pOldDelay->p - pOldDelay->w );
  2205. Assert( ( pNewDelay->p - pNewDelay->w ) == ( pOldDelay->p - pOldDelay->w ) );
  2206. // Let's make sure that the filters have the same values
  2207. if ( pFilter != NULL )
  2208. {
  2209. for (int i = 0 ; i < FLT_M + 1 ; ++i)
  2210. {
  2211. pNewDelay->pflt->b[i] = pFilter->b[i];
  2212. pNewDelay->pflt->a[i] = pFilter->a[i];
  2213. pNewDelay->pflt->w[i] = pFilter->w[i];
  2214. }
  2215. }
  2216. pNewDelay->b = pOldDelay->b;
  2217. pNewDelay->t = pOldDelay->t;
  2218. pNewDelay->xf = pOldDelay->xf;
  2219. pNewDelay->tnew = pOldDelay->tnew;
  2220. return pNewDelay;
  2221. }
  2222. void DLY_Compare( const dly_t & leftDelay, const dly_t & rightDelay )
  2223. {
  2224. Assert ( &leftDelay != &rightDelay );
  2225. Assert( leftDelay.fused == rightDelay.fused );
  2226. Assert( leftDelay.type == rightDelay.type );
  2227. Assert( leftDelay.D == rightDelay.D );
  2228. Assert( leftDelay.t == rightDelay.t );
  2229. Assert( leftDelay.tnew == rightDelay.tnew );
  2230. Assert( leftDelay.xf == rightDelay.xf );
  2231. Assert( leftDelay.t1 == rightDelay.t1 );
  2232. Assert( leftDelay.t2 == rightDelay.t2 );
  2233. Assert( leftDelay.t3 == rightDelay.t3 );
  2234. Assert( leftDelay.a1 == rightDelay.a1 );
  2235. Assert( leftDelay.a2 == rightDelay.a2 );
  2236. Assert( leftDelay.a3 == rightDelay.a3 );
  2237. Assert( leftDelay.D0 == rightDelay.D0 );
  2238. Assert( leftDelay.t1 == rightDelay.t1 );
  2239. Assert( (leftDelay.p - leftDelay.w) == (rightDelay.p - rightDelay.w) );
  2240. for ( int i = 0 ; i < leftDelay.D + 1 ; ++i )
  2241. {
  2242. Assert( leftDelay.w[i] == rightDelay.w[i] );
  2243. }
  2244. Assert( leftDelay.a == rightDelay.a );
  2245. Assert( leftDelay.b == rightDelay.b );
  2246. if ( CheckPointers( leftDelay.pflt, rightDelay.pflt ) )
  2247. {
  2248. FLT_Compare( *leftDelay.pflt, *rightDelay.pflt );
  2249. }
  2250. }
  2251. #endif
  2252. // Allocate new delay, convert from float params in prc preset to internal parameters
  2253. // Uses filter params in prc if delay is type lowpass
  2254. // delay parameter order
  2255. typedef enum {
  2256. dly_idtype, // NOTE: first 8 params must match those in mdy_e
  2257. dly_idelay,
  2258. dly_ifeedback,
  2259. dly_igain,
  2260. dly_iftype,
  2261. dly_icutoff,
  2262. dly_iqwidth,
  2263. dly_iquality,
  2264. dly_itap1,
  2265. dly_itap2,
  2266. dly_itap3,
  2267. dly_cparam
  2268. } dly_e;
  2269. // delay parameter ranges
  2270. prm_rng_t dly_rng[] = {
  2271. {dly_cparam, 0, 0}, // first entry is # of parameters
  2272. // delay params
  2273. {dly_idtype, 0, DLY_MAX}, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS etc
  2274. {dly_idelay, -1.0, 1000.0}, // delay in milliseconds (-1 forces auto dsp to set delay value from room size)
  2275. {dly_ifeedback, 0.0, 0.99}, // feedback 0-1.0
  2276. {dly_igain, 0.0, 10.0}, // final gain of output stage, 0-10.0
  2277. // filter params if dly type DLY_LOWPASS or DLY_FLINEAR
  2278. {dly_iftype, 0, FTR_MAX},
  2279. {dly_icutoff, 10.0, 22050.0},
  2280. {dly_iqwidth, 100.0, 11025.0},
  2281. {dly_iquality, 0, QUA_MAX},
  2282. // note: -1 flag tells auto dsp to get value directly from room size
  2283. {dly_itap1, -1.0, 1000.0}, // delay in milliseconds NOTE: delay > tap3 > tap2 > tap1
  2284. {dly_itap2, -1.0, 1000.0}, // delay in milliseconds
  2285. {dly_itap3, -1.0, 1000.0}, // delay in milliseconds
  2286. };
  2287. dly_t * DLY_Params ( prc_t *pprc )
  2288. {
  2289. dly_t *pdly = NULL;
  2290. int D, a, b;
  2291. float delay = fabs(pprc->prm[dly_idelay]);
  2292. float feedback = pprc->prm[dly_ifeedback];
  2293. float gain = pprc->prm[dly_igain];
  2294. int type = pprc->prm[dly_idtype];
  2295. float ftype = pprc->prm[dly_iftype];
  2296. float cutoff = pprc->prm[dly_icutoff];
  2297. float qwidth = pprc->prm[dly_iqwidth];
  2298. float qual = pprc->prm[dly_iquality];
  2299. float t1 = fabs(pprc->prm[dly_itap1]);
  2300. float t2 = fabs(pprc->prm[dly_itap2]);
  2301. float t3 = fabs(pprc->prm[dly_itap3]);
  2302. D = MSEC_TO_SAMPS(delay); // delay samples
  2303. a = feedback * PMAX; // feedback
  2304. b = gain * PMAX; // gain
  2305. switch ( (int) type )
  2306. {
  2307. case DLY_PLAIN:
  2308. case DLY_PLAIN_4TAP:
  2309. case DLY_ALLPASS:
  2310. case DLY_LINEAR:
  2311. pdly = DLY_Alloc( D, a, b, type );
  2312. break;
  2313. case DLY_FLINEAR:
  2314. case DLY_LOWPASS:
  2315. case DLY_LOWPASS_4TAP:
  2316. {
  2317. // set up dummy lowpass filter to convert params
  2318. prc_t prcf;
  2319. prcf.prm[flt_iquality] = qual; // 0,1,2 - (0 or 1 low quality implies faster execution time)
  2320. prcf.prm[flt_icutoff] = cutoff;
  2321. prcf.prm[flt_iftype] = ftype;
  2322. prcf.prm[flt_iqwidth] = qwidth;
  2323. prcf.prm[flt_igain] = 1.0;
  2324. flt_t *pflt = (flt_t *)FLT_Params ( &prcf );
  2325. if ( !pflt )
  2326. {
  2327. DevMsg ("DSP: Warning, failed to allocate filter.\n" );
  2328. return NULL;
  2329. }
  2330. pdly = DLY_AllocLP ( D, a, b, type, pflt->M, pflt->L, pflt->a, pflt->b );
  2331. FLT_Free ( pflt );
  2332. break;
  2333. }
  2334. }
  2335. // set up multi-tap delays
  2336. if ( pdly && DLY_HAS_MULTITAP((int)type) )
  2337. DLY_ChangeTaps( pdly, D, MSEC_TO_SAMPS(t1), MSEC_TO_SAMPS(t2), MSEC_TO_SAMPS(t3) );
  2338. return pdly;
  2339. }
  2340. inline void * DLY_VParams ( void *p )
  2341. {
  2342. PRC_CheckParams( (prc_t *)p, dly_rng );
  2343. return (void *) DLY_Params ((prc_t *)p);
  2344. }
  2345. // get next value from delay line, move x into delay line
  2346. inline int DLY_GetNext ( dly_t *pdly, int x )
  2347. {
  2348. switch (pdly->type)
  2349. {
  2350. default:
  2351. case DLY_PLAIN:
  2352. return ReverbSimple( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  2353. case DLY_ALLPASS:
  2354. return DelayAllpass( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  2355. case DLY_LOWPASS:
  2356. 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 );
  2357. case DLY_LINEAR:
  2358. return DelayLinear( pdly->D, pdly->t, pdly->w, &pdly->p, x );
  2359. case DLY_FLINEAR:
  2360. return DelayLinearLowPass( 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 );
  2361. case DLY_PLAIN_4TAP:
  2362. return ReverbSimple_multitap( pdly->D, pdly->t, pdly->t1, pdly->t2, pdly->t3, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  2363. case DLY_LOWPASS_4TAP:
  2364. 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 );
  2365. }
  2366. }
  2367. inline void DLY_GetNext_Opt ( dly_t *pdly, int * pIn, LocalOutputSample_t * pOut, int nCount )
  2368. {
  2369. switch (pdly->type)
  2370. {
  2371. default:
  2372. case DLY_PLAIN:
  2373. ReverbSimple_Opt( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, pIn, pOut, nCount );
  2374. break;
  2375. case DLY_ALLPASS:
  2376. DelayAllpass_Opt3<2, MM_ADD>( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, pIn, pOut, nCount );
  2377. break;
  2378. case DLY_LOWPASS:
  2379. DelayLowPass_Opt3( pdly->D, pdly->t, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, pIn, pOut, nCount );
  2380. break;
  2381. case DLY_LINEAR:
  2382. DelayLinear_Opt( pdly->D, pdly->t, pdly->w, &pdly->p, pIn, pOut, nCount );
  2383. break;
  2384. case DLY_FLINEAR:
  2385. DelayLinearLowPass_Opt3( pdly->D, pdly->t, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, pIn, pOut, nCount );
  2386. break;
  2387. case DLY_PLAIN_4TAP:
  2388. ReverbSimple_multitap_Opt( pdly->D, pdly->t, pdly->t1, pdly->t2, pdly->t3, pdly->w, &pdly->p, pdly->a, pdly->b, pIn, pOut, nCount );
  2389. break;
  2390. case DLY_LOWPASS_4TAP:
  2391. DelayLowpass_multitap_Opt( 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, pIn, pOut, nCount );
  2392. break;
  2393. }
  2394. }
  2395. inline int DLY_GetNextXfade ( dly_t *pdly, int x )
  2396. {
  2397. switch (pdly->type)
  2398. {
  2399. default:
  2400. case DLY_PLAIN:
  2401. return ReverbSimple_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  2402. case DLY_ALLPASS:
  2403. return DelayAllpass_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  2404. case DLY_LOWPASS:
  2405. 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 );
  2406. case DLY_LINEAR:
  2407. return DelayLinear_xfade( pdly->D, pdly->t, pdly->tnew, pdly->xf, pdly->w, &pdly->p, x );
  2408. case DLY_FLINEAR:
  2409. 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 );
  2410. case DLY_PLAIN_4TAP:
  2411. 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 );
  2412. case DLY_LOWPASS_4TAP:
  2413. 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 );
  2414. }
  2415. }
  2416. // batch version for performance
  2417. // UNDONE: a) unwind this more - pb increments by 2 to avoid pb->left or pb->right deref.
  2418. // UNDONE: b) all filter and delay params are dereferenced outside of DLY_GetNext and passed as register values
  2419. // UNDONE: c) pull case statement in dly_getnext out, so loop directly calls the inline dly_*() routine.
  2420. inline void DLY_GetNextN( dly_t *pdly, portable_samplepair_t *pbuffer, int SampleCount, int op )
  2421. {
  2422. int count = SampleCount;
  2423. portable_samplepair_t *pb = pbuffer;
  2424. switch (op)
  2425. {
  2426. default:
  2427. case OP_LEFT:
  2428. while (count--)
  2429. {
  2430. pb->left = DLY_GetNext( pdly, pb->left );
  2431. pb++;
  2432. }
  2433. return;
  2434. case OP_RIGHT:
  2435. while (count--)
  2436. {
  2437. pb->right = DLY_GetNext( pdly, pb->right );
  2438. pb++;
  2439. }
  2440. return;
  2441. case OP_LEFT_DUPLICATE:
  2442. while (count--)
  2443. {
  2444. pb->left = pb->right = DLY_GetNext( pdly, pb->left );
  2445. pb++;
  2446. }
  2447. return;
  2448. }
  2449. }
  2450. // get tap on t'th sample in delay - don't update buffer pointers, this is done via DLY_GetNext
  2451. // Only valid for DLY_LINEAR.
  2452. inline int DLY_GetTap ( dly_t *pdly, int t )
  2453. {
  2454. return GetDly (pdly->D, pdly->w, pdly->p, t );
  2455. }
  2456. #define SWAP(a,b,t) {(t) = (a); (a) = (b); (b) = (t);}
  2457. // make instantaneous change to tap values t0..t3
  2458. // all values of t must be less than original delay D
  2459. // only processed for DLY_LOWPASS_4TAP & DLY_PLAIN_4TAP
  2460. // NOTE: pdly->a feedback must have been set before this call!
  2461. void DLY_ChangeTaps ( dly_t *pdly, int t0, int t1, int t2, int t3 )
  2462. {
  2463. if (!pdly)
  2464. return;
  2465. int temp;
  2466. // sort taps to make sure t3 > t2 > t1 > t0 !
  2467. for (int i = 0; i < 4; i++)
  2468. {
  2469. if (t0 > t1) SWAP(t0, t1, temp);
  2470. if (t1 > t2) SWAP(t1, t2, temp);
  2471. if (t2 > t3) SWAP(t2, t3, temp);
  2472. }
  2473. pdly->t = MIN ( t0, pdly->D0 );
  2474. pdly->t1 = MIN ( t1, pdly->D0 );
  2475. pdly->t2 = MIN ( t2, pdly->D0 );
  2476. pdly->t3 = MIN ( t3, pdly->D0 );
  2477. }
  2478. // make instantaneous change for first delay tap 't' to new delay value.
  2479. // t tap value must be <= original D (ie: we don't do any reallocation here)
  2480. void DLY_ChangeVal ( dly_t *pdly, int t )
  2481. {
  2482. // never set delay > original delay
  2483. pdly->t = MIN ( t, pdly->D0 );
  2484. }
  2485. // ignored - use MDY_ for modulatable delay
  2486. inline void DLY_Mod ( void *p, float v ) { return; }
  2487. /////////////////////////////////////////////////////////////////////////////
  2488. // Ramp - used for varying smoothly between int parameters ie: modulation delays
  2489. /////////////////////////////////////////////////////////////////////////////
  2490. struct rmp_t
  2491. {
  2492. int initval; // initial ramp value
  2493. int target; // final ramp value
  2494. int sign; // increasing (1) or decreasing (-1) ramp
  2495. uint nEndRampTimeInMs;
  2496. int yprev; // previous output value
  2497. bool fhitend; // true if hit end of ramp
  2498. bool bEndAtTime; // if true, fhitend is true when ramp time is hit (even if target not hit)
  2499. // if false, then fhitend is true only when target is hit
  2500. pos_one_t ps; // current ramp output
  2501. };
  2502. // ramp smoothly between initial value and target value in approx 'ramptime' seconds.
  2503. // (initial value may be greater or less than target value)
  2504. // never changes output by more than +1 or -1 (which can cause the ramp to take longer to complete than ramptime - see bEndAtTime)
  2505. // called once per sample while ramping
  2506. // ramptime - duration of ramp in seconds
  2507. // initval - initial ramp value
  2508. // targetval - target ramp value
  2509. // if bEndAtTime is true, then RMP_HitEnd returns true when ramp time is reached, EVEN IF TARGETVAL IS NOT REACHED
  2510. // if bEndAtTime is false, then RMP_HitEnd returns true when targetval is reached, EVEN IF DELTA IN RAMP VALUES IS > +/- 1
  2511. void RMP_Init( rmp_t *prmp, float ramptime, int initval, int targetval, bool bEndAtTime )
  2512. {
  2513. int rise;
  2514. int run;
  2515. if (prmp)
  2516. Q_memset( prmp, 0, sizeof (rmp_t) );
  2517. else
  2518. return;
  2519. run = (int) (ramptime * SOUND_DMA_SPEED); // 'samples' in ramp
  2520. rise = (targetval - initval); // height of ramp
  2521. // init fixed point iterator to iterate along the height of the ramp 'rise'
  2522. // always iterates from 0..'rise', increasing in value
  2523. POS_ONE_Init( &prmp->ps, ABS( rise ), ABS((float) rise) / ((float) run) );
  2524. prmp->yprev = initval;
  2525. prmp->initval = initval;
  2526. prmp->target = targetval;
  2527. prmp->sign = SIGN( rise );
  2528. float fMinRampTime = MAX( ramptime, 0.016f ); // At minimum we are going to wait for 16 ms (a 60 Hz frame, to avoid issue with ramping at the sample level).
  2529. prmp->nEndRampTimeInMs = Plat_MSTime() + (int)( fMinRampTime * 1000.0f ); // Time when we know it is safe to not cross-fade anymore (time is expired).
  2530. prmp->bEndAtTime = bEndAtTime;
  2531. }
  2532. // continues from current position to new target position
  2533. void RMP_SetNext( rmp_t *prmp, float ramptime, int targetval )
  2534. {
  2535. RMP_Init ( prmp, ramptime, prmp->yprev, targetval, prmp->bEndAtTime );
  2536. }
  2537. inline bool RMP_HitEnd ( rmp_t *prmp )
  2538. {
  2539. return prmp->fhitend;
  2540. }
  2541. inline void RMP_SetEnd ( rmp_t *prmp )
  2542. {
  2543. prmp->fhitend = true;
  2544. }
  2545. // get next ramp value & update ramp, if bEndAtTime is true, never varies by more than +1 or -1 between calls
  2546. // when ramp hits target value, it thereafter always returns last value
  2547. inline int RMP_GetNext( rmp_t *prmp )
  2548. {
  2549. int y;
  2550. int d;
  2551. // if we hit ramp end, return last value
  2552. if (prmp->fhitend)
  2553. return prmp->yprev;
  2554. // get next integer position in ramp height.
  2555. d = POS_ONE_GetNext( &prmp->ps );
  2556. if ( prmp->ps.fhitend )
  2557. prmp->fhitend = true;
  2558. // increase or decrease from initval, depending on ramp sign
  2559. if ( prmp->sign > 0 )
  2560. y = prmp->initval + d;
  2561. else
  2562. y = prmp->initval - d;
  2563. // if bEndAtTime is true, only update current height by a max of +1 or -1
  2564. // this also means that for short ramp times, we may not hit target
  2565. if (prmp->bEndAtTime)
  2566. {
  2567. if ( ABS( y - prmp->yprev ) >= 1 )
  2568. prmp->yprev += prmp->sign;
  2569. }
  2570. else
  2571. {
  2572. // always hits target - but varies by more than +/- 1
  2573. prmp->yprev = y;
  2574. }
  2575. return prmp->yprev;
  2576. }
  2577. // get current ramp value, don't update ramp
  2578. inline int RMP_GetCurrent( rmp_t *prmp )
  2579. {
  2580. return prmp->yprev;
  2581. }
  2582. void RMP_Print( const rmp_t & rmp, int nIndentation )
  2583. {
  2584. const char * pIndent = GetIndentationText( nIndentation );
  2585. DevMsg( "%sRmp: %p [Addr]\n", pIndent, &rmp );
  2586. DevMsg( "%sinitval: %d\n", pIndent, rmp.initval );
  2587. DevMsg( "%starget: %d\n", pIndent, rmp.target );
  2588. DevMsg( "%ssign: %d\n", pIndent, rmp.sign );
  2589. DevMsg( "%sfhitend: %d\n", pIndent, rmp.fhitend );
  2590. DevMsg( "%sbEndAtTime: %d\n", pIndent, rmp.bEndAtTime );
  2591. POS_ONE_Print( rmp.ps, nIndentation + 1 );
  2592. }
  2593. #if CHECK_VALUES_AFTER_REFACTORING
  2594. void RMP_Compare( const rmp_t & leftRmp, const rmp_t & rightRmp )
  2595. {
  2596. Assert ( &leftRmp != &rightRmp );
  2597. Assert( leftRmp.initval == rightRmp.initval );
  2598. Assert( leftRmp.target == rightRmp.target );
  2599. Assert( leftRmp.sign == rightRmp.sign );
  2600. Assert( leftRmp.fhitend == rightRmp.fhitend );
  2601. Assert( leftRmp.bEndAtTime == rightRmp.bEndAtTime );
  2602. POS_ONE_Compare( leftRmp.ps, rightRmp.ps );
  2603. }
  2604. #endif
  2605. //////////////
  2606. // mod delay
  2607. //////////////
  2608. // modulate delay time anywhere from 0..D using MDY_ChangeVal. no output glitches (uses RMP)
  2609. #if CHECK_VALUES_AFTER_REFACTORING
  2610. #define CMDYS 128
  2611. #else
  2612. #define CMDYS 64 // max # of mod delays active (steals from delays)
  2613. #endif
  2614. struct mdy_t
  2615. {
  2616. bool fused;
  2617. bool fchanging; // true if modulating to new delay value
  2618. dly_t *pdly; // delay
  2619. float ramptime; // ramp 'glide' time - time in seconds to change between values
  2620. int mtime; // time in samples between delay changes. 0 implies no self-modulating
  2621. int mtimecur; // current time in samples until next delay change
  2622. float depth; // modulate delay from D to D - (D*depth) depth 0-1.0
  2623. int mix; // PMAX as % processed fx signal mix
  2624. rmp_t rmp_interp; // interpolation ramp 0...PMAX
  2625. bool bPhaseInvert; // if true, invert phase of output
  2626. };
  2627. mdy_t mdys[CMDYS];
  2628. void MDY_Init( mdy_t *pmdy ) { if (pmdy) Q_memset( pmdy, 0, sizeof (mdy_t) ); };
  2629. void MDY_Free( mdy_t *pmdy ) { if (pmdy) { DLY_Free (pmdy->pdly); Q_memset( pmdy, 0, sizeof (mdy_t) ); } };
  2630. void MDY_InitAll() { for (int i = 0; i < CMDYS; i++) MDY_Init( &mdys[i] ); };
  2631. void MDY_FreeAll() { for (int i = 0; i < CMDYS; i++) MDY_Free( &mdys[i] ); };
  2632. // allocate mod delay, given previously allocated dly (NOTE: mod delay only sweeps tap 0, not t1,t2 or t3)
  2633. // ramptime is time in seconds for delay to change from dcur to dnew
  2634. // modtime is time in seconds between modulations. 0 if no self-modulation
  2635. // depth is 0-1.0 multiplier, new delay values when modulating are Dnew = randomlong (D - D*depth, D)
  2636. // mix - 0-1.0, default 1.0 for 100% fx mix - pans between input signal and fx signal
  2637. mdy_t *MDY_Alloc ( dly_t *pdly, float ramptime, float modtime, float depth, float mix )
  2638. {
  2639. int i;
  2640. mdy_t *pmdy;
  2641. if ( !pdly )
  2642. return NULL;
  2643. for (i = 0; i < CMDYS; i++)
  2644. {
  2645. if ( !mdys[i].fused )
  2646. {
  2647. pmdy = &mdys[i];
  2648. MDY_Init ( pmdy );
  2649. pmdy->pdly = pdly;
  2650. if ( !pmdy->pdly )
  2651. {
  2652. DevMsg ("DSP: Warning, failed to allocate delay for mod delay.\n" );
  2653. return NULL;
  2654. }
  2655. pmdy->fused = true;
  2656. pmdy->ramptime = ramptime;
  2657. pmdy->mtime = SEC_TO_SAMPS(modtime);
  2658. pmdy->mtimecur = pmdy->mtime;
  2659. pmdy->depth = depth;
  2660. pmdy->mix = int ( PMAX * mix );
  2661. pmdy->bPhaseInvert = false;
  2662. return pmdy;
  2663. }
  2664. }
  2665. DevMsg ("DSP: Warning, failed to allocate mod delay.\n" );
  2666. return NULL;
  2667. }
  2668. void MDY_Print( const mdy_t & modDelay, int nIndentation )
  2669. {
  2670. const char * pIndent = GetIndentationText( nIndentation );
  2671. DevMsg( "%sModDelay: %p [Addr]\n", pIndent, &modDelay );
  2672. DevMsg( "%sfused: %d\n", pIndent, modDelay.fused );
  2673. DevMsg( "%sfchanging: %d\n", pIndent, modDelay.fchanging );
  2674. DevMsg( "%spdly: ", pIndent );
  2675. if ( modDelay.pdly != NULL )
  2676. {
  2677. DLY_Print( *modDelay.pdly, nIndentation + 1 );
  2678. }
  2679. else
  2680. {
  2681. DevMsg( "NULL\n" );
  2682. }
  2683. DevMsg( "%sramptime: %f\n", pIndent, modDelay.ramptime );
  2684. DevMsg( "%smtime: %d\n", pIndent, modDelay.mtime );
  2685. DevMsg( "%smtimecur: %d\n", pIndent, modDelay.mtimecur );
  2686. DevMsg( "%sdepth: %f\n", pIndent, modDelay.depth );
  2687. DevMsg( "%smix: %d\n", pIndent, modDelay.mix );
  2688. RMP_Print( modDelay.rmp_interp, nIndentation + 1 );
  2689. DevMsg( "%sbPhaseInvert: %d\n", pIndent, modDelay.bPhaseInvert );
  2690. }
  2691. #if CHECK_VALUES_AFTER_REFACTORING
  2692. mdy_t * MDY_Clone( mdy_t * pOldModDelay )
  2693. {
  2694. dly_t * pNewDelay = DLY_Clone( pOldModDelay->pdly );
  2695. // SAMPS_TO_SEC does not work as expected (number too small?) - we'll override the number anyway
  2696. // MDY_Alloc() should set the pdly accordingly.
  2697. mdy_t * pNewModDelay = MDY_Alloc( pNewDelay, pOldModDelay->ramptime, SAMPS_TO_SEC(pOldModDelay->mtime), pOldModDelay->depth, pOldModDelay->mix );
  2698. pNewModDelay->fchanging = pOldModDelay->fchanging;
  2699. pNewModDelay->ramptime = pOldModDelay->ramptime;
  2700. pNewModDelay->mtime = pOldModDelay->mtime;
  2701. pNewModDelay->mtimecur = pOldModDelay->mtimecur;
  2702. pNewModDelay->depth = pOldModDelay->depth;
  2703. pNewModDelay->mix = pOldModDelay->mix;
  2704. pNewModDelay->rmp_interp = pOldModDelay->rmp_interp;
  2705. pNewModDelay->bPhaseInvert = pOldModDelay->bPhaseInvert;
  2706. return pNewModDelay;
  2707. }
  2708. void MDY_Compare( const mdy_t & leftModDelay, const mdy_t & rightModDelay )
  2709. {
  2710. Assert ( &leftModDelay != &rightModDelay );
  2711. Assert( leftModDelay.fused == rightModDelay.fused );
  2712. Assert( leftModDelay.fchanging == rightModDelay.fchanging );
  2713. if ( CheckPointers( leftModDelay.pdly, rightModDelay.pdly ) )
  2714. {
  2715. DLY_Compare( *leftModDelay.pdly, *rightModDelay.pdly );
  2716. }
  2717. Assert( leftModDelay.ramptime == rightModDelay.ramptime );
  2718. Assert( leftModDelay.mtime == rightModDelay.mtime );
  2719. Assert( leftModDelay.mtimecur == rightModDelay.mtimecur );
  2720. Assert( leftModDelay.depth == rightModDelay.depth );
  2721. Assert( leftModDelay.mix == rightModDelay.mix );
  2722. RMP_Compare( leftModDelay.rmp_interp, rightModDelay.rmp_interp );
  2723. Assert( leftModDelay.bPhaseInvert == rightModDelay.bPhaseInvert );
  2724. }
  2725. #endif
  2726. // change to new delay tap value t samples, ramp linearly over ramptime seconds
  2727. void MDY_ChangeVal ( mdy_t *pmdy, int t )
  2728. {
  2729. // if D > original delay value, cap at original value
  2730. t = MIN (pmdy->pdly->D0, t);
  2731. pmdy->fchanging = true;
  2732. // init interpolation ramp - always hit target
  2733. RMP_Init ( &pmdy->rmp_interp, pmdy->ramptime, 0, PMAX, false );
  2734. // init delay xfade values
  2735. pmdy->pdly->tnew = t;
  2736. pmdy->pdly->xf = 0;
  2737. }
  2738. // interpolate between current and target delay values
  2739. inline int MDY_GetNext( mdy_t *pmdy, int x )
  2740. {
  2741. int xout;
  2742. if ( !pmdy->fchanging )
  2743. {
  2744. // not modulating...
  2745. xout = DLY_GetNext( pmdy->pdly, x );
  2746. if ( !pmdy->mtime )
  2747. {
  2748. // return right away if not modulating (not changing and not self modulating)
  2749. goto mdy_return;
  2750. }
  2751. }
  2752. else
  2753. {
  2754. // modulating...
  2755. xout = DLY_GetNextXfade( pmdy->pdly, x );
  2756. // get xfade ramp & set up delay xfade value for next call to DLY_GetNextXfade()
  2757. pmdy->pdly->xf = RMP_GetNext( &pmdy->rmp_interp ); // 0...PMAX
  2758. if ( RMP_HitEnd( &pmdy->rmp_interp ) )
  2759. {
  2760. // done. set delay tap & value = target
  2761. DLY_ChangeVal( pmdy->pdly, pmdy->pdly->tnew );
  2762. pmdy->pdly->t = pmdy->pdly->tnew;
  2763. pmdy->fchanging = false;
  2764. }
  2765. }
  2766. // if self-modulating and timer has expired, get next change
  2767. if ( pmdy->mtime && !pmdy->mtimecur-- )
  2768. {
  2769. pmdy->mtimecur = pmdy->mtime;
  2770. int D0 = pmdy->pdly->D0;
  2771. int Dnew;
  2772. float D1;
  2773. // modulate between 0 and 100% of d0
  2774. D1 = (float)D0 * (1.0 - pmdy->depth);
  2775. Dnew = LocalRandomInt( (int)D1, D0 );
  2776. // set up modulation to new value
  2777. MDY_ChangeVal ( pmdy, Dnew );
  2778. }
  2779. mdy_return:
  2780. // reverse phase of output
  2781. if ( pmdy->bPhaseInvert )
  2782. xout = -xout;
  2783. // 100% fx mix
  2784. if ( pmdy->mix == PMAX)
  2785. return xout;
  2786. // special case 50/50 mix
  2787. if ( pmdy->mix == PMAX / 2)
  2788. return ( (xout + x) >> 1 );
  2789. // return mix of input and processed signal
  2790. return ( x + (((xout - x) * pmdy->mix) >> PBITS) );
  2791. }
  2792. // batch version for performance
  2793. // UNDONE: unwind MDY_GetNext so that it directly calls DLY_GetNextN:
  2794. // UNDONE: a) if not currently modulating and never self-modulating, then just unwind like DLY_GetNext
  2795. // UNDONE: b) if not currently modulating, figure out how many samples N until self-modulation timer kicks in again
  2796. // and stream out N samples just like DLY_GetNext
  2797. inline void MDY_GetNextN( mdy_t *pmdy, portable_samplepair_t *pbuffer, int SampleCount, int op )
  2798. {
  2799. int count = SampleCount;
  2800. portable_samplepair_t *pb = pbuffer;
  2801. switch (op)
  2802. {
  2803. default:
  2804. case OP_LEFT:
  2805. while (count--)
  2806. {
  2807. pb->left = MDY_GetNext( pmdy, pb->left );
  2808. pb++;
  2809. }
  2810. return;
  2811. case OP_RIGHT:
  2812. while (count--)
  2813. {
  2814. pb->right = MDY_GetNext( pmdy, pb->right );
  2815. pb++;
  2816. }
  2817. return;
  2818. case OP_LEFT_DUPLICATE:
  2819. while (count--)
  2820. {
  2821. pb->left = pb->right = MDY_GetNext( pmdy, pb->left );
  2822. pb++;
  2823. }
  2824. return;
  2825. }
  2826. }
  2827. // parameter order
  2828. typedef enum {
  2829. mdy_idtype, // NOTE: first 8 params must match params in dly_e
  2830. mdy_idelay,
  2831. mdy_ifeedback,
  2832. mdy_igain,
  2833. mdy_iftype,
  2834. mdy_icutoff,
  2835. mdy_iqwidth,
  2836. mdy_iquality,
  2837. mdy_imodrate,
  2838. mdy_imoddepth,
  2839. mdy_imodglide,
  2840. mdy_imix,
  2841. mdy_ibxfade,
  2842. mdy_cparam
  2843. } mdy_e;
  2844. // parameter ranges
  2845. prm_rng_t mdy_rng[] = {
  2846. {mdy_cparam, 0, 0}, // first entry is # of parameters
  2847. // delay params
  2848. {mdy_idtype, 0, DLY_MAX}, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  2849. {mdy_idelay, 0.0, 1000.0}, // delay in milliseconds
  2850. {mdy_ifeedback, 0.0, 0.99}, // feedback 0-1.0
  2851. {mdy_igain, 0.0, 1.0}, // final gain of output stage, 0-1.0
  2852. // filter params if mdy type DLY_LOWPASS
  2853. {mdy_iftype, 0, FTR_MAX},
  2854. {mdy_icutoff, 10.0, 22050.0},
  2855. {mdy_iqwidth, 100.0, 11025.0},
  2856. {mdy_iquality, 0, QUA_MAX},
  2857. {mdy_imodrate, 0.01, 200.0}, // frequency at which delay values change to new random value. 0 is no self-modulation
  2858. {mdy_imoddepth, 0.0, 1.0}, // how much delay changes (decreases) from current value (0-1.0)
  2859. {mdy_imodglide, 0.01, 100.0}, // glide time between dcur and dnew in milliseconds
  2860. {mdy_imix, 0.0, 1.0} // 1.0 = full fx mix, 0.5 = 50% fx, 50% dry
  2861. };
  2862. // convert user parameters to internal parameters, allocate and return
  2863. mdy_t * MDY_Params ( prc_t *pprc )
  2864. {
  2865. mdy_t *pmdy;
  2866. dly_t *pdly;
  2867. float ramptime = pprc->prm[mdy_imodglide] / 1000.0; // get ramp time in seconds
  2868. float modtime = 0.0f;
  2869. if ( pprc->prm[mdy_imodrate] != 0.0f )
  2870. {
  2871. modtime = 1.0 / pprc->prm[mdy_imodrate]; // time between modulations in seconds
  2872. }
  2873. float depth = pprc->prm[mdy_imoddepth]; // depth of modulations 0-1.0
  2874. float mix = pprc->prm[mdy_imix];
  2875. // alloc plain, allpass or lowpass delay
  2876. pdly = DLY_Params( pprc );
  2877. if ( !pdly )
  2878. return NULL;
  2879. pmdy = MDY_Alloc ( pdly, ramptime, modtime, depth, mix );
  2880. return pmdy;
  2881. }
  2882. inline void * MDY_VParams ( void *p )
  2883. {
  2884. PRC_CheckParams ( (prc_t *)p, mdy_rng );
  2885. return (void *) MDY_Params ((prc_t *)p);
  2886. }
  2887. // v is +/- 0-1.0
  2888. // change current delay value 0..D
  2889. void MDY_Mod ( mdy_t *pmdy, float v )
  2890. {
  2891. int D0 = pmdy->pdly->D0; // base delay value
  2892. float v2;
  2893. // if v is < -2.0 then delay is v + 10.0
  2894. // invert phase of output. hack.
  2895. if ( v < -2.0 )
  2896. {
  2897. v = v + 10.0;
  2898. pmdy->bPhaseInvert = true;
  2899. }
  2900. else
  2901. {
  2902. pmdy->bPhaseInvert = false;
  2903. }
  2904. v2 = -(v + 1.0)/2.0; // v2 varies -1.0-0.0
  2905. // D0 varies 0..D0
  2906. D0 = D0 + (int)((float)D0 * v2);
  2907. // change delay
  2908. MDY_ChangeVal( pmdy, D0 );
  2909. return;
  2910. }
  2911. ///////////////////
  2912. // Parallel reverbs
  2913. ///////////////////
  2914. // Reverb A
  2915. // M parallel reverbs, mixed to mono output
  2916. #if CHECK_VALUES_AFTER_REFACTORING
  2917. #define CRVAS 128
  2918. #else
  2919. #define CRVAS 64 // max number of parallel series reverbs active
  2920. #endif
  2921. #define CRVA_DLYS 12 // max number of delays making up reverb_a
  2922. struct rva_t
  2923. {
  2924. bool fused;
  2925. int m; // number of parallel plain or lowpass delays
  2926. int fparallel; // true if filters in parallel with delays, otherwise single output filter
  2927. flt_t *pflt; // series filters
  2928. dly_t *pdlys[CRVA_DLYS]; // array of pointers to delays
  2929. mdy_t *pmdlys[CRVA_DLYS]; // array of pointers to mod delays
  2930. bool fmoddly; // true if using mod delays
  2931. };
  2932. rva_t rvas[CRVAS];
  2933. void RVA_Init ( rva_t *prva ) { if ( prva ) Q_memset (prva, 0, sizeof (rva_t)); }
  2934. void RVA_InitAll( void ) { for (int i = 0; i < CRVAS; i++) RVA_Init ( &rvas[i] ); }
  2935. // free parallel series reverb
  2936. void RVA_Free( rva_t *prva )
  2937. {
  2938. int i;
  2939. if ( prva )
  2940. {
  2941. // free all delays
  2942. for (i = 0; i < CRVA_DLYS; i++)
  2943. DLY_Free ( prva->pdlys[i] );
  2944. // zero all ptrs to delays in mdy array
  2945. for (i = 0; i < CRVA_DLYS; i++)
  2946. {
  2947. if ( prva->pmdlys[i] )
  2948. prva->pmdlys[i]->pdly = NULL;
  2949. }
  2950. // free all mod delays
  2951. for (i = 0; i < CRVA_DLYS; i++)
  2952. MDY_Free ( prva->pmdlys[i] );
  2953. FLT_Free( prva->pflt );
  2954. Q_memset( prva, 0, sizeof (rva_t) );
  2955. }
  2956. }
  2957. void RVA_FreeAll( void ) { for (int i = 0; i < CRVAS; i++) RVA_Free( &rvas[i] ); }
  2958. // create parallel reverb - m parallel reverbs summed
  2959. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  2960. // a array of reverb feedback parms for parallel reverbs (CRVB_P_DLYS)
  2961. // if a[i] < 0 then this is a predelay - use DLY_FLINEAR instead of DLY_LOWPASS
  2962. // b array of CRVB_P_DLYS - mix params for parallel reverbs
  2963. // m - number of parallel delays
  2964. // pflt - filter template, to be used by all parallel delays
  2965. // fparallel - true if filter operates in parallel with delays, otherwise filter output only
  2966. // fmoddly - > 0 if delays are all mod delays (milliseconds of delay modulation)
  2967. // fmodrate - # of delay repetitions between changes to mod delay
  2968. // ftaps - if > 0, use 4 taps per reverb delay unit (increases density) tap = D - n*ftaps n = 0,1,2,3
  2969. rva_t * RVA_Alloc ( int *D, int *a, int *b, int m, flt_t *pflt, int fparallel, float fmoddly, float fmodrate, float ftaps )
  2970. {
  2971. int i;
  2972. int dtype;
  2973. rva_t *prva;
  2974. flt_t *pflt2 = NULL;
  2975. bool btaps = ftaps > 0.0;
  2976. // find open slot
  2977. for ( i = 0; i < CRVAS; i++ )
  2978. {
  2979. if ( !rvas[i].fused )
  2980. break;
  2981. }
  2982. // return null if no free slots
  2983. if (i == CRVAS)
  2984. {
  2985. DevMsg ("DSP: Warning, failed to allocate reverb.\n" );
  2986. return NULL;
  2987. }
  2988. prva = &rvas[i];
  2989. // if series filter specified, alloc two series filters
  2990. if ( pflt && !fparallel)
  2991. {
  2992. // use filter data as template for a filter on output (2 cascaded filters)
  2993. pflt2 = FLT_Alloc (0, pflt->M, pflt->L, pflt->a, pflt->b, 1.0);
  2994. if (!pflt2)
  2995. {
  2996. DevMsg ("DSP: Warning, failed to allocate flt for reverb.\n" );
  2997. return NULL;
  2998. }
  2999. pflt2->pf1 = FLT_Alloc (0, pflt->M, pflt->L, pflt->a, pflt->b, 1.0);
  3000. pflt2->N = 1;
  3001. }
  3002. // allocate parallel delays
  3003. for (i = 0; i < m; i++)
  3004. {
  3005. // set delay type
  3006. if ( pflt && fparallel )
  3007. // if a[i] param is < 0, allocate delay as predelay instead of feedback delay
  3008. dtype = a[i] < 0 ? DLY_FLINEAR : DLY_LOWPASS;
  3009. else
  3010. // if no filter specified, alloc as plain or multitap plain delay
  3011. dtype = btaps ? DLY_PLAIN_4TAP : DLY_PLAIN;
  3012. if ( dtype == DLY_LOWPASS && btaps )
  3013. dtype = DLY_LOWPASS_4TAP;
  3014. // if filter specified and parallel specified, alloc 1 filter per delay
  3015. if ( DLY_HAS_FILTER(dtype) )
  3016. prva->pdlys[i] = DLY_AllocLP( D[i], abs(a[i]), b[i], dtype, pflt->M, pflt->L, pflt->a, pflt->b );
  3017. else
  3018. prva->pdlys[i] = DLY_Alloc( D[i], abs(a[i]), b[i], dtype );
  3019. if ( DLY_HAS_MULTITAP(dtype) )
  3020. {
  3021. // set up delay taps to increase density around delay value.
  3022. // value of ftaps is the seed for all tap values
  3023. float t1 = MAX(MSEC_TO_SAMPS(5), D[i] * (1.0 - ftaps * 3.141592) );
  3024. float t2 = MAX(MSEC_TO_SAMPS(7), D[i] * (1.0 - ftaps * 1.697043) );
  3025. float t3 = MAX(MSEC_TO_SAMPS(10), D[i] * (1.0 - ftaps * 0.96325) );
  3026. DLY_ChangeTaps( prva->pdlys[i], (int)t1, (int)t2, (int)t3, D[i] );
  3027. }
  3028. }
  3029. if ( fmoddly > 0.0 )
  3030. {
  3031. // alloc mod delays, using previously alloc'd delays
  3032. // ramptime is time in seconds for delay to change from dcur to dnew
  3033. // modtime is time in seconds between modulations. 0 if no self-modulation
  3034. // depth is 0-1.0 multiplier, new delay values when modulating are Dnew = randomlong (D - D*depth, D)
  3035. float ramptime;
  3036. float modtime;
  3037. float depth;
  3038. for (i = 0; i < m; i++)
  3039. {
  3040. int D = prva->pdlys[i]->D;
  3041. modtime = (float)D / (float)(SOUND_DMA_SPEED); // seconds per delay
  3042. depth = (fmoddly / 1000.0) / modtime; // convert milliseconds to 'depth' %
  3043. depth = clamp (depth, 0.01, 0.99);
  3044. modtime = modtime * fmodrate; // modulate every N delay passes
  3045. ramptime = fpmin(20.0f/1000.0f, modtime / 2); // ramp between delay values in N ms
  3046. prva->pmdlys[i] = MDY_Alloc( prva->pdlys[i], ramptime, modtime, depth, 1.0 );
  3047. }
  3048. prva->fmoddly = true;
  3049. }
  3050. // if we failed to alloc any reverb, free all, return NULL
  3051. for (i = 0; i < m; i++)
  3052. {
  3053. if ( !prva->pdlys[i] )
  3054. {
  3055. FLT_Free( pflt2 );
  3056. RVA_Free( prva );
  3057. DevMsg ("DSP: Warning, failed to allocate delay for reverb.\n" );
  3058. return NULL;
  3059. }
  3060. }
  3061. prva->fused = true;
  3062. prva->m = m;
  3063. prva->fparallel = fparallel;
  3064. prva->pflt = pflt2;
  3065. return prva;
  3066. }
  3067. void RVA_Print( const rva_t & rva, int nIndentation )
  3068. {
  3069. const char * pIndent = GetIndentationText( nIndentation );
  3070. DevMsg( "%sRVA: %p [Addr]\n", pIndent, &rva );
  3071. DevMsg( "%sfused: %d\n", pIndent, ( int ) rva.fused );
  3072. DevMsg( "%sm: %d\n", pIndent, rva.m );
  3073. DevMsg( "%sfparallel: %d\n", pIndent, rva.fparallel );
  3074. DevMsg( "%sFilter:", pIndent );
  3075. if ( rva.pflt != NULL )
  3076. {
  3077. FLT_Print( *rva.pflt, nIndentation + 1 );
  3078. }
  3079. else
  3080. {
  3081. DevMsg( "NULL\n" );
  3082. }
  3083. for ( int i = 0 ; i < CRVA_DLYS ; ++i )
  3084. {
  3085. DevMsg( "%sDelay[%d]: ", pIndent, i );
  3086. if ( rva.pdlys[i] != NULL )
  3087. {
  3088. DLY_Print( *rva.pdlys[i], nIndentation + 1 );
  3089. }
  3090. else
  3091. {
  3092. DevMsg( "NULL\n" );
  3093. }
  3094. }
  3095. for ( int i = 0 ; i < CRVA_DLYS ; ++i )
  3096. {
  3097. DevMsg( "%sModDelay[%d]: ", pIndent, i );
  3098. if ( rva.pmdlys[i] != NULL )
  3099. {
  3100. MDY_Print( *rva.pmdlys[i], nIndentation + 1 );
  3101. }
  3102. else
  3103. {
  3104. DevMsg( "NULL\n" );
  3105. }
  3106. }
  3107. DevMsg( "%sfmoddly: %d\n", pIndent, rva.fmoddly );
  3108. }
  3109. #if CHECK_VALUES_AFTER_REFACTORING
  3110. rva_t * RVA_Clone( rva_t * pOldRva )
  3111. {
  3112. int i;
  3113. for ( i = 0; i < CRVAS; i++ )
  3114. {
  3115. if ( !rvas[i].fused )
  3116. break;
  3117. }
  3118. // return null if no free slots
  3119. if (i == CRVAS)
  3120. {
  3121. DevMsg ("DSP: Warning, failed to allocate reverb.\n" );
  3122. return NULL;
  3123. }
  3124. rva_t * pNewRva = &rvas[i];
  3125. memcpy(pNewRva, pOldRva, sizeof(rva_t));
  3126. pNewRva->pflt = FLT_Clone(pOldRva->pflt);
  3127. for ( int j = 0 ; j < CRVA_DLYS ; ++j )
  3128. {
  3129. // First we do MDYs. In some cases, MDYs can point to DLY that can be stored in the pdlys array
  3130. // In that case instead of cloning the DLY, we will just update the pointer.
  3131. if ( pOldRva->pmdlys[j] != NULL )
  3132. {
  3133. pNewRva->pmdlys[j] = MDY_Clone( pOldRva->pmdlys[j] );
  3134. if ( pOldRva->pmdlys[j]->pdly == pOldRva->pdlys[j] )
  3135. {
  3136. // Update the pointer instead of cloning it
  3137. pNewRva->pdlys[j] = pNewRva->pmdlys[j]->pdly;
  3138. continue; // Don't clone afterward
  3139. }
  3140. }
  3141. if ( pOldRva->pdlys[j] != NULL )
  3142. {
  3143. pNewRva->pdlys[j] = DLY_Clone( pOldRva->pdlys[j] );
  3144. }
  3145. }
  3146. return pNewRva;
  3147. }
  3148. void RVA_Compare( const rva_t & leftRva, const rva_t & rightRva )
  3149. {
  3150. Assert ( &leftRva != &rightRva );
  3151. Assert( leftRva.fused == rightRva.fused );
  3152. Assert( leftRva.m == rightRva.m );
  3153. Assert( leftRva.fparallel == rightRva.fparallel );
  3154. if ( CheckPointers( leftRva.pflt, rightRva.pflt ) )
  3155. {
  3156. FLT_Compare( *leftRva.pflt, *rightRva.pflt );
  3157. }
  3158. for ( int i = 0 ; i < CRVA_DLYS ; ++i )
  3159. {
  3160. if ( CheckPointers( leftRva.pdlys[i], rightRva.pdlys[i] ) )
  3161. {
  3162. DLY_Compare( *leftRva.pdlys[i], *rightRva.pdlys[i] );
  3163. }
  3164. }
  3165. for ( int i = 0 ; i < CRVA_DLYS ; ++i )
  3166. {
  3167. if ( CheckPointers( leftRva.pmdlys[i], rightRva.pmdlys[i] ) )
  3168. {
  3169. MDY_Compare( *leftRva.pmdlys[i], *rightRva.pmdlys[i] );
  3170. }
  3171. }
  3172. Assert( leftRva.fmoddly == rightRva.fmoddly );
  3173. }
  3174. #endif
  3175. // parallel reverberator
  3176. //
  3177. // for each input sample x do:
  3178. // x0 = plain(D0,w0,&p0,a0,x)
  3179. // x1 = plain(D1,w1,&p1,a1,x)
  3180. // x2 = plain(D2,w2,&p2,a2,x)
  3181. // x3 = plain(D3,w3,&p3,a3,x)
  3182. // y = b0*x0 + b1*x1 + b2*x2 + b3*x3
  3183. //
  3184. // rgdly - array of M delays:
  3185. // D - Delay values (typical - 29, 37, 44, 50, 27, 31)
  3186. // w - array of delayed values
  3187. // p - array of pointers to circular delay line pointers
  3188. // a - array of M feedback values (typical - all equal, like 0.75 * PMAX)
  3189. // b - array of M gain values for plain reverb outputs (1, .9, .8, .7)
  3190. // xin - input value
  3191. // if fparallel, filters are built into delays,
  3192. // otherwise, filter is in feedback loop
  3193. int g_MapIntoPBITSDivInt[] =
  3194. {
  3195. 0, PMAX/1, PMAX/2, PMAX/3, PMAX/4, PMAX/5, PMAX/6, PMAX/7, PMAX/8,
  3196. PMAX/9, PMAX/10, PMAX/11,PMAX/12,PMAX/13,PMAX/14,PMAX/15,PMAX/16,
  3197. };
  3198. inline int RVA_GetNext( rva_t *prva, int x )
  3199. {
  3200. int m = prva->m;
  3201. int y = 0;
  3202. if ( prva->fmoddly )
  3203. {
  3204. // get output of parallel mod delays
  3205. for (int i = 0; i < m; i++ )
  3206. y += MDY_GetNext( prva->pmdlys[i], x );
  3207. }
  3208. else
  3209. {
  3210. // get output of parallel delays
  3211. for (int i = 0; i < m; i++ )
  3212. y += DLY_GetNext( prva->pdlys[i], x );
  3213. }
  3214. // PERFORMANCE: y/m is now baked into the 'b' gain params for each delay ( b = b/m )
  3215. // y = (y * g_MapIntoPBITSDivInt[m]) >> PBITS;
  3216. if ( prva->fparallel )
  3217. return y;
  3218. // run series filters if present
  3219. if ( prva->pflt )
  3220. {
  3221. y = FLT_GetNext( prva->pflt, y);
  3222. }
  3223. return y;
  3224. }
  3225. template <int READER, int WRITER>
  3226. inline void RVA_GetNext_Opt( rva_t *pRva, portable_samplepair_t * pBuffer, int nCount )
  3227. {
  3228. int m = pRva->m;
  3229. // Because we do one filter at a time (and not one sample at a time)
  3230. // We either have to copy the input on an intermediate buffer, or write the output to an intermediate buffer.
  3231. // The faster is to use an intermediate output buffer as we can quickly zero it (it is slower to copy the input).
  3232. // Unlike the samples, the buffers here are actually short (so we use less memory - less L2 cache misses).
  3233. int nSizeToUse = sizeof(LocalOutputSample_t) * nCount;
  3234. int nSizeToAllocate = ALIGN_VALUE( nSizeToUse, CACHE_LINE_SIZE ); // Align on 128 as we are going to clear per cache-line
  3235. LocalOutputSample_t * pOutputSample = (LocalOutputSample_t *)alloca( nSizeToAllocate + CACHE_LINE_SIZE); // One more cache line as we are going to clear more than necessary...
  3236. pOutputSample = (LocalOutputSample_t *)ALIGN_VALUE( (intp) pOutputSample, CACHE_LINE_SIZE );
  3237. int nNumberOfCacheLinesToClear = ALIGN_VALUE( nSizeToAllocate, CACHE_LINE_SIZE ) / CACHE_LINE_SIZE;
  3238. LocalOutputSample_t * pCurrentCacheLine = pOutputSample;
  3239. // Given that we often have 500 to 1000 samples, it means that we are going to clear 2 to 4 Kb.
  3240. // (i.e. up to 32 cache lines). This will saturate the cache pipeline (but it easier to do it now instead of doing it within each filter).
  3241. while ( nNumberOfCacheLinesToClear > 0 )
  3242. {
  3243. PREZERO_128( pCurrentCacheLine, 0 );
  3244. pCurrentCacheLine += CACHE_LINE_SIZE / sizeof(LocalOutputSample_t);
  3245. --nNumberOfCacheLinesToClear;
  3246. }
  3247. // Then we are going to apply to the buffer each filter (one after the other for a set of samples)
  3248. // We are going to increase the number of loads and stores but at the end we can reduce the number of switches and unroll some calculation
  3249. int * pInputSample;
  3250. if ( READER == CHANNEL_LEFT )
  3251. {
  3252. pInputSample = &pBuffer->left;
  3253. }
  3254. else
  3255. {
  3256. Assert( READER == CHANNEL_RIGHT );
  3257. pInputSample = &pBuffer->right;
  3258. }
  3259. // At that point, each reader will have to skip one integer after reading one.
  3260. // Prefetch a bit (the next cache line) - again may continue saturate the buffer - but this will be read soon anyway.
  3261. PREFETCH_128( pInputSample, 128 );
  3262. if ( pRva->fmoddly )
  3263. {
  3264. // get output of parallel mod delays
  3265. for ( int i = 0; i < m; i++ )
  3266. {
  3267. mdy_t * pModDelay = pRva->pmdlys[i];
  3268. for ( int j = 0 ; j < nCount ; ++j )
  3269. {
  3270. int nSampleIn = pInputSample[j * 2]; // *2 because the input has both left AND right
  3271. int nSampleOut = MDY_GetNext( pModDelay, nSampleIn );
  3272. pOutputSample[j] += nSampleOut; // First operation could actually only write '=' instead of '+='
  3273. }
  3274. }
  3275. }
  3276. else
  3277. {
  3278. // get output of parallel delays
  3279. for ( int i = 0; i < m; i++ )
  3280. {
  3281. dly_t * pDelay = pRva->pdlys[i];
  3282. #if 0
  3283. for ( int j = 0 ; j < nCount ; ++j )
  3284. {
  3285. int nSampleIn = pInputSample[j * 2]; // *2 because the input has both left AND right
  3286. int nSampleOut = DLY_GetNext( pDelay, nSampleIn );
  3287. pOutputSample[j] += nSampleOut; // First operation could actually only write '=' instead of '+='
  3288. }
  3289. #else
  3290. DLY_GetNext_Opt( pDelay, pInputSample, pOutputSample, nCount );
  3291. #endif
  3292. }
  3293. }
  3294. // PERFORMANCE: y/m is now baked into the 'b' gain params for each delay ( b = b/m )
  3295. // y = (y * g_MapIntoPBITSDivInt[m]) >> PBITS;
  3296. if ( pRva->fparallel == false )
  3297. {
  3298. // run series filters if present
  3299. flt_t * pFilter = pRva->pflt;
  3300. if ( pFilter != NULL)
  3301. {
  3302. for ( int j = 0 ; j < nCount ; ++j )
  3303. {
  3304. // For this, we are actually using the sample from the output buffer
  3305. int nSampleIn = pOutputSample[j];
  3306. int nSampleOut = FLT_GetNext( pFilter, nSampleIn );
  3307. pOutputSample[j] = nSampleOut;
  3308. }
  3309. }
  3310. }
  3311. // At the end, we have to write back the final result to the buffer (from pOutputSample to pBuffer).
  3312. // Because we have to skip integers it is not a simple memcpy.
  3313. if ( WRITER == ( 1 << CHANNEL_LEFT ) )
  3314. {
  3315. portable_samplepair_t * RESTRICT pWriteBuffer = pBuffer;
  3316. LocalOutputSample_t * RESTRICT pReadBuffer = pOutputSample;
  3317. while ( nCount >= 16 )
  3318. {
  3319. pWriteBuffer[0].left = pReadBuffer[0];
  3320. pWriteBuffer[1].left = pReadBuffer[1];
  3321. pWriteBuffer[2].left = pReadBuffer[2];
  3322. pWriteBuffer[3].left = pReadBuffer[3];
  3323. pWriteBuffer[4].left = pReadBuffer[4];
  3324. pWriteBuffer[5].left = pReadBuffer[5];
  3325. pWriteBuffer[6].left = pReadBuffer[6];
  3326. pWriteBuffer[7].left = pReadBuffer[7];
  3327. pWriteBuffer[8].left = pReadBuffer[8];
  3328. pWriteBuffer[9].left = pReadBuffer[9];
  3329. pWriteBuffer[10].left = pReadBuffer[10];
  3330. pWriteBuffer[11].left = pReadBuffer[11];
  3331. pWriteBuffer[12].left = pReadBuffer[12];
  3332. pWriteBuffer[13].left = pReadBuffer[13];
  3333. pWriteBuffer[14].left = pReadBuffer[14];
  3334. pWriteBuffer[15].left = pReadBuffer[15];
  3335. nCount -= 16;
  3336. pWriteBuffer += 16;
  3337. pReadBuffer += 16;
  3338. }
  3339. while ( nCount >= 1 )
  3340. {
  3341. pWriteBuffer->left = *pReadBuffer;
  3342. --nCount;
  3343. ++pWriteBuffer;
  3344. ++pReadBuffer;
  3345. }
  3346. }
  3347. else if ( WRITER == ( 1 << CHANNEL_RIGHT) )
  3348. {
  3349. portable_samplepair_t * RESTRICT pWriteBuffer = pBuffer;
  3350. LocalOutputSample_t * RESTRICT pReadBuffer = pOutputSample;
  3351. while ( nCount >= 16 )
  3352. {
  3353. pWriteBuffer[0].right = pReadBuffer[0];
  3354. pWriteBuffer[1].right = pReadBuffer[1];
  3355. pWriteBuffer[2].right = pReadBuffer[2];
  3356. pWriteBuffer[3].right = pReadBuffer[3];
  3357. pWriteBuffer[4].right = pReadBuffer[4];
  3358. pWriteBuffer[5].right = pReadBuffer[5];
  3359. pWriteBuffer[6].right = pReadBuffer[6];
  3360. pWriteBuffer[7].right = pReadBuffer[7];
  3361. pWriteBuffer[8].right = pReadBuffer[8];
  3362. pWriteBuffer[9].right = pReadBuffer[9];
  3363. pWriteBuffer[10].right = pReadBuffer[10];
  3364. pWriteBuffer[11].right = pReadBuffer[11];
  3365. pWriteBuffer[12].right = pReadBuffer[12];
  3366. pWriteBuffer[13].right = pReadBuffer[13];
  3367. pWriteBuffer[14].right = pReadBuffer[14];
  3368. pWriteBuffer[15].right = pReadBuffer[15];
  3369. nCount -= 16;
  3370. pWriteBuffer += 16;
  3371. pReadBuffer += 16;
  3372. }
  3373. while ( nCount >= 1 )
  3374. {
  3375. pWriteBuffer->right = *pReadBuffer;
  3376. --nCount;
  3377. ++pWriteBuffer;
  3378. ++pReadBuffer;
  3379. }
  3380. }
  3381. else
  3382. {
  3383. Assert( WRITER == ( ( 1 << CHANNEL_LEFT ) | ( 1 << CHANNEL_RIGHT ) ) );
  3384. portable_samplepair_t * RESTRICT pWriteBuffer = pBuffer;
  3385. LocalOutputSample_t * RESTRICT pReadBuffer = pOutputSample;
  3386. // Because we are writing left and write in this version, we could potentially use VMX operations
  3387. // Read 8 samples at a time (2 bytes * 8), sign extend them on 4 VMX registers and write them.
  3388. while ( nCount >= 16 )
  3389. {
  3390. pWriteBuffer[0].left = pWriteBuffer[0].right = pReadBuffer[0];
  3391. pWriteBuffer[1].left = pWriteBuffer[1].right = pReadBuffer[1];
  3392. pWriteBuffer[2].left = pWriteBuffer[2].right = pReadBuffer[2];
  3393. pWriteBuffer[3].left = pWriteBuffer[3].right = pReadBuffer[3];
  3394. pWriteBuffer[4].left = pWriteBuffer[4].right = pReadBuffer[4];
  3395. pWriteBuffer[5].left = pWriteBuffer[5].right = pReadBuffer[5];
  3396. pWriteBuffer[6].left = pWriteBuffer[6].right = pReadBuffer[6];
  3397. pWriteBuffer[7].left = pWriteBuffer[7].right = pReadBuffer[7];
  3398. pWriteBuffer[8].left = pWriteBuffer[8].right = pReadBuffer[8];
  3399. pWriteBuffer[9].left = pWriteBuffer[9].right = pReadBuffer[9];
  3400. pWriteBuffer[10].left = pWriteBuffer[10].right = pReadBuffer[10];
  3401. pWriteBuffer[11].left = pWriteBuffer[11].right = pReadBuffer[11];
  3402. pWriteBuffer[12].left = pWriteBuffer[12].right = pReadBuffer[12];
  3403. pWriteBuffer[13].left = pWriteBuffer[13].right = pReadBuffer[13];
  3404. pWriteBuffer[14].left = pWriteBuffer[14].right = pReadBuffer[14];
  3405. pWriteBuffer[15].left = pWriteBuffer[15].right = pReadBuffer[15];
  3406. nCount -= 16;
  3407. pWriteBuffer += 16;
  3408. pReadBuffer += 16;
  3409. }
  3410. while ( nCount >= 1 )
  3411. {
  3412. pWriteBuffer->left = pWriteBuffer->right = *pReadBuffer;
  3413. --nCount;
  3414. ++pWriteBuffer;
  3415. ++pReadBuffer;
  3416. }
  3417. }
  3418. }
  3419. // batch version for performance
  3420. // UNDONE: unwind RVA_GetNextN so that it directly calls DLY_GetNextN or MDY_GetNextN
  3421. inline void RVA_GetNextN( rva_t *prva, 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 = RVA_GetNext( prva, pb->left );
  3432. pb++;
  3433. }
  3434. return;
  3435. case OP_RIGHT:
  3436. while (count--)
  3437. {
  3438. pb->right = RVA_GetNext( prva, pb->right );
  3439. pb++;
  3440. }
  3441. return;
  3442. case OP_LEFT_DUPLICATE:
  3443. while (count--)
  3444. {
  3445. pb->left = pb->right = RVA_GetNext( prva, pb->left );
  3446. pb++;
  3447. }
  3448. return;
  3449. }
  3450. }
  3451. #if CHECK_VALUES_AFTER_REFACTORING
  3452. inline void RVA_GetNextN2( rva_t *pRva1, portable_samplepair_t *pbuffer1, rva_t *pRva2, portable_samplepair_t *pbuffer2, int SampleCount, int op )
  3453. {
  3454. int count = SampleCount;
  3455. portable_samplepair_t *pb1 = pbuffer1;
  3456. portable_samplepair_t *pb2 = pbuffer2;
  3457. switch (op)
  3458. {
  3459. default:
  3460. case OP_LEFT:
  3461. while (count--)
  3462. {
  3463. pb1->left = RVA_GetNext( pRva1, pb1->left );
  3464. pb2->left = RVA_GetNext( pRva2, pb2->left );
  3465. RVA_Compare( *pRva1, *pRva2 );
  3466. pb1++;
  3467. pb2++;
  3468. }
  3469. return;
  3470. case OP_RIGHT:
  3471. while (count--)
  3472. {
  3473. pb1->right = RVA_GetNext( pRva1, pb1->right );
  3474. pb2->right = RVA_GetNext( pRva2, pb2->right );
  3475. RVA_Compare( *pRva1, *pRva2 );
  3476. pb1++;
  3477. pb2++;
  3478. }
  3479. return;
  3480. case OP_LEFT_DUPLICATE:
  3481. while (count--)
  3482. {
  3483. pb1->left = pb1->right = RVA_GetNext( pRva1, pb1->left );
  3484. pb2->left = pb2->right = RVA_GetNext( pRva2, pb2->left );
  3485. RVA_Compare( *pRva1, *pRva2 );
  3486. pb1++;
  3487. pb2++;
  3488. }
  3489. return;
  3490. }
  3491. }
  3492. void CheckCloneAccuracy( rva_t *prva, portable_samplepair_t *pbuffer, int nSampleCount, int op )
  3493. {
  3494. // Try not to modify the original values so the sound is kept pristine even with this test
  3495. portable_samplepair_t * pTempBuffer1 = DuplicateSamplePairs( pbuffer, nSampleCount );
  3496. rva_t * pTempRva1 = RVA_Clone(prva);
  3497. RVA_Compare( *prva, *pTempRva1 );
  3498. portable_samplepair_t * pTempBuffer2 = DuplicateSamplePairs( pbuffer, nSampleCount );
  3499. rva_t * pTempRva2 = RVA_Clone(prva);
  3500. RVA_Compare( *prva, *pTempRva2 );
  3501. portable_samplepair_t * pTempBuffer3 = DuplicateSamplePairs( pbuffer, nSampleCount );
  3502. rva_t * pTempRva3 = RVA_Clone(prva);
  3503. RVA_Compare( *prva, *pTempRva3 );
  3504. // If we clone correctly, we should have the same output on the two buffers.
  3505. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  3506. RVA_GetNextN( pTempRva1, pTempBuffer1, nSampleCount, op );
  3507. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  3508. RVA_GetNextN( pTempRva2, pTempBuffer2, nSampleCount, op );
  3509. RVA_Compare( *pTempRva1, *pTempRva2 );
  3510. bool bFailed = ( memcmp( pTempBuffer1, pTempBuffer2, nSampleCount * sizeof( portable_samplepair_t ) ) != 0 );
  3511. if ( bFailed )
  3512. {
  3513. Warning("[Sound] Detected desynchronization during RVA cloning.\n");
  3514. // Normally the content should be the same, only the addresses (tagged [Addr]) should be different.
  3515. // No address should be the same (if that were the case, it would mean we missed something during the cloning).
  3516. DevMsg( "\n\nCloned RVA 1:\n\n" );
  3517. RVA_Print( *pTempRva1, 0 );
  3518. DevMsg( "\n\nCloned RVA 2:\n\n" );
  3519. RVA_Print( *pTempRva2, 0 );
  3520. // After that, let's try to re-clone again and display the values before any modification.
  3521. FreeDuplicatedSamplePairs( pTempBuffer1, nSampleCount );
  3522. RVA_Free(pTempRva1);
  3523. FreeDuplicatedSamplePairs( pTempBuffer2, nSampleCount );
  3524. RVA_Free(pTempRva2);
  3525. pTempBuffer1 = DuplicateSamplePairs( pbuffer, nSampleCount );
  3526. pTempRva1 = RVA_Clone(prva);
  3527. RVA_Compare( *prva, *pTempRva1 );
  3528. pTempBuffer2 = DuplicateSamplePairs( pbuffer, nSampleCount );
  3529. pTempRva2 = RVA_Clone(prva);
  3530. RVA_Compare( *prva, *pTempRva2 );
  3531. DevMsg( "\n\nInitial RVA:\n\n" );
  3532. RVA_Print( *prva, 0 );
  3533. DevMsg( "\n\nCloned RVA 1:\n\n" );
  3534. RVA_Print( *pTempRva1, 0 );
  3535. DevMsg( "\n\nCloned RVA 2:\n\n" );
  3536. RVA_Print( *pTempRva2, 0 );
  3537. // Re-run the transform so we can compare with the official result
  3538. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  3539. RVA_GetNextN( pTempRva1, pTempBuffer1, nSampleCount, op );
  3540. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  3541. RVA_GetNextN( pTempRva2, pTempBuffer2, nSampleCount, op );
  3542. RVA_Compare( *pTempRva1, *pTempRva2 );
  3543. }
  3544. // This will break the input buffer content, if this test is executed the sound will be off (esp. for reverberations and delays)
  3545. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  3546. #if 0
  3547. // Use this method so it will compare sample by sample (help track more complex desyncs, but will slow the game down by a ton
  3548. RVA_GetNextN2( prva, pbuffer, pTempRva3, pTempBuffer3, nSampleCount, op );
  3549. #else
  3550. RVA_GetNextN( prva, pbuffer, nSampleCount, op );
  3551. #endif
  3552. RVA_Compare( *prva, *pTempRva1 );
  3553. bFailed = ( memcmp( pTempBuffer1, pbuffer, nSampleCount * sizeof( portable_samplepair_t ) ) != 0 );
  3554. if ( bFailed )
  3555. {
  3556. Warning("[Sound] Detected desynchronization during RVA cloning.\n");
  3557. // Normally the content should be the same, only the addresses (tagged [Addr]) should be different.
  3558. // No address should be the same (if that were the case, it would mean that we missed something during the cloning).
  3559. DevMsg( "\n\nInitial RVA:\n\n" );
  3560. RVA_Print( *prva, 0 );
  3561. DevMsg( "\n\nCloned RVA:\n\n" );
  3562. RVA_Print( *pTempRva1, 0 );
  3563. // Re-clone here to help detect the issue (before any modification)
  3564. portable_samplepair_t * pTempBuffer4 = DuplicateSamplePairs( pbuffer, nSampleCount );
  3565. rva_t * pTempRva4 = RVA_Clone(prva);
  3566. DevMsg( "\n\nNew clone RVA:\n\n" );
  3567. RVA_Print( *pTempRva4, 0 );
  3568. FreeDuplicatedSamplePairs( pTempBuffer4, nSampleCount );
  3569. RVA_Free(pTempRva4);
  3570. }
  3571. FreeDuplicatedSamplePairs( pTempBuffer1, nSampleCount );
  3572. RVA_Free(pTempRva1);
  3573. FreeDuplicatedSamplePairs( pTempBuffer2, nSampleCount );
  3574. RVA_Free(pTempRva2);
  3575. FreeDuplicatedSamplePairs( pTempBuffer3, nSampleCount );
  3576. RVA_Free(pTempRva3);
  3577. }
  3578. #endif
  3579. inline void RVA_GetNextN_Opt( rva_t *prva, portable_samplepair_t *pbuffer, int nSampleCount, int op )
  3580. {
  3581. #if CHECK_VALUES_AFTER_REFACTORING
  3582. // Duplicate the values before the original buffer is going to be modified in CheckCloneAccuracy()
  3583. portable_samplepair_t * pTempBuffer = DuplicateSamplePairs( pbuffer, nSampleCount );
  3584. rva_t * pTempRva = RVA_Clone( prva );
  3585. RVA_Compare( *prva, *pTempRva );
  3586. CheckCloneAccuracy( prva, pbuffer, nSampleCount, op );
  3587. int count = nSampleCount;
  3588. portable_samplepair_t *pb = pTempBuffer;
  3589. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  3590. switch (op)
  3591. {
  3592. default:
  3593. case OP_LEFT:
  3594. RVA_GetNext_Opt<CHANNEL_LEFT, 1 << CHANNEL_LEFT>( pTempRva, pb, count );
  3595. break;
  3596. case OP_RIGHT:
  3597. RVA_GetNext_Opt<CHANNEL_RIGHT, 1 << CHANNEL_RIGHT>( pTempRva, pb, count );
  3598. break;
  3599. case OP_LEFT_DUPLICATE:
  3600. RVA_GetNext_Opt<CHANNEL_LEFT, (1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT)>( pTempRva, pb, count );
  3601. break;
  3602. }
  3603. RVA_Compare( *prva, *pTempRva );
  3604. bool bFailed = ( memcmp( pTempBuffer, pbuffer, nSampleCount * sizeof( portable_samplepair_t ) ) != 0 );
  3605. Assert( bFailed == false );
  3606. FreeDuplicatedSamplePairs( pTempBuffer, nSampleCount );
  3607. RVA_Free(pTempRva);
  3608. #else
  3609. if ( snd_dsp_optimization.GetBool() )
  3610. {
  3611. switch (op)
  3612. {
  3613. default:
  3614. case OP_LEFT:
  3615. RVA_GetNext_Opt<CHANNEL_LEFT, 1 << CHANNEL_LEFT>( prva, pbuffer, nSampleCount );
  3616. break;
  3617. case OP_RIGHT:
  3618. RVA_GetNext_Opt<CHANNEL_RIGHT, 1 << CHANNEL_RIGHT>( prva, pbuffer, nSampleCount );
  3619. break;
  3620. case OP_LEFT_DUPLICATE:
  3621. RVA_GetNext_Opt<CHANNEL_LEFT, (1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT)>( prva, pbuffer, nSampleCount );
  3622. break;
  3623. }
  3624. }
  3625. else
  3626. {
  3627. RVA_GetNextN( prva, pbuffer, nSampleCount, op );
  3628. }
  3629. #endif
  3630. }
  3631. // reverb parameter order
  3632. typedef enum
  3633. {
  3634. // parameter order
  3635. rva_size_max,
  3636. rva_size_min,
  3637. rva_inumdelays,
  3638. rva_ifeedback,
  3639. rva_igain,
  3640. rva_icutoff,
  3641. rva_ifparallel,
  3642. rva_imoddly,
  3643. rva_imodrate,
  3644. rva_width,
  3645. rva_depth,
  3646. rva_height,
  3647. rva_fbwidth,
  3648. rva_fbdepth,
  3649. rva_fbheight,
  3650. rva_iftaps,
  3651. rva_cparam // # of params
  3652. } rva_e;
  3653. // filter parameter ranges
  3654. prm_rng_t rva_rng[] = {
  3655. {rva_cparam, 0, 0}, // first entry is # of parameters
  3656. // reverb params
  3657. {rva_size_max, 0.0, 1000.0}, // max room delay in milliseconds
  3658. {rva_size_min, 0.0, 1000.0}, // min room delay in milliseconds
  3659. {rva_inumdelays,1.0, 12.0}, // controls # of parallel or series delays
  3660. {rva_ifeedback, 0.0, 1.0}, // feedback of delays
  3661. {rva_igain, 0.0, 10.0}, // output gain
  3662. // filter params for each parallel reverb (quality set to 0 for max execution speed)
  3663. {rva_icutoff, 10, 22050},
  3664. {rva_ifparallel, 0, 1}, // if 1, then all filters operate in parallel with delays. otherwise filter output only
  3665. {rva_imoddly, 0.0, 50.0}, // if > 0 then all delays are modulating delays, mod param controls milliseconds of mod depth
  3666. {rva_imodrate, 0.0, 10.0}, // how many delay repetitions pass between mod changes to delayl
  3667. // override params - for more detailed description of room
  3668. // note: width/depth/height < 0 only for some automatic dsp presets
  3669. {rva_width, -1000.0, 1000.0}, // 0-1000.0 millisec (room width in feet) - used instead of size if non-zero
  3670. {rva_depth, -1000.0, 1000.0}, // 0-1000.0 room depth in feet - used instead of size if non-zero
  3671. {rva_height, -1000.0, 1000.0}, // 0-1000.0 room height in feet - used instead of size if non-zero
  3672. {rva_fbwidth, -1.0, 1.0}, // 0-1.0 material reflectivity - used as feedback param instead of decay if non-zero
  3673. {rva_fbdepth, -1.0, 1.0}, // 0-1.0 material reflectivity - used as feedback param instead of decay if non-zero
  3674. {rva_fbheight, -1.0, 1.0}, // 0-1.0 material reflectivity - used as feedback param instead of decay if non-zero
  3675. // if < 0, a predelay is allocated, then feedback is -1*param given
  3676. {rva_iftaps, 0.0, 0.333} // if > 0, use 3 extra taps with delay values = d * (1 - faps*n) n = 0,1,2,3
  3677. };
  3678. #define RVA_BASEM 1 // base number of parallel delays
  3679. // nominal delay and feedback values. More delays = more density.
  3680. #define RVADLYSMAX 49
  3681. float rvadlys[] = {18, 23, 28, 33, 42, 21, 26, 36, 39, 45, 47, 30};
  3682. 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};
  3683. #define SWAP(a,b,t) {(t) = (a); (a) = (b); (b) = (t);}
  3684. #define RVA_MIN_SEPARATION 7 // minimum separation between reverbs, in ms.
  3685. // Construct D,a,b delay arrays given array of length,width,height sizes and feedback values
  3686. // rgd[] array of delay values in milliseconds (feet)
  3687. // rgf[] array of feedback values 0..1
  3688. // m # of parallel reverbs to construct
  3689. // D[] array of output delay values for parallel reverbs
  3690. // a[] array of output feedback values
  3691. // b[] array of output gain values = 1/m
  3692. // gain - output gain
  3693. // feedback - default feedback if rgf members are 0
  3694. void RVA_ConstructDelays( float *rgd, float *rgf, int m, int *D, int *a, int *b, float gain, float feedback )
  3695. {
  3696. int i;
  3697. float r;
  3698. int d;
  3699. float t, d1, d2, dm;
  3700. bool bpredelay;
  3701. // sort descending, so rgd[0] is largest delay & rgd[2] is smallest
  3702. if (rgd[2] > rgd[1]) { SWAP(rgd[2], rgd[1], t); SWAP(rgf[2], rgf[1], t); }
  3703. if (rgd[1] > rgd[0]) { SWAP(rgd[0], rgd[1], t); SWAP(rgf[0], rgf[1], t); }
  3704. if (rgd[2] > rgd[1]) { SWAP(rgd[2], rgd[1], t); SWAP(rgf[2], rgf[1], t); }
  3705. // if all feedback values 0, use default feedback
  3706. if (rgf[0] == 0.0 && rgf[1] == 0.0 && rgf[2] == 0.0 )
  3707. {
  3708. // use feedback param for all
  3709. rgf[0] = rgf[1] = rgf[2] = feedback;
  3710. // adjust feedback down for larger delays so that decay is constant for all delays
  3711. rgf[0] = DLY_NormalizeFeedback( rgd[2], rgf[2], rgd[0] );
  3712. rgf[1] = DLY_NormalizeFeedback( rgd[2], rgf[2], rgd[1] );
  3713. }
  3714. // make sure all reverbs are different by at least RVA_MIN_SEPARATION * m/3 m is 3,6,9 or 12
  3715. int dmin = (m/3) * RVA_MIN_SEPARATION;
  3716. d1 = rgd[1] - rgd[2];
  3717. if (d1 <= dmin)
  3718. rgd[1] += (dmin-d1); // make difference = dmin
  3719. d2 = rgd[0] - rgd[1];
  3720. if (d2 <= dmin)
  3721. rgd[0] += (dmin-d1); // make difference = dmin
  3722. for ( i = 0; i < m; i++ )
  3723. {
  3724. // reverberations due to room width, depth, height
  3725. // assume sound moves at approx 1ft/ms
  3726. int j = (int)(fmod ((float)i, 3.0f)); // j counts 0,1,2 0,1,2 0,1..
  3727. d = (int)rgd[j];
  3728. r = fabs(rgf[j]);
  3729. bpredelay = ((rgf[j] < 0) && i < 3);
  3730. // re-use predelay values as reverb values:
  3731. if (rgf[j] < 0 && !bpredelay)
  3732. d = MAX((int)(rgd[j] / 4.0), RVA_MIN_SEPARATION);
  3733. if (i < 3)
  3734. dm = 0.0;
  3735. else
  3736. dm = MAX( RVA_MIN_SEPARATION * (i/3), ((i/3) * ((float)d * 0.18)) );
  3737. d += (int)dm;
  3738. D[i] = MSEC_TO_SAMPS(d);
  3739. // 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
  3740. // feedback - due to wall/floor/ceiling reflectivity
  3741. a[i] = (int) MIN (0.999 * PMAX, (float)PMAX * r);
  3742. if (bpredelay)
  3743. a[i] = -a[i]; // flag delay as predelay
  3744. b[i] = (int)((float)(gain * PMAX) / (float)m);
  3745. }
  3746. }
  3747. void RVA_PerfTest()
  3748. {
  3749. double time1, time2;
  3750. int i;
  3751. int k;
  3752. int j;
  3753. int m;
  3754. int a[100];
  3755. time1 = Plat_FloatTime();
  3756. for (m = 0; m < 1000; m++)
  3757. {
  3758. for (i = 0, j = 10000; i < 10000; i++, j--)
  3759. {
  3760. // j = j % 6;
  3761. // k = (i * j) >> PBITS;
  3762. k = i / ((j % 6) + 1);
  3763. }
  3764. }
  3765. time2 = Plat_FloatTime();
  3766. DevMsg("divide = %2.5f \n", (time2-time1));
  3767. for (i=1;i<10;i++)
  3768. a[i] = PMAX / i;
  3769. time1 = Plat_FloatTime();
  3770. for (m = 0; m < 1000; m++)
  3771. {
  3772. for (i = 0, j = 10000; i < 10000; i++, j--)
  3773. {
  3774. k = (i * a[(j % 6) + 1] ) >> PBITS;
  3775. }
  3776. }
  3777. time2 = Plat_FloatTime();
  3778. DevMsg("shift & multiply = %2.5f \n", (time2-time1));
  3779. }
  3780. rva_t * RVA_Params ( prc_t *pprc )
  3781. {
  3782. rva_t *prva;
  3783. float size_max = pprc->prm[rva_size_max]; // max delay size
  3784. float size_min = pprc->prm[rva_size_min]; // min delay size
  3785. float numdelays = pprc->prm[rva_inumdelays]; // controls # of parallel delays
  3786. float feedback = pprc->prm[rva_ifeedback]; // 0-1.0 controls feedback parameters
  3787. float gain = pprc->prm[rva_igain]; // 0-10.0 controls output gain
  3788. float cutoff = pprc->prm[rva_icutoff]; // filter cutoff
  3789. float fparallel = pprc->prm[rva_ifparallel]; // if true, all filters are in delay feedback paths - otherwise single flt on output
  3790. float fmoddly = pprc->prm[rva_imoddly]; // if > 0, milliseconds of delay mod depth
  3791. float fmodrate = pprc->prm[rva_imodrate]; // if fmoddly > 0, # of delay repetitions between modulations
  3792. float width = fabs(pprc->prm[rva_width]); // 0-1000 controls size of 1/3 of delays - used instead of size if non-zero
  3793. float depth = fabs(pprc->prm[rva_depth]); // 0-1000 controls size of 1/3 of delays - used instead of size if non-zero
  3794. float height = fabs(pprc->prm[rva_height]); // 0-1000 controls size of 1/3 of delays - used instead of size if non-zero
  3795. float fbwidth = pprc->prm[rva_fbwidth]; // feedback parameter for walls 0..2
  3796. float fbdepth = pprc->prm[rva_fbdepth]; // feedback parameter for floor
  3797. float fbheight = pprc->prm[rva_fbheight]; // feedback parameter for ceiling
  3798. 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
  3799. // RVA_PerfTest();
  3800. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  3801. // a array of reverb feedback parms for parallel delays
  3802. // b array of CRVB_P_DLYS - mix params for parallel reverbs
  3803. // m - number of parallel delays
  3804. int D[CRVA_DLYS];
  3805. int a[CRVA_DLYS];
  3806. int b[CRVA_DLYS];
  3807. int m;
  3808. // limit # delays 1-12
  3809. m = iclamp (numdelays, RVA_BASEM, CRVA_DLYS);
  3810. // set up D (delay) a (feedback) b (gain) arrays
  3811. if ( int(width) || int(height) || int(depth) )
  3812. {
  3813. // if width, height, depth given, use values as simple delays
  3814. float rgd[3];
  3815. float rgfb[3];
  3816. // force m to 3, 6, 9 or 12
  3817. if (m < 3) m = 3;
  3818. if (m > 3 && m < 6) m = 6;
  3819. if (m > 6 && m < 9) m = 9;
  3820. if (m > 9) m = 12;
  3821. rgd[0] = width; rgfb[0] = fbwidth;
  3822. rgd[1] = depth; rgfb[1] = fbdepth;
  3823. rgd[2] = height; rgfb[2] = fbheight;
  3824. RVA_ConstructDelays( rgd, rgfb, m, D, a, b, gain, feedback );
  3825. }
  3826. else
  3827. {
  3828. // use size parameter instead of width/depth/height
  3829. for ( int i = 0; i < m; i++ )
  3830. {
  3831. // delays of parallel reverb. D[0] = size_min.
  3832. D[i] = MSEC_TO_SAMPS( size_min + (int)( ((float)(size_max - size_min) / (float)m) * (float)i) );
  3833. // feedback and gain of parallel reverb
  3834. if (i == 0)
  3835. {
  3836. // set feedback for smallest delay
  3837. a[i] = (int) MIN (0.999 * PMAX, (float)PMAX * feedback );
  3838. }
  3839. else
  3840. {
  3841. // adjust feedback down for larger delays so that decay time is constant
  3842. a[i] = (int) MIN (0.999 * PMAX, (float)PMAX * DLY_NormalizeFeedback( D[0], feedback, D[i] ) );
  3843. }
  3844. b[i] = (int) ((float)(gain * PMAX) / (float)m);
  3845. }
  3846. }
  3847. // add filter
  3848. flt_t *pflt = NULL;
  3849. if ( cutoff )
  3850. {
  3851. // set up dummy lowpass filter to convert params
  3852. prc_t prcf;
  3853. prcf.prm[flt_iquality] = QUA_LO; // force filter to low quality for faster execution time
  3854. prcf.prm[flt_icutoff] = cutoff;
  3855. prcf.prm[flt_iftype] = FLT_LP;
  3856. prcf.prm[flt_iqwidth] = 0;
  3857. prcf.prm[flt_igain] = 1.0;
  3858. pflt = (flt_t *)FLT_Params ( &prcf );
  3859. }
  3860. prva = RVA_Alloc ( D, a, b, m, pflt, fparallel, fmoddly, fmodrate, ftaps );
  3861. FLT_Free( pflt );
  3862. return prva;
  3863. }
  3864. inline void * RVA_VParams ( void *p )
  3865. {
  3866. PRC_CheckParams ( (prc_t *)p, rva_rng );
  3867. return (void *) RVA_Params ((prc_t *)p);
  3868. }
  3869. inline void RVA_Mod ( void *p, float v ) { return; }
  3870. ////////////
  3871. // Diffusor
  3872. ///////////
  3873. // (N series allpass reverbs)
  3874. #if CHECK_VALUES_AFTER_REFACTORING
  3875. #define CDFRS 128
  3876. #else
  3877. #define CDFRS 64 // max number of series reverbs active
  3878. #endif
  3879. #define CDFR_DLYS 16 // max number of delays making up diffusor
  3880. struct dfr_t
  3881. {
  3882. bool fused;
  3883. int n; // series allpass delays
  3884. int w[CDFR_DLYS]; // internal state array for series allpass filters
  3885. dly_t *pdlys[CDFR_DLYS]; // array of pointers to delays
  3886. };
  3887. dfr_t dfrs[CDFRS];
  3888. void DFR_Init ( dfr_t *pdfr ) { if ( pdfr ) Q_memset (pdfr, 0, sizeof (dfr_t)); }
  3889. void DFR_InitAll( void ) { for (int i = 0; i < CDFRS; i++) DFR_Init ( &dfrs[i] ); }
  3890. // free parallel series reverb
  3891. void DFR_Free( dfr_t *pdfr )
  3892. {
  3893. if ( pdfr )
  3894. {
  3895. // free all delays
  3896. for (int i = 0; i < CDFR_DLYS; i++)
  3897. DLY_Free ( pdfr->pdlys[i] );
  3898. Q_memset( pdfr, 0, sizeof (dfr_t) );
  3899. }
  3900. }
  3901. void DFR_FreeAll( void ) { for (int i = 0; i < CDFRS; i++) DFR_Free( &dfrs[i] ); }
  3902. // create n series allpass reverbs
  3903. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  3904. // a array of reverb feedback parms for series delays
  3905. // b array of gain params for parallel reverbs
  3906. // n - number of series delays
  3907. dfr_t * DFR_Alloc ( int *D, int *a, int *b, int n )
  3908. {
  3909. int i;
  3910. dfr_t *pdfr;
  3911. // find open slot
  3912. for (i = 0; i < CDFRS; i++)
  3913. {
  3914. if (!dfrs[i].fused)
  3915. break;
  3916. }
  3917. // return null if no free slots
  3918. if (i == CDFRS)
  3919. {
  3920. DevMsg ("DSP: Warning, failed to allocate diffusor.\n" );
  3921. return NULL;
  3922. }
  3923. pdfr = &dfrs[i];
  3924. DFR_Init( pdfr );
  3925. // alloc reverbs
  3926. for (i = 0; i < n; i++)
  3927. pdfr->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_ALLPASS );
  3928. // if we failed to alloc any reverb, free all, return NULL
  3929. for (i = 0; i < n; i++)
  3930. {
  3931. if ( !pdfr->pdlys[i])
  3932. {
  3933. DFR_Free( pdfr );
  3934. DevMsg ("DSP: Warning, failed to allocate delay for diffusor.\n" );
  3935. return NULL;
  3936. }
  3937. }
  3938. pdfr->fused = true;
  3939. pdfr->n = n;
  3940. return pdfr;
  3941. }
  3942. void DFR_Print( const dfr_t & dfr, int nIndentation )
  3943. {
  3944. const char * pIndent = GetIndentationText( nIndentation );
  3945. DevMsg( "%sDFR: %p [Addr]\n", pIndent, &dfr );
  3946. DevMsg( "%sfused: %d\n", pIndent, ( int ) dfr.fused );
  3947. for ( int i = 0 ; i < CDFR_DLYS ; ++i )
  3948. {
  3949. DevMsg( "%sDelay[%d]: ", pIndent, i );
  3950. if ( dfr.pdlys[i] != NULL )
  3951. {
  3952. DLY_Print( *dfr.pdlys[i], nIndentation + 1 );
  3953. }
  3954. else
  3955. {
  3956. DevMsg( "NULL\n" );
  3957. }
  3958. }
  3959. }
  3960. #if CHECK_VALUES_AFTER_REFACTORING
  3961. dfr_t * DFR_Clone( dfr_t * pOldDfr )
  3962. {
  3963. int i;
  3964. for ( i = 0; i < CDFRS; i++ )
  3965. {
  3966. if ( !dfrs[i].fused )
  3967. break;
  3968. }
  3969. // return null if no free slots
  3970. if (i == CDFRS)
  3971. {
  3972. DevMsg ("DSP: Warning, failed to allocate diffusor.\n" );
  3973. return NULL;
  3974. }
  3975. dfr_t * pNewDfr = &dfrs[i];
  3976. memcpy(pNewDfr, pOldDfr, sizeof(dfr_t));
  3977. for ( int j = 0 ; j < CRVA_DLYS ; ++j )
  3978. {
  3979. // First we do MDYs. In some cases, MDYs can point to DLY that can be stored in the pdlys array
  3980. // In that case instead of cloning the DLY, we will just update the pointer.
  3981. if ( pOldDfr->pdlys[j] != NULL )
  3982. {
  3983. pNewDfr->pdlys[j] = DLY_Clone( pOldDfr->pdlys[j] );
  3984. }
  3985. }
  3986. return pNewDfr;
  3987. }
  3988. void DFR_Compare( const dfr_t & leftDfr, const dfr_t & rightDfr )
  3989. {
  3990. Assert ( &leftDfr != &rightDfr );
  3991. Assert( leftDfr.fused == rightDfr.fused );
  3992. for ( int i = 0 ; i < CDFR_DLYS ; ++i )
  3993. {
  3994. if ( CheckPointers( leftDfr.pdlys[i], rightDfr.pdlys[i] ) )
  3995. {
  3996. DLY_Compare( *leftDfr.pdlys[i], *rightDfr.pdlys[i] );
  3997. }
  3998. }
  3999. }
  4000. #endif
  4001. // series reverberator
  4002. inline int DFR_GetNext( dfr_t *pdfr, int x )
  4003. {
  4004. int i;
  4005. int y;
  4006. dly_t *pdly;
  4007. y = x;
  4008. for (i = 0; i < pdfr->n; i++)
  4009. {
  4010. pdly = pdfr->pdlys[i];
  4011. y = DelayAllpass( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, y );
  4012. }
  4013. return y;
  4014. }
  4015. template <int READER, int WRITER>
  4016. inline void DFR_GetNext_Opt ( dfr_t *pdfr, portable_samplepair_t * pBuffer, int nCount )
  4017. {
  4018. // Because we do one filter at a time (and not one sample at a time)
  4019. // We either have to copy the input on an intermediate buffer, or write the output to an intermediate buffer.
  4020. // The faster is to use an intermediate output buffer as we can quickly zero it (it is slower to copy the input).
  4021. // Unlike the samples, the buffers here are actually short (so we use less memory - less L2 cache misses).
  4022. int nSizeToUse = sizeof(LocalOutputSample_t) * nCount;
  4023. int nSizeToAllocate = ALIGN_VALUE( nSizeToUse, CACHE_LINE_SIZE ); // Align on 128 as we are going to clear per cache-line
  4024. LocalOutputSample_t * pOutputSample = (LocalOutputSample_t *)alloca( nSizeToAllocate + CACHE_LINE_SIZE); // One more cache line as we are going to clear more than necessary...
  4025. pOutputSample = (LocalOutputSample_t *)ALIGN_VALUE( (intp)pOutputSample, CACHE_LINE_SIZE );
  4026. int nNumberOfCacheLinesToClear = ALIGN_VALUE( nSizeToAllocate, CACHE_LINE_SIZE ) / CACHE_LINE_SIZE;
  4027. LocalOutputSample_t * pCurrentCacheLine = pOutputSample;
  4028. // Given that we often have 500 to 1000 samples, it means that we are going to clear 2 to 4 Kb.
  4029. // (i.e. up to 32 cache lines). This will saturate the cache pipeline (but it easier to do it now instead of doing it within each filter).
  4030. while ( nNumberOfCacheLinesToClear > 0 )
  4031. {
  4032. PREZERO_128( pCurrentCacheLine, 0 );
  4033. pCurrentCacheLine += CACHE_LINE_SIZE / sizeof(LocalOutputSample_t);
  4034. --nNumberOfCacheLinesToClear;
  4035. }
  4036. // Then we are going to apply to the buffer each filter (one after the other for a set of samples)
  4037. // We are going to increase the number of loads and stores but at the end we can reduce the number of switches and unroll some calculation
  4038. int * pInputSample;
  4039. if ( READER == CHANNEL_LEFT )
  4040. {
  4041. pInputSample = &pBuffer->left;
  4042. }
  4043. else
  4044. {
  4045. Assert( READER == CHANNEL_RIGHT );
  4046. pInputSample = &pBuffer->right;
  4047. }
  4048. // At that point, each reader will have to skip one integer after reading one.
  4049. // Prefetch a bit (the next cache line) - again may continue saturate the buffer - but this will be read soon anyway.
  4050. PREFETCH_128( pInputSample, 128 );
  4051. // We are using the delay pass differently here compared to other cases, instead of adding the delay one after the other,
  4052. // they are used in feedback loop. Output of one is the input of the other...
  4053. if ( pdfr->n != 0)
  4054. {
  4055. // The first one has the normal input (with increment of 2), and normal output (with increment of 1).
  4056. // We don't care about the previous value so replace instead of adding to 0
  4057. dly_t *pdly = pdfr->pdlys[0];
  4058. DelayAllpass_Opt3<2, MM_REPLACE>( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, pInputSample, pOutputSample, nCount );
  4059. }
  4060. else
  4061. {
  4062. Assert( false ); // This code does not handle this gracefully - normally we would copy the input to the output directly...
  4063. // TODO: Add support for this
  4064. }
  4065. // Then we do the delays after (so starting at 1)
  4066. for (int i = 1; i < pdfr->n; ++i)
  4067. {
  4068. dly_t *pdly = pdfr->pdlys[i];
  4069. // This time, the input is the previous output, thus the increment is 1
  4070. // And we replace the value (for the feedback loop) instead of adding
  4071. DelayAllpass_Opt3<1, MM_REPLACE>( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, pOutputSample, pOutputSample, nCount );
  4072. }
  4073. // At the end, we have to write back the final result to the buffer (from pOutputSample to pBuffer).
  4074. // Because we have to skip integers it is not a simple memcpy.
  4075. if ( WRITER == ( 1 << CHANNEL_LEFT ) )
  4076. {
  4077. portable_samplepair_t * RESTRICT pWriteBuffer = pBuffer;
  4078. LocalOutputSample_t * RESTRICT pReadBuffer = pOutputSample;
  4079. while ( nCount >= 16 )
  4080. {
  4081. pWriteBuffer[0].left = pReadBuffer[0];
  4082. pWriteBuffer[1].left = pReadBuffer[1];
  4083. pWriteBuffer[2].left = pReadBuffer[2];
  4084. pWriteBuffer[3].left = pReadBuffer[3];
  4085. pWriteBuffer[4].left = pReadBuffer[4];
  4086. pWriteBuffer[5].left = pReadBuffer[5];
  4087. pWriteBuffer[6].left = pReadBuffer[6];
  4088. pWriteBuffer[7].left = pReadBuffer[7];
  4089. pWriteBuffer[8].left = pReadBuffer[8];
  4090. pWriteBuffer[9].left = pReadBuffer[9];
  4091. pWriteBuffer[10].left = pReadBuffer[10];
  4092. pWriteBuffer[11].left = pReadBuffer[11];
  4093. pWriteBuffer[12].left = pReadBuffer[12];
  4094. pWriteBuffer[13].left = pReadBuffer[13];
  4095. pWriteBuffer[14].left = pReadBuffer[14];
  4096. pWriteBuffer[15].left = pReadBuffer[15];
  4097. nCount -= 16;
  4098. pWriteBuffer += 16;
  4099. pReadBuffer += 16;
  4100. }
  4101. while ( nCount >= 1 )
  4102. {
  4103. pWriteBuffer->left = *pReadBuffer;
  4104. --nCount;
  4105. ++pWriteBuffer;
  4106. ++pReadBuffer;
  4107. }
  4108. }
  4109. else if ( WRITER == ( 1 << CHANNEL_RIGHT) )
  4110. {
  4111. portable_samplepair_t * RESTRICT pWriteBuffer = pBuffer;
  4112. LocalOutputSample_t * RESTRICT pReadBuffer = pOutputSample;
  4113. while ( nCount >= 16 )
  4114. {
  4115. pWriteBuffer[0].right = pReadBuffer[0];
  4116. pWriteBuffer[1].right = pReadBuffer[1];
  4117. pWriteBuffer[2].right = pReadBuffer[2];
  4118. pWriteBuffer[3].right = pReadBuffer[3];
  4119. pWriteBuffer[4].right = pReadBuffer[4];
  4120. pWriteBuffer[5].right = pReadBuffer[5];
  4121. pWriteBuffer[6].right = pReadBuffer[6];
  4122. pWriteBuffer[7].right = pReadBuffer[7];
  4123. pWriteBuffer[8].right = pReadBuffer[8];
  4124. pWriteBuffer[9].right = pReadBuffer[9];
  4125. pWriteBuffer[10].right = pReadBuffer[10];
  4126. pWriteBuffer[11].right = pReadBuffer[11];
  4127. pWriteBuffer[12].right = pReadBuffer[12];
  4128. pWriteBuffer[13].right = pReadBuffer[13];
  4129. pWriteBuffer[14].right = pReadBuffer[14];
  4130. pWriteBuffer[15].right = pReadBuffer[15];
  4131. nCount -= 16;
  4132. pWriteBuffer += 16;
  4133. pReadBuffer += 16;
  4134. }
  4135. while ( nCount >= 1 )
  4136. {
  4137. pWriteBuffer->right = *pReadBuffer;
  4138. --nCount;
  4139. ++pWriteBuffer;
  4140. ++pReadBuffer;
  4141. }
  4142. }
  4143. else
  4144. {
  4145. Assert( WRITER == ( ( 1 << CHANNEL_LEFT ) | ( 1 << CHANNEL_RIGHT ) ) );
  4146. portable_samplepair_t * RESTRICT pWriteBuffer = pBuffer;
  4147. LocalOutputSample_t * RESTRICT pReadBuffer = pOutputSample;
  4148. // Because we are writing left and write in this version, we could potentially use VMX operations
  4149. // Read 8 samples at a time (2 bytes * 8), sign extend them on 4 VMX registers and write them.
  4150. while ( nCount >= 16 )
  4151. {
  4152. pWriteBuffer[0].left = pWriteBuffer[0].right = pReadBuffer[0];
  4153. pWriteBuffer[1].left = pWriteBuffer[1].right = pReadBuffer[1];
  4154. pWriteBuffer[2].left = pWriteBuffer[2].right = pReadBuffer[2];
  4155. pWriteBuffer[3].left = pWriteBuffer[3].right = pReadBuffer[3];
  4156. pWriteBuffer[4].left = pWriteBuffer[4].right = pReadBuffer[4];
  4157. pWriteBuffer[5].left = pWriteBuffer[5].right = pReadBuffer[5];
  4158. pWriteBuffer[6].left = pWriteBuffer[6].right = pReadBuffer[6];
  4159. pWriteBuffer[7].left = pWriteBuffer[7].right = pReadBuffer[7];
  4160. pWriteBuffer[8].left = pWriteBuffer[8].right = pReadBuffer[8];
  4161. pWriteBuffer[9].left = pWriteBuffer[9].right = pReadBuffer[9];
  4162. pWriteBuffer[10].left = pWriteBuffer[10].right = pReadBuffer[10];
  4163. pWriteBuffer[11].left = pWriteBuffer[11].right = pReadBuffer[11];
  4164. pWriteBuffer[12].left = pWriteBuffer[12].right = pReadBuffer[12];
  4165. pWriteBuffer[13].left = pWriteBuffer[13].right = pReadBuffer[13];
  4166. pWriteBuffer[14].left = pWriteBuffer[14].right = pReadBuffer[14];
  4167. pWriteBuffer[15].left = pWriteBuffer[15].right = pReadBuffer[15];
  4168. nCount -= 16;
  4169. pWriteBuffer += 16;
  4170. pReadBuffer += 16;
  4171. }
  4172. while ( nCount >= 1 )
  4173. {
  4174. pWriteBuffer->left = pWriteBuffer->right = *pReadBuffer;
  4175. --nCount;
  4176. ++pWriteBuffer;
  4177. ++pReadBuffer;
  4178. }
  4179. }
  4180. }
  4181. // batch version for performance
  4182. inline void DFR_GetNextN( dfr_t *pdfr, portable_samplepair_t *pbuffer, int SampleCount, int op )
  4183. {
  4184. int count = SampleCount;
  4185. portable_samplepair_t *pb = pbuffer;
  4186. switch (op)
  4187. {
  4188. default:
  4189. case OP_LEFT:
  4190. while (count--)
  4191. {
  4192. pb->left = DFR_GetNext( pdfr, pb->left );
  4193. pb++;
  4194. }
  4195. return;
  4196. case OP_RIGHT:
  4197. while (count--)
  4198. {
  4199. pb->right = DFR_GetNext( pdfr, pb->right );
  4200. pb++;
  4201. }
  4202. return;
  4203. case OP_LEFT_DUPLICATE:
  4204. while (count--)
  4205. {
  4206. pb->left = pb->right = DFR_GetNext( pdfr, pb->left );
  4207. pb++;
  4208. }
  4209. return;
  4210. }
  4211. }
  4212. #if CHECK_VALUES_AFTER_REFACTORING
  4213. void CheckCloneAccuracy( dfr_t *pDfr, portable_samplepair_t *pbuffer, int nSampleCount, int op )
  4214. {
  4215. // Try not to modify the original values so the sound is kept pristine even with this test
  4216. portable_samplepair_t * pTempBuffer1 = DuplicateSamplePairs( pbuffer, nSampleCount );
  4217. dfr_t * pTempDfr1 = DFR_Clone(pDfr);
  4218. DFR_Compare( *pDfr, *pTempDfr1 );
  4219. portable_samplepair_t * pTempBuffer2 = DuplicateSamplePairs( pbuffer, nSampleCount );
  4220. dfr_t * pTempDfr2 = DFR_Clone(pDfr);
  4221. DFR_Compare( *pDfr, *pTempDfr2 );
  4222. portable_samplepair_t * pTempBuffer3 = DuplicateSamplePairs( pbuffer, nSampleCount );
  4223. dfr_t * pTempDfr3 = DFR_Clone(pDfr);
  4224. DFR_Compare( *pDfr, *pTempDfr3 );
  4225. // If we clone correctly, we should have the same output on the two buffers.
  4226. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  4227. DFR_GetNextN( pTempDfr1, pTempBuffer1, nSampleCount, op );
  4228. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  4229. DFR_GetNextN( pTempDfr2, pTempBuffer2, nSampleCount, op );
  4230. DFR_Compare( *pTempDfr1, *pTempDfr2 );
  4231. bool bFailed = ( memcmp( pTempBuffer1, pTempBuffer2, nSampleCount * sizeof( portable_samplepair_t ) ) != 0 );
  4232. if ( bFailed )
  4233. {
  4234. Warning("[Sound] Detected desynchronization during DFR cloning.\n");
  4235. // Normally the content should be the same, only the addresses (tagged [Addr]) should be different.
  4236. // No address should be the same (if that were the case, it would mean we missed something during the cloning).
  4237. DevMsg( "\n\nCloned RVA 1:\n\n" );
  4238. DFR_Print( *pTempDfr1, 0 );
  4239. DevMsg( "\n\nCloned RVA 2:\n\n" );
  4240. DFR_Print( *pTempDfr2, 0 );
  4241. // After that, let's try to re-clone again and display the values before any modification.
  4242. FreeDuplicatedSamplePairs( pTempBuffer1, nSampleCount );
  4243. DFR_Free(pTempDfr1);
  4244. FreeDuplicatedSamplePairs( pTempBuffer2, nSampleCount );
  4245. DFR_Free(pTempDfr2);
  4246. pTempBuffer1 = DuplicateSamplePairs( pbuffer, nSampleCount );
  4247. pTempDfr1 = DFR_Clone(pDfr);
  4248. DFR_Compare( *pDfr, *pTempDfr1 );
  4249. pTempBuffer2 = DuplicateSamplePairs( pbuffer, nSampleCount );
  4250. pTempDfr2 = DFR_Clone(pDfr);
  4251. DFR_Compare( *pDfr, *pTempDfr2 );
  4252. DevMsg( "\n\nInitial DFR:\n\n" );
  4253. DFR_Print( *pDfr, 0 );
  4254. DevMsg( "\n\nCloned DFR 1:\n\n" );
  4255. DFR_Print( *pTempDfr1, 0 );
  4256. DevMsg( "\n\nCloned DFR 2:\n\n" );
  4257. DFR_Print( *pTempDfr2, 0 );
  4258. // Re-run the transform so we can compare with the official result
  4259. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  4260. DFR_GetNextN( pTempDfr1, pTempBuffer1, nSampleCount, op );
  4261. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  4262. DFR_GetNextN( pTempDfr2, pTempBuffer2, nSampleCount, op );
  4263. DFR_Compare( *pTempDfr1, *pTempDfr2 );
  4264. }
  4265. // This will break the input buffer content, if this test is executed the sound will be off (esp. for reverberations and delays)
  4266. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  4267. #if 0
  4268. // Use this method so it will compare sample by sample (help track more complex desyncs, but will slow the game down by a ton
  4269. DFR_GetNextN2( prva, pbuffer, pTempRva3, pTempBuffer3, nSampleCount, op );
  4270. #else
  4271. DFR_GetNextN( pDfr, pbuffer, nSampleCount, op );
  4272. #endif
  4273. DFR_Compare( *pDfr, *pTempDfr1 );
  4274. bFailed = ( memcmp( pTempBuffer1, pbuffer, nSampleCount * sizeof( portable_samplepair_t ) ) != 0 );
  4275. if ( bFailed )
  4276. {
  4277. Warning("[Sound] Detected desynchronization during DFR cloning.\n");
  4278. // Normally the content should be the same, only the addresses (tagged [Addr]) should be different.
  4279. // No address should be the same (if that were the case, it would mean that we missed something during the cloning).
  4280. DevMsg( "\n\nInitial DFR:\n\n" );
  4281. DFR_Print( *pDfr, 0 );
  4282. DevMsg( "\n\nCloned DFR:\n\n" );
  4283. DFR_Print( *pTempDfr1, 0 );
  4284. // Re-clone here to help detect the issue (before any modification)
  4285. portable_samplepair_t * pTempBuffer4 = DuplicateSamplePairs( pbuffer, nSampleCount );
  4286. dfr_t * pTempDfr4 = DFR_Clone(pDfr);
  4287. DevMsg( "\n\nNew clone DFR:\n\n" );
  4288. DFR_Print( *pTempDfr4, 0 );
  4289. FreeDuplicatedSamplePairs( pTempBuffer4, nSampleCount );
  4290. DFR_Free(pTempDfr4);
  4291. }
  4292. FreeDuplicatedSamplePairs( pTempBuffer1, nSampleCount );
  4293. DFR_Free(pTempDfr1);
  4294. FreeDuplicatedSamplePairs( pTempBuffer2, nSampleCount );
  4295. DFR_Free(pTempDfr2);
  4296. FreeDuplicatedSamplePairs( pTempBuffer3, nSampleCount );
  4297. DFR_Free(pTempDfr3);
  4298. }
  4299. #endif
  4300. inline void DFR_GetNextN_Opt( dfr_t *pdfr, portable_samplepair_t *pbuffer, int nSampleCount, int op )
  4301. {
  4302. #if CHECK_VALUES_AFTER_REFACTORING
  4303. // Duplicate the values before the original buffer is going to be modified in CheckCloneAccuracy()
  4304. portable_samplepair_t * pTempBuffer = DuplicateSamplePairs( pbuffer, nSampleCount );
  4305. dfr_t * pTempDfr = DFR_Clone( pdfr );
  4306. DFR_Compare( *pdfr, *pTempDfr );
  4307. CheckCloneAccuracy( pdfr, pbuffer, nSampleCount, op );
  4308. int count = nSampleCount;
  4309. portable_samplepair_t *pb = pTempBuffer;
  4310. LocalRandomSeed(); // Some of the filters are using Random, so we can see some divergence in some cases. Force the same seed.
  4311. switch ( op )
  4312. {
  4313. default:
  4314. case OP_LEFT:
  4315. DFR_GetNext_Opt<CHANNEL_LEFT, 1 << CHANNEL_LEFT>( pTempDfr, pb, count );
  4316. break;
  4317. case OP_RIGHT:
  4318. DFR_GetNext_Opt<CHANNEL_RIGHT, 1 << CHANNEL_RIGHT>( pTempDfr, pb, count );
  4319. break;
  4320. case OP_LEFT_DUPLICATE:
  4321. DFR_GetNext_Opt<CHANNEL_LEFT, (1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT)>( pTempDfr, pb, count );
  4322. break;
  4323. }
  4324. DFR_Compare( *pdfr, *pTempDfr );
  4325. bool bFailed = ( memcmp( pTempBuffer, pbuffer, nSampleCount * sizeof( portable_samplepair_t ) ) != 0 );
  4326. Assert( bFailed == false );
  4327. FreeDuplicatedSamplePairs( pTempBuffer, nSampleCount );
  4328. DFR_Free( pTempDfr );
  4329. #else
  4330. if ( snd_dsp_optimization.GetBool() )
  4331. {
  4332. switch (op)
  4333. {
  4334. default:
  4335. case OP_LEFT:
  4336. DFR_GetNext_Opt<CHANNEL_LEFT, 1 << CHANNEL_LEFT>( pdfr, pbuffer, nSampleCount );
  4337. break;
  4338. case OP_RIGHT:
  4339. DFR_GetNext_Opt<CHANNEL_RIGHT, 1 << CHANNEL_RIGHT>( pdfr, pbuffer, nSampleCount );
  4340. break;
  4341. case OP_LEFT_DUPLICATE:
  4342. DFR_GetNext_Opt<CHANNEL_LEFT, (1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT)>( pdfr, pbuffer, nSampleCount );
  4343. break;
  4344. }
  4345. }
  4346. else
  4347. {
  4348. DFR_GetNextN( pdfr, pbuffer, nSampleCount, op );
  4349. }
  4350. #endif
  4351. }
  4352. #define DFR_BASEN 1 // base number of series allpass delays
  4353. // nominal diffusor delay and feedback values
  4354. float dfrdlys[] = {13, 19, 26, 21, 32, 36, 38, 16, 24, 28, 41, 35, 10, 46, 50, 27};
  4355. 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};
  4356. // diffusor parameter order
  4357. typedef enum
  4358. {
  4359. // parameter order
  4360. dfr_isize,
  4361. dfr_inumdelays,
  4362. dfr_ifeedback,
  4363. dfr_igain,
  4364. dfr_cparam // # of params
  4365. } dfr_e;
  4366. // diffusor parameter ranges
  4367. prm_rng_t dfr_rng[] = {
  4368. {dfr_cparam, 0, 0}, // first entry is # of parameters
  4369. {dfr_isize, 0.0, 1.0}, // 0-1.0 scales all delays
  4370. {dfr_inumdelays,0.0, 4.0}, // 0-4.0 controls # of series delays
  4371. {dfr_ifeedback, 0.0, 1.0}, // 0-1.0 scales all feedback parameters
  4372. {dfr_igain, 0.0, 10.0}, // 0-1.0 scales all feedback parameters
  4373. };
  4374. dfr_t * DFR_Params ( prc_t *pprc )
  4375. {
  4376. dfr_t *pdfr;
  4377. int i;
  4378. int s;
  4379. float size = pprc->prm[dfr_isize]; // 0-1.0 scales all delays
  4380. float numdelays = pprc->prm[dfr_inumdelays]; // 0-4.0 controls # of series delays
  4381. float feedback = pprc->prm[dfr_ifeedback]; // 0-1.0 scales all feedback parameters
  4382. float gain = pprc->prm[dfr_igain]; // 0-10.0 controls output gain
  4383. // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  4384. // a array of reverb feedback parms for series delays (CRVB_S_DLYS)
  4385. // b gain of each reverb section
  4386. // n - number of series delays
  4387. int D[CDFR_DLYS];
  4388. int a[CDFR_DLYS];
  4389. int b[CDFR_DLYS];
  4390. int n;
  4391. if (gain == 0.0)
  4392. gain = 1.0;
  4393. // get # series diffusors
  4394. // limit m, n to half max number of delays
  4395. n = iclamp (numdelays, DFR_BASEN, CDFR_DLYS/2);
  4396. // compute delays for diffusors
  4397. for (i = 0; i < n; i++)
  4398. {
  4399. s = (int)( dfrdlys[i] * size );
  4400. // delay of diffusor
  4401. D[i] = MSEC_TO_SAMPS(s);
  4402. // feedback and gain of diffusor
  4403. a[i] = MIN (0.999 * PMAX, dfrfbs[i] * PMAX * feedback);
  4404. b[i] = (int) ( (float)(gain * (float)PMAX) );
  4405. }
  4406. pdfr = DFR_Alloc ( D, a, b, n );
  4407. return pdfr;
  4408. }
  4409. inline void * DFR_VParams ( void *p )
  4410. {
  4411. PRC_CheckParams ((prc_t *)p, dfr_rng);
  4412. return (void *) DFR_Params ((prc_t *)p);
  4413. }
  4414. inline void DFR_Mod ( void *p, float v ) { return; }
  4415. //////////////////////
  4416. // LFO wav definitions
  4417. //////////////////////
  4418. #define CLFOSAMPS 512 // samples per wav table - single cycle only
  4419. #define LFOBITS 14 // bits of peak amplitude of lfo wav
  4420. #define LFOAMP ((1<<LFOBITS)-1) // peak amplitude of lfo wav
  4421. //types of lfo wavs
  4422. #define LFO_SIN 0 // sine wav
  4423. #define LFO_TRI 1 // triangle wav
  4424. #define LFO_SQR 2 // square wave, 50% duty cycle
  4425. #define LFO_SAW 3 // forward saw wav
  4426. #define LFO_RND 4 // random wav
  4427. #define LFO_LOG_IN 5 // logarithmic fade in
  4428. #define LFO_LOG_OUT 6 // logarithmic fade out
  4429. #define LFO_LIN_IN 7 // linear fade in
  4430. #define LFO_LIN_OUT 8 // linear fade out
  4431. #define LFO_MAX LFO_LIN_OUT
  4432. #define CLFOWAV 9 // number of LFO wav tables
  4433. struct lfowav_t // lfo or envelope wave table
  4434. {
  4435. int type; // lfo type
  4436. dly_t *pdly; // delay holds wav values and step pointers
  4437. };
  4438. lfowav_t lfowavs[CLFOWAV];
  4439. // deallocate lfo wave table. Called only when sound engine exits.
  4440. void LFOWAV_Free( lfowav_t *plw )
  4441. {
  4442. // free delay
  4443. if ( plw )
  4444. DLY_Free( plw->pdly );
  4445. Q_memset( plw, 0, sizeof (lfowav_t) );
  4446. }
  4447. // deallocate all lfo wave tables. Called only when sound engine exits.
  4448. void LFOWAV_FreeAll( void )
  4449. {
  4450. for ( int i = 0; i < CLFOWAV; i++ )
  4451. LFOWAV_Free( &lfowavs[i] );
  4452. }
  4453. // fill lfo array w with count samples of lfo type 'type'
  4454. // all lfo wavs except fade out, rnd, and log_out should start with 0 output
  4455. void LFOWAV_Fill( CircularBufferSample_t *w, int count, int type )
  4456. {
  4457. int i,x;
  4458. switch (type)
  4459. {
  4460. default:
  4461. case LFO_SIN: // sine wav, all values 0 <= x <= LFOAMP, initial value = 0
  4462. for (i = 0; i < count; i++ )
  4463. {
  4464. x = ( int )( (float)(LFOAMP) * sinf( (2.0 * M_PI_F * (float)i / (float)count ) + (M_PI_F * 1.5) ) );
  4465. w[i] = (x + LFOAMP)/2;
  4466. }
  4467. break;
  4468. case LFO_TRI: // triangle wav, all values 0 <= x <= LFOAMP, initial value = 0
  4469. for (i = 0; i < count; i++)
  4470. {
  4471. w[i] = ( int ) ( (float)(2 * LFOAMP * i ) / (float)(count) );
  4472. if ( i > count / 2 )
  4473. w[i] = ( int ) ( (float) (2 * LFOAMP) - (float)( 2 * LFOAMP * i ) / (float)(count) );
  4474. }
  4475. break;
  4476. case LFO_SQR: // square wave, 50% duty cycle, all values 0 <= x <= LFOAMP, initial value = 0
  4477. for (i = 0; i < count; i++)
  4478. w[i] = i > count / 2 ? 0 : LFOAMP;
  4479. break;
  4480. case LFO_SAW: // forward saw wav, aall values 0 <= x <= LFOAMP, initial value = 0
  4481. for (i = 0; i < count; i++)
  4482. w[i] = ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
  4483. break;
  4484. case LFO_RND: // random wav, all values 0 <= x <= LFOAMP
  4485. for (i = 0; i < count; i++)
  4486. w[i] = ( int ) ( LocalRandomInt(0, LFOAMP) );
  4487. break;
  4488. case LFO_LOG_IN: // logarithmic fade in, all values 0 <= x <= LFOAMP, initial value = 0
  4489. for (i = 0; i < count; i++)
  4490. w[i] = ( int ) ( (float)(LFOAMP) * powf( (float)i / (float)count, 2));
  4491. break;
  4492. case LFO_LOG_OUT: // logarithmic fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
  4493. for (i = 0; i < count; i++)
  4494. w[i] = ( int ) ( (float)(LFOAMP) * powf( 1.0 - ((float)i / (float)count), 2 ));
  4495. break;
  4496. case LFO_LIN_IN: // linear fade in, all values 0 <= x <= LFOAMP, initial value = 0
  4497. for (i = 0; i < count; i++)
  4498. w[i] = ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
  4499. break;
  4500. case LFO_LIN_OUT: // linear fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
  4501. for (i = 0; i < count; i++)
  4502. w[i] = LFOAMP - ( int ) ( (float)(LFOAMP) * (float)i / (float)(count) );
  4503. break;
  4504. }
  4505. }
  4506. // allocate all lfo wave tables. Called only when sound engine loads.
  4507. void LFOWAV_InitAll()
  4508. {
  4509. int i;
  4510. dly_t *pdly;
  4511. Q_memset( lfowavs, 0, sizeof( lfowavs ) );
  4512. // alloc space for each lfo wav type
  4513. for (i = 0; i < CLFOWAV; i++)
  4514. {
  4515. pdly = DLY_Alloc( CLFOSAMPS, 0, 0 , DLY_PLAIN);
  4516. lfowavs[i].pdly = pdly;
  4517. lfowavs[i].type = i;
  4518. LFOWAV_Fill( pdly->w, CLFOSAMPS, i );
  4519. }
  4520. // if any dlys fail to alloc, free all
  4521. for (i = 0; i < CLFOWAV; i++)
  4522. {
  4523. if ( !lfowavs[i].pdly )
  4524. LFOWAV_FreeAll();
  4525. }
  4526. }
  4527. ////////////////////////////////////////
  4528. // LFO iterators - one shot and looping
  4529. ////////////////////////////////////////
  4530. #if CHECK_VALUES_AFTER_REFACTORING
  4531. #define CLFO 32
  4532. #else
  4533. #define CLFO 16 // max active lfos (this steals from active delays)
  4534. #endif
  4535. struct lfo_t
  4536. {
  4537. bool fused; // true if slot take
  4538. dly_t *pdly; // delay points to lfo wav within lfowav_t (don't free this)
  4539. int gain;
  4540. float f; // playback frequency in hz
  4541. pos_t pos; // current position within wav table, looping
  4542. pos_one_t pos1; // current position within wav table, one shot
  4543. int foneshot; // true - one shot only, don't repeat
  4544. };
  4545. lfo_t lfos[CLFO];
  4546. void LFO_Init( lfo_t *plfo ) { if ( plfo ) Q_memset( plfo, 0, sizeof (lfo_t) ); }
  4547. void LFO_InitAll( void ) { for (int i = 0; i < CLFO; i++) LFO_Init(&lfos[i]); }
  4548. void LFO_Free( lfo_t *plfo ) { if ( plfo ) Q_memset( plfo, 0, sizeof (lfo_t) ); }
  4549. void LFO_FreeAll( void ) { for (int i = 0; i < CLFO; i++) LFO_Free(&lfos[i]); }
  4550. // get step value given desired playback frequency
  4551. inline float LFO_HzToStep ( float freqHz )
  4552. {
  4553. float lfoHz;
  4554. // calculate integer and fractional step values,
  4555. // assume an update rate of SOUND_DMA_SPEED samples/sec
  4556. // 1 cycle/CLFOSAMPS * SOUND_DMA_SPEED samps/sec = cycles/sec = current lfo rate
  4557. //
  4558. // lforate * X = freqHz so X = freqHz/lforate = update rate
  4559. lfoHz = (float)(SOUND_DMA_SPEED) / (float)(CLFOSAMPS);
  4560. return freqHz / lfoHz;
  4561. }
  4562. // return pointer to new lfo
  4563. lfo_t * LFO_Alloc( int wtype, float freqHz, bool foneshot, float gain )
  4564. {
  4565. int i;
  4566. int type = MIN ( CLFOWAV - 1, wtype );
  4567. float lfostep;
  4568. for (i = 0; i < CLFO; i++)
  4569. if (!lfos[i].fused)
  4570. {
  4571. lfo_t *plfo = &lfos[i];
  4572. LFO_Init( plfo );
  4573. plfo->fused = true;
  4574. plfo->pdly = lfowavs[type].pdly; // pdly in lfo points to wav table data in lfowavs
  4575. plfo->f = freqHz;
  4576. plfo->foneshot = foneshot;
  4577. plfo->gain = gain * PMAX;
  4578. lfostep = LFO_HzToStep( freqHz );
  4579. // init positional pointer (ie: fixed point updater for controlling pitch of lfo)
  4580. if ( !foneshot )
  4581. POS_Init(&(plfo->pos), plfo->pdly->D, lfostep );
  4582. else
  4583. POS_ONE_Init(&(plfo->pos1), plfo->pdly->D,lfostep );
  4584. return plfo;
  4585. }
  4586. DevMsg ("DSP: Warning, failed to allocate LFO.\n" );
  4587. return NULL;
  4588. }
  4589. void LFO_Print( const lfo_t & crs, int nIndentation )
  4590. {
  4591. DevMsg( "LFO_Print is not implemented\n" );
  4592. }
  4593. // get next lfo value
  4594. // Value returned is 0..LFOAMP. can be normalized by shifting right by LFOBITS
  4595. // To play back at correct passed in frequency, routien should be
  4596. // called once for every output sample (ie: at SOUND_DMA_SPEED)
  4597. // x is dummy param
  4598. inline int LFO_GetNext( lfo_t *plfo, int x )
  4599. {
  4600. int i;
  4601. // get current position
  4602. if ( !plfo->foneshot )
  4603. i = POS_GetNext( &plfo->pos );
  4604. else
  4605. i = POS_ONE_GetNext( &plfo->pos1 );
  4606. // return current sample
  4607. if (plfo->gain == PMAX)
  4608. return plfo->pdly->w[i];
  4609. else
  4610. return (plfo->pdly->w[i] * plfo->gain ) >> PBITS;
  4611. }
  4612. // batch version for performance
  4613. inline void LFO_GetNextN( lfo_t *plfo, portable_samplepair_t *pbuffer, int SampleCount, int op )
  4614. {
  4615. int count = SampleCount;
  4616. portable_samplepair_t *pb = pbuffer;
  4617. switch (op)
  4618. {
  4619. default:
  4620. case OP_LEFT:
  4621. while (count--)
  4622. {
  4623. pb->left = LFO_GetNext( plfo, pb->left );
  4624. pb++;
  4625. }
  4626. return;
  4627. case OP_RIGHT:
  4628. while (count--)
  4629. {
  4630. pb->right = LFO_GetNext( plfo, pb->right );
  4631. pb++;
  4632. }
  4633. return;
  4634. case OP_LEFT_DUPLICATE:
  4635. while (count--)
  4636. {
  4637. pb->left = pb->right = LFO_GetNext( plfo, pb->left );
  4638. pb++;
  4639. }
  4640. return;
  4641. }
  4642. }
  4643. // uses lfowav, rate, foneshot
  4644. typedef enum
  4645. {
  4646. // parameter order
  4647. lfo_iwav,
  4648. lfo_irate,
  4649. lfo_ifoneshot,
  4650. lfo_igain,
  4651. lfo_cparam // # of params
  4652. } lfo_e;
  4653. // parameter ranges
  4654. prm_rng_t lfo_rng[] = {
  4655. {lfo_cparam, 0, 0}, // first entry is # of parameters
  4656. {lfo_iwav, 0.0, LFO_MAX}, // lfo type to use (LFO_SIN, LFO_RND...)
  4657. {lfo_irate, 0.0, 16000.0}, // modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
  4658. {lfo_ifoneshot, 0.0, 1.0}, // 1.0 if lfo is oneshot
  4659. {lfo_igain, 0.0, 10.0}, // output gain
  4660. };
  4661. lfo_t * LFO_Params ( prc_t *pprc )
  4662. {
  4663. lfo_t *plfo;
  4664. bool foneshot = pprc->prm[lfo_ifoneshot] > 0 ? true : false;
  4665. float gain = pprc->prm[lfo_igain];
  4666. plfo = LFO_Alloc ( pprc->prm[lfo_iwav], pprc->prm[lfo_irate], foneshot, gain );
  4667. return plfo;
  4668. }
  4669. void LFO_ChangeVal ( lfo_t *plfo, float fhz )
  4670. {
  4671. float fstep = LFO_HzToStep( fhz );
  4672. // change lfo playback rate to new frequency fhz
  4673. if ( plfo->foneshot )
  4674. POS_ChangeVal( &plfo->pos, fstep );
  4675. else
  4676. POS_ChangeVal( &plfo->pos1.p, fstep );
  4677. }
  4678. inline void * LFO_VParams ( void *p )
  4679. {
  4680. PRC_CheckParams ( (prc_t *)p, lfo_rng );
  4681. return (void *) LFO_Params ((prc_t *)p);
  4682. }
  4683. // v is +/- 0-1.0
  4684. // v changes current lfo frequency up/down by +/- v%
  4685. inline void LFO_Mod ( lfo_t *plfo, float v )
  4686. {
  4687. float fhz;
  4688. float fhznew;
  4689. fhz = plfo->f;
  4690. fhznew = fhz * (1.0 + v);
  4691. LFO_ChangeVal ( plfo, fhznew );
  4692. return;
  4693. }
  4694. ////////////////////////////////////////
  4695. // Time Compress/expand with pitch shift
  4696. ////////////////////////////////////////
  4697. // realtime pitch shift - ie: pitch shift without change to playback rate
  4698. #if CHECK_VALUES_AFTER_REFACTORING
  4699. #define CPTCS 128
  4700. #else
  4701. #define CPTCS 64
  4702. #endif
  4703. struct ptc_t
  4704. {
  4705. bool fused;
  4706. dly_t *pdly_in; // input buffer space
  4707. dly_t *pdly_out; // output buffer space
  4708. CircularBufferSample_t *pin; // input buffer (pdly_in->w)
  4709. CircularBufferSample_t *pout; // output buffer (pdly_out->w)
  4710. int cin; // # samples in input buffer
  4711. int cout; // # samples in output buffer
  4712. int cxfade; // # samples in crossfade segment
  4713. int ccut; // # samples to cut
  4714. int cduplicate; // # samples to duplicate (redundant - same as ccut)
  4715. int iin; // current index into input buffer (reading)
  4716. pos_one_t psn; // stepping index through output buffer
  4717. bool fdup; // true if duplicating, false if cutting
  4718. float fstep; // pitch shift & time compress/expand
  4719. };
  4720. ptc_t ptcs[CPTCS];
  4721. void PTC_Init( ptc_t *pptc ) { if (pptc) Q_memset( pptc, 0, sizeof (ptc_t) ); };
  4722. void PTC_Free( ptc_t *pptc )
  4723. {
  4724. if (pptc)
  4725. {
  4726. DLY_Free (pptc->pdly_in);
  4727. DLY_Free (pptc->pdly_out);
  4728. Q_memset( pptc, 0, sizeof (ptc_t) );
  4729. }
  4730. };
  4731. void PTC_InitAll() { for (int i = 0; i < CPTCS; i++) PTC_Init( &ptcs[i] ); };
  4732. void PTC_FreeAll() { for (int i = 0; i < CPTCS; i++) PTC_Free( &ptcs[i] ); };
  4733. // Time compressor/expander with pitch shift (ie: pitch changes, playback rate does not)
  4734. //
  4735. // Algorithm:
  4736. // 1) Duplicate or discard chunks of sound to provide tslice * fstep seconds of sound.
  4737. // (The user-selectable size of the buffer to process is tslice milliseconds in length)
  4738. // 2) Resample this compressed/expanded buffer at fstep to produce a pitch shifted
  4739. // output with the same duration as the input (ie: #samples out = # samples in, an
  4740. // obvious requirement for realtime inline processing).
  4741. // timeslice is size in milliseconds of full buffer to process.
  4742. // timeslice * fstep is the size of the expanded/compressed buffer
  4743. // timexfade is length in milliseconds of crossfade region between duplicated or cut sections
  4744. // fstep is % expanded/compressed sound normalized to 0.01-2.0 (1% - 200%)
  4745. // input buffer:
  4746. // iin-->
  4747. // [0... tslice ...D] input samples 0...D (D is NEWEST sample)
  4748. // [0... ...n][m... tseg ...D] region to be cut or duplicated m...D
  4749. // [0... [p..txf1..n][m... tseg ...D] fade in region 1 txf1 p...n
  4750. // [0... ...n][m..[q..txf2..D] fade out region 2 txf2 q...D
  4751. // pitch up: duplicate into output buffer: tdup = tseg
  4752. // [0... ...n][m... tdup ...D][m... tdup ...D] output buffer size with duplicate region
  4753. // [0... ...n][m..[p...xf1..n][m... tdup ...D] fade in p...n while fading out q...D
  4754. // [0... ...n][m..[q...xf2..D][m... tdup ...D]
  4755. // [0... ...n][m..[.XFADE...n][m... tdup ...D] final duplicated output buffer - resample at fstep
  4756. // pitch down: cut into output buffer: tcut = tseg
  4757. // [0... ...n][m... tcut ...D] input samples with cut region delineated m...D
  4758. // [0... ...n] output buffer size after cut
  4759. // [0... [q..txf2...D] fade in txf1 q...D while fade out txf2 p...n
  4760. // [0... [.XFADE ...D] final cut output buffer - resample at fstep
  4761. ptc_t * PTC_Alloc( float timeslice, float timexfade, float fstep )
  4762. {
  4763. int i;
  4764. ptc_t *pptc;
  4765. float tout;
  4766. int cin, cout;
  4767. float tslice = timeslice;
  4768. float txfade = timexfade;
  4769. float tcutdup;
  4770. // find time compressor slot
  4771. for ( i = 0; i < CPTCS; i++ )
  4772. {
  4773. if ( !ptcs[i].fused )
  4774. break;
  4775. }
  4776. if ( i == CPTCS )
  4777. {
  4778. DevMsg ("DSP: Warning, failed to allocate pitch shifter.\n" );
  4779. return NULL;
  4780. }
  4781. pptc = &ptcs[i];
  4782. PTC_Init ( pptc );
  4783. // get size of region to cut or duplicate
  4784. tcutdup = abs((fstep - 1.0) * timeslice);
  4785. // to prevent buffer overruns:
  4786. // make sure timeslice is greater than cut/dup time
  4787. tslice = MAX ( tslice, 1.1 * tcutdup);
  4788. // make sure xfade time smaller than cut/dup time, and smaller than (timeslice-cutdup) time
  4789. txfade = MIN ( txfade, 0.9 * tcutdup );
  4790. txfade = MIN ( txfade, 0.9 * (tslice - tcutdup));
  4791. pptc->cxfade = MSEC_TO_SAMPS( txfade );
  4792. pptc->ccut = MSEC_TO_SAMPS( tcutdup );
  4793. pptc->cduplicate = MSEC_TO_SAMPS( tcutdup );
  4794. // alloc delay lines (buffers)
  4795. tout = tslice * fstep;
  4796. cin = MSEC_TO_SAMPS( tslice );
  4797. cout = MSEC_TO_SAMPS( tout );
  4798. pptc->pdly_in = DLY_Alloc( cin, 0, 1, DLY_LINEAR ); // alloc input buffer
  4799. pptc->pdly_out = DLY_Alloc( cout, 0, 1, DLY_LINEAR); // alloc output buffer
  4800. if ( !pptc->pdly_in || !pptc->pdly_out )
  4801. {
  4802. PTC_Free( pptc );
  4803. DevMsg ("DSP: Warning, failed to allocate delay for pitch shifter.\n" );
  4804. return NULL;
  4805. }
  4806. // buffer pointers
  4807. pptc->pin = pptc->pdly_in->w;
  4808. pptc->pout = pptc->pdly_out->w;
  4809. // input buffer index
  4810. pptc->iin = 0;
  4811. // output buffer index
  4812. POS_ONE_Init ( &pptc->psn, cout, fstep );
  4813. // if fstep > 1.0 we're pitching shifting up, so fdup = true
  4814. pptc->fdup = fstep > 1.0 ? true : false;
  4815. pptc->cin = cin;
  4816. pptc->cout = cout;
  4817. pptc->fstep = fstep;
  4818. pptc->fused = true;
  4819. return pptc;
  4820. }
  4821. void PTC_Print( const ptc_t & crs, int nIndentation )
  4822. {
  4823. DevMsg( "PTC_Print is not implemented\n" );
  4824. }
  4825. // linear crossfader
  4826. // yfadein - instantaneous value fading in
  4827. // ydafeout -instantaneous value fading out
  4828. // nsamples - duration in #samples of fade
  4829. // isample - index in to fade 0...nsamples-1
  4830. inline int xfade ( int yfadein, int yfadeout, int nsamples, int isample )
  4831. {
  4832. int yout;
  4833. int m = (isample << PBITS ) / nsamples;
  4834. // yout = ((yfadein * m) >> PBITS) + ((yfadeout * (PMAX - m)) >> PBITS);
  4835. yout = (yfadeout + (yfadein - yfadeout) * m ) >> PBITS;
  4836. return yout;
  4837. }
  4838. // w - pointer to start of input buffer samples
  4839. // v - pointer to start of output buffer samples
  4840. // cin - # of input buffer samples
  4841. // cout = # of output buffer samples
  4842. // cxfade = # of crossfade samples
  4843. // cduplicate = # of samples in duplicate/cut segment
  4844. void TimeExpand( CircularBufferSample_t *w, CircularBufferSample_t *v, int cin, int cout, int cxfade, int cduplicate )
  4845. {
  4846. int i,j;
  4847. int m;
  4848. int p;
  4849. int q;
  4850. int D;
  4851. // input buffer
  4852. // xfade source duplicate
  4853. // [0...........][p.......n][m...........D]
  4854. // output buffer
  4855. // xfade region duplicate
  4856. // [0.....................n][m..[q.......D][m...........D]
  4857. // D - index of last sample in input buffer
  4858. // m - index of 1st sample in duplication region
  4859. // p - index of 1st sample of crossfade source
  4860. // q - index of 1st sample in crossfade region
  4861. D = cin - 1;
  4862. m = cin - cduplicate;
  4863. p = m - cxfade;
  4864. q = cin - cxfade;
  4865. // copy up to crossfade region
  4866. for (i = 0; i < q; i++)
  4867. v[i] = w[i];
  4868. // crossfade region
  4869. j = p;
  4870. for (i = q; i <= D; i++)
  4871. v[i] = xfade (w[j++], w[i], cxfade, i-q); // fade out p..n, fade in q..D
  4872. // duplicate region
  4873. j = D+1;
  4874. for (i = m; i <= D; i++)
  4875. v[j++] = w[i];
  4876. }
  4877. // cut ccut samples from end of input buffer, crossfade end of cut section
  4878. // with end of remaining section
  4879. // w - pointer to start of input buffer samples
  4880. // v - pointer to start of output buffer samples
  4881. // cin - # of input buffer samples
  4882. // cout = # of output buffer samples
  4883. // cxfade = # of crossfade samples
  4884. // ccut = # of samples in cut segment
  4885. void TimeCompress( CircularBufferSample_t *w, CircularBufferSample_t *v, int cin, int cout, int cxfade, int ccut )
  4886. {
  4887. int i,j;
  4888. int m;
  4889. int p;
  4890. int q;
  4891. int D;
  4892. // input buffer
  4893. // xfade source
  4894. // [0.....................n][m..[p.......D]
  4895. // xfade region cut
  4896. // [0...........][q.......n][m...........D]
  4897. // output buffer
  4898. // xfade to source
  4899. // [0...........][p.......D]
  4900. // D - index of last sample in input buffer
  4901. // m - index of 1st sample in cut region
  4902. // p - index of 1st sample of crossfade source
  4903. // q - index of 1st sample in crossfade region
  4904. D = cin - 1;
  4905. m = cin - ccut;
  4906. p = cin - cxfade;
  4907. q = m - cxfade;
  4908. // copy up to crossfade region
  4909. for (i = 0; i < q; i++)
  4910. v[i] = w[i];
  4911. // crossfade region
  4912. j = p;
  4913. for (i = q; i < m; i++)
  4914. v[i] = xfade (w[j++], w[i], cxfade, i-q); // fade out p..n, fade in q..D
  4915. // skip rest of input buffer
  4916. }
  4917. // get next sample
  4918. // put input sample into input (delay) buffer
  4919. // get output sample from output buffer, step by fstep %
  4920. // output buffer is time expanded or compressed version of previous input buffer
  4921. inline int PTC_GetNext( ptc_t *pptc, int x )
  4922. {
  4923. int iout, xout;
  4924. bool fhitend = false;
  4925. // write x into input buffer
  4926. Assert (pptc->iin < pptc->cin);
  4927. pptc->pin[pptc->iin] = x;
  4928. pptc->iin++;
  4929. // check for end of input buffer
  4930. if ( pptc->iin >= pptc->cin )
  4931. fhitend = true;
  4932. // read sample from output buffer, resampling at fstep
  4933. iout = POS_ONE_GetNext( &pptc->psn );
  4934. Assert (iout < pptc->cout);
  4935. xout = pptc->pout[iout];
  4936. if ( fhitend )
  4937. {
  4938. // if hit end of input buffer (ie: input buffer is full)
  4939. // reset input buffer pointer
  4940. // reset output buffer pointer
  4941. // rebuild entire output buffer (TimeCompress/TimeExpand)
  4942. pptc->iin = 0;
  4943. POS_ONE_Init( &pptc->psn, pptc->cout, pptc->fstep );
  4944. if ( pptc->fdup )
  4945. TimeExpand ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->cduplicate );
  4946. else
  4947. TimeCompress ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->ccut );
  4948. }
  4949. return xout;
  4950. }
  4951. // batch version for performance
  4952. inline void PTC_GetNextN( ptc_t *pptc, portable_samplepair_t *pbuffer, int SampleCount, int op )
  4953. {
  4954. int count = SampleCount;
  4955. portable_samplepair_t *pb = pbuffer;
  4956. switch (op)
  4957. {
  4958. default:
  4959. case OP_LEFT:
  4960. while (count--)
  4961. {
  4962. pb->left = PTC_GetNext( pptc, pb->left );
  4963. pb++;
  4964. }
  4965. return;
  4966. case OP_RIGHT:
  4967. while (count--)
  4968. {
  4969. pb->right = PTC_GetNext( pptc, pb->right );
  4970. pb++;
  4971. }
  4972. return;
  4973. case OP_LEFT_DUPLICATE:
  4974. while (count--)
  4975. {
  4976. pb->left = pb->right = PTC_GetNext( pptc, pb->left );
  4977. pb++;
  4978. }
  4979. return;
  4980. }
  4981. }
  4982. // change time compression to new value
  4983. // fstep is new value
  4984. // ramptime is how long change takes in seconds (ramps smoothly), 0 for no ramp
  4985. void PTC_ChangeVal( ptc_t *pptc, float fstep, float ramptime )
  4986. {
  4987. // UNDONE: ignored
  4988. // UNDONE: just realloc time compressor with new fstep
  4989. }
  4990. // uses pitch:
  4991. // 1.0 = playback normal rate
  4992. // 0.5 = cut 50% of sound (2x playback)
  4993. // 1.5 = add 50% sound (0.5x playback)
  4994. typedef enum
  4995. {
  4996. // parameter order
  4997. ptc_ipitch,
  4998. ptc_itimeslice,
  4999. ptc_ixfade,
  5000. ptc_cparam // # of params
  5001. } ptc_e;
  5002. // diffusor parameter ranges
  5003. prm_rng_t ptc_rng[] = {
  5004. {ptc_cparam, 0, 0}, // first entry is # of parameters
  5005. {ptc_ipitch, 0.1, 4.0}, // 0-n.0 where 1.0 = 1 octave up and 0.5 is one octave down
  5006. {ptc_itimeslice, 20.0, 300.0}, // in milliseconds - size of sound chunk to analyze and cut/duplicate - 100ms nominal
  5007. {ptc_ixfade, 1.0, 200.0}, // in milliseconds - size of crossfade region between spliced chunks - 20ms nominal
  5008. };
  5009. ptc_t * PTC_Params ( prc_t *pprc )
  5010. {
  5011. ptc_t *pptc;
  5012. float pitch = pprc->prm[ptc_ipitch];
  5013. float timeslice = pprc->prm[ptc_itimeslice];
  5014. float txfade = pprc->prm[ptc_ixfade];
  5015. pptc = PTC_Alloc( timeslice, txfade, pitch );
  5016. return pptc;
  5017. }
  5018. inline void * PTC_VParams ( void *p )
  5019. {
  5020. PRC_CheckParams ( (prc_t *)p, ptc_rng );
  5021. return (void *) PTC_Params ((prc_t *)p);
  5022. }
  5023. // change to new pitch value
  5024. // v is +/- 0-1.0
  5025. // v changes current pitch up/down by +/- v%
  5026. void PTC_Mod ( ptc_t *pptc, float v )
  5027. {
  5028. float fstep;
  5029. float fstepnew;
  5030. fstep = pptc->fstep;
  5031. fstepnew = fstep * (1.0 + v);
  5032. PTC_ChangeVal( pptc, fstepnew, 0.01 );
  5033. }
  5034. ////////////////////
  5035. // ADSR envelope
  5036. ////////////////////
  5037. #if CHECK_VALUES_AFTER_REFACTORING
  5038. #define CENVS 128
  5039. #else
  5040. #define CENVS 64 // max # of envelopes active
  5041. #endif
  5042. #define CENVRMPS 4 // A, D, S, R
  5043. #define ENV_LIN 0 // linear a,d,s,r
  5044. #define ENV_EXP 1 // exponential a,d,s,r
  5045. #define ENV_MAX ENV_EXP
  5046. #define ENV_BITS 14 // bits of resolution of ramp
  5047. struct env_t
  5048. {
  5049. bool fused;
  5050. bool fhitend; // true if done
  5051. bool fexp; // true if exponential ramps
  5052. int ienv; // current ramp
  5053. rmp_t rmps[CENVRMPS]; // ramps
  5054. };
  5055. env_t envs[CENVS];
  5056. void ENV_Init( env_t *penv ) { if (penv) Q_memset( penv, 0, sizeof (env_t) ); };
  5057. void ENV_Free( env_t *penv ) { if (penv) Q_memset( penv, 0, sizeof (env_t) ); };
  5058. void ENV_InitAll() { for (int i = 0; i < CENVS; i++) ENV_Init( &envs[i] ); };
  5059. void ENV_FreeAll() { for (int i = 0; i < CENVS; i++) ENV_Free( &envs[i] ); };
  5060. // allocate ADSR envelope
  5061. // all times are in seconds
  5062. // amp1 - attack amplitude multiplier 0-1.0
  5063. // amp2 - sustain amplitude multiplier 0-1.0
  5064. // amp3 - end of sustain amplitude multiplier 0-1.0
  5065. env_t *ENV_Alloc ( int type, float famp1, float famp2, float famp3, float attack, float decay, float sustain, float release, bool fexp)
  5066. {
  5067. int i;
  5068. env_t *penv;
  5069. for (i = 0; i < CENVS; i++)
  5070. {
  5071. if ( !envs[i].fused )
  5072. {
  5073. int amp1 = famp1 * (1 << ENV_BITS); // ramp resolution
  5074. int amp2 = famp2 * (1 << ENV_BITS);
  5075. int amp3 = famp3 * (1 << ENV_BITS);
  5076. penv = &envs[i];
  5077. ENV_Init (penv);
  5078. // UNDONE: ignoring type = ENV_EXP - use oneshot LFOS instead with sawtooth/exponential
  5079. // set up ramps
  5080. RMP_Init( &penv->rmps[0], attack, 0, amp1, true );
  5081. RMP_Init( &penv->rmps[1], decay, amp1, amp2, true );
  5082. RMP_Init( &penv->rmps[2], sustain, amp2, amp3, true );
  5083. RMP_Init( &penv->rmps[3], release, amp3, 0, true );
  5084. penv->ienv = 0;
  5085. penv->fused = true;
  5086. penv->fhitend = false;
  5087. penv->fexp = fexp;
  5088. return penv;
  5089. }
  5090. }
  5091. DevMsg ("DSP: Warning, failed to allocate envelope.\n" );
  5092. return NULL;
  5093. }
  5094. void ENV_Print( const env_t & env, int nIndentation )
  5095. {
  5096. DevMsg( "ENV_Print is not implemented\n" );
  5097. }
  5098. inline int ENV_GetNext( env_t *penv, int x )
  5099. {
  5100. if ( !penv->fhitend )
  5101. {
  5102. int i;
  5103. int y;
  5104. i = penv->ienv;
  5105. y = RMP_GetNext ( &penv->rmps[i] );
  5106. // check for next ramp
  5107. if ( penv->rmps[i].fhitend )
  5108. i++;
  5109. penv->ienv = i;
  5110. // check for end of all ramps
  5111. if ( i > 3)
  5112. penv->fhitend = true;
  5113. // multiply input signal by ramp
  5114. if (penv->fexp)
  5115. return (((x * y) >> ENV_BITS) * y) >> ENV_BITS;
  5116. else
  5117. return (x * y) >> ENV_BITS;
  5118. }
  5119. return 0;
  5120. }
  5121. // batch version for performance
  5122. inline void ENV_GetNextN( env_t *penv, portable_samplepair_t *pbuffer, int SampleCount, int op )
  5123. {
  5124. int count = SampleCount;
  5125. portable_samplepair_t *pb = pbuffer;
  5126. switch (op)
  5127. {
  5128. default:
  5129. case OP_LEFT:
  5130. while (count--)
  5131. {
  5132. pb->left = ENV_GetNext( penv, pb->left );
  5133. pb++;
  5134. }
  5135. return;
  5136. case OP_RIGHT:
  5137. while (count--)
  5138. {
  5139. pb->right = ENV_GetNext( penv, pb->right );
  5140. pb++;
  5141. }
  5142. return;
  5143. case OP_LEFT_DUPLICATE:
  5144. while (count--)
  5145. {
  5146. pb->left = pb->right = ENV_GetNext( penv, pb->left );
  5147. pb++;
  5148. }
  5149. return;
  5150. }
  5151. }
  5152. // uses lfowav, amp1, amp2, amp3, attack, decay, sustain, release
  5153. // lfowav is type, currently ignored - ie: LFO_LIN_IN, LFO_LOG_IN
  5154. // parameter order
  5155. typedef enum
  5156. {
  5157. env_itype,
  5158. env_iamp1,
  5159. env_iamp2,
  5160. env_iamp3,
  5161. env_iattack,
  5162. env_idecay,
  5163. env_isustain,
  5164. env_irelease,
  5165. env_ifexp,
  5166. env_cparam // # of params
  5167. } env_e;
  5168. // parameter ranges
  5169. prm_rng_t env_rng[] = {
  5170. {env_cparam, 0, 0}, // first entry is # of parameters
  5171. {env_itype, 0.0,ENV_MAX}, // ENV_LINEAR, ENV_LOG - currently ignored
  5172. {env_iamp1, 0.0, 1.0}, // attack peak amplitude 0-1.0
  5173. {env_iamp2, 0.0, 1.0}, // decay target amplitued 0-1.0
  5174. {env_iamp3, 0.0, 1.0}, // sustain target amplitude 0-1.0
  5175. {env_iattack, 0.0, 20000.0}, // attack time in milliseconds
  5176. {env_idecay, 0.0, 20000.0}, // envelope decay time in milliseconds
  5177. {env_isustain, 0.0, 20000.0}, // sustain time in milliseconds
  5178. {env_irelease, 0.0, 20000.0}, // release time in milliseconds
  5179. {env_ifexp, 0.0, 1.0}, // 1.0 if exponential ramps
  5180. };
  5181. env_t * ENV_Params ( prc_t *pprc )
  5182. {
  5183. env_t *penv;
  5184. float type = pprc->prm[env_itype];
  5185. float amp1 = pprc->prm[env_iamp1];
  5186. float amp2 = pprc->prm[env_iamp2];
  5187. float amp3 = pprc->prm[env_iamp3];
  5188. float attack = pprc->prm[env_iattack]/1000.0;
  5189. float decay = pprc->prm[env_idecay]/1000.0;
  5190. float sustain = pprc->prm[env_isustain]/1000.0;
  5191. float release = pprc->prm[env_irelease]/1000.0;
  5192. float fexp = pprc->prm[env_ifexp];
  5193. bool bexp;
  5194. bexp = fexp > 0.0 ? 1 : 0;
  5195. penv = ENV_Alloc ( type, amp1, amp2, amp3, attack, decay, sustain, release, bexp );
  5196. return penv;
  5197. }
  5198. inline void * ENV_VParams ( void *p )
  5199. {
  5200. PRC_CheckParams( (prc_t *)p, env_rng );
  5201. return (void *) ENV_Params ((prc_t *)p);
  5202. }
  5203. inline void ENV_Mod ( void *p, float v ) { return; }
  5204. //////////////////////////
  5205. // Gate & envelope follower
  5206. //////////////////////////
  5207. #if CHECK_VALUES_AFTER_REFACTORING
  5208. #define CEFOS 128
  5209. #else
  5210. #define CEFOS 64 // max # of envelope followers active
  5211. #endif
  5212. struct efo_t
  5213. {
  5214. bool fused;
  5215. int xout; // current output value
  5216. // gate params
  5217. bool bgate; // if true, gate function is on
  5218. bool bgateon; // if true, gate is on
  5219. bool bexp; // if true, use exponential fade out
  5220. int thresh; // amplitude threshold for gate on
  5221. int thresh_off; // amplitidue threshold for gate off
  5222. float attack_time; // gate attack time in seconds
  5223. float decay_time; // gate decay time in seconds
  5224. rmp_t rmp_attack; // gate on ramp - attack
  5225. rmp_t rmp_decay; // gate off ramp - decay
  5226. };
  5227. efo_t efos[CEFOS];
  5228. void EFO_Init( efo_t *pefo ) { if (pefo) Q_memset( pefo, 0, sizeof (efo_t) ); };
  5229. void EFO_Free( efo_t *pefo ) { if (pefo) Q_memset( pefo, 0, sizeof (efo_t) ); };
  5230. void EFO_InitAll() { for (int i = 0; i < CEFOS; i++) EFO_Init( &efos[i] ); };
  5231. void EFO_FreeAll() { for (int i = 0; i < CEFOS; i++) EFO_Free( &efos[i] ); };
  5232. // return true when gate is off AND decay ramp has hit end
  5233. inline bool EFO_GateOff( efo_t *pefo )
  5234. {
  5235. return ( !pefo->bgateon && RMP_HitEnd( &pefo->rmp_decay ) );
  5236. }
  5237. // allocate enveloper follower
  5238. #define EFO_HYST_AMP 1000 // hysteresis amplitude
  5239. efo_t *EFO_Alloc ( float threshold, float attack_sec, float decay_sec, bool bexp )
  5240. {
  5241. int i;
  5242. efo_t *pefo;
  5243. for (i = 0; i < CEFOS; i++)
  5244. {
  5245. if ( !efos[i].fused )
  5246. {
  5247. pefo = &efos[i];
  5248. EFO_Init ( pefo );
  5249. pefo->xout = 0;
  5250. pefo->fused = true;
  5251. // init gate params
  5252. pefo->bgate = threshold > 0.0;
  5253. if (pefo->bgate)
  5254. {
  5255. pefo->attack_time = attack_sec;
  5256. pefo->decay_time = decay_sec;
  5257. RMP_Init( &pefo->rmp_attack, attack_sec, 0, PMAX, false);
  5258. RMP_Init( &pefo->rmp_decay, decay_sec, PMAX, 0, false);
  5259. RMP_SetEnd( &pefo->rmp_attack );
  5260. RMP_SetEnd( &pefo->rmp_decay );
  5261. pefo->thresh = threshold;
  5262. pefo->thresh_off = MAX(1, threshold - EFO_HYST_AMP);
  5263. pefo->bgateon = false;
  5264. pefo->bexp = bexp;
  5265. }
  5266. return pefo;
  5267. }
  5268. }
  5269. DevMsg ("DSP: Warning, failed to allocate envelope follower.\n" );
  5270. return NULL;
  5271. }
  5272. void EFO_Print( const efo_t & crs, int nIndentation )
  5273. {
  5274. DevMsg( "EFO_Print is not implemented\n" );
  5275. }
  5276. // values of L for CEFO_BITS_DIVIDE: L = (1 - 1/(1 << CEFO_BITS_DIVIDE))
  5277. // 1 L = 0.5
  5278. // 2 L = 0.75
  5279. // 3 L = 0.875
  5280. // 4 L = 0.9375
  5281. // 5 L = 0.96875
  5282. // 6 L = 0.984375
  5283. // 7 L = 0.9921875
  5284. // 8 L = 0.99609375
  5285. // 9 L = 0.998046875
  5286. // 10 L = 0.9990234375
  5287. // 11 L = 0.99951171875
  5288. // 12 L = 0.999755859375
  5289. // decay time constant for values of L, for E = 10^-3 = 60dB of attenuation
  5290. //
  5291. // Neff = Ln E / Ln L = -6.9077552 / Ln L
  5292. //
  5293. // 1 L = 0.5 Neff = 10 samples
  5294. // 2 L = 0.75 Neff = 24
  5295. // 3 L = 0.875 Neff = 51
  5296. // 4 L = 0.9375 Neff = 107
  5297. // 5 L = 0.96875 Neff = 217
  5298. // 6 L = 0.984375 Neff = 438
  5299. // 7 L = 0.9921875 Neff = 880
  5300. // 8 L = 0.99609375 Neff = 1764
  5301. // 9 L = 0.998046875 Neff = 3533
  5302. // 10 L = 0.9990234375 Neff = 7070
  5303. // 11 L = 0.99951171875 Neff = 14143
  5304. // 12 L = 0.999755859375 Neff = 28290
  5305. #define CEFO_BITS 11 // 14143 samples in gate window (3hz)
  5306. inline int EFO_GetNext( efo_t *pefo, int x )
  5307. {
  5308. int r;
  5309. int xa = abs(x);
  5310. int xdif;
  5311. // get envelope:
  5312. // Cn = L * Cn-1 + ( 1 - L ) * |x|
  5313. // which simplifies to:
  5314. // Cn = |x| + (Cn-1 - |x|) * L
  5315. // for 0 < L < 1
  5316. // increasing L increases time to rise or fall to a new input level
  5317. // so: increasing CEFO_BITS_DIVIDE increases rise/fall time
  5318. // where: L = (1 - 1/(1 << CEFO_BITS))
  5319. // xdif = Cn-1 - |x|
  5320. // so: xdif * L = xdif - xdif / (1 << CEFO_BITS) = ((xdif << CEFO_BITS) - xdif ) >> CEFO_BITS
  5321. xdif = pefo->xout - xa;
  5322. pefo->xout = xa + (((xdif << CEFO_BITS) - xdif) >> CEFO_BITS);
  5323. if ( pefo->bgate )
  5324. {
  5325. // gate
  5326. bool bgateon_prev = pefo->bgateon;
  5327. // gate hysteresis
  5328. if (bgateon_prev)
  5329. // gate was on - it's off only if amp drops below thresh_off
  5330. pefo->bgateon = ( pefo->xout >= pefo->thresh_off );
  5331. else
  5332. // gate was off - it's on only if amp > thresh
  5333. pefo->bgateon = ( pefo->xout >= pefo->thresh );
  5334. if ( pefo->bgateon )
  5335. {
  5336. // gate is on
  5337. if ( bgateon_prev && RMP_HitEnd( &pefo->rmp_attack ))
  5338. return x; // gate is fully on
  5339. if ( !bgateon_prev )
  5340. {
  5341. // gate just turned on, start ramp attack
  5342. // start attack from previous decay ramp if active
  5343. r = RMP_HitEnd( &pefo->rmp_decay ) ? 0 : RMP_GetNext( &pefo->rmp_decay );
  5344. RMP_SetEnd( &pefo->rmp_decay);
  5345. // DevMsg ("GATE ON \n");
  5346. RMP_Init( &pefo->rmp_attack, pefo->attack_time, r, PMAX, false);
  5347. return (x * r) >> PBITS;
  5348. }
  5349. if ( !RMP_HitEnd( &pefo->rmp_attack ) )
  5350. {
  5351. r = RMP_GetNext( &pefo->rmp_attack );
  5352. // gate is on and ramping up
  5353. return (x * r) >> PBITS;
  5354. }
  5355. }
  5356. else
  5357. {
  5358. // gate is fully off
  5359. if ( !bgateon_prev && RMP_HitEnd( &pefo->rmp_decay))
  5360. return 0;
  5361. if ( bgateon_prev )
  5362. {
  5363. // gate just turned off, start ramp decay
  5364. // start decay from previous attack ramp if active
  5365. r = RMP_HitEnd( &pefo->rmp_attack ) ? PMAX : RMP_GetNext( &pefo->rmp_attack );
  5366. RMP_SetEnd( &pefo->rmp_attack);
  5367. RMP_Init( &pefo->rmp_decay, pefo->decay_time, r, 0, false);
  5368. // DevMsg ("GATE OFF \n");
  5369. // if exponential set, gate has exponential ramp down. Otherwise linear ramp down.
  5370. if ( pefo->bexp )
  5371. return ( (((x * r) >> PBITS) * r ) >> PBITS );
  5372. else
  5373. return (x * r) >> PBITS;
  5374. }
  5375. else if ( !RMP_HitEnd( &pefo->rmp_decay ) )
  5376. {
  5377. // gate is off and ramping down
  5378. r = RMP_GetNext( &pefo->rmp_decay );
  5379. // if exponential set, gate has exponential ramp down. Otherwise linear ramp down.
  5380. if ( pefo->bexp )
  5381. return ( (((x * r) >> PBITS) * r ) >> PBITS );
  5382. else
  5383. return (x * r) >> PBITS;
  5384. }
  5385. }
  5386. return x;
  5387. }
  5388. return pefo->xout;
  5389. }
  5390. // batch version for performance
  5391. inline void EFO_GetNextN( efo_t *pefo, portable_samplepair_t *pbuffer, int SampleCount, int op )
  5392. {
  5393. int count = SampleCount;
  5394. portable_samplepair_t *pb = pbuffer;
  5395. switch (op)
  5396. {
  5397. default:
  5398. case OP_LEFT:
  5399. while (count--)
  5400. {
  5401. pb->left = EFO_GetNext( pefo, pb->left );
  5402. pb++;
  5403. }
  5404. return;
  5405. case OP_RIGHT:
  5406. while (count--)
  5407. {
  5408. pb->right = EFO_GetNext( pefo, pb->right );
  5409. pb++;
  5410. }
  5411. return;
  5412. case OP_LEFT_DUPLICATE:
  5413. while (count--)
  5414. {
  5415. pb->left = pb->right = EFO_GetNext( pefo, pb->left );
  5416. pb++;
  5417. }
  5418. return;
  5419. }
  5420. }
  5421. // parameter order
  5422. typedef enum
  5423. {
  5424. efo_ithreshold,
  5425. efo_iattack,
  5426. efo_idecay,
  5427. efo_iexp,
  5428. efo_cparam // # of params
  5429. } efo_e;
  5430. // parameter ranges
  5431. prm_rng_t efo_rng[] = {
  5432. {efo_cparam, 0, 0}, // first entry is # of parameters
  5433. {efo_ithreshold, -140.0, 0.0}, // gate threshold in db. if 0.0 then no gate.
  5434. {efo_iattack, 0.0, 20000.0}, // attack time in milliseconds
  5435. {efo_idecay, 0.0, 20000.0}, // envelope decay time in milliseconds
  5436. {efo_iexp, 0.0, 1.0}, // if 1, use exponential decay ramp (for more realistic reverb tail)
  5437. };
  5438. efo_t * EFO_Params ( prc_t *pprc )
  5439. {
  5440. efo_t *penv;
  5441. float threshold = Gain_To_Amplitude( dB_To_Gain(pprc->prm[efo_ithreshold]) );
  5442. float attack = pprc->prm[efo_iattack]/1000.0;
  5443. float decay = pprc->prm[efo_idecay]/1000.0;
  5444. float fexp = pprc->prm[efo_iexp];
  5445. bool bexp;
  5446. // check for no gate
  5447. if ( pprc->prm[efo_ithreshold] == 0.0 )
  5448. threshold = 0.0;
  5449. bexp = fexp > 0.0 ? 1 : 0;
  5450. penv = EFO_Alloc ( threshold, attack, decay, bexp );
  5451. return penv;
  5452. }
  5453. inline void * EFO_VParams ( void *p )
  5454. {
  5455. PRC_CheckParams( (prc_t *)p, efo_rng );
  5456. return (void *) EFO_Params ((prc_t *)p);
  5457. }
  5458. inline void EFO_Mod ( void *p, float v ) { return; }
  5459. ///////////////////////////////////////////
  5460. // Chorus - lfo modulated delay
  5461. ///////////////////////////////////////////
  5462. #if CHECK_VALUES_AFTER_REFACTORING
  5463. #define CCRSS 128
  5464. #else
  5465. #define CCRSS 64 // max number chorus' active
  5466. #endif
  5467. struct crs_t
  5468. {
  5469. bool fused;
  5470. mdy_t *pmdy; // modulatable delay
  5471. lfo_t *plfo; // modulating lfo
  5472. int lfoprev; // previous modulator value from lfo
  5473. };
  5474. crs_t crss[CCRSS];
  5475. void CRS_Init( crs_t *pcrs ) { if (pcrs) Q_memset( pcrs, 0, sizeof (crs_t) ); };
  5476. void CRS_Free( crs_t *pcrs )
  5477. {
  5478. if (pcrs)
  5479. {
  5480. MDY_Free ( pcrs->pmdy );
  5481. LFO_Free ( pcrs->plfo );
  5482. Q_memset( pcrs, 0, sizeof (crs_t) );
  5483. }
  5484. }
  5485. void CRS_InitAll() { for (int i = 0; i < CCRSS; i++) CRS_Init( &crss[i] ); }
  5486. void CRS_FreeAll() { for (int i = 0; i < CCRSS; i++) CRS_Free( &crss[i] ); }
  5487. // fstep is base pitch shift, ie: floating point step value, where 1.0 = +1 octave, 0.5 = -1 octave
  5488. // lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  5489. // fHz is modulation frequency in Hz
  5490. // depth is modulation depth, 0-1.0
  5491. // mix is mix of chorus and clean signal
  5492. #define CRS_DELAYMAX 100 // max milliseconds of sweepable delay
  5493. #define CRS_RAMPTIME 5 // milliseconds to ramp between new delay values
  5494. crs_t * CRS_Alloc( int lfotype, float fHz, float fdepth, float mix )
  5495. {
  5496. int i;
  5497. crs_t *pcrs;
  5498. dly_t *pdly;
  5499. mdy_t *pmdy;
  5500. lfo_t *plfo;
  5501. float ramptime;
  5502. int D;
  5503. // find free chorus slot
  5504. for ( i = 0; i < CCRSS; i++ )
  5505. {
  5506. if ( !crss[i].fused )
  5507. break;
  5508. }
  5509. if ( i == CCRSS )
  5510. {
  5511. DevMsg ("DSP: Warning, failed to allocate chorus.\n" );
  5512. return NULL;
  5513. }
  5514. pcrs = &crss[i];
  5515. CRS_Init ( pcrs );
  5516. D = fdepth * MSEC_TO_SAMPS(CRS_DELAYMAX); // sweep from 0 - n milliseconds
  5517. ramptime = (float) CRS_RAMPTIME / 1000.0; // # milliseconds to ramp between new values
  5518. pdly = DLY_Alloc ( D, 0, 1, DLY_LINEAR );
  5519. pmdy = MDY_Alloc ( pdly, ramptime, 0.0, 0.0, mix );
  5520. plfo = LFO_Alloc ( lfotype, fHz, false, 1.0 );
  5521. if ( !plfo || !pmdy )
  5522. {
  5523. LFO_Free ( plfo );
  5524. MDY_Free ( pmdy );
  5525. DevMsg ("DSP: Warning, failed to allocate lfo or mdy for chorus.\n" );
  5526. return NULL;
  5527. }
  5528. pcrs->pmdy = pmdy;
  5529. pcrs->plfo = plfo;
  5530. pcrs->fused = true;
  5531. return pcrs;
  5532. }
  5533. void CRS_Print( const crs_t & crs, int nIndentation )
  5534. {
  5535. DevMsg( "CRS_Print is not implemented\n" );
  5536. }
  5537. // return next chorused sample (modulated delay) mixed with input sample
  5538. inline int CRS_GetNext( crs_t *pcrs, int x )
  5539. {
  5540. int l;
  5541. int y;
  5542. // get current mod delay value
  5543. y = MDY_GetNext ( pcrs->pmdy, x );
  5544. // get next lfo value for modulation
  5545. // note: lfo must return 0 as first value
  5546. l = LFO_GetNext ( pcrs->plfo, x );
  5547. // if modulator has changed, change mdy
  5548. if ( l != pcrs->lfoprev )
  5549. {
  5550. // calculate new tap starts at D)
  5551. int D = pcrs->pmdy->pdly->D0;
  5552. int tap;
  5553. // lfo should always output values 0 <= l <= LFOMAX
  5554. if (l < 0)
  5555. l = 0;
  5556. tap = D - ((l * D) >> LFOBITS);
  5557. MDY_ChangeVal ( pcrs->pmdy, tap );
  5558. pcrs->lfoprev = l;
  5559. }
  5560. return y;
  5561. }
  5562. // batch version for performance
  5563. inline void CRS_GetNextN( crs_t *pcrs, portable_samplepair_t *pbuffer, int SampleCount, int op )
  5564. {
  5565. int count = SampleCount;
  5566. portable_samplepair_t *pb = pbuffer;
  5567. switch (op)
  5568. {
  5569. default:
  5570. case OP_LEFT:
  5571. while (count--)
  5572. {
  5573. pb->left = CRS_GetNext( pcrs, pb->left );
  5574. pb++;
  5575. }
  5576. return;
  5577. case OP_RIGHT:
  5578. while (count--)
  5579. {
  5580. pb->right = CRS_GetNext( pcrs, pb->right );
  5581. pb++;
  5582. }
  5583. return;
  5584. case OP_LEFT_DUPLICATE:
  5585. while (count--)
  5586. {
  5587. pb->left = pb->right = CRS_GetNext( pcrs, pb->left );
  5588. pb++;
  5589. }
  5590. return;
  5591. }
  5592. }
  5593. // parameter order
  5594. typedef enum {
  5595. crs_ilfotype,
  5596. crs_irate,
  5597. crs_idepth,
  5598. crs_imix,
  5599. crs_cparam
  5600. } crs_e;
  5601. // parameter ranges
  5602. prm_rng_t crs_rng[] = {
  5603. {crs_cparam, 0, 0}, // first entry is # of parameters
  5604. {crs_ilfotype, 0, LFO_MAX}, // lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  5605. {crs_irate, 0.0, 1000.0}, // rate is modulation frequency in Hz
  5606. {crs_idepth, 0.0, 1.0}, // depth is modulation depth, 0-1.0
  5607. {crs_imix, 0.0, 1.0}, // mix is mix of chorus and clean signal
  5608. };
  5609. // uses pitch, lfowav, rate, depth
  5610. crs_t * CRS_Params ( prc_t *pprc )
  5611. {
  5612. crs_t *pcrs;
  5613. pcrs = CRS_Alloc ( pprc->prm[crs_ilfotype], pprc->prm[crs_irate], pprc->prm[crs_idepth], pprc->prm[crs_imix] );
  5614. return pcrs;
  5615. }
  5616. inline void * CRS_VParams ( void *p )
  5617. {
  5618. PRC_CheckParams ( (prc_t *)p, crs_rng );
  5619. return (void *) CRS_Params ((prc_t *)p);
  5620. }
  5621. inline void CRS_Mod ( void *p, float v ) { return; }
  5622. ////////////////////////////////////////////////////
  5623. // amplifier - modulatable gain, distortion
  5624. ////////////////////////////////////////////////////
  5625. #if CHECK_VALUES_AFTER_REFACTORING
  5626. #define CAMPS 128
  5627. #else
  5628. #define CAMPS 64 // max number amps active
  5629. #endif
  5630. #define AMPSLEW 10 // milliseconds of slew time between gain changes
  5631. struct amp_t
  5632. {
  5633. bool fused;
  5634. int gain; // amplification 0-6.0 * PMAX
  5635. int gain_max; // original gain setting
  5636. int distmix; // 0-1.0 mix of distortion with clean * PMAX
  5637. int vfeed; // 0-1.0 feedback with distortion * PMAX
  5638. int vthresh; // amplitude of clipping threshold 0..32768
  5639. bool fchanging; // true if modulating to new amp value
  5640. float ramptime; // ramp 'glide' time - time in seconds to change between values
  5641. int mtime; // time in samples between amp changes. 0 implies no self-modulating
  5642. int mtimecur; // current time in samples until next amp change
  5643. int depth; // modulate amp from A to A - (A*depth) depth 0-1.0
  5644. bool brand; // if true, use random modulation otherwise alternate btwn max/min
  5645. rmp_t rmp_interp; // interpolation ramp 0...PMAX
  5646. };
  5647. amp_t amps[CAMPS];
  5648. void AMP_Init( amp_t *pamp ) { if (pamp) Q_memset( pamp, 0, sizeof (amp_t) ); };
  5649. void AMP_Free( amp_t *pamp )
  5650. {
  5651. if (pamp)
  5652. {
  5653. Q_memset( pamp, 0, sizeof (amp_t) );
  5654. }
  5655. }
  5656. void AMP_InitAll() { for (int i = 0; i < CAMPS; i++) AMP_Init( &amps[i] ); }
  5657. void AMP_FreeAll() { for (int i = 0; i < CAMPS; i++) AMP_Free( &amps[i] ); }
  5658. amp_t * AMP_Alloc( float gain, float vthresh, float distmix, float vfeed, float ramptime, float modtime, float depth, bool brand )
  5659. {
  5660. int i;
  5661. amp_t *pamp;
  5662. // find free amp slot
  5663. for ( i = 0; i < CAMPS; i++ )
  5664. {
  5665. if ( !amps[i].fused )
  5666. break;
  5667. }
  5668. if ( i == CAMPS )
  5669. {
  5670. DevMsg ("DSP: Warning, failed to allocate amp.\n" );
  5671. return NULL;
  5672. }
  5673. pamp = &amps[i];
  5674. AMP_Init ( pamp );
  5675. pamp->fused = true;
  5676. pamp->gain = gain * PMAX;
  5677. pamp->gain_max = gain * PMAX;
  5678. pamp->distmix = distmix * PMAX;
  5679. pamp->vfeed = vfeed * PMAX;
  5680. pamp->vthresh = vthresh * 32767.0;
  5681. // modrate, 0.01, 200.0}, // frequency at which amplitude values change to new random value. 0 is no self-modulation
  5682. // moddepth, 0.0, 1.0}, // how much amplitude changes (decreases) from current value (0-1.0)
  5683. // modglide, 0.01, 100.0}, // glide time between mapcur and ampnew in milliseconds
  5684. pamp->ramptime = ramptime;
  5685. pamp->mtime = SEC_TO_SAMPS(modtime);
  5686. pamp->mtimecur = pamp->mtime;
  5687. pamp->depth = depth * PMAX;
  5688. pamp->brand = brand;
  5689. return pamp;
  5690. }
  5691. void AMP_Print( const amp_t & crs, int nIndentation )
  5692. {
  5693. DevMsg( "AMP_Print is not implemented\n" );
  5694. }
  5695. // return next amplified sample
  5696. inline int AMP_GetNext( amp_t *pamp, int x )
  5697. {
  5698. int y = x;
  5699. int d;
  5700. // if distortion is on, add distortion, feedback
  5701. if ( pamp->vthresh < PMAX && pamp->distmix )
  5702. {
  5703. int vthresh = pamp->vthresh;
  5704. /* if ( pamp->vfeed > 0.0 )
  5705. {
  5706. // UNDONE: feedback
  5707. }
  5708. */
  5709. // clip distort
  5710. d = ( y > vthresh ? vthresh : ( y < -vthresh ? -vthresh : y));
  5711. // mix distorted with clean (1.0 = full distortion)
  5712. if ( pamp->distmix < PMAX )
  5713. y = y + (((d - y) * pamp->distmix ) >> PBITS);
  5714. else
  5715. y = d;
  5716. }
  5717. // get output for current gain value
  5718. int xout = (y * pamp->gain) >> PBITS;
  5719. if ( !pamp->fchanging && !pamp->mtime )
  5720. {
  5721. // if not modulating and not self modulating, return right away
  5722. return xout;
  5723. }
  5724. if (pamp->fchanging)
  5725. {
  5726. // modulating...
  5727. // get next gain value
  5728. pamp->gain = RMP_GetNext( &pamp->rmp_interp ); // 0...next gain
  5729. if ( RMP_HitEnd( &pamp->rmp_interp ) )
  5730. {
  5731. // done.
  5732. pamp->fchanging = false;
  5733. }
  5734. }
  5735. // if self-modulating and timer has expired, get next change
  5736. if ( pamp->mtime && !pamp->mtimecur-- )
  5737. {
  5738. pamp->mtimecur = pamp->mtime;
  5739. int gain_new;
  5740. int G1;
  5741. int G2 = pamp->gain_max;
  5742. // modulate between 0 and 100% of gain_max
  5743. G1 = pamp->gain_max - ((pamp->gain_max * pamp->depth) >> PBITS);
  5744. if (pamp->brand)
  5745. {
  5746. gain_new = LocalRandomInt( MIN(G1,G2), MAX(G1,G2) );
  5747. }
  5748. else
  5749. {
  5750. // alternate between min & max
  5751. gain_new = (pamp->gain == G1 ? G2 : G1);
  5752. }
  5753. // set up modulation to new value
  5754. pamp->fchanging = true;
  5755. // init gain ramp - always hit target
  5756. RMP_Init ( &pamp->rmp_interp, pamp->ramptime, pamp->gain, gain_new, false );
  5757. }
  5758. return xout;
  5759. }
  5760. // batch version for performance
  5761. inline void AMP_GetNextN( amp_t *pamp, portable_samplepair_t *pbuffer, int SampleCount, int op )
  5762. {
  5763. int count = SampleCount;
  5764. portable_samplepair_t *pb = pbuffer;
  5765. switch (op)
  5766. {
  5767. default:
  5768. case OP_LEFT:
  5769. while (count--)
  5770. {
  5771. pb->left = AMP_GetNext( pamp, pb->left );
  5772. pb++;
  5773. }
  5774. return;
  5775. case OP_RIGHT:
  5776. while (count--)
  5777. {
  5778. pb->right = AMP_GetNext( pamp, pb->right );
  5779. pb++;
  5780. }
  5781. return;
  5782. case OP_LEFT_DUPLICATE:
  5783. while (count--)
  5784. {
  5785. pb->left = pb->right = AMP_GetNext( pamp, pb->left );
  5786. pb++;
  5787. }
  5788. return;
  5789. }
  5790. }
  5791. inline void AMP_Mod( amp_t *pamp, float v )
  5792. {
  5793. }
  5794. // parameter order
  5795. typedef enum {
  5796. amp_gain,
  5797. amp_vthresh,
  5798. amp_distmix,
  5799. amp_vfeed,
  5800. amp_imodrate,
  5801. amp_imoddepth,
  5802. amp_imodglide,
  5803. amp_irand,
  5804. amp_cparam
  5805. } amp_e;
  5806. // parameter ranges
  5807. prm_rng_t amp_rng[] = {
  5808. {amp_cparam, 0, 0}, // first entry is # of parameters
  5809. {amp_gain, 0.0, 1000.0}, // amplification
  5810. {amp_vthresh, 0.0, 1.0}, // threshold for distortion (1.0 = no distortion)
  5811. {amp_distmix, 0.0, 1.0}, // mix of clean and distortion (1.0 = full distortion, 0.0 = full clean)
  5812. {amp_vfeed, 0.0, 1.0}, // distortion feedback
  5813. {amp_imodrate, 0.0, 200.0}, // frequency at which amplitude values change to new random value. 0 is no self-modulation
  5814. {amp_imoddepth, 0.0, 1.0}, // how much amplitude changes (decreases) from current value (0-1.0)
  5815. {amp_imodglide, 0.01, 100.0}, // glide time between mapcur and ampnew in milliseconds
  5816. {amp_irand, 0.0, 1.0}, // if 1, use random modulation otherwise alternate from max-min-max
  5817. };
  5818. amp_t * AMP_Params ( prc_t *pprc )
  5819. {
  5820. amp_t *pamp;
  5821. float ramptime = 0.0;
  5822. float modtime = 0.0;
  5823. float depth = 0.0;
  5824. float rand = pprc->prm[amp_irand];
  5825. bool brand;
  5826. if (pprc->prm[amp_imodrate] > 0.0)
  5827. {
  5828. ramptime = pprc->prm[amp_imodglide] / 1000.0; // get ramp time in seconds
  5829. modtime = 1.0 / MAX(pprc->prm[amp_imodrate], 0.01); // time between modulations in seconds
  5830. depth = pprc->prm[amp_imoddepth]; // depth of modulations 0-1.0
  5831. }
  5832. brand = rand > 0.0 ? 1 : 0;
  5833. pamp = AMP_Alloc ( pprc->prm[amp_gain], pprc->prm[amp_vthresh], pprc->prm[amp_distmix], pprc->prm[amp_vfeed],
  5834. ramptime, modtime, depth, brand );
  5835. return pamp;
  5836. }
  5837. inline void * AMP_VParams ( void *p )
  5838. {
  5839. PRC_CheckParams ( (prc_t *)p, amp_rng );
  5840. return (void *) AMP_Params ((prc_t *)p);
  5841. }
  5842. /////////////////
  5843. // NULL processor
  5844. /////////////////
  5845. struct nul_t
  5846. {
  5847. int type;
  5848. };
  5849. nul_t nuls[] = {0};
  5850. void NULL_Init ( nul_t *pnul ) { }
  5851. void NULL_InitAll( ) { }
  5852. void NULL_Free ( nul_t *pnul ) { }
  5853. void NULL_FreeAll ( ) { }
  5854. nul_t *NULL_Alloc ( ) { return &nuls[0]; }
  5855. inline int NULL_GetNext ( void *p, int x) { return x; }
  5856. inline void NULL_GetNextN( nul_t *pnul, portable_samplepair_t *pbuffer, int SampleCount, int op ) { return; }
  5857. inline void NULL_Mod ( void *p, float v ) { return; }
  5858. inline void * NULL_VParams ( void *p ) { return (void *) (&nuls[0]); }
  5859. //////////////////////////
  5860. // DSP processors presets - see dsp_presets.txt
  5861. //////////////////////////
  5862. // init array of processors - first store pfnParam, pfnGetNext and pfnFree functions for type,
  5863. // then call the pfnParam function to initialize each processor
  5864. // prcs - an array of prc structures, all with initialized params
  5865. // count - number of elements in the array
  5866. // returns false if failed to init one or more processors
  5867. bool PRC_InitAll( prc_t *prcs, int count )
  5868. {
  5869. int i;
  5870. prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
  5871. prc_GetNext_t pfnGetNext; // get next function
  5872. prc_GetNextN_t pfnGetNextN; // get next function, batch version
  5873. prc_Free_t pfnFree;
  5874. prc_Mod_t pfnMod;
  5875. bool fok = true;;
  5876. if ( count == 0 )
  5877. count = 1;
  5878. // set up pointers to XXX_Free, XXX_GetNext and XXX_Params functions
  5879. for (i = 0; i < count; i++)
  5880. {
  5881. switch (prcs[i].type)
  5882. {
  5883. default:
  5884. case PRC_NULL:
  5885. pfnFree = (prc_Free_t)NULL_Free;
  5886. pfnGetNext = (prc_GetNext_t)NULL_GetNext;
  5887. pfnGetNextN = (prc_GetNextN_t)NULL_GetNextN;
  5888. pfnParam = NULL_VParams;
  5889. pfnMod = (prc_Mod_t)NULL_Mod;
  5890. break;
  5891. case PRC_DLY:
  5892. pfnFree = (prc_Free_t)DLY_Free;
  5893. pfnGetNext = (prc_GetNext_t)DLY_GetNext;
  5894. pfnGetNextN = (prc_GetNextN_t)DLY_GetNextN;
  5895. pfnParam = DLY_VParams;
  5896. pfnMod = (prc_Mod_t)DLY_Mod;
  5897. break;
  5898. case PRC_RVA:
  5899. pfnFree = (prc_Free_t)RVA_Free;
  5900. pfnGetNext = (prc_GetNext_t)RVA_GetNext;
  5901. pfnGetNextN = (prc_GetNextN_t)RVA_GetNextN_Opt;
  5902. pfnParam = RVA_VParams;
  5903. pfnMod = (prc_Mod_t)RVA_Mod;
  5904. break;
  5905. case PRC_FLT:
  5906. pfnFree = (prc_Free_t)FLT_Free;
  5907. pfnGetNext = (prc_GetNext_t)FLT_GetNext;
  5908. pfnGetNextN = (prc_GetNextN_t)FLT_GetNextN;
  5909. pfnParam = FLT_VParams;
  5910. pfnMod = (prc_Mod_t)FLT_Mod;
  5911. break;
  5912. case PRC_CRS:
  5913. pfnFree = (prc_Free_t)CRS_Free;
  5914. pfnGetNext = (prc_GetNext_t)CRS_GetNext;
  5915. pfnGetNextN = (prc_GetNextN_t)CRS_GetNextN;
  5916. pfnParam = CRS_VParams;
  5917. pfnMod = (prc_Mod_t)CRS_Mod;
  5918. break;
  5919. case PRC_PTC:
  5920. pfnFree = (prc_Free_t)PTC_Free;
  5921. pfnGetNext = (prc_GetNext_t)PTC_GetNext;
  5922. pfnGetNextN = (prc_GetNextN_t)PTC_GetNextN;
  5923. pfnParam = PTC_VParams;
  5924. pfnMod = (prc_Mod_t)PTC_Mod;
  5925. break;
  5926. case PRC_ENV:
  5927. pfnFree = (prc_Free_t)ENV_Free;
  5928. pfnGetNext = (prc_GetNext_t)ENV_GetNext;
  5929. pfnGetNextN = (prc_GetNextN_t)ENV_GetNextN;
  5930. pfnParam = ENV_VParams;
  5931. pfnMod = (prc_Mod_t)ENV_Mod;
  5932. break;
  5933. case PRC_LFO:
  5934. pfnFree = (prc_Free_t)LFO_Free;
  5935. pfnGetNext = (prc_GetNext_t)LFO_GetNext;
  5936. pfnGetNextN = (prc_GetNextN_t)LFO_GetNextN;
  5937. pfnParam = LFO_VParams;
  5938. pfnMod = (prc_Mod_t)LFO_Mod;
  5939. break;
  5940. case PRC_EFO:
  5941. pfnFree = (prc_Free_t)EFO_Free;
  5942. pfnGetNext = (prc_GetNext_t)EFO_GetNext;
  5943. pfnGetNextN = (prc_GetNextN_t)EFO_GetNextN;
  5944. pfnParam = EFO_VParams;
  5945. pfnMod = (prc_Mod_t)EFO_Mod;
  5946. break;
  5947. case PRC_MDY:
  5948. pfnFree = (prc_Free_t)MDY_Free;
  5949. pfnGetNext = (prc_GetNext_t)MDY_GetNext;
  5950. pfnGetNextN = (prc_GetNextN_t)MDY_GetNextN;
  5951. pfnParam = MDY_VParams;
  5952. pfnMod = (prc_Mod_t)MDY_Mod;
  5953. break;
  5954. case PRC_DFR:
  5955. pfnFree = (prc_Free_t)DFR_Free;
  5956. pfnGetNext = (prc_GetNext_t)DFR_GetNext;
  5957. pfnGetNextN = (prc_GetNextN_t)DFR_GetNextN_Opt;
  5958. pfnParam = DFR_VParams;
  5959. pfnMod = (prc_Mod_t)DFR_Mod;
  5960. break;
  5961. case PRC_AMP:
  5962. pfnFree = (prc_Free_t)AMP_Free;
  5963. pfnGetNext = (prc_GetNext_t)AMP_GetNext;
  5964. pfnGetNextN = (prc_GetNextN_t)AMP_GetNextN;
  5965. pfnParam = AMP_VParams;
  5966. pfnMod = (prc_Mod_t)AMP_Mod;
  5967. break;
  5968. }
  5969. // set up function pointers
  5970. prcs[i].pfnParam = pfnParam;
  5971. prcs[i].pfnGetNext = pfnGetNext;
  5972. prcs[i].pfnGetNextN = pfnGetNextN;
  5973. prcs[i].pfnFree = pfnFree;
  5974. prcs[i].pfnMod = pfnMod;
  5975. // call param function, store pdata for the processor type
  5976. prcs[i].pdata = pfnParam ( (void *) (&prcs[i]) );
  5977. if ( !prcs[i].pdata )
  5978. fok = false;
  5979. }
  5980. return fok;
  5981. }
  5982. // free individual processor's data
  5983. void PRC_Free ( prc_t *pprc )
  5984. {
  5985. if ( pprc->pfnFree && pprc->pdata )
  5986. pprc->pfnFree ( pprc->pdata );
  5987. }
  5988. // free all processors for supplied array
  5989. // prcs - array of processors
  5990. // count - elements in array
  5991. void PRC_FreeAll ( prc_t *prcs, int count )
  5992. {
  5993. for (int i = 0; i < count; i++)
  5994. PRC_Free( &prcs[i] );
  5995. }
  5996. // get next value for processor - (usually called directly by PSET_GetNext)
  5997. inline int PRC_GetNext ( prc_t *pprc, int x )
  5998. {
  5999. return pprc->pfnGetNext ( pprc->pdata, x );
  6000. }
  6001. // automatic parameter range limiting
  6002. // force parameters between specified min/max in param_rng
  6003. void PRC_CheckParams ( prc_t *pprc, prm_rng_t *prng )
  6004. {
  6005. // first entry in param_rng is # of parameters
  6006. int cprm = prng[0].iprm;
  6007. for (int i = 0; i < cprm; i++)
  6008. {
  6009. // if parameter is 0.0, always allow it (this is 'off' for most params)
  6010. if ( pprc->prm[i] != 0.0 && (pprc->prm[i] > prng[i+1].hi || pprc->prm[i] < prng[i+1].lo) )
  6011. {
  6012. DevMsg ("DSP: Warning, clamping out of range parameter.\n" );
  6013. pprc->prm[i] = iclamp (pprc->prm[i], prng[i+1].lo, prng[i+1].hi);
  6014. }
  6015. }
  6016. }
  6017. void PRC_Print( const prc_t &prc, int nIndentation )
  6018. {
  6019. const char * pIndent = GetIndentationText( nIndentation );
  6020. DevMsg( "%sPRC: %p [Addr]\n", pIndent, &prc );
  6021. const char * pType = "Unknown";
  6022. // Use a switch case instead of a table as it is more resistant to change (and this code is not performance critical).
  6023. switch ( prc.type )
  6024. {
  6025. case PRC_NULL: pType = "NULL"; break;
  6026. case PRC_DLY: pType = "DLY - Simple feedback reverb"; break;
  6027. case PRC_RVA: pType = "RVA - Parallel reverbs"; break;
  6028. case PRC_FLT: pType = "FLT - Lowpass or highpass filter"; break;
  6029. case PRC_CRS: pType = "CRS - Chorus"; break;
  6030. case PRC_PTC: pType = "PTC - Pitch shifter"; break;
  6031. case PRC_ENV: pType = "ENV - Adsr envelope"; break;
  6032. case PRC_LFO: pType = "LFO"; break;
  6033. case PRC_EFO: pType = "EFO - Envelope follower"; break;
  6034. case PRC_MDY: pType = "MDY - Mod delay"; break;
  6035. case PRC_DFR: pType = "DFR - Diffusor - n series allpass delays"; break;
  6036. case PRC_AMP: pType = "AMP - Amplifier with distortion"; break;
  6037. }
  6038. DevMsg( "%sprm: ", pIndent );
  6039. for (int i = 0 ; i < CPRCPARAMS ; ++i )
  6040. {
  6041. DevMsg( "%f ", prc.prm[i] );
  6042. }
  6043. DevMsg( "\n" );
  6044. DevMsg( "%sType: %s -", pIndent, pType );
  6045. switch ( prc.type )
  6046. {
  6047. case PRC_DLY: DLY_Print( *(dly_t *)prc.pdata, nIndentation + 1 ); break;
  6048. case PRC_RVA: RVA_Print( *(rva_t *)prc.pdata, nIndentation + 1 ); break;
  6049. case PRC_FLT: FLT_Print( *(flt_t *)prc.pdata, nIndentation + 1 ); break;
  6050. case PRC_CRS: CRS_Print( *(crs_t *)prc.pdata, nIndentation + 1 ); break;
  6051. case PRC_PTC: PTC_Print( *(ptc_t *)prc.pdata, nIndentation + 1 ); break;
  6052. case PRC_ENV: ENV_Print( *(env_t *)prc.pdata, nIndentation + 1 ); break;
  6053. case PRC_LFO: LFO_Print( *(lfo_t *)prc.pdata, nIndentation + 1 ); break;
  6054. case PRC_EFO: EFO_Print( *(efo_t *)prc.pdata, nIndentation + 1 ); break;
  6055. case PRC_MDY: MDY_Print( *(mdy_t *)prc.pdata, nIndentation + 1 ); break;
  6056. case PRC_DFR: DFR_Print( *(dfr_t *)prc.pdata, nIndentation + 1 ); break;
  6057. case PRC_AMP: AMP_Print( *(amp_t *)prc.pdata, nIndentation + 1 ); break;
  6058. }
  6059. }
  6060. // DSP presets
  6061. // A dsp preset comprises one or more dsp processors in linear, parallel or feedback configuration
  6062. // preset configurations
  6063. //
  6064. #define PSET_SIMPLE 0
  6065. // x(n)--->P(0)--->y(n)
  6066. #define PSET_LINEAR 1
  6067. // x(n)--->P(0)-->P(1)-->...P(m)--->y(n)
  6068. #define PSET_PARALLEL2 5
  6069. // x(n)--->P(0)-->(+)-->y(n)
  6070. // ^
  6071. // |
  6072. // x(n)--->P(1)-----
  6073. #define PSET_PARALLEL4 6
  6074. // x(n)--->P(0)-->P(1)-->(+)-->y(n)
  6075. // ^
  6076. // |
  6077. // x(n)--->P(2)-->P(3)-----
  6078. #define PSET_PARALLEL5 7
  6079. // x(n)--->P(0)-->P(1)-->(+)-->P(4)-->y(n)
  6080. // ^
  6081. // |
  6082. // x(n)--->P(2)-->P(3)-----
  6083. #define PSET_FEEDBACK 8
  6084. // x(n)-P(0)--(+)-->P(1)-->P(2)---->y(n)
  6085. // ^ |
  6086. // | v
  6087. // -----P(4)<--P(3)--
  6088. #define PSET_FEEDBACK3 9
  6089. // x(n)---(+)-->P(0)--------->y(n)
  6090. // ^ |
  6091. // | v
  6092. // -----P(2)<--P(1)--
  6093. #define PSET_FEEDBACK4 10
  6094. // x(n)---(+)-->P(0)-------->P(3)--->y(n)
  6095. // ^ |
  6096. // | v
  6097. // ---P(2)<--P(1)--
  6098. #define PSET_MOD 11
  6099. //
  6100. // x(n)------>P(1)--P(2)--P(3)--->y(n)
  6101. // ^
  6102. // x(n)------>P(0)....:
  6103. #define PSET_MOD2 12
  6104. //
  6105. // x(n)-------P(1)-->y(n)
  6106. // ^
  6107. // x(n)-->P(0)..:
  6108. #define PSET_MOD3 13
  6109. //
  6110. // x(n)-------P(1)-->P(2)-->y(n)
  6111. // ^
  6112. // x(n)-->P(0)..:
  6113. #if CHECK_VALUES_AFTER_REFACTORING
  6114. #define CPSETS 128
  6115. #else
  6116. #define CPSETS 64 // max number of presets simultaneously active
  6117. #endif
  6118. #define CPSET_PRCS 5 // max # of processors per dsp preset
  6119. #define CPSET_STATES (CPSET_PRCS+3) // # of internal states
  6120. // NOTE: do not reorder members of pset_t - g_psettemplates relies on it!!!
  6121. struct pset_t
  6122. {
  6123. int type; // preset configuration type
  6124. int cprcs; // number of processors for this preset
  6125. prc_t prcs[CPSET_PRCS]; // processor preset data
  6126. float mix_min; // min dsp mix at close range
  6127. float mix_max; // max dsp mix at long range
  6128. float db_min; // if sndlvl of a new sound is < db_min, reduce mix_min/max by db_mixdrop
  6129. float db_mixdrop; // reduce mix_min/max by n% if sndlvl of new sound less than db_min
  6130. float duration; // if > 0, duration of preset in seconds (duration 0 = infinite)
  6131. float fade; // fade out time, exponential fade
  6132. int csamp_duration; // duration counter # samples
  6133. int w[CPSET_STATES]; // internal states
  6134. int fused;
  6135. uint nLastUpdatedTimeInMilliseconds;
  6136. };
  6137. pset_t psets[CPSETS];
  6138. pset_t *g_psettemplates = NULL;
  6139. int g_cpsettemplates = 0;
  6140. // returns true if preset will expire after duration
  6141. bool PSET_IsOneShot( pset_t *ppset )
  6142. {
  6143. if ( ppset == NULL )
  6144. {
  6145. return false;
  6146. }
  6147. return ppset->duration > 0.0;
  6148. }
  6149. // return true if preset is no longer active - duration has expired
  6150. bool PSET_HasExpired( pset_t *ppset )
  6151. {
  6152. if (!PSET_IsOneShot( ppset ))
  6153. return false;
  6154. return ppset->csamp_duration <= 0;
  6155. }
  6156. // if preset is oneshot, update duration counter by SampleCount samples
  6157. void PSET_UpdateDuration( pset_t *ppset, int SampleCount )
  6158. {
  6159. if ( PSET_IsOneShot( ppset ) )
  6160. {
  6161. // if oneshot preset and not expired, decrement sample count
  6162. if (ppset->csamp_duration > 0)
  6163. ppset->csamp_duration -= SampleCount;
  6164. }
  6165. }
  6166. // A dsp processor (prc) performs a single-sample function, such as pitch shift, delay, reverb, filter
  6167. // init a preset - just clear state array
  6168. void PSET_Init( pset_t *ppset )
  6169. {
  6170. // clear state array
  6171. if (ppset)
  6172. Q_memset( ppset->w, 0, sizeof (int) * (CPSET_STATES) );
  6173. }
  6174. // clear runtime slots
  6175. void PSET_InitAll( void )
  6176. {
  6177. for (int i = 0; i < CPSETS; i++)
  6178. Q_memset( &psets[i], 0, sizeof(pset_t));
  6179. }
  6180. // free the preset - free all processors
  6181. void PSET_Free( pset_t *ppset )
  6182. {
  6183. if (ppset)
  6184. {
  6185. // free processors
  6186. PRC_FreeAll ( ppset->prcs, ppset->cprcs );
  6187. // clear
  6188. Q_memset( ppset, 0, sizeof (pset_t));
  6189. }
  6190. }
  6191. void PSET_FreeAll() { for (int i = 0; i < CPSETS; i++) PSET_Free( &psets[i] ); };
  6192. // return preset struct, given index into preset template array
  6193. // NOTE: should not ever be more than 2 or 3 of these active simultaneously
  6194. pset_t * PSET_Alloc ( int ipsettemplate )
  6195. {
  6196. pset_t *ppset;
  6197. bool fok;
  6198. // don't excede array bounds
  6199. if ( ipsettemplate >= g_cpsettemplates)
  6200. ipsettemplate = 0;
  6201. // find free slot
  6202. int i = 0;
  6203. for (; i < CPSETS; i++)
  6204. {
  6205. if ( !psets[i].fused )
  6206. break;
  6207. }
  6208. if ( i == CPSETS )
  6209. return NULL;
  6210. if (das_debug.GetInt())
  6211. {
  6212. int j = 0;
  6213. for (int i = 0; i < CPSETS; i++)
  6214. {
  6215. if ( psets[i].fused )
  6216. j++;
  6217. }
  6218. DevMsg("total preset slots used: %d \n", j);
  6219. }
  6220. ppset = &psets[i];
  6221. // clear preset
  6222. Q_memset(ppset, 0, sizeof(pset_t));
  6223. // copy template into preset
  6224. *ppset = g_psettemplates[ipsettemplate];
  6225. ppset->fused = true;
  6226. // clear state array
  6227. PSET_Init ( ppset );
  6228. // init all processors, set up processor function pointers
  6229. fok = PRC_InitAll( ppset->prcs, ppset->cprcs );
  6230. if ( !fok )
  6231. {
  6232. // failed to init one or more processors
  6233. Warning( "Sound DSP: preset failed to init.\n");
  6234. PRC_FreeAll ( ppset->prcs, ppset->cprcs );
  6235. return NULL;
  6236. }
  6237. // if preset has duration, setup duration sample counter
  6238. if ( PSET_IsOneShot( ppset ) )
  6239. {
  6240. ppset->csamp_duration = SEC_TO_SAMPS( ppset->duration );
  6241. }
  6242. return ppset;
  6243. }
  6244. void PSET_Print( const pset_t & pset, int nIndentation )
  6245. {
  6246. const char * pIndent = GetIndentationText( nIndentation );
  6247. DevMsg( "%sPSET: %p [Addr]\n", pIndent, &pset );
  6248. DevMsg( "%sType: %d\n", pIndent, pset.type );
  6249. DevMsg( "%scprcs: %d\n", pIndent, pset.cprcs );
  6250. for ( int i = 0 ; i < pset.cprcs ; ++i )
  6251. {
  6252. PRC_Print( pset.prcs[i], nIndentation + 1 );
  6253. }
  6254. DevMsg( "%smix_min: %f\n", pIndent, pset.mix_min );
  6255. DevMsg( "%smix_max: %f\n", pIndent, pset.mix_max );
  6256. DevMsg( "%sdb_min: %f\n", pIndent, pset.db_min );
  6257. DevMsg( "%sdb_mixdrop: %f\n", pIndent, pset.db_mixdrop );
  6258. DevMsg( "%sduration: %f\n", pIndent, pset.duration );
  6259. DevMsg( "%sfade: %f\n", pIndent, pset.fade );
  6260. DevMsg( "%scsamp_duration: %d\n", pIndent, pset.csamp_duration );
  6261. DevMsg( "%sw: ", pIndent );
  6262. for (int i = 0 ; i < CPSET_STATES ; ++i )
  6263. {
  6264. DevMsg( "%d ", pset.w[i] );
  6265. }
  6266. DevMsg( "\n" );
  6267. DevMsg("%sfused: %d\n", pIndent, pset.fused );
  6268. }
  6269. // batch version of PSET_GetNext for linear array of processors. For performance.
  6270. // ppset - preset array
  6271. // pbuffer - input sample data
  6272. // SampleCount - size of input buffer
  6273. // OP: OP_LEFT - process left channel in place
  6274. // OP_RIGHT - process right channel in place
  6275. // OP_LEFT_DUPLICATe - process left channel, duplicate into right
  6276. inline void PSET_GetNextN( pset_t *ppset, portable_samplepair_t *pbuffer, int SampleCount, int op )
  6277. {
  6278. portable_samplepair_t *pbf = pbuffer;
  6279. prc_t *pprc;
  6280. int count = ppset->cprcs;
  6281. switch ( ppset->type )
  6282. {
  6283. default:
  6284. case PSET_SIMPLE:
  6285. {
  6286. // x(n)--->P(0)--->y(n)
  6287. ppset->prcs[0].pfnGetNextN (ppset->prcs[0].pdata, pbf, SampleCount, op);
  6288. return;
  6289. }
  6290. case PSET_LINEAR:
  6291. {
  6292. // w0 w1 w2
  6293. // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
  6294. // w0 w1 w2 w3 w4 w5
  6295. // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
  6296. // call batch processors in sequence - no internal state for batch processing
  6297. // point to first processor
  6298. pprc = &ppset->prcs[0];
  6299. for (int i = 0; i < count; i++)
  6300. {
  6301. pprc->pfnGetNextN (pprc->pdata, pbf, SampleCount, op);
  6302. pprc++;
  6303. }
  6304. return;
  6305. }
  6306. }
  6307. }
  6308. // Get next sample from this preset. called once for every sample in buffer
  6309. // ppset is pointer to preset
  6310. // x is input sample
  6311. inline int PSET_GetNext ( pset_t *ppset, int x )
  6312. {
  6313. // pset_simple and pset_linear have no internal state:
  6314. // this is REQUIRED for all presets that have a batch getnextN equivalent!
  6315. if ( ppset->type == PSET_SIMPLE )
  6316. {
  6317. // x(n)--->P(0)--->y(n)
  6318. return ppset->prcs[0].pfnGetNext (ppset->prcs[0].pdata, x);
  6319. }
  6320. prc_t *pprc;
  6321. int count = ppset->cprcs;
  6322. if ( ppset->type == PSET_LINEAR )
  6323. {
  6324. int y = x;
  6325. // w0 w1 w2
  6326. // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
  6327. // w0 w1 w2 w3 w4 w5
  6328. // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
  6329. // call processors in reverse order, from count to 1
  6330. //for (int i = count; i > 0; i--, pprc--)
  6331. // w[i] = pprc->pfnGetNext (pprc->pdata, w[i-1]);
  6332. // return w[count];
  6333. // point to first processor, update sequentially, no state preserved
  6334. pprc = &ppset->prcs[0];
  6335. switch (count)
  6336. {
  6337. default:
  6338. case 5:
  6339. y = pprc->pfnGetNext (pprc->pdata, y);
  6340. pprc++;
  6341. case 4:
  6342. y = pprc->pfnGetNext (pprc->pdata, y);
  6343. pprc++;
  6344. case 3:
  6345. y = pprc->pfnGetNext (pprc->pdata, y);
  6346. pprc++;
  6347. case 2:
  6348. y = pprc->pfnGetNext (pprc->pdata, y);
  6349. pprc++;
  6350. case 1:
  6351. case 0:
  6352. y = pprc->pfnGetNext (pprc->pdata, y);
  6353. }
  6354. return y;
  6355. }
  6356. // all other preset types have internal state:
  6357. // initialize 0'th element of state array
  6358. int *w = ppset->w;
  6359. w[0] = x;
  6360. switch ( ppset->type )
  6361. {
  6362. default:
  6363. case PSET_PARALLEL2:
  6364. { // w0 w1 w3
  6365. // x(n)--->P(0)-->(+)-->y(n)
  6366. // ^
  6367. // w0 w2 |
  6368. // x(n)--->P(1)-----
  6369. pprc = &ppset->prcs[0];
  6370. w[3] = w[1] + w[2];
  6371. w[1] = pprc->pfnGetNext( pprc->pdata, w[0] );
  6372. pprc++;
  6373. w[2] = pprc->pfnGetNext( pprc->pdata, w[0] );
  6374. return w[3];
  6375. }
  6376. case PSET_PARALLEL4:
  6377. { // w0 w1 w2 w5
  6378. // x(n)--->P(0)-->P(1)-->(+)-->y(n)
  6379. // ^
  6380. // w0 w3 w4 |
  6381. // x(n)--->P(2)-->P(3)-----
  6382. pprc = &ppset->prcs[0];
  6383. w[5] = w[2] + w[4];
  6384. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  6385. w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  6386. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  6387. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
  6388. return w[5];
  6389. }
  6390. case PSET_PARALLEL5:
  6391. { // w0 w1 w2 w5 w6
  6392. // x(n)--->P(0)-->P(1)-->(+)--P(4)-->y(n)
  6393. // ^
  6394. // w0 w3 w4 |
  6395. // x(n)--->P(2)-->P(3)-----
  6396. pprc = &ppset->prcs[0];
  6397. w[5] = w[2] + w[4];
  6398. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  6399. w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  6400. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  6401. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
  6402. return pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
  6403. }
  6404. case PSET_FEEDBACK:
  6405. {
  6406. // w0 w1 w2 w3 w4 w7
  6407. // x(n)-P(0)--(+)-->P(1)-->P(2)-->---->y(n)
  6408. // ^ |
  6409. // | w6 w5 v
  6410. // -----P(4)<--P(3)--
  6411. pprc = &ppset->prcs[0];
  6412. // start with adders
  6413. w[2] = w[1] + w[6];
  6414. // evaluate in reverse order
  6415. w[6] = pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
  6416. w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[4] );
  6417. w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  6418. w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  6419. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  6420. return w[4];
  6421. }
  6422. case PSET_FEEDBACK3:
  6423. {
  6424. // w0 w1 w2
  6425. // x(n)---(+)-->P(0)--------->y(n)
  6426. // ^ |
  6427. // | w4 w3 v
  6428. // -----P(2)<--P(1)--
  6429. pprc = &ppset->prcs[0];
  6430. // start with adders
  6431. w[1] = w[0] + w[4];
  6432. // evaluate in reverse order
  6433. w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  6434. w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  6435. w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
  6436. return w[2];
  6437. }
  6438. case PSET_FEEDBACK4:
  6439. {
  6440. // w0 w1 w2 w5
  6441. // x(n)---(+)-->P(0)-------->P(3)--->y(n)
  6442. // ^ |
  6443. // | w4 w3 v
  6444. // ---P(2)<--P(1)--
  6445. pprc = &ppset->prcs[0];
  6446. // start with adders
  6447. w[1] = w[0] + w[4];
  6448. // evaluate in reverse order
  6449. w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[2] );
  6450. w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  6451. w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  6452. w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
  6453. return w[2];
  6454. }
  6455. case PSET_MOD:
  6456. {
  6457. // w0 w1 w3 w4
  6458. // x(n)------>P(1)--P(2)--P(3)--->y(n)
  6459. // w0 w2 ^
  6460. // x(n)------>P(0)....:
  6461. pprc = &ppset->prcs[0];
  6462. w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  6463. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[1] );
  6464. // modulate processor 2
  6465. pprc[2].pfnMod( pprc[2].pdata, ((float)w[2] / (float)PMAX));
  6466. // get modulator output
  6467. w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  6468. w[1] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  6469. return w[4];
  6470. }
  6471. case PSET_MOD2:
  6472. {
  6473. // w0 w2
  6474. // x(n)---------P(1)-->y(n)
  6475. // w0 w1 ^
  6476. // x(n)-->P(0)....:
  6477. pprc = &ppset->prcs[0];
  6478. // modulate processor 1
  6479. pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
  6480. // get modulator output
  6481. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  6482. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  6483. return w[2];
  6484. }
  6485. case PSET_MOD3:
  6486. {
  6487. // w0 w2 w3
  6488. // x(n)----------P(1)-->P(2)-->y(n)
  6489. // w0 w1 ^
  6490. // x(n)-->P(0).....:
  6491. pprc = &ppset->prcs[0];
  6492. w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[2] );
  6493. // modulate processor 1
  6494. pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
  6495. // get modulator output
  6496. w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  6497. w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  6498. return w[2];
  6499. }
  6500. }
  6501. }
  6502. /////////////
  6503. // DSP system
  6504. /////////////
  6505. // Main interface
  6506. // Whenever the preset # changes on any of these processors, the old processor is faded out, new is faded in.
  6507. // dsp_chan is optionally set when a sound is played - a preset is sent with the start_static/dynamic sound.
  6508. //
  6509. // sound1---->dsp_chan--> -------------(+)---->dsp_water--->dsp_player--->out
  6510. // sound2---->dsp_chan--> | |
  6511. // sound3---------------> ----dsp_room---
  6512. // | |
  6513. // --dsp_indirect-
  6514. // dsp_room - set this cvar to a preset # to change the room dsp. room fx are more prevalent farther from player.
  6515. // use: when player moves into a new room, all sounds played in room take on its reverberant character
  6516. // dsp_water - set this cvar (once) to a preset # for serial underwater sound.
  6517. // use: when player goes under water, all sounds pass through this dsp (such as low pass filter)
  6518. // dsp_player - set this cvar to a preset # to cause all sounds to run through the effect (serial, in-line).
  6519. // use: player is deafened, player fires special weapon, player is hit by special weapon.
  6520. // dsp_facingaway- set this cvar to a preset # appropriate for sounds which are played facing away from player (weapon,voice)
  6521. //
  6522. // dsp_spatial - set by system to create modulated spatial delays for left/right/front/back ears - delay value
  6523. // modulates by distance to nearest l/r surface in world
  6524. // Dsp presets
  6525. #ifdef PORTAL2
  6526. ConVar dsp_room ("dsp_room", "1", FCVAR_DEMO ); // room dsp preset - sounds more distant from player (1ch)
  6527. #else
  6528. ConVar dsp_room ("dsp_room", "0", FCVAR_DEMO ); // room dsp preset - sounds more distant from player (1ch)
  6529. #endif
  6530. ConVar dsp_water ("dsp_water", "14", FCVAR_DEMO ); // "14" underwater dsp preset - sound when underwater (1-2ch)
  6531. static int dsp_player_value = 0;
  6532. static void dsp_player_changed( IConVar *pConVar, const char *pOldValue, float flOldValue )
  6533. {
  6534. #ifndef DEDICATED
  6535. CClientState &cl = GetBaseLocalClient();
  6536. if ( cl.ishltv || !cl.IsConnected() )
  6537. #endif
  6538. {
  6539. ConVarRef var( pConVar );
  6540. dsp_player_value = var.GetInt();
  6541. }
  6542. // When connected to the server sync up convar value only via server message
  6543. }
  6544. int dsp_player_get()
  6545. {
  6546. return dsp_player_value;
  6547. }
  6548. void dsp_player_set( int val )
  6549. {
  6550. extern ConVar dsp_player;
  6551. dsp_player.SetValue( val );
  6552. dsp_player_value = val;
  6553. }
  6554. ConVar dsp_player ("dsp_player", "0", FCVAR_DEMO | FCVAR_SERVER_CAN_EXECUTE | FCVAR_RELEASE, "", dsp_player_changed ); // dsp on player - sound when player hit by special device (1-2ch)
  6555. ConVar dsp_facingaway ("dsp_facingaway", "0", FCVAR_DEMO ); // "30" sounds that face away from player (weapons, voice) (1-4ch)
  6556. ConVar dsp_speaker ("dsp_speaker", "50", FCVAR_DEMO ); // "50" small distorted speaker sound (1ch)
  6557. ConVar dsp_spatial ("dsp_spatial", "40", FCVAR_DEMO ); // spatial delays for l/r front/rear ears
  6558. ConVar dsp_automatic ("dsp_automatic", "0", FCVAR_DEMO ); // automatic room type detection. if non zero, replaces dsp_room
  6559. int ipset_room_prev;
  6560. int ipset_water_prev;
  6561. int ipset_player_prev;
  6562. int ipset_facingaway_prev;
  6563. int ipset_speaker_prev;
  6564. int ipset_spatial_prev;
  6565. int ipset_automatic_prev;
  6566. // legacy room_type support
  6567. ConVar dsp_room_type ( "room_type", "0", FCVAR_DEMO );
  6568. int ipset_room_typeprev;
  6569. // DSP processors
  6570. int idsp_room;
  6571. int idsp_water;
  6572. int idsp_player;
  6573. int idsp_facingaway;
  6574. int idsp_speaker;
  6575. int idsp_spatial;
  6576. int idsp_automatic;
  6577. ConVar dsp_off ("dsp_off", "0", FCVAR_CHEAT ); // set to 1 to disable all dsp processing
  6578. ConVar dsp_slow_cpu ("dsp_slow_cpu", "0", FCVAR_CHEAT ); // set to 1 if cpu bound - ie: does not process dsp_room fx
  6579. ConVar snd_profile ("snd_profile", "0", FCVAR_DEMO ); // 1 - profile dsp, 2 - mix, 3 - load sound, 4 - all sound
  6580. ConVar dsp_volume ("dsp_volume", "0.8", FCVAR_CHEAT ); // 0.0 - 2.0; master dsp volume control
  6581. ConVar dsp_vol_5ch ("dsp_vol_5ch", "0.5", FCVAR_DEMO ); // 0.0 - 1.0; attenuate master dsp volume for 5ch surround
  6582. ConVar dsp_vol_4ch ("dsp_vol_4ch", "0.5", FCVAR_DEMO ); // 0.0 - 1.0; attenuate master dsp volume for 4ch surround
  6583. ConVar dsp_vol_2ch ("dsp_vol_2ch", "1.0", FCVAR_DEMO ); // 0.0 - 1.0; attenuate master dsp volume for 2ch surround
  6584. ConVar dsp_enhance_stereo("dsp_enhance_stereo", "0", FCVAR_ARCHIVE ); // 1) use dsp_spatial delays on all reverb channels
  6585. // DSP preset executor
  6586. #if CHECK_VALUES_AFTER_REFACTORING
  6587. #define CDSPS 64
  6588. #else
  6589. #define CDSPS 32 // max number dsp executors active
  6590. #endif
  6591. #define DSPCHANMAX 5 // max number of channels dsp can process (allocs a separate processor for each channel)
  6592. struct dsp_t
  6593. {
  6594. bool fused;
  6595. bool bEnabled;
  6596. int cchan; // 1-5 channels, ie: mono, FrontLeft, FrontRight, RearLeft, RearRight, FrontCenter
  6597. pset_t *ppset[DSPCHANMAX]; // current preset (1-5 channels)
  6598. int ipset; // current ipreset
  6599. pset_t *ppsetprev[DSPCHANMAX]; // previous preset (1-5 channels)
  6600. int ipsetprev; // previous ipreset
  6601. float xfade; // crossfade time between previous preset and new
  6602. float xfade_default; // default xfade value, set in DSP_Alloc
  6603. bool bexpfade; // true if exponential crossfade
  6604. int ipsetsav_oneshot; // previous preset before one-shot preset was set
  6605. rmp_t xramp; // crossfade ramp
  6606. };
  6607. dsp_t dsps[CDSPS];
  6608. void DSP_Init( int idsp )
  6609. {
  6610. dsp_t *pdsp;
  6611. Assert( idsp < CDSPS );
  6612. if (idsp < 0 || idsp >= CDSPS)
  6613. return;
  6614. pdsp = &dsps[idsp];
  6615. Q_memset( pdsp, 0, sizeof (dsp_t) );
  6616. }
  6617. void DSP_Free( int idsp )
  6618. {
  6619. dsp_t *pdsp;
  6620. Assert( idsp < CDSPS );
  6621. if (idsp < 0 || idsp >= CDSPS)
  6622. return;
  6623. pdsp = &dsps[idsp];
  6624. for (int i = 0; i < pdsp->cchan; i++)
  6625. {
  6626. if ( pdsp->ppset[i] )
  6627. PSET_Free( pdsp->ppset[i] );
  6628. if ( pdsp->ppsetprev[i] )
  6629. PSET_Free( pdsp->ppsetprev[i] );
  6630. }
  6631. Q_memset( pdsp, 0, sizeof (dsp_t) );
  6632. }
  6633. // Init all dsp processors - called once, during engine startup
  6634. void DSP_InitAll ( bool bLoadPresetFile )
  6635. {
  6636. // only load template file on engine startup
  6637. if ( bLoadPresetFile )
  6638. DSP_LoadPresetFile();
  6639. // order is important, don't rearange.
  6640. FLT_InitAll();
  6641. DLY_InitAll();
  6642. RVA_InitAll();
  6643. LFOWAV_InitAll();
  6644. LFO_InitAll();
  6645. CRS_InitAll();
  6646. PTC_InitAll();
  6647. ENV_InitAll();
  6648. EFO_InitAll();
  6649. MDY_InitAll();
  6650. AMP_InitAll();
  6651. PSET_InitAll();
  6652. for (int idsp = 0; idsp < CDSPS; idsp++)
  6653. DSP_Init( idsp );
  6654. }
  6655. // free all resources associated with dsp - called once, during engine shutdown
  6656. void DSP_FreeAll (void)
  6657. {
  6658. // order is important, don't rearange.
  6659. for (int idsp = 0; idsp < CDSPS; idsp++)
  6660. DSP_Free( idsp );
  6661. AMP_FreeAll();
  6662. MDY_FreeAll();
  6663. EFO_FreeAll();
  6664. ENV_FreeAll();
  6665. PTC_FreeAll();
  6666. CRS_FreeAll();
  6667. LFO_FreeAll();
  6668. LFOWAV_FreeAll();
  6669. RVA_FreeAll();
  6670. DLY_FreeAll();
  6671. FLT_FreeAll();
  6672. }
  6673. // allocate a new dsp processor chain, kill the old processor. Called during dsp init only.
  6674. // ipset is new preset
  6675. // xfade is crossfade time when switching between presets (milliseconds)
  6676. // cchan is how many simultaneous preset channels to allocate (1-4)
  6677. // return index to new dsp
  6678. int DSP_Alloc( int ipset, float xfade, int cchan )
  6679. {
  6680. dsp_t *pdsp;
  6681. int i;
  6682. int idsp;
  6683. int cchans = iclamp( cchan, 1, DSPCHANMAX);
  6684. // find free slot
  6685. for ( idsp = 0; idsp < CDSPS; idsp++ )
  6686. {
  6687. if ( !dsps[idsp].fused )
  6688. break;
  6689. }
  6690. if ( idsp >= CDSPS )
  6691. return -1;
  6692. pdsp = &dsps[idsp];
  6693. DSP_Init ( idsp );
  6694. pdsp->fused = true;
  6695. pdsp->bEnabled = true;
  6696. pdsp->cchan = cchans;
  6697. // allocate a preset processor for each channel
  6698. pdsp->ipset = ipset;
  6699. pdsp->ipsetprev = 0;
  6700. pdsp->ipsetsav_oneshot = 0;
  6701. for (i = 0; i < pdsp->cchan; i++)
  6702. {
  6703. pdsp->ppset[i] = ( pdsp->ipset != 0 ) ? PSET_Alloc ( ipset ) : NULL; // Allocate a preset only if it is meaningful
  6704. // This will also remove ambiguities where ipset is zero, but the pointer is not NULL
  6705. pdsp->ppsetprev[i] = NULL;
  6706. }
  6707. // set up crossfade time in seconds
  6708. pdsp->xfade = xfade / 1000.0;
  6709. pdsp->xfade_default = pdsp->xfade;
  6710. RMP_SetEnd(&pdsp->xramp);
  6711. return idsp;
  6712. }
  6713. // call modulation function of specified processor within dsp preset
  6714. // idsp - dsp preset
  6715. // channel - channel 1-5 (l,r,rl,rr,fc)
  6716. // iproc - which processor to change (normally 0)
  6717. // value - new parameter value for processor
  6718. // NOTE: routine returns with no result or error if any parameter is invalid.
  6719. void DSP_ChangePresetValue( int idsp, int channel, int iproc, float value )
  6720. {
  6721. dsp_t *pdsp;
  6722. pset_t *ppset; // preset
  6723. prc_Mod_t pfnMod; // modulation function
  6724. if (idsp < 0 || idsp >= CDSPS)
  6725. return;
  6726. if (channel >= DSPCHANMAX)
  6727. return;
  6728. if (iproc >= CPSET_PRCS)
  6729. return;
  6730. // get ptr to processor preset
  6731. pdsp = &dsps[idsp];
  6732. // assert that this dsp processor has enough separate channels
  6733. Assert(channel <= pdsp->cchan);
  6734. ppset = pdsp->ppset[channel];
  6735. if (!ppset)
  6736. return;
  6737. // get ptr to modulation function
  6738. pfnMod = ppset->prcs[iproc].pfnMod;
  6739. if (!pfnMod)
  6740. return;
  6741. // call modulation function with new value
  6742. pfnMod (ppset->prcs[iproc].pdata, value);
  6743. }
  6744. void DSP_Print( const dsp_t & dsp, int nIndentation )
  6745. {
  6746. const char * pIndent = GetIndentationText( nIndentation );
  6747. DevMsg( "%sDSP: %p [Addr]\n", pIndent, &dsp );
  6748. DevMsg( "%sfused: %s\n", pIndent, dsp.fused ? "True" : "False" );
  6749. DevMsg( "%sbEnabled: %s\n", pIndent, dsp.bEnabled ? "True" : "False" );
  6750. DevMsg( "%scchan: %d\n", pIndent, dsp.cchan );
  6751. DevMsg( "%sCurrent preset: %d\n", pIndent, dsp.ipset );
  6752. for (int i = 0 ; i < DSPCHANMAX ; ++i )
  6753. {
  6754. pset_t * pPreset = dsp.ppset[i];
  6755. DevMsg( "%sPSET[%d]: ", pIndent, i );
  6756. if ( pPreset == NULL )
  6757. {
  6758. DevMsg( "None\n" );
  6759. continue;
  6760. }
  6761. PSET_Print( *pPreset, nIndentation + 1 );
  6762. }
  6763. DevMsg( "%sPrevious preset: %d\n", pIndent, dsp.ipsetprev );
  6764. for (int i = 0 ; i < DSPCHANMAX ; ++i )
  6765. {
  6766. pset_t * pPreset = dsp.ppsetprev[i];
  6767. DevMsg( "%sPSET[%d]: ", pIndent, i );
  6768. if ( pPreset == NULL )
  6769. {
  6770. DevMsg( "None\n" );
  6771. continue;
  6772. }
  6773. PSET_Print( *pPreset, nIndentation + 1 );
  6774. }
  6775. DevMsg( "%sxfade: %f\n", pIndent, dsp.xfade );
  6776. DevMsg( "%sxfade default: %f\n", pIndent, dsp.xfade_default );
  6777. DevMsg( "%sbexpfade: %s\n", pIndent, dsp.bexpfade ? "True" : "False" );
  6778. RMP_Print( dsp.xramp, nIndentation + 1 );
  6779. }
  6780. #define DSP_AUTOMATIC 1 // corresponds to Generic preset
  6781. // if dsp_room == DSP_AUTOMATIC, then use dsp_automatic value for dsp
  6782. // any subsequent reset of dsp_room will disable automatic room detection.
  6783. // return true if automatic room detection is enabled
  6784. bool DSP_CheckDspAutoEnabled( void )
  6785. {
  6786. return (dsp_room.GetInt() == DSP_AUTOMATIC);
  6787. }
  6788. // set dsp_automatic preset, used in place of dsp_room when automatic room detection enabled
  6789. void DSP_SetDspAuto( int dsp_preset )
  6790. {
  6791. // set dsp_preset into dsp_automatic
  6792. dsp_automatic.SetValue( dsp_preset );
  6793. }
  6794. // wrapper on dsp_room GetInt so that dsp_automatic can override
  6795. int dsp_room_GetInt ( void )
  6796. {
  6797. // if dsp_automatic is not enabled, get room
  6798. if (! DSP_CheckDspAutoEnabled())
  6799. return dsp_room.GetInt();
  6800. // automatic room detection is on, get dsp_automatic instead of dsp_room
  6801. return dsp_automatic.GetInt();
  6802. }
  6803. // wrapper on idsp_room preset so that idsp_automatic can override
  6804. int Get_idsp_room ( void )
  6805. {
  6806. // if dsp_automatic is not enabled, get room
  6807. if ( !DSP_CheckDspAutoEnabled())
  6808. return idsp_room;
  6809. // automatic room detection is on, return dsp_automatic preset instead of dsp_room preset
  6810. return idsp_automatic;
  6811. }
  6812. // free previous
  6813. inline void DSP_FreePrevPreset( dsp_t *pdsp )
  6814. {
  6815. Assert( pdsp );
  6816. bool didFree = false;
  6817. for (int i = 0; i < pdsp->cchan; i++)
  6818. {
  6819. if ( pdsp->ppsetprev[i] )
  6820. {
  6821. PSET_Free( pdsp->ppsetprev[i] );
  6822. pdsp->ppsetprev[i] = NULL;
  6823. didFree = true;
  6824. }
  6825. }
  6826. if ( didFree && snd_dsp_spew_changes.GetBool() )
  6827. {
  6828. DevMsg( "[Sound DSP] Free previous preset %d.\n", pdsp->ipsetprev );
  6829. }
  6830. pdsp->ipsetprev = 0;
  6831. }
  6832. extern ConVar dsp_mix_min;
  6833. extern ConVar dsp_mix_max;
  6834. extern ConVar dsp_db_min;
  6835. extern ConVar dsp_db_mixdrop;
  6836. // alloc new preset if different from current
  6837. // xfade from prev to new preset
  6838. // free previous preset, copy current into previous, set up xfade from previous to new
  6839. void DSP_SetPreset( int idsp, int ipsetnew, const char * pDspName)
  6840. {
  6841. dsp_t *pdsp;
  6842. pset_t *ppsetnew[DSPCHANMAX];
  6843. Assert (idsp >= 0 && idsp < CDSPS);
  6844. pdsp = &dsps[idsp];
  6845. // validate new preset range
  6846. if ( ipsetnew >= g_cpsettemplates || ipsetnew < 0 )
  6847. return;
  6848. // ignore if new preset is same as current preset
  6849. if ( ipsetnew == pdsp->ipset )
  6850. return;
  6851. if ( snd_dsp_spew_changes.GetBool() )
  6852. {
  6853. DevMsg( "[Sound DSP] For Dsp %d, %s switch presets from %d to %d.\n", idsp, pDspName, pdsp->ipset, ipsetnew );
  6854. }
  6855. // alloc new presets (each channel is a duplicate preset)
  6856. Assert (pdsp->cchan <= DSPCHANMAX);
  6857. for (int i = 0; i < pdsp->cchan; i++)
  6858. {
  6859. ppsetnew[i] = PSET_Alloc ( ipsetnew );
  6860. if ( !ppsetnew[i] )
  6861. {
  6862. DevMsg("WARNING: DSP preset failed to allocate.\n");
  6863. return;
  6864. }
  6865. }
  6866. Assert (pdsp);
  6867. // free PREVIOUS previous preset if not 0, it will be replaced with a new prev
  6868. DSP_FreePrevPreset( pdsp );
  6869. for (int i = 0; i < pdsp->cchan; i++)
  6870. {
  6871. pdsp->ppsetprev[i] = pdsp->ppset[i]; // current becomes previous
  6872. pdsp->ppset[i] = ppsetnew[i]; // new becomes current
  6873. }
  6874. pdsp->ipsetprev = pdsp->ipset;
  6875. pdsp->ipset = ipsetnew;
  6876. #if 0
  6877. if ( pdsp->ppsetprev )
  6878. {
  6879. uint nCurrentTime = Plat_MSTime();
  6880. if ( nCurrentTime > pdsp->ppsetprev[0]->nLastUpdatedTimeInMilliseconds + snd_dsp_cancel_old_preset_after_N_milliseconds.GetInt() )
  6881. {
  6882. if ( snd_dsp_spew_changes.GetBool() )
  6883. {
  6884. DevMsg( "[Sound DSP] For Dsp %d, %s previous preset %d has not been updated for a while. Do not cross-fade form it.\n", idsp, pDspName, pdsp->ipsetprev );
  6885. }
  6886. // The preset that we are going to cross from is actually quite old.
  6887. // Let's cancel it too, so we can only hear the new preset. This case does not happen often but avoid some old sounds to be played.
  6888. DSP_FreePrevPreset( pdsp );
  6889. }
  6890. }
  6891. #endif
  6892. if ( idsp == idsp_room || idsp == idsp_automatic )
  6893. {
  6894. // set up new dsp mix min & max, db_min & db_drop params so that new channels get new mix values
  6895. // NOTE: only new sounds will get the new mix min/max values set in their dspmix param
  6896. // NOTE: so - no crossfade is needed betweeen dspmix and dspmix prev, but this also means
  6897. // NOTE: that currently playing ambients will not see changes to dspmix at all.
  6898. float mix_min = pdsp->ppset[0]->mix_min;
  6899. float mix_max = pdsp->ppset[0]->mix_max;
  6900. float db_min = pdsp->ppset[0]->db_min;
  6901. float db_mixdrop = pdsp->ppset[0]->db_mixdrop;
  6902. dsp_mix_min.SetValue( mix_min );
  6903. dsp_mix_max.SetValue( mix_max );
  6904. dsp_db_min.SetValue( db_min );
  6905. dsp_db_mixdrop.SetValue( db_mixdrop );
  6906. }
  6907. RMP_SetEnd( &pdsp->xramp ); // oliviern: I'm not sure this is necessary as we call RMP_Init afterward
  6908. // Potentially something to remove if not used?
  6909. // shouldn't be crossfading if current dsp preset == previous dsp preset
  6910. Assert (pdsp->ipset != pdsp->ipsetprev);
  6911. // if new preset is one-shot, keep previous preset to restore when one-shot times out
  6912. // but: don't restore previous one-shots!
  6913. pdsp->ipsetsav_oneshot = 0;
  6914. if ( PSET_IsOneShot( pdsp->ppset[0] ) && !PSET_IsOneShot( pdsp->ppsetprev[0] ) )
  6915. pdsp->ipsetsav_oneshot = pdsp->ipsetprev;
  6916. // get new xfade time from previous preset (ie: fade out time). if 0 use default. if < 0, use exponential xfade
  6917. if ( ( pdsp->ppsetprev[0] != NULL) && ( fabs(pdsp->ppsetprev[0]->fade) > 0.0 ) )
  6918. {
  6919. pdsp->xfade = fabs(pdsp->ppsetprev[0]->fade);
  6920. pdsp->bexpfade = pdsp->ppsetprev[0]->fade < 0 ? 1 : 0;
  6921. }
  6922. else
  6923. {
  6924. // no previous preset - use defauts, set in DSP_Alloc
  6925. pdsp->xfade = pdsp->xfade_default;
  6926. pdsp->bexpfade = false;
  6927. }
  6928. RMP_Init( &(pdsp->xramp), pdsp->xfade, 0, PMAX, false );
  6929. }
  6930. #define DSP_AUTO_BASE 60 // presets 60-100 in g_psettemplates are reserved as autocreated presets
  6931. #define DSP_CAUTO_PRESETS 40 // must be same as DAS_CNODES!!!
  6932. // construct a dsp preset based on provided parameters,
  6933. // preset is constructed within g_psettemplates[] array.
  6934. // return preset #
  6935. // parameter batch
  6936. struct adsp_auto_params_t
  6937. {
  6938. // passed in params
  6939. bool bskyabove; // true if sky is mostly above player
  6940. int width; // max width of room in inches
  6941. int length; // max length of room in inches (length always > width)
  6942. int height; // max height of room in inches
  6943. float fdiffusion; // diffusion of room 0..1.0
  6944. float freflectivity; // average reflectivity of all surfaces in room 0..1.0
  6945. float surface_refl[6]; // reflectivity for left,right,front,back,ceiling,floor surfaces 0.0 for open surface (sky or no hit)
  6946. // derived params
  6947. int shape; // ADSP_ROOM, etc 0...4
  6948. int size; // ADSP_SIZE_SMALL, etc 0...3
  6949. int len; // ADSP_LENGTH_SHORT, etc 0...3
  6950. int wid; // ADSP_WIDTH_NARROW, etc 0...3
  6951. int ht; // ADSP_HEIGHT_LOW, etc 0...3
  6952. int reflectivity; // ADSP_DULL, etc 0..3
  6953. int diffusion; // ADSP_EMPTY, etc 0...3
  6954. };
  6955. // room shapes
  6956. #define ADSP_ROOM 0
  6957. #define ADSP_DUCT 1
  6958. #define ADSP_HALL 2
  6959. #define ADSP_TUNNEL 3
  6960. #define ADSP_STREET 4
  6961. #define ADSP_ALLEY 5
  6962. #define ADSP_COURTYARD 6
  6963. #define ADSP_OPEN_SPACE 7 // NOTE: 7..10 must remain in order !!!
  6964. #define ADSP_OPEN_WALL 8
  6965. #define ADSP_OPEN_STREET 9
  6966. #define ADSP_OPEN_COURTYARD 10
  6967. // room sizes
  6968. #define ADSP_SIZE_SMALL 0 // NOTE: must remain 0..4!!!
  6969. #define ADSP_SIZE_MEDIUM 1
  6970. #define ADSP_SIZE_LARGE 2
  6971. #define ADSP_SIZE_HUGE 3
  6972. #define ADSP_SIZE_GIGANTIC 4
  6973. #define ADSP_SIZE_MAX 5
  6974. #define ADSP_LENGTH_SHORT 0
  6975. #define ADSP_LENGTH_MEDIUM 1
  6976. #define ADSP_LENGTH_LONG 2
  6977. #define ADSP_LENGTH_VLONG 3
  6978. #define ADSP_LENGTH_XLONG 4
  6979. #define ADSP_LENGTH_MAX 5
  6980. #define ADSP_WIDTH_NARROW 0
  6981. #define ADSP_WIDTH_MEDIUM 1
  6982. #define ADSP_WIDTH_WIDE 2
  6983. #define ADSP_WIDTH_VWIDE 3
  6984. #define ADSP_WIDTH_XWIDE 4
  6985. #define ADSP_WIDTH_MAX 5
  6986. #define ADSP_HEIGHT_LOW 0
  6987. #define ADSP_HEIGTH_MEDIUM 1
  6988. #define ADSP_HEIGHT_TALL 2
  6989. #define ADSP_HEIGHT_VTALL 3
  6990. #define ADSP_HEIGHT_XTALL 4
  6991. #define ADSP_HEIGHT_MAX 5
  6992. // select type 1..5 based on params
  6993. // 1:simple reverb
  6994. // 2:diffusor + reverb
  6995. // 3:diffusor + delay + reverb
  6996. // 4:simple delay
  6997. // 5:diffusor + delay
  6998. #define AROOM_SMALL (10.0 * 12.0) // small room
  6999. #define AROOM_MEDIUM (20.0 * 12.0) // medium room
  7000. #define AROOM_LARGE (40.0 * 12.0) // large room
  7001. #define AROOM_HUGE (100.0 * 12.0) // huge room
  7002. #define AROOM_GIGANTIC (200.0 * 12.0) // gigantic room
  7003. #define AROOM_DUCT_WIDTH (4.0 * 12.0) // max width for duct
  7004. #define AROOM_DUCT_HEIGHT (6.0 * 12.0)
  7005. #define AROOM_HALL_WIDTH (8.0 * 12.0) // max width for hall
  7006. #define AROOM_HALL_HEIGHT (16.0 * 12.0) // max height for hall
  7007. #define AROOM_TUNNEL_WIDTH (20.0 * 12.0) // max width for tunnel
  7008. #define AROOM_TUNNEL_HEIGHT (30.0 * 12.0) // max height for tunnel
  7009. #define AROOM_STREET_WIDTH (12.0 * 12.0) // min width for street
  7010. #define AROOM_SHORT_LENGTH (12.0 * 12.0) // max length for short hall
  7011. #define AROOM_MEDIUM_LENGTH (24.0 * 12.0) // min length for medium hall
  7012. #define AROOM_LONG_LENGTH (48.0 * 12.0) // min length for long hall
  7013. #define AROOM_VLONG_LENGTH (96.0 * 12.0) // min length for very long hall
  7014. #define AROOM_XLONG_LENGTH (192.0 * 12.0) // min length for huge hall
  7015. #define AROOM_LOW_HEIGHT (4.0 * 12.0) // short ceiling
  7016. #define AROOM_MEDIUM_HEIGHT (128) // medium ceiling
  7017. #define AROOM_TALL_HEIGHT (18.0 * 12.0) // tall ceiling
  7018. #define AROOM_VTALL_HEIGHT (32.0 * 12.0) // very tall ceiling
  7019. #define AROOM_XTALL_HEIGHT (64.0 * 12.0) // huge tall ceiling
  7020. #define AROOM_NARROW_WIDTH (6.0 * 12.0) // narrow width
  7021. #define AROOM_MEDIUM_WIDTH (12.0 * 12.0) // medium width
  7022. #define AROOM_WIDE_WIDTH (24.0 * 12.0) // wide width
  7023. #define AROOM_VWIDE_WIDTH (48.0 * 12.0) // very wide
  7024. #define AROOM_XWIDE_WIDTH (96.0 * 12.0) // huge width
  7025. #define BETWEEN(a,b,c) ( ((a) > (b)) && ((a) <= (c)) )
  7026. #define ADSP_IsShaft(pa) (pa->height > (3.0 * pa->length))
  7027. #define ADSP_IsRoom(pa) (pa->length <= (2.5 * pa->width))
  7028. #define ADSP_IsHall(pa) ((pa->length > (2.5 * pa->width)) && (BETWEEN(pa->width, AROOM_DUCT_WIDTH, AROOM_HALL_WIDTH)))
  7029. #define ADSP_IsTunnel(pa) ((pa->length > (4.0 * pa->width)) && (pa->width > AROOM_HALL_WIDTH))
  7030. #define ADSP_IsDuct(pa) ((pa->length > (4.0 * pa->width)) && (pa->width <= AROOM_DUCT_WIDTH))
  7031. #define ADSP_IsCourtyard(pa) (pa->length <= (2.5 * pa->width))
  7032. #define ADSP_IsAlley(pa) ((pa->length > (2.5 * pa->width)) && (pa->width <= AROOM_STREET_WIDTH))
  7033. #define ADSP_IsStreet(pa) ((pa->length > (2.5 * pa->width)) && (pa->width > AROOM_STREET_WIDTH))
  7034. #define ADSP_IsSmallRoom(pa) (pa->length <= AROOM_SMALL)
  7035. #define ADSP_IsMediumRoom(pa) ((BETWEEN(pa->length, AROOM_SMALL, AROOM_MEDIUM)) ) // && (BETWEEN(pa->width, AROOM_SMALL, AROOM_MEDIUM)))
  7036. #define ADSP_IsLargeRoom(pa) (BETWEEN(pa->length, AROOM_MEDIUM, AROOM_LARGE) ) // && BETWEEN(pa->width, AROOM_MEDIUM, AROOM_LARGE))
  7037. #define ADSP_IsHugeRoom(pa) (BETWEEN(pa->length, AROOM_LARGE, AROOM_HUGE) ) // && BETWEEN(pa->width, AROOM_LARGE, AROOM_HUGE))
  7038. #define ADSP_IsGiganticRoom(pa) ((pa->length > AROOM_HUGE) ) // && (pa->width > AROOM_HUGE))
  7039. #define ADSP_IsShortLength(pa) (pa->length <= AROOM_SHORT_LENGTH)
  7040. #define ADSP_IsMediumLength(pa) (BETWEEN(pa->length, AROOM_SHORT_LENGTH, AROOM_MEDIUM_LENGTH))
  7041. #define ADSP_IsLongLength(pa) (BETWEEN(pa->length, AROOM_MEDIUM_LENGTH, AROOM_LONG_LENGTH))
  7042. #define ADSP_IsVLongLength(pa) (BETWEEN(pa->length, AROOM_LONG_LENGTH, AROOM_VLONG_LENGTH))
  7043. #define ADSP_IsXLongLength(pa) (pa->length > AROOM_VLONG_LENGTH)
  7044. #define ADSP_IsLowHeight(pa) (pa->height <= AROOM_LOW_HEIGHT)
  7045. #define ADSP_IsMediumHeight(pa) (BETWEEN(pa->height, AROOM_LOW_HEIGHT, AROOM_MEDIUM_HEIGHT))
  7046. #define ADSP_IsTallHeight(pa) (BETWEEN(pa->height, AROOM_MEDIUM_HEIGHT, AROOM_TALL_HEIGHT))
  7047. #define ADSP_IsVTallHeight(pa) (BETWEEN(pa->height, AROOM_TALL_HEIGHT, AROOM_VTALL_HEIGHT))
  7048. #define ADSP_IsXTallHeight(pa) (pa->height > AROOM_VTALL_HEIGHT)
  7049. #define ADSP_IsNarrowWidth(pa) (pa->width <= AROOM_NARROW_WIDTH)
  7050. #define ADSP_IsMediumWidth(pa) (BETWEEN(pa->width, AROOM_NARROW_WIDTH, AROOM_MEDIUM_WIDTH))
  7051. #define ADSP_IsWideWidth(pa) (BETWEEN(pa->width, AROOM_MEDIUM_WIDTH, AROOM_WIDE_WIDTH))
  7052. #define ADSP_IsVWideWidth(pa) (BETWEEN(pa->width, AROOM_WIDE_WIDTH, AROOM_VWIDE_WIDTH))
  7053. #define ADSP_IsXWideWidth(pa) (pa->width > AROOM_VWIDE_WIDTH)
  7054. #define ADSP_IsInside(pa) (!(pa->bskyabove))
  7055. // room diffusion
  7056. #define ADSP_EMPTY 0
  7057. #define ADSP_SPARSE 1
  7058. #define ADSP_CLUTTERED 2
  7059. #define ADSP_FULL 3
  7060. #define ADSP_DIFFUSION_MAX 4
  7061. #define AROOM_DIF_EMPTY 0.01 // 1% of space by volume is other objects
  7062. #define AROOM_DIF_SPARSE 0.1 // 10% "
  7063. #define AROOM_DIF_CLUTTERED 0.3 // 30% "
  7064. #define AROOM_DIF_FULL 0.5 // 50% "
  7065. #define ADSP_IsEmpty(pa) (pa->fdiffusion <= AROOM_DIF_EMPTY)
  7066. #define ADSP_IsSparse(pa) (BETWEEN(pa->fdiffusion, AROOM_DIF_EMPTY, AROOM_DIF_SPARSE))
  7067. #define ADSP_IsCluttered(pa) (BETWEEN(pa->fdiffusion, AROOM_DIF_SPARSE, AROOM_DIF_CLUTTERED))
  7068. #define ADSP_IsFull(pa) (pa->fdiffusion > AROOM_DIF_CLUTTERED)
  7069. #define ADSP_IsDiffuse(pa) (pa->diffusion > ADSP_SPARSE)
  7070. // room acoustic reflectivity
  7071. // tile 0.3 * 3.3 = 0.99
  7072. // metal 0.25 * 3.3 = 0.83
  7073. // concrete,rock,brick,glass,gravel 0.2 * 3.3 = 0.66
  7074. // metal panel/vent, wood, water 0.1 * 3.3 = 0.33
  7075. // carpet,sand,snow,dirt 0.01 * 3.3 = 0.03
  7076. #define ADSP_DULL 0
  7077. #define ADSP_FLAT 1
  7078. #define ADSP_REFLECTIVE 2
  7079. #define ADSP_BRIGHT 3
  7080. #define ADSP_REFLECTIVITY_MAX 4
  7081. #define AROOM_REF_DULL 0.04
  7082. #define AROOM_REF_FLAT 0.50
  7083. #define AROOM_REF_REFLECTIVE 0.80
  7084. #define AROOM_REF_BRIGHT 0.99
  7085. #define ADSP_IsDull(pa) (pa->freflectivity <= AROOM_REF_DULL)
  7086. #define ADSP_IsFlat(pa) (BETWEEN(pa->freflectivity, AROOM_REF_DULL, AROOM_REF_FLAT))
  7087. #define ADSP_IsReflective(pa) (BETWEEN(pa->freflectivity, AROOM_REF_FLAT, AROOM_REF_REFLECTIVE))
  7088. #define ADSP_IsBright(pa) (pa->freflectivity > AROOM_REF_REFLECTIVE)
  7089. #define ADSP_IsRefl(pa) (pa->reflectivity > ADSP_FLAT)
  7090. // convert numeric size params to #defined size params
  7091. void ADSP_GetSize( adsp_auto_params_t *pa )
  7092. {
  7093. pa->size = ((ADSP_IsSmallRoom(pa) ? 1 : 0) * ADSP_SIZE_SMALL) +
  7094. ((ADSP_IsMediumRoom(pa) ? 1 : 0) * ADSP_SIZE_MEDIUM) +
  7095. ((ADSP_IsLargeRoom(pa) ? 1 : 0) * ADSP_SIZE_LARGE) +
  7096. ((ADSP_IsHugeRoom(pa) ? 1 : 0) * ADSP_SIZE_HUGE) +
  7097. ((ADSP_IsGiganticRoom(pa) ? 1 : 0) * ADSP_SIZE_GIGANTIC);
  7098. pa->len = ((ADSP_IsShortLength(pa) ? 1 : 0) * ADSP_LENGTH_SHORT) +
  7099. ((ADSP_IsMediumLength(pa) ? 1 : 0) * ADSP_LENGTH_MEDIUM) +
  7100. ((ADSP_IsLongLength(pa) ? 1 : 0) * ADSP_LENGTH_LONG) +
  7101. ((ADSP_IsVLongLength(pa) ? 1 : 0) * ADSP_LENGTH_VLONG) +
  7102. ((ADSP_IsXLongLength(pa) ? 1 : 0) * ADSP_LENGTH_XLONG);
  7103. pa->wid = ((ADSP_IsNarrowWidth(pa) ? 1 : 0) * ADSP_WIDTH_NARROW) +
  7104. ((ADSP_IsMediumWidth(pa) ? 1 : 0) * ADSP_WIDTH_MEDIUM) +
  7105. ((ADSP_IsWideWidth(pa) ? 1 : 0) * ADSP_WIDTH_WIDE) +
  7106. ((ADSP_IsVWideWidth(pa) ? 1 : 0) * ADSP_WIDTH_VWIDE) +
  7107. ((ADSP_IsXWideWidth(pa) ? 1 : 0) * ADSP_WIDTH_XWIDE);
  7108. pa->ht = ((ADSP_IsLowHeight(pa) ? 1 : 0) * ADSP_HEIGHT_LOW) +
  7109. ((ADSP_IsMediumHeight(pa) ? 1 : 0) * ADSP_HEIGTH_MEDIUM) +
  7110. ((ADSP_IsTallHeight(pa) ? 1 : 0) * ADSP_HEIGHT_TALL) +
  7111. ((ADSP_IsVTallHeight(pa) ? 1 : 0) * ADSP_HEIGHT_VTALL) +
  7112. ((ADSP_IsXTallHeight(pa) ? 1 : 0) * ADSP_HEIGHT_XTALL);
  7113. pa->reflectivity =
  7114. ((ADSP_IsDull(pa) ? 1 : 0) * ADSP_DULL) +
  7115. ((ADSP_IsFlat(pa) ? 1 : 0) * ADSP_FLAT) +
  7116. ((ADSP_IsReflective(pa) ? 1 : 0) * ADSP_REFLECTIVE) +
  7117. ((ADSP_IsBright(pa) ? 1 : 0) * ADSP_BRIGHT);
  7118. pa->diffusion =
  7119. ((ADSP_IsEmpty(pa) ? 1 : 0) * ADSP_EMPTY) +
  7120. ((ADSP_IsSparse(pa) ? 1 : 0) * ADSP_SPARSE) +
  7121. ((ADSP_IsCluttered(pa) ? 1 : 0) * ADSP_CLUTTERED) +
  7122. ((ADSP_IsFull(pa) ? 1 : 0) * ADSP_FULL);
  7123. Assert(pa->size < ADSP_SIZE_MAX);
  7124. Assert(pa->len < ADSP_LENGTH_MAX);
  7125. Assert(pa->wid < ADSP_WIDTH_MAX);
  7126. Assert(pa->ht < ADSP_HEIGHT_MAX);
  7127. Assert(pa->reflectivity < ADSP_REFLECTIVITY_MAX);
  7128. Assert(pa->diffusion < ADSP_DIFFUSION_MAX);
  7129. if ( pa->shape != ADSP_COURTYARD && pa->shape != ADSP_OPEN_COURTYARD )
  7130. {
  7131. // fix up size for streets, alleys, halls, ducts, tunnelsy
  7132. if (pa->shape == ADSP_STREET || pa->shape == ADSP_ALLEY )
  7133. pa->size = pa->wid;
  7134. else
  7135. pa->size = (pa->len + pa->wid) / 2;
  7136. }
  7137. }
  7138. void ADSP_GetOutsideSize( adsp_auto_params_t *pa )
  7139. {
  7140. ADSP_GetSize( pa );
  7141. }
  7142. // return # of sides that had max length or sky hits (out of 6 sides).
  7143. int ADSP_COpenSides( adsp_auto_params_t *pa )
  7144. {
  7145. int count = 0;
  7146. // only look at left,right,front,back walls - ignore floor, ceiling
  7147. for (int i = 0; i < 4; i++)
  7148. {
  7149. if (pa->surface_refl[i] == 0.0)
  7150. count++;
  7151. }
  7152. return count;
  7153. }
  7154. // given auto params, return shape and size of room
  7155. void ADSP_GetAutoShape( adsp_auto_params_t *pa )
  7156. {
  7157. // INSIDE:
  7158. // shapes: duct, hall, tunnel, shaft (vertical duct, hall or tunnel)
  7159. // sizes: short->long, narrow->wide, low->tall
  7160. // shapes: room
  7161. // sizes: small->large, low->tall
  7162. // OUTSIDE:
  7163. // shapes: street, alley
  7164. // sizes: short->long, narrow->wide
  7165. // shapes: courtyard
  7166. // sizes: small->large
  7167. // shapes: open_space, wall, open_street, open_corner, open_courtyard
  7168. // sizes: open, narrow->wide
  7169. bool bshaft = false;
  7170. int t;
  7171. if (ADSP_IsInside(pa))
  7172. {
  7173. if (ADSP_IsShaft(pa))
  7174. {
  7175. // temp swap height and length
  7176. bshaft = true;
  7177. t = pa->height;
  7178. pa->height = pa->length;
  7179. pa->length = t;
  7180. if (das_debug.GetInt() > 1)
  7181. DevMsg("VERTICAL SHAFT Detected \n");
  7182. }
  7183. // get shape
  7184. if (ADSP_IsDuct(pa))
  7185. {
  7186. pa->shape = ADSP_DUCT;
  7187. ADSP_GetSize( pa );
  7188. if (das_debug.GetInt() > 1)
  7189. DevMsg("DUCT Detected \n");
  7190. goto autoshape_exit;
  7191. }
  7192. if (ADSP_IsHall(pa))
  7193. {
  7194. // get size
  7195. pa->shape = ADSP_HALL;
  7196. ADSP_GetSize( pa );
  7197. if (das_debug.GetInt() > 1)
  7198. DevMsg("HALL Detected \n");
  7199. goto autoshape_exit;
  7200. }
  7201. if (ADSP_IsTunnel(pa))
  7202. {
  7203. // get size
  7204. pa->shape = ADSP_TUNNEL;
  7205. ADSP_GetSize( pa );
  7206. if (das_debug.GetInt() > 1)
  7207. DevMsg("TUNNEL Detected \n");
  7208. goto autoshape_exit;
  7209. }
  7210. // default
  7211. // (ADSP_IsRoom(pa))
  7212. {
  7213. // get size
  7214. pa->shape = ADSP_ROOM;
  7215. ADSP_GetSize( pa );
  7216. if (das_debug.GetInt() > 1)
  7217. DevMsg("ROOM Detected \n");
  7218. goto autoshape_exit;
  7219. }
  7220. }
  7221. // outside:
  7222. if (ADSP_COpenSides(pa) > 0) // side hit sky, or side has max length
  7223. {
  7224. // get shape - courtyard, street, wall or open space
  7225. // 10..7
  7226. pa->shape = ADSP_OPEN_COURTYARD - (ADSP_COpenSides(pa) - 1);
  7227. ADSP_GetOutsideSize( pa );
  7228. if (das_debug.GetInt() > 1)
  7229. DevMsg("OPEN SIDED OUTDOOR AREA Detected \n");
  7230. goto autoshape_exit;
  7231. }
  7232. // all sides closed:
  7233. // get shape - closed street or alley or courtyard
  7234. if (ADSP_IsCourtyard(pa))
  7235. {
  7236. pa->shape = ADSP_COURTYARD;
  7237. ADSP_GetOutsideSize( pa );
  7238. if (das_debug.GetInt() > 1)
  7239. DevMsg("OUTSIDE COURTYARD Detected \n");
  7240. goto autoshape_exit;
  7241. }
  7242. if (ADSP_IsAlley(pa))
  7243. {
  7244. pa->shape = ADSP_ALLEY;
  7245. ADSP_GetOutsideSize( pa );
  7246. if (das_debug.GetInt() > 1)
  7247. DevMsg("OUTSIDE ALLEY Detected \n");
  7248. goto autoshape_exit;
  7249. }
  7250. // default to 'street' if sides are closed
  7251. // if (ADSP_IsStreet(pa))
  7252. {
  7253. pa->shape = ADSP_STREET;
  7254. ADSP_GetOutsideSize( pa );
  7255. if (das_debug.GetInt() > 1)
  7256. DevMsg("OUTSIDE STREET Detected \n");
  7257. goto autoshape_exit;
  7258. }
  7259. autoshape_exit:
  7260. // swap height & length if needed
  7261. if (bshaft)
  7262. {
  7263. t = pa->height;
  7264. pa->height = pa->length;
  7265. pa->length = t;
  7266. }
  7267. }
  7268. int MapReflectivityToDLYCutoff[] =
  7269. {
  7270. 1000, // DULL
  7271. 2000, // FLAT
  7272. 4000, // REFLECTIVE
  7273. 6000 // BRIGHT
  7274. };
  7275. float MapSizeToDLYFeedback[] =
  7276. {
  7277. 0.9, // 0.6, // SMALL
  7278. 0.8, // 0.5, // MEDIUM
  7279. 0.7, // 0.4, // LARGE
  7280. 0.6, // 0.3, // HUGE
  7281. 0.5, // 0.2, // GIGANTIC
  7282. };
  7283. void ADSP_SetupAutoDelay( prc_t *pprc_dly, adsp_auto_params_t *pa )
  7284. {
  7285. // shapes:
  7286. // inside: duct, long hall, long tunnel, large room
  7287. // outside: open courtyard, street wall, space
  7288. // outside: closed courtyard, alley, street
  7289. // size 0..4
  7290. // len 0..3
  7291. // wid 0..3
  7292. // reflectivity: 0..3
  7293. // diffusion 0..3
  7294. // dtype: delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  7295. // delay: delay in milliseconds (room max size in feet)
  7296. // feedback: feedback 0-1.0
  7297. // gain: final gain of output stage, 0-1.0
  7298. int size = pa->length * 2.0;
  7299. if (pa->shape == ADSP_ALLEY || pa->shape == ADSP_STREET || pa->shape == ADSP_OPEN_STREET)
  7300. size = pa->width * 2.0;
  7301. pprc_dly->type = PRC_DLY;
  7302. pprc_dly->prm[dly_idtype] = DLY_LOWPASS; // delay with feedback
  7303. pprc_dly->prm[dly_idelay] = clamp((size / 12.0), 5.0, 500.0);
  7304. pprc_dly->prm[dly_ifeedback] = MapSizeToDLYFeedback[pa->len];
  7305. // reduce gain based on distance reflection travels
  7306. // float g = 1.0 - ( clamp(pprc_dly->prm[dly_idelay], 10.0, 1000.0) / (1000.0 - 10.0) );
  7307. // pprc_dly->prm[dly_igain] = g;
  7308. pprc_dly->prm[dly_iftype] = FLT_LP;
  7309. if (ADSP_IsInside(pa))
  7310. pprc_dly->prm[dly_icutoff] = MapReflectivityToDLYCutoff[pa->reflectivity];
  7311. else
  7312. pprc_dly->prm[dly_icutoff] = (int)((float)(MapReflectivityToDLYCutoff[pa->reflectivity]) * 0.75);
  7313. pprc_dly->prm[dly_iqwidth] = 0;
  7314. pprc_dly->prm[dly_iquality] = QUA_LO;
  7315. float l = clamp((pa->length * 2.0 / 12.0), 14.0, 500.0);
  7316. float w = clamp((pa->width * 2.0 / 12.0), 14.0, 500.0);
  7317. // convert to multitap delay
  7318. pprc_dly->prm[dly_idtype] = DLY_LOWPASS_4TAP;
  7319. pprc_dly->prm[dly_idelay] = l;
  7320. pprc_dly->prm[dly_itap1] = w;
  7321. pprc_dly->prm[dly_itap2] = l; // max(7, l * 0.7 );
  7322. pprc_dly->prm[dly_itap3] = l; // max(7, w * 0.7 );
  7323. pprc_dly->prm[dly_igain] = 1.0;
  7324. }
  7325. int MapReflectivityToRVACutoff[] =
  7326. {
  7327. 1000, // DULL
  7328. 2000, // FLAT
  7329. 4000, // REFLECTIVE
  7330. 6000 // BRIGHT
  7331. };
  7332. float MapSizeToRVANumDelays[] =
  7333. {
  7334. 3, // SMALL 3 reverbs
  7335. 6, // MEDIUM 6 reverbs
  7336. 6, // LARGE 6 reverbs
  7337. 9, // HUGE 9 reverbs
  7338. 12, // GIGANTIC 12 reverbs
  7339. };
  7340. float MapSizeToRVAFeedback[] =
  7341. {
  7342. 0.75, // SMALL
  7343. 0.8, // MEDIUM
  7344. 0.9, // LARGE
  7345. 0.95, // HUGE
  7346. 0.98, // GIGANTIC
  7347. };
  7348. void ADSP_SetupAutoReverb( prc_t *pprc_rva, adsp_auto_params_t *pa )
  7349. {
  7350. // shape: hall, tunnel or room
  7351. // size 0..4
  7352. // reflectivity: 0..3
  7353. // diffusion 0..3
  7354. // size: 0-2.0 scales nominal delay parameters (18 to 47 ms * scale = delay)
  7355. // numdelays: 0-12 controls # of parallel or series delays
  7356. // decay: 0-2.0 scales feedback parameters (.7 to .9 * scale/2.0 = feedback)
  7357. // fparallel: if true, filters are built into delays, otherwise filter output only
  7358. // fmoddly: if true, all delays are modulating delays
  7359. float gain = 1.0;
  7360. pprc_rva->type = PRC_RVA;
  7361. pprc_rva->prm[rva_size_max] = 50.0;
  7362. pprc_rva->prm[rva_size_min] = 30.0;
  7363. if (ADSP_IsRoom(pa))
  7364. pprc_rva->prm[rva_inumdelays] = MapSizeToRVANumDelays[pa->size];
  7365. else
  7366. pprc_rva->prm[rva_inumdelays] = MapSizeToRVANumDelays[pa->len];
  7367. pprc_rva->prm[rva_ifeedback] = 0.9;
  7368. pprc_rva->prm[rva_icutoff] = MapReflectivityToRVACutoff[pa->reflectivity];
  7369. pprc_rva->prm[rva_ifparallel] = 1;
  7370. pprc_rva->prm[rva_imoddly] = ADSP_IsEmpty(pa) ? 0 : 4;
  7371. pprc_rva->prm[rva_imodrate] = 3.48;
  7372. pprc_rva->prm[rva_iftaps] = 0; // 0.1 // use extra delay taps to increase density
  7373. pprc_rva->prm[rva_width] = clamp( ((float)(pa->width) / 12.0), 6.0, 500.0); // in feet
  7374. pprc_rva->prm[rva_depth] = clamp( ((float)(pa->length) / 12.0), 6.0, 500.0);
  7375. pprc_rva->prm[rva_height] = clamp( ((float)(pa->height) / 12.0), 6.0, 500.0);
  7376. // room
  7377. pprc_rva->prm[rva_fbwidth] = 0.9; // MapSizeToRVAFeedback[pa->size]; // larger size = more feedback
  7378. pprc_rva->prm[rva_fbdepth] = 0.9; // MapSizeToRVAFeedback[pa->size];
  7379. pprc_rva->prm[rva_fbheight] = 0.5; // MapSizeToRVAFeedback[pa->size];
  7380. // feedback is based on size of room:
  7381. if (ADSP_IsInside(pa))
  7382. {
  7383. if (pa->shape == ADSP_HALL)
  7384. {
  7385. pprc_rva->prm[rva_fbwidth] = 0.7; //MapSizeToRVAFeedback[pa->wid];
  7386. pprc_rva->prm[rva_fbdepth] = -0.5; //MapSizeToRVAFeedback[pa->len];
  7387. pprc_rva->prm[rva_fbheight] = 0.3; //MapSizeToRVAFeedback[pa->ht];
  7388. }
  7389. if (pa->shape == ADSP_TUNNEL)
  7390. {
  7391. pprc_rva->prm[rva_fbwidth] = 0.9;
  7392. pprc_rva->prm[rva_fbdepth] = -0.8; // fixed pre-delay, no feedback
  7393. pprc_rva->prm[rva_fbheight] = 0.3;
  7394. }
  7395. }
  7396. else
  7397. {
  7398. if (pa->shape == ADSP_ALLEY)
  7399. {
  7400. pprc_rva->prm[rva_fbwidth] = 0.9;
  7401. pprc_rva->prm[rva_fbdepth] = -0.8; // fixed pre-delay, no feedback
  7402. pprc_rva->prm[rva_fbheight] = 0.0;
  7403. }
  7404. }
  7405. if (!ADSP_IsInside(pa))
  7406. pprc_rva->prm[rva_fbheight] = 0.0;
  7407. pprc_rva->prm[rva_igain] = gain;
  7408. }
  7409. // diffusor templates for auto create
  7410. // size: 0-1.0 scales all delays (13ms to 41ms * scale = delay)
  7411. // numdelays: 0-4.0 controls # of series delays
  7412. // decay: 0-1.0 scales all feedback parameters
  7413. // prctype size #dly feedback
  7414. #define PRC_DFRA_S {PRC_DFR, {0.5, 2, 0.10}, NULL,NULL,NULL,NULL,NULL} // S room
  7415. #define PRC_DFRA_M {PRC_DFR, {0.75, 2, 0.12}, NULL,NULL,NULL,NULL,NULL} // M room
  7416. #define PRC_DFRA_L {PRC_DFR, {1.0, 3, 0.13}, NULL,NULL,NULL,NULL,NULL} // L room
  7417. #define PRC_DFRA_VL {PRC_DFR, {1.0, 3, 0.15}, NULL,NULL,NULL,NULL,NULL} // VL room
  7418. prc_t g_prc_dfr_auto[] = {PRC_DFRA_S, PRC_DFRA_M, PRC_DFRA_L, PRC_DFRA_VL, PRC_DFRA_VL};
  7419. #define CDFRTEMPLATES (sizeof(g_prc_dfr_auto)/sizeof(pset_t)) // number of diffusor templates
  7420. // copy diffusor template from preset list, based on room size
  7421. void ADSP_SetupAutoDiffusor( prc_t *pprc_dfr, adsp_auto_params_t *pa )
  7422. {
  7423. int i = iclamp(pa->size, 0, (int)CDFRTEMPLATES - 1);
  7424. // copy diffusor preset based on size
  7425. *pprc_dfr = g_prc_dfr_auto[i];
  7426. }
  7427. // return index to processor given processor type and preset
  7428. // skips N processors of similar type
  7429. // returns -1 if type not found
  7430. int ADSP_FindProc( pset_t *ppset, int proc_type, int skip )
  7431. {
  7432. int skipcount = skip;
  7433. for (int i = 0; i < ppset->cprcs; i++)
  7434. {
  7435. // look for match on processor type
  7436. if ( ppset->prcs[i].type == proc_type )
  7437. {
  7438. // skip first N procs of similar type,
  7439. // return index to processor
  7440. if (!skipcount)
  7441. return i;
  7442. skipcount--;
  7443. }
  7444. }
  7445. return -1;
  7446. }
  7447. // interpolate parameter:
  7448. // pnew - target preset
  7449. // pmin - preset with parameter with min value
  7450. // pmax - preset with parameter with max value
  7451. // proc_type - type of processor to look for ie: PRC_RVA or PRC_DLY
  7452. // skipprocs - skip n processors of type
  7453. // iparam - which parameter within processor to interpolate
  7454. // index -
  7455. // index_max: use index/index_max as interpolater between pmin param and pmax param
  7456. // if bexp is true, interpolate exponentially as (index/index_max)^2
  7457. // NOTE: returns with no result if processor type is not found in all presets.
  7458. 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, float flScale = 1.0 )
  7459. {
  7460. // find processor index in pnew
  7461. int iproc_new = ADSP_FindProc( pnew, proc_type, skipprocs);
  7462. int iproc_min = ADSP_FindProc( pmin, proc_type, skipprocs);
  7463. int iproc_max = ADSP_FindProc( pmax, proc_type, skipprocs);
  7464. // make sure processor type found in all presets
  7465. if ( iproc_new < 0 || iproc_min < 0 || iproc_max < 0 )
  7466. return;
  7467. float findex = (float)index/(float)index_max;
  7468. float vmin = pmin->prcs[iproc_min].prm[iparam];
  7469. float vmax = pmax->prcs[iproc_max].prm[iparam];
  7470. float vinterp;
  7471. // interpolate
  7472. if (!bexp)
  7473. vinterp = vmin + (vmax - vmin) * findex;
  7474. else
  7475. vinterp = vmin + (vmax - vmin) * findex * findex;
  7476. pnew->prcs[iproc_new].prm[iparam] = vinterp * flScale;
  7477. return;
  7478. }
  7479. // directly set parameter
  7480. void ADSP_SetParam( pset_t *pnew, int proc_type, int skipprocs, int iparam, float value )
  7481. {
  7482. int iproc_new = ADSP_FindProc( pnew, proc_type, skipprocs);
  7483. if (iproc_new >= 0)
  7484. pnew->prcs[iproc_new].prm[iparam] = value;
  7485. }
  7486. // directly set parameter if min or max is negative
  7487. 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 )
  7488. {
  7489. // find processor index in pnew
  7490. int iproc_new = ADSP_FindProc( pnew, proc_type, skipprocs);
  7491. int iproc_min = ADSP_FindProc( pmin, proc_type, skipprocs);
  7492. int iproc_max = ADSP_FindProc( pmax, proc_type, skipprocs);
  7493. // make sure processor type found in all presets
  7494. if ( iproc_new < 0 || iproc_min < 0 || iproc_max < 0 )
  7495. return;
  7496. float vmin = pmin->prcs[iproc_min].prm[iparam];
  7497. float vmax = pmax->prcs[iproc_max].prm[iparam];
  7498. if ( vmin < 0.0 || vmax < 0.0 )
  7499. ADSP_SetParam( pnew, proc_type, skipprocs, iparam, value );
  7500. else
  7501. ADSP_InterpParam( pnew, pmin, pmax, proc_type, skipprocs, iparam, index, index_max, bexp);
  7502. return;
  7503. }
  7504. // given min and max preset and auto parameters, create new preset
  7505. // NOTE: the # and type of processors making up pmin and pmax presets must be identical!
  7506. ConVar adsp_scale_delay_gain("adsp_scale_delay_gain", "0.2", FCVAR_NONE );
  7507. ConVar adsp_scale_delay_feedback("adsp_scale_delay_feedback", "0.2", FCVAR_NONE );
  7508. void ADSP_InterpolatePreset( pset_t *pnew, pset_t *pmin, pset_t *pmax, adsp_auto_params_t *pa, int iskip )
  7509. {
  7510. int i;
  7511. // if size > mid size, then copy basic processors from MAX preset,
  7512. // otherwise, copy from MIN preset
  7513. if ( !iskip )
  7514. {
  7515. // only copy on 1st call
  7516. if ( pa->size > ADSP_SIZE_MEDIUM )
  7517. {
  7518. *pnew = *pmax;
  7519. }
  7520. else
  7521. {
  7522. *pnew = *pmin;
  7523. }
  7524. }
  7525. // DFR
  7526. // interpolate all DFR params on size
  7527. for (i = 0; i < dfr_cparam; i++)
  7528. ADSP_InterpParam( pnew, pmin, pmax, PRC_DFR, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7529. // RVA
  7530. // interpolate size_max, size_min, feedback, #delays, moddly, imodrate, based on ap size
  7531. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_ifeedback, pa->size, ADSP_SIZE_MAX, 0);
  7532. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_size_min, pa->size, ADSP_SIZE_MAX, 1);
  7533. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_size_max, pa->size, ADSP_SIZE_MAX, 1);
  7534. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_igain, pa->size, ADSP_SIZE_MAX, 0);
  7535. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_inumdelays, pa->size, ADSP_SIZE_MAX , 0);
  7536. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_imoddly, pa->size, ADSP_SIZE_MAX , 0);
  7537. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_imodrate, pa->size, ADSP_SIZE_MAX , 0);
  7538. // interpolate width,depth,height based on ap width length & height - exponential interpolation
  7539. // if pmin or pmax parameters are < 0, directly set value from w/l/h
  7540. float w = clamp( ((float)(pa->width) / 12.0), 6.0, 500.0); // in feet
  7541. float l = clamp( ((float)(pa->length) / 12.0), 6.0, 500.0);
  7542. float h = clamp( ((float)(pa->height) / 12.0), 6.0, 500.0);
  7543. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_RVA, iskip, rva_width, pa->wid, ADSP_WIDTH_MAX, 1, w);
  7544. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_RVA, iskip, rva_depth, pa->len, ADSP_LENGTH_MAX, 1, l);
  7545. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_RVA, iskip, rva_height, pa->ht, ADSP_HEIGHT_MAX, 1, h);
  7546. // interpolate w/d/h feedback based on ap w/d/f
  7547. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_fbwidth, pa->wid, ADSP_WIDTH_MAX , 0);
  7548. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_fbdepth, pa->len, ADSP_LENGTH_MAX , 0);
  7549. ADSP_InterpParam( pnew, pmin, pmax, PRC_RVA, iskip, rva_fbheight, pa->ht, ADSP_HEIGHT_MAX , 0);
  7550. // interpolate cutoff based on ap reflectivity
  7551. // NOTE: cutoff goes from max to min! ie: small bright - large dull
  7552. ADSP_InterpParam( pnew, pmax, pmin, PRC_RVA, iskip, rva_icutoff, pa->reflectivity, ADSP_REFLECTIVITY_MAX , 0);
  7553. // don't interpolate: fparallel, ftaps
  7554. // DLY
  7555. // directly set delay value from pa->length if pmin or pmax value is < 0
  7556. l = clamp((pa->length * 2.0 / 12.0), 14.0, 500.0);
  7557. w = clamp((pa->width * 2.0 / 12.0), 14.0, 500.0);
  7558. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_idelay, pa->len, ADSP_LENGTH_MAX, 1, l);
  7559. // interpolate feedback, gain, based on max size (length)
  7560. ADSP_InterpParam( pnew, pmin, pmax, PRC_DLY, iskip, dly_ifeedback, pa->len, ADSP_LENGTH_MAX , 0, adsp_scale_delay_gain.GetFloat() );
  7561. ADSP_InterpParam( pnew, pmin, pmax, PRC_DLY, iskip, dly_igain, pa->len, ADSP_LENGTH_MAX , 0, adsp_scale_delay_feedback.GetFloat());
  7562. // directly set tap value from pa->width if pmin or pmax value is < 0
  7563. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_itap1, pa->len, ADSP_LENGTH_MAX, 1, w);
  7564. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_itap2, pa->len, ADSP_LENGTH_MAX, 1, l);
  7565. ADSP_SetParamIfNegative( pnew, pmin, pmax, PRC_DLY, iskip, dly_itap3, pa->len, ADSP_LENGTH_MAX, 1, l);
  7566. // interpolate cutoff and qwidth based on reflectivity NOTE: this can affect gain!
  7567. // NOTE: cutoff goes from max to min! ie: small bright - large dull
  7568. ADSP_InterpParam( pnew, pmax, pmin, PRC_DLY, iskip, dly_icutoff, pa->len, ADSP_LENGTH_MAX , 0);
  7569. ADSP_InterpParam( pnew, pmax, pmin, PRC_DLY, iskip, dly_iqwidth, pa->len, ADSP_LENGTH_MAX , 0);
  7570. // interpolate all other parameters for all other processor types based on size
  7571. // PRC_MDY, PRC_AMP, PRC_FLT, PTC, CRS, ENV, EFO, LFO
  7572. for (i = 0; i < mdy_cparam; i++)
  7573. ADSP_InterpParam( pnew, pmin, pmax, PRC_MDY, iskip, i, pa->len, ADSP_LENGTH_MAX , 0);
  7574. for (i = 0; i < amp_cparam; i++)
  7575. ADSP_InterpParam( pnew, pmin, pmax, PRC_AMP, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7576. for (i = 0; i < flt_cparam; i++)
  7577. ADSP_InterpParam( pnew, pmin, pmax, PRC_FLT, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7578. for (i = 0; i < ptc_cparam; i++)
  7579. ADSP_InterpParam( pnew, pmin, pmax, PRC_PTC, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7580. for (i = 0; i < crs_cparam; i++)
  7581. ADSP_InterpParam( pnew, pmin, pmax, PRC_CRS, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7582. for (i = 0; i < env_cparam; i++)
  7583. ADSP_InterpParam( pnew, pmin, pmax, PRC_ENV, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7584. for (i = 0; i < efo_cparam; i++)
  7585. ADSP_InterpParam( pnew, pmin, pmax, PRC_EFO, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7586. for (i = 0; i < lfo_cparam; i++)
  7587. ADSP_InterpParam( pnew, pmin, pmax, PRC_LFO, iskip, i, pa->size, ADSP_SIZE_MAX , 0);
  7588. }
  7589. // these convars store the index to the first preset for each shape type in dsp_presets.txt
  7590. ConVar adsp_room_min ("adsp_room_min", "102");
  7591. ConVar adsp_duct_min ("adsp_duct_min", "106");
  7592. ConVar adsp_hall_min ("adsp_hall_min", "110");
  7593. ConVar adsp_tunnel_min ("adsp_tunnel_min", "114");
  7594. ConVar adsp_street_min ("adsp_street_min", "118");
  7595. ConVar adsp_alley_min ("adsp_alley_min", "122");
  7596. ConVar adsp_courtyard_min ("adsp_courtyard_min", "126");
  7597. ConVar adsp_openspace_min ("adsp_openspace_min", "130");
  7598. ConVar adsp_openwall_min ("adsp_openwall_min", "130");
  7599. ConVar adsp_openstreet_min ("adsp_openstreet_min", "118");
  7600. ConVar adsp_opencourtyard_min ("adsp_opencourtyard_min", "126");
  7601. // given room parameters, construct and return a dsp preset representing the room.
  7602. // bskyabove, width, length, height, fdiffusion, freflectivity are all passed-in room parameters
  7603. // psurf_refl is a passed-in array of reflectivity values for 6 surfaces
  7604. // inode is the location within g_psettemplates[] that the dsp preset will be constructed (inode = dsp preset#)
  7605. // cnode should always = DSP_CAUTO_PRESETS
  7606. // returns idsp preset.
  7607. int DSP_ConstructPreset( bool bskyabove, int width, int length, int height, float fdiffusion, float freflectivity, float *psurf_refl, int inode, int cnodes)
  7608. {
  7609. adsp_auto_params_t ap;
  7610. adsp_auto_params_t *pa;
  7611. pset_t new_pset; // preset
  7612. pset_t pset_min;
  7613. pset_t pset_max;
  7614. int ipreset;
  7615. int ipset_min;
  7616. int ipset_max;
  7617. if (inode >= DSP_CAUTO_PRESETS)
  7618. {
  7619. Assert(false); // check DAS_CNODES == DSP_CAUTO_PRESETS!!!
  7620. return 0;
  7621. }
  7622. // fill parameter struct
  7623. ap.bskyabove = bskyabove;
  7624. ap.width = width;
  7625. ap.length = length;
  7626. ap.height = height;
  7627. ap.fdiffusion = fdiffusion;
  7628. ap.freflectivity = freflectivity;
  7629. for (int i = 0; i < 6; i++)
  7630. ap.surface_refl[i] = psurf_refl[i];
  7631. if (ap.bskyabove)
  7632. ap.surface_refl[4] = 0.0;
  7633. // select shape, size based on params
  7634. ADSP_GetAutoShape( &ap );
  7635. // set up min/max presets based on shape
  7636. switch ( ap.shape )
  7637. {
  7638. default:
  7639. case ADSP_ROOM: ipset_min = adsp_room_min.GetInt(); break;
  7640. case ADSP_DUCT: ipset_min = adsp_duct_min.GetInt(); break;
  7641. case ADSP_HALL: ipset_min = adsp_hall_min.GetInt(); break;
  7642. case ADSP_TUNNEL: ipset_min = adsp_tunnel_min.GetInt(); break;
  7643. case ADSP_STREET: ipset_min = adsp_street_min.GetInt(); break;
  7644. case ADSP_ALLEY: ipset_min = adsp_alley_min.GetInt(); break;
  7645. case ADSP_COURTYARD: ipset_min = adsp_courtyard_min.GetInt(); break;
  7646. case ADSP_OPEN_SPACE: ipset_min = adsp_openspace_min.GetInt(); break;
  7647. case ADSP_OPEN_WALL: ipset_min = adsp_openwall_min.GetInt(); break;
  7648. case ADSP_OPEN_STREET: ipset_min = adsp_openstreet_min.GetInt(); break;
  7649. case ADSP_OPEN_COURTYARD: ipset_min = adsp_opencourtyard_min.GetInt(); break;
  7650. }
  7651. // presets in dsp_presets.txt are ordered as:
  7652. // <shape><empty><min>
  7653. // <shape><empty><max>
  7654. // <shape><diffuse><min>
  7655. // <shape><diffuse><max>
  7656. pa = &ap;
  7657. if ( ADSP_IsDiffuse(pa) )
  7658. ipset_min += 2;
  7659. ipset_max = ipset_min + 1;
  7660. pset_min = g_psettemplates[ipset_min];
  7661. pset_max = g_psettemplates[ipset_max];
  7662. if( das_debug.GetInt() )
  7663. {
  7664. DevMsg( "DAS: Min Preset Index: %i\nDAS: Max Preset Index: %i\n", ipset_min, ipset_max );
  7665. }
  7666. // given min and max preset and auto parameters, create new preset
  7667. // interpolate between 1st instances of each processor type (ie: PRC_DLY) appearing in preset
  7668. ADSP_InterpolatePreset( &new_pset, &pset_min, &pset_max, &ap, 0 );
  7669. // interpolate between 2nd instances of each processor type (ie: PRC_DLY) appearing in preset
  7670. ADSP_InterpolatePreset( &new_pset, &pset_min, &pset_max, &ap, 1 );
  7671. // copy constructed preset back into node's template location
  7672. ipreset = DSP_AUTO_BASE + inode;
  7673. g_psettemplates[ipreset] = new_pset;
  7674. return ipreset;
  7675. }
  7676. ///////////////////////////////////////
  7677. // Helpers: called only from DSP_Process
  7678. ///////////////////////////////////////
  7679. // return true if batch processing version of preset exists
  7680. inline bool FBatchPreset( pset_t *ppset )
  7681. {
  7682. switch (ppset->type)
  7683. {
  7684. case PSET_LINEAR:
  7685. return true;
  7686. case PSET_SIMPLE:
  7687. return true;
  7688. default:
  7689. return false;
  7690. }
  7691. }
  7692. // Helper: called only from DSP_Process
  7693. // mix front stereo buffer to mono buffer, apply dsp fx
  7694. inline void DSP_ProcessStereoToMono(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  7695. {
  7696. VPROF( "DSP_ProcessStereoToMono" );
  7697. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  7698. int count = sampleCount;
  7699. int av;
  7700. int x;
  7701. if ( !bcrossfading )
  7702. {
  7703. if ( !pdsp->ipset )
  7704. return;
  7705. if ( FBatchPreset(pdsp->ppset[0]))
  7706. {
  7707. // convert Stereo to Mono in place, then batch process fx: perf KDB
  7708. // front->left + front->right / 2 into front->left, front->right duplicated.
  7709. while ( count-- )
  7710. {
  7711. pbf->left = (pbf->left + pbf->right) >> 1;
  7712. pbf++;
  7713. }
  7714. // process left (mono), duplicate output into right
  7715. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  7716. }
  7717. else
  7718. {
  7719. // avg left and right -> mono fx -> duplicate out left and right
  7720. while ( count-- )
  7721. {
  7722. av = ( ( pbf->left + pbf->right ) >> 1 );
  7723. x = PSET_GetNext( pdsp->ppset[0], av );
  7724. x = CLIP_DSP( x );
  7725. pbf->left = pbf->right = x;
  7726. pbf++;
  7727. }
  7728. }
  7729. return;
  7730. }
  7731. // crossfading to current preset from previous preset
  7732. if ( bcrossfading )
  7733. {
  7734. int r;
  7735. int fl;
  7736. int fr;
  7737. int flp;
  7738. int frp;
  7739. int xf_fl;
  7740. int xf_fr;
  7741. bool bexp = pdsp->bexpfade;
  7742. bool bfadetostereo = (pdsp->ipset == 0);
  7743. bool bfadefromstereo = (pdsp->ipsetprev == 0);
  7744. Assert ( !(bfadetostereo && bfadefromstereo) ); // don't call if ipset & ipsetprev both 0!
  7745. if ( bfadetostereo || bfadefromstereo )
  7746. {
  7747. // special case if fading to or from preset 0, stereo passthrough
  7748. while ( count-- )
  7749. {
  7750. av = ( ( pbf->left + pbf->right ) >> 1 );
  7751. // get current preset values
  7752. if ( pdsp->ipset )
  7753. {
  7754. fl = fr = PSET_GetNext( pdsp->ppset[0], av );
  7755. }
  7756. else
  7757. {
  7758. fl = pbf->left;
  7759. fr = pbf->right;
  7760. }
  7761. // get previous preset values
  7762. if ( pdsp->ipsetprev )
  7763. {
  7764. frp = flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  7765. }
  7766. else
  7767. {
  7768. flp = pbf->left;
  7769. frp = pbf->right;
  7770. }
  7771. fl = CLIP_DSP(fl);
  7772. fr = CLIP_DSP(fr);
  7773. flp = CLIP_DSP(flp);
  7774. frp = CLIP_DSP(frp);
  7775. // get current ramp value
  7776. r = RMP_GetNext( &pdsp->xramp );
  7777. // crossfade from previous to current preset
  7778. if (!bexp)
  7779. {
  7780. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  7781. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  7782. }
  7783. else
  7784. {
  7785. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  7786. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  7787. }
  7788. pbf->left = xf_fl; // crossfaded front left, duplicate in right channel
  7789. pbf->right = xf_fr;
  7790. pbf++;
  7791. }
  7792. return;
  7793. }
  7794. // crossfade mono to mono preset
  7795. while ( count-- )
  7796. {
  7797. av = ( ( pbf->left + pbf->right ) >> 1 );
  7798. // get current preset values
  7799. fl = PSET_GetNext( pdsp->ppset[0], av );
  7800. // get previous preset values
  7801. flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  7802. fl = CLIP_DSP(fl);
  7803. flp = CLIP_DSP(flp);
  7804. // get current ramp value
  7805. r = RMP_GetNext( &pdsp->xramp );
  7806. // crossfade from previous to current preset
  7807. if (!bexp)
  7808. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  7809. else
  7810. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  7811. pbf->left = xf_fl; // crossfaded front left, duplicate in right channel
  7812. pbf->right = xf_fl;
  7813. pbf++;
  7814. }
  7815. }
  7816. }
  7817. // Helper: called only from DSP_Process
  7818. // DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
  7819. inline void DSP_ProcessStereoToStereo(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  7820. {
  7821. VPROF( "DSP_ProcessStereoToStereo" );
  7822. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  7823. int count = sampleCount;
  7824. int fl, fr;
  7825. if ( !bcrossfading )
  7826. {
  7827. if ( !pdsp->ipset )
  7828. return;
  7829. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) )
  7830. {
  7831. // process left & right
  7832. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT );
  7833. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  7834. }
  7835. else
  7836. {
  7837. // left -> left fx, right -> right fx
  7838. while ( count-- )
  7839. {
  7840. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  7841. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  7842. fl = CLIP_DSP( fl );
  7843. fr = CLIP_DSP( fr );
  7844. pbf->left = fl;
  7845. pbf->right = fr;
  7846. pbf++;
  7847. }
  7848. }
  7849. return;
  7850. }
  7851. // crossfading to current preset from previous preset
  7852. if ( bcrossfading )
  7853. {
  7854. int r;
  7855. int flp, frp;
  7856. int xf_fl, xf_fr;
  7857. bool bexp = pdsp->bexpfade;
  7858. while ( count-- )
  7859. {
  7860. // get current preset values
  7861. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  7862. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  7863. // get previous preset values
  7864. flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  7865. frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  7866. // get current ramp value
  7867. r = RMP_GetNext( &pdsp->xramp );
  7868. fl = CLIP_DSP( fl );
  7869. fr = CLIP_DSP( fr );
  7870. flp = CLIP_DSP( flp );
  7871. frp = CLIP_DSP( frp );
  7872. // crossfade from previous to current preset
  7873. if (!bexp)
  7874. {
  7875. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  7876. xf_fr = XFADE(fr, frp, r);
  7877. }
  7878. else
  7879. {
  7880. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  7881. xf_fr = XFADE_EXP(fr, frp, r);
  7882. }
  7883. pbf->left = xf_fl; // crossfaded front left
  7884. pbf->right = xf_fr;
  7885. pbf++;
  7886. }
  7887. }
  7888. }
  7889. // Helper: called only from DSP_Process
  7890. // DSP_Process quad in to mono out (front left = front right)
  7891. inline void DSP_ProcessQuadToMono(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  7892. {
  7893. VPROF( "DSP_ProcessQuadToMono" );
  7894. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  7895. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  7896. int count = sampleCount;
  7897. int x;
  7898. int av;
  7899. if ( !bcrossfading )
  7900. {
  7901. if ( !pdsp->ipset )
  7902. return;
  7903. if ( FBatchPreset(pdsp->ppset[0]) )
  7904. {
  7905. // convert Quad to Mono in place, then batch process fx: perf KDB
  7906. // left front + rear -> left, right front + rear -> right
  7907. while ( count-- )
  7908. {
  7909. pbf->left = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  7910. pbf++;
  7911. pbr++;
  7912. }
  7913. // process left (mono), duplicate into right
  7914. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  7915. // copy processed front to rear
  7916. count = sampleCount;
  7917. pbf = pbfront;
  7918. pbr = pbrear;
  7919. while ( count-- )
  7920. {
  7921. pbr->left = pbf->left;
  7922. pbr->right = pbf->right;
  7923. pbf++;
  7924. pbr++;
  7925. }
  7926. }
  7927. else
  7928. {
  7929. // avg fl,fr,rl,rr into mono fx, duplicate on all channels
  7930. while ( count-- )
  7931. {
  7932. av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  7933. x = PSET_GetNext( pdsp->ppset[0], av );
  7934. x = CLIP_DSP( x );
  7935. pbr->left = pbr->right = pbf->left = pbf->right = x;
  7936. pbf++;
  7937. pbr++;
  7938. }
  7939. }
  7940. return;
  7941. }
  7942. if ( bcrossfading )
  7943. {
  7944. int r;
  7945. int fl, fr, rl, rr;
  7946. int flp, frp, rlp, rrp;
  7947. int xf_fl, xf_fr, xf_rl, xf_rr;
  7948. bool bexp = pdsp->bexpfade;
  7949. bool bfadetoquad = (pdsp->ipset == 0);
  7950. bool bfadefromquad = (pdsp->ipsetprev == 0);
  7951. if ( bfadetoquad || bfadefromquad )
  7952. {
  7953. // special case if previous or current preset is 0 (quad passthrough)
  7954. while ( count-- )
  7955. {
  7956. av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  7957. // get current preset values
  7958. // current preset is 0, which implies fading to passthrough quad output
  7959. // need to fade from mono to quad
  7960. if ( pdsp->ipset )
  7961. {
  7962. rl = rr = fl = fr = PSET_GetNext( pdsp->ppset[0], av );
  7963. }
  7964. else
  7965. {
  7966. fl = pbf->left;
  7967. fr = pbf->right;
  7968. rl = pbr->left;
  7969. rr = pbr->right;
  7970. }
  7971. // get previous preset values
  7972. if ( pdsp->ipsetprev )
  7973. {
  7974. rrp = rlp = frp = flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  7975. }
  7976. else
  7977. {
  7978. flp = pbf->left;
  7979. frp = pbf->right;
  7980. rlp = pbr->left;
  7981. rrp = pbr->right;
  7982. }
  7983. fl = CLIP_DSP(fl);
  7984. fr = CLIP_DSP(fr);
  7985. flp = CLIP_DSP(flp);
  7986. frp = CLIP_DSP(frp);
  7987. rl = CLIP_DSP(rl);
  7988. rr = CLIP_DSP(rr);
  7989. rlp = CLIP_DSP(rlp);
  7990. rrp = CLIP_DSP(rrp);
  7991. // get current ramp value
  7992. r = RMP_GetNext( &pdsp->xramp );
  7993. // crossfade from previous to current preset
  7994. if (!bexp)
  7995. {
  7996. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  7997. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  7998. xf_rl = XFADE(rl, rlp, r); // crossfade front left previous to front left
  7999. xf_rr = XFADE(rr, rrp, r); // crossfade front left previous to front left
  8000. }
  8001. else
  8002. {
  8003. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8004. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  8005. xf_rl = XFADE_EXP(rl, rlp, r); // crossfade front left previous to front left
  8006. xf_rr = XFADE_EXP(rr, rrp, r); // crossfade front left previous to front left
  8007. }
  8008. pbf->left = xf_fl;
  8009. pbf->right = xf_fr;
  8010. pbr->left = xf_rl;
  8011. pbr->right = xf_rr;
  8012. pbf++;
  8013. pbr++;
  8014. }
  8015. return;
  8016. }
  8017. while ( count-- )
  8018. {
  8019. av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  8020. // get current preset values
  8021. fl = PSET_GetNext( pdsp->ppset[0], av );
  8022. // get previous preset values
  8023. flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  8024. // get current ramp value
  8025. r = RMP_GetNext( &pdsp->xramp );
  8026. fl = CLIP_DSP( fl );
  8027. flp = CLIP_DSP( flp );
  8028. // crossfade from previous to current preset
  8029. if (!bexp)
  8030. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8031. else
  8032. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8033. pbf->left = xf_fl; // crossfaded front left, duplicated to all channels
  8034. pbf->right = xf_fl;
  8035. pbr->left = xf_fl;
  8036. pbr->right = xf_fl;
  8037. pbf++;
  8038. pbr++;
  8039. }
  8040. }
  8041. }
  8042. // Helper: called only from DSP_Process
  8043. // DSP_Process quad in to stereo out (preserve stereo spatialization, throw away front/rear)
  8044. inline void DSP_ProcessQuadToStereo(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  8045. {
  8046. VPROF( "DSP_ProcessQuadToStereo" );
  8047. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  8048. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  8049. int count = sampleCount;
  8050. int fl, fr;
  8051. if ( !bcrossfading )
  8052. {
  8053. if ( !pdsp->ipset )
  8054. return;
  8055. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) )
  8056. {
  8057. // convert Quad to Stereo in place, then batch process fx: perf KDB
  8058. // left front + rear -> left, right front + rear -> right
  8059. while ( count-- )
  8060. {
  8061. pbf->left = (pbf->left + pbr->left) >> 1;
  8062. pbf->right = (pbf->right + pbr->right) >> 1;
  8063. pbf++;
  8064. pbr++;
  8065. }
  8066. // process left & right
  8067. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT);
  8068. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  8069. // copy processed front to rear
  8070. count = sampleCount;
  8071. pbf = pbfront;
  8072. pbr = pbrear;
  8073. while ( count-- )
  8074. {
  8075. pbr->left = pbf->left;
  8076. pbr->right = pbf->right;
  8077. pbf++;
  8078. pbr++;
  8079. }
  8080. }
  8081. else
  8082. {
  8083. // left front + rear -> left fx, right front + rear -> right fx
  8084. while ( count-- )
  8085. {
  8086. fl = PSET_GetNext( pdsp->ppset[0], (pbf->left + pbr->left) >> 1);
  8087. fr = PSET_GetNext( pdsp->ppset[1], (pbf->right + pbr->right) >> 1);
  8088. fl = CLIP_DSP( fl );
  8089. fr = CLIP_DSP( fr );
  8090. pbr->left = pbf->left = fl;
  8091. pbr->right = pbf->right = fr;
  8092. pbf++;
  8093. pbr++;
  8094. }
  8095. }
  8096. return;
  8097. }
  8098. // crossfading to current preset from previous preset
  8099. if ( bcrossfading )
  8100. {
  8101. int r;
  8102. int fl, fr, rl, rr;
  8103. int flp, frp, rlp, rrp;
  8104. int xf_fl, xf_fr, xf_rl, xf_rr;
  8105. int avl, avr;
  8106. bool bexp = pdsp->bexpfade;
  8107. bool bfadetoquad = (pdsp->ipset == 0);
  8108. bool bfadefromquad = (pdsp->ipsetprev == 0);
  8109. if ( bfadetoquad || bfadefromquad )
  8110. {
  8111. // special case if previous or current preset is 0 (quad passthrough)
  8112. while ( count-- )
  8113. {
  8114. avl = (pbf->left + pbr->left) >> 1;
  8115. avr = (pbf->right + pbr->right) >> 1;
  8116. // get current preset values
  8117. // current preset is 0, which implies fading to passthrough quad output
  8118. // need to fade from stereo to quad
  8119. if ( pdsp->ipset )
  8120. {
  8121. rl = fl = PSET_GetNext( pdsp->ppset[0], avl );
  8122. rr = fr = PSET_GetNext( pdsp->ppset[0], avr );
  8123. }
  8124. else
  8125. {
  8126. fl = pbf->left;
  8127. fr = pbf->right;
  8128. rl = pbr->left;
  8129. rr = pbr->right;
  8130. }
  8131. // get previous preset values
  8132. if ( pdsp->ipsetprev )
  8133. {
  8134. rlp = flp = PSET_GetNext( pdsp->ppsetprev[0], avl );
  8135. rrp = frp = PSET_GetNext( pdsp->ppsetprev[0], avr );
  8136. }
  8137. else
  8138. {
  8139. flp = pbf->left;
  8140. frp = pbf->right;
  8141. rlp = pbr->left;
  8142. rrp = pbr->right;
  8143. }
  8144. fl = CLIP_DSP(fl);
  8145. fr = CLIP_DSP(fr);
  8146. flp = CLIP_DSP(flp);
  8147. frp = CLIP_DSP(frp);
  8148. rl = CLIP_DSP(rl);
  8149. rr = CLIP_DSP(rr);
  8150. rlp = CLIP_DSP(rlp);
  8151. rrp = CLIP_DSP(rrp);
  8152. // get current ramp value
  8153. r = RMP_GetNext( &pdsp->xramp );
  8154. // crossfade from previous to current preset
  8155. if (!bexp)
  8156. {
  8157. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8158. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  8159. xf_rl = XFADE(rl, rlp, r); // crossfade front left previous to front left
  8160. xf_rr = XFADE(rr, rrp, r); // crossfade front left previous to front left
  8161. }
  8162. else
  8163. {
  8164. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8165. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  8166. xf_rl = XFADE_EXP(rl, rlp, r); // crossfade front left previous to front left
  8167. xf_rr = XFADE_EXP(rr, rrp, r); // crossfade front left previous to front left
  8168. }
  8169. pbf->left = xf_fl;
  8170. pbf->right = xf_fr;
  8171. pbr->left = xf_rl;
  8172. pbr->right = xf_rr;
  8173. pbf++;
  8174. pbr++;
  8175. }
  8176. return;
  8177. }
  8178. while ( count-- )
  8179. {
  8180. avl = (pbf->left + pbr->left) >> 1;
  8181. avr = (pbf->right + pbr->right) >> 1;
  8182. // get current preset values
  8183. fl = PSET_GetNext( pdsp->ppset[0], avl );
  8184. fr = PSET_GetNext( pdsp->ppset[1], avr );
  8185. // get previous preset values
  8186. flp = PSET_GetNext( pdsp->ppsetprev[0], avl );
  8187. frp = PSET_GetNext( pdsp->ppsetprev[1], avr );
  8188. fl = CLIP_DSP( fl );
  8189. fr = CLIP_DSP( fr );
  8190. // get previous preset values
  8191. flp = CLIP_DSP( flp );
  8192. frp = CLIP_DSP( frp );
  8193. // get current ramp value
  8194. r = RMP_GetNext( &pdsp->xramp );
  8195. // crossfade from previous to current preset
  8196. if (!bexp)
  8197. {
  8198. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8199. xf_fr = XFADE(fr, frp, r);
  8200. }
  8201. else
  8202. {
  8203. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8204. xf_fr = XFADE_EXP(fr, frp, r);
  8205. }
  8206. pbf->left = xf_fl; // crossfaded front left
  8207. pbf->right = xf_fr;
  8208. pbr->left = xf_fl; // duplicate front channel to rear channel
  8209. pbr->right = xf_fr;
  8210. pbf++;
  8211. pbr++;
  8212. }
  8213. }
  8214. }
  8215. // Helper: called only from DSP_Process
  8216. // DSP_Process quad in to quad out
  8217. inline void DSP_ProcessQuadToQuad(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, int sampleCount, bool bcrossfading )
  8218. {
  8219. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  8220. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  8221. int count = sampleCount;
  8222. int fl, fr, rl, rr;
  8223. if ( !bcrossfading )
  8224. {
  8225. if ( !pdsp->ipset )
  8226. return;
  8227. // each channel gets its own processor
  8228. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) && FBatchPreset(pdsp->ppset[2]) && FBatchPreset(pdsp->ppset[3]))
  8229. {
  8230. // batch process fx front & rear, left & right: perf KDB
  8231. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT);
  8232. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  8233. PSET_GetNextN( pdsp->ppset[2], pbrear, sampleCount, OP_LEFT );
  8234. PSET_GetNextN( pdsp->ppset[3], pbrear, sampleCount, OP_RIGHT );
  8235. }
  8236. else
  8237. {
  8238. while ( count-- )
  8239. {
  8240. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  8241. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  8242. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  8243. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  8244. pbf->left = CLIP_DSP( fl );
  8245. pbf->right = CLIP_DSP( fr );
  8246. pbr->left = CLIP_DSP( rl );
  8247. pbr->right = CLIP_DSP( rr );
  8248. pbf++;
  8249. pbr++;
  8250. }
  8251. }
  8252. return;
  8253. }
  8254. // crossfading to current preset from previous preset
  8255. if ( bcrossfading )
  8256. {
  8257. int r;
  8258. int fl, fr, rl, rr;
  8259. int flp, frp, rlp, rrp;
  8260. int xf_fl, xf_fr, xf_rl, xf_rr;
  8261. bool bexp = pdsp->bexpfade;
  8262. while ( count-- )
  8263. {
  8264. // get current preset values
  8265. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  8266. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  8267. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  8268. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  8269. // get previous preset values
  8270. flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  8271. frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  8272. rlp = PSET_GetNext( pdsp->ppsetprev[2], pbr->left );
  8273. rrp = PSET_GetNext( pdsp->ppsetprev[3], pbr->right );
  8274. // get current ramp value
  8275. r = RMP_GetNext( &pdsp->xramp );
  8276. // crossfade from previous to current preset
  8277. if (!bexp)
  8278. {
  8279. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8280. xf_fr = XFADE(fr, frp, r);
  8281. xf_rl = XFADE(rl, rlp, r);
  8282. xf_rr = XFADE(rr, rrp, r);
  8283. }
  8284. else
  8285. {
  8286. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8287. xf_fr = XFADE_EXP(fr, frp, r);
  8288. xf_rl = XFADE_EXP(rl, rlp, r);
  8289. xf_rr = XFADE_EXP(rr, rrp, r);
  8290. }
  8291. pbf->left = CLIP_DSP(xf_fl); // crossfaded front left
  8292. pbf->right = CLIP_DSP(xf_fr);
  8293. pbr->left = CLIP_DSP(xf_rl);
  8294. pbr->right = CLIP_DSP(xf_rr);
  8295. pbf++;
  8296. pbr++;
  8297. }
  8298. }
  8299. }
  8300. // Helper: called only from DSP_Process
  8301. // DSP_Process quad + center in to mono out (front left = front right)
  8302. inline void DSP_Process5To1(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, portable_samplepair_t *pbcenter, int sampleCount, bool bcrossfading )
  8303. {
  8304. VPROF( "DSP_Process5To1" );
  8305. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  8306. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  8307. portable_samplepair_t *pbc = pbcenter; // pointer to buffer of center mono samples to process
  8308. int count = sampleCount;
  8309. int x;
  8310. int av;
  8311. if ( !bcrossfading )
  8312. {
  8313. if ( !pdsp->ipset )
  8314. return;
  8315. if ( FBatchPreset(pdsp->ppset[0]) )
  8316. {
  8317. // convert Quad + Center to Mono in place, then batch process fx: perf KDB
  8318. // left front + rear -> left, right front + rear -> right
  8319. while ( count-- )
  8320. {
  8321. // pbf->left = ((pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) / 5);
  8322. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  8323. av >>= 8;
  8324. pbf->left = av;
  8325. pbf++;
  8326. pbr++;
  8327. pbc++;
  8328. }
  8329. // process left (mono), duplicate into right
  8330. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  8331. // copy processed front to rear & center
  8332. count = sampleCount;
  8333. pbf = pbfront;
  8334. pbr = pbrear;
  8335. pbc = pbcenter;
  8336. while ( count-- )
  8337. {
  8338. pbr->left = pbf->left;
  8339. pbr->right = pbf->right;
  8340. pbc->left = pbf->left;
  8341. pbf++;
  8342. pbr++;
  8343. pbc++;
  8344. }
  8345. }
  8346. else
  8347. {
  8348. // avg fl,fr,rl,rr,fc into mono fx, duplicate on all channels
  8349. while ( count-- )
  8350. {
  8351. // av = ((pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) / 5);
  8352. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  8353. av >>= 8;
  8354. x = PSET_GetNext( pdsp->ppset[0], av );
  8355. x = CLIP_DSP( x );
  8356. pbr->left = pbr->right = pbf->left = pbf->right = pbc->left = x;
  8357. pbf++;
  8358. pbr++;
  8359. pbc++;
  8360. }
  8361. }
  8362. return;
  8363. }
  8364. if ( bcrossfading )
  8365. {
  8366. int r;
  8367. int fl, fr, rl, rr, fc;
  8368. int flp, frp, rlp, rrp, fcp;
  8369. int xf_fl, xf_fr, xf_rl, xf_rr, xf_fc;
  8370. bool bexp = pdsp->bexpfade;
  8371. bool bfadetoquad = (pdsp->ipset == 0);
  8372. bool bfadefromquad = (pdsp->ipsetprev == 0);
  8373. if ( bfadetoquad || bfadefromquad )
  8374. {
  8375. // special case if previous or current preset is 0 (quad passthrough)
  8376. while ( count-- )
  8377. {
  8378. // av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  8379. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  8380. av >>= 8;
  8381. // get current preset values
  8382. // current preset is 0, which implies fading to passthrough quad output
  8383. // need to fade from mono to quad
  8384. if ( pdsp->ipset )
  8385. {
  8386. fc = rl = rr = fl = fr = PSET_GetNext( pdsp->ppset[0], av );
  8387. }
  8388. else
  8389. {
  8390. fl = pbf->left;
  8391. fr = pbf->right;
  8392. rl = pbr->left;
  8393. rr = pbr->right;
  8394. fc = pbc->left;
  8395. }
  8396. // get previous preset values
  8397. if ( pdsp->ipsetprev )
  8398. {
  8399. fcp = rrp = rlp = frp = flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  8400. }
  8401. else
  8402. {
  8403. flp = pbf->left;
  8404. frp = pbf->right;
  8405. rlp = pbr->left;
  8406. rrp = pbr->right;
  8407. fcp = pbc->left;
  8408. }
  8409. fl = CLIP_DSP(fl);
  8410. fr = CLIP_DSP(fr);
  8411. flp = CLIP_DSP(flp);
  8412. frp = CLIP_DSP(frp);
  8413. rl = CLIP_DSP(rl);
  8414. rr = CLIP_DSP(rr);
  8415. rlp = CLIP_DSP(rlp);
  8416. rrp = CLIP_DSP(rrp);
  8417. fc = CLIP_DSP(fc);
  8418. fcp = CLIP_DSP(fcp);
  8419. // get current ramp value
  8420. r = RMP_GetNext( &pdsp->xramp );
  8421. // crossfade from previous to current preset
  8422. if (!bexp)
  8423. {
  8424. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8425. xf_fr = XFADE(fr, frp, r); // crossfade front left previous to front left
  8426. xf_rl = XFADE(rl, rlp, r); // crossfade front left previous to front left
  8427. xf_rr = XFADE(rr, rrp, r); // crossfade front left previous to front left
  8428. xf_fc = XFADE(fc, fcp, r); // crossfade front left previous to front left
  8429. }
  8430. else
  8431. {
  8432. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8433. xf_fr = XFADE_EXP(fr, frp, r); // crossfade front left previous to front left
  8434. xf_rl = XFADE_EXP(rl, rlp, r); // crossfade front left previous to front left
  8435. xf_rr = XFADE_EXP(rr, rrp, r); // crossfade front left previous to front left
  8436. xf_fc = XFADE_EXP(fc, fcp, r); // crossfade front left previous to front left
  8437. }
  8438. pbf->left = xf_fl;
  8439. pbf->right = xf_fr;
  8440. pbr->left = xf_rl;
  8441. pbr->right = xf_rr;
  8442. pbc->left = xf_fc;
  8443. pbf++;
  8444. pbr++;
  8445. pbc++;
  8446. }
  8447. return;
  8448. }
  8449. while ( count-- )
  8450. {
  8451. // av = ((pbf->left + pbf->right + pbr->left + pbr->right) >> 2);
  8452. av = (pbf->left + pbf->right + pbr->left + pbr->right + pbc->left) * 51; // 51/255 = 1/5
  8453. av >>= 8;
  8454. // get current preset values
  8455. fl = PSET_GetNext( pdsp->ppset[0], av );
  8456. // get previous preset values
  8457. flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  8458. // get current ramp value
  8459. r = RMP_GetNext( &pdsp->xramp );
  8460. fl = CLIP_DSP( fl );
  8461. flp = CLIP_DSP( flp );
  8462. // crossfade from previous to current preset
  8463. if (!bexp)
  8464. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8465. else
  8466. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8467. pbf->left = xf_fl; // crossfaded front left, duplicated to all channels
  8468. pbf->right = xf_fl;
  8469. pbr->left = xf_fl;
  8470. pbr->right = xf_fl;
  8471. pbc->left = xf_fl;
  8472. pbf++;
  8473. pbr++;
  8474. pbc++;
  8475. }
  8476. }
  8477. }
  8478. // Helper: called only from DSP_Process
  8479. // DSP_Process quad + center in to quad + center out
  8480. inline void DSP_Process5To5(dsp_t *pdsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, portable_samplepair_t *pbcenter, int sampleCount, bool bcrossfading )
  8481. {
  8482. VPROF( "DSP_Process5To5" );
  8483. portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  8484. portable_samplepair_t *pbr = pbrear; // pointer to buffer of rear stereo samples to process
  8485. portable_samplepair_t *pbc = pbcenter; // pointer to buffer of center mono samples to process
  8486. int count = sampleCount;
  8487. int fl, fr, rl, rr, fc;
  8488. if ( !bcrossfading )
  8489. {
  8490. if ( !pdsp->ipset )
  8491. return;
  8492. // each channel gets its own processor
  8493. if ( FBatchPreset(pdsp->ppset[0]) && FBatchPreset(pdsp->ppset[1]) && FBatchPreset(pdsp->ppset[2]) && FBatchPreset(pdsp->ppset[3]))
  8494. {
  8495. // batch process fx front & rear, left & right: perf KDB
  8496. PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT);
  8497. PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  8498. PSET_GetNextN( pdsp->ppset[2], pbrear, sampleCount, OP_LEFT );
  8499. PSET_GetNextN( pdsp->ppset[3], pbrear, sampleCount, OP_RIGHT );
  8500. PSET_GetNextN( pdsp->ppset[4], pbcenter, sampleCount, OP_LEFT );
  8501. }
  8502. else
  8503. {
  8504. while ( count-- )
  8505. {
  8506. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  8507. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  8508. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  8509. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  8510. fc = PSET_GetNext( pdsp->ppset[4], pbc->left );
  8511. pbf->left = CLIP_DSP( fl );
  8512. pbf->right = CLIP_DSP( fr );
  8513. pbr->left = CLIP_DSP( rl );
  8514. pbr->right = CLIP_DSP( rr );
  8515. pbc->left = CLIP_DSP( fc );
  8516. pbf++;
  8517. pbr++;
  8518. pbc++;
  8519. }
  8520. }
  8521. return;
  8522. }
  8523. // crossfading to current preset from previous preset
  8524. if ( bcrossfading )
  8525. {
  8526. int r;
  8527. int fl, fr, rl, rr, fc;
  8528. int flp, frp, rlp, rrp, fcp;
  8529. int xf_fl, xf_fr, xf_rl, xf_rr, xf_fc;
  8530. bool bexp = pdsp->bexpfade;
  8531. while ( count-- )
  8532. {
  8533. // get current preset values
  8534. fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  8535. fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  8536. rl = PSET_GetNext( pdsp->ppset[2], pbr->left );
  8537. rr = PSET_GetNext( pdsp->ppset[3], pbr->right );
  8538. fc = PSET_GetNext( pdsp->ppset[4], pbc->left );
  8539. // get previous preset values
  8540. flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  8541. frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  8542. rlp = PSET_GetNext( pdsp->ppsetprev[2], pbr->left );
  8543. rrp = PSET_GetNext( pdsp->ppsetprev[3], pbr->right );
  8544. fcp = PSET_GetNext( pdsp->ppsetprev[4], pbc->left );
  8545. // get current ramp value
  8546. r = RMP_GetNext( &pdsp->xramp );
  8547. // crossfade from previous to current preset
  8548. if (!bexp)
  8549. {
  8550. xf_fl = XFADE(fl, flp, r); // crossfade front left previous to front left
  8551. xf_fr = XFADE(fr, frp, r);
  8552. xf_rl = XFADE(rl, rlp, r);
  8553. xf_rr = XFADE(rr, rrp, r);
  8554. xf_fc = XFADE(fc, fcp, r);
  8555. }
  8556. else
  8557. {
  8558. xf_fl = XFADE_EXP(fl, flp, r); // crossfade front left previous to front left
  8559. xf_fr = XFADE_EXP(fr, frp, r);
  8560. xf_rl = XFADE_EXP(rl, rlp, r);
  8561. xf_rr = XFADE_EXP(rr, rrp, r);
  8562. xf_fc = XFADE_EXP(fc, fcp, r);
  8563. }
  8564. pbf->left = CLIP_DSP(xf_fl); // crossfaded front left
  8565. pbf->right = CLIP_DSP(xf_fr);
  8566. pbr->left = CLIP_DSP(xf_rl);
  8567. pbr->right = CLIP_DSP(xf_rr);
  8568. pbc->left = CLIP_DSP(xf_fc);
  8569. pbf++;
  8570. pbr++;
  8571. pbc++;
  8572. }
  8573. }
  8574. }
  8575. // 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
  8576. // "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
  8577. // outside of this time period modifying any of the dsp convars. It doesn't seem to be an issue just save/loading between levels
  8578. static bool g_bNeedPresetRestore = false;
  8579. //-----------------------------------------------------------------------------
  8580. // Purpose:
  8581. //-----------------------------------------------------------------------------
  8582. struct PreserveDSP_t
  8583. {
  8584. ConVar *cvar;
  8585. float oldvalue;
  8586. };
  8587. static PreserveDSP_t g_PreserveDSP[] =
  8588. {
  8589. { &dsp_room },
  8590. { &dsp_water },
  8591. { &dsp_player },
  8592. { &dsp_facingaway },
  8593. { &dsp_speaker },
  8594. { &dsp_spatial },
  8595. { &dsp_automatic }
  8596. };
  8597. //-----------------------------------------------------------------------------
  8598. // Purpose: Called at the top of CheckNewDspPresets to restore ConVars to real values
  8599. //-----------------------------------------------------------------------------
  8600. void DSP_CheckRestorePresets()
  8601. {
  8602. if ( !g_bNeedPresetRestore )
  8603. return;
  8604. g_bNeedPresetRestore = false;
  8605. int i;
  8606. int c = ARRAYSIZE( g_PreserveDSP );
  8607. // Restore
  8608. for ( i = 0 ; i < c; ++i )
  8609. {
  8610. PreserveDSP_t& slot = g_PreserveDSP[ i ];
  8611. ConVar *cv = slot.cvar;
  8612. Assert( cv );
  8613. float flVal = cv->GetFloat();
  8614. if ( cv == &dsp_player )
  8615. flVal = dsp_player_get();
  8616. if ( flVal != 0.0f )
  8617. {
  8618. // NOTE: dsp_speaker is being (correctly) save/restored by maps, which would trigger this warning
  8619. //Warning( "DSP_CheckRestorePresets: Value of %s was changed between DSP_ClearState and CheckNewDspPresets, not restoring to old value\n", cv->GetName() );
  8620. continue;
  8621. }
  8622. if ( cv == &dsp_player )
  8623. dsp_player_set( slot.oldvalue );
  8624. else
  8625. cv->SetValue( slot.oldvalue );
  8626. }
  8627. // reinit all dsp processors (only load preset file on engine init, however)
  8628. AllocDsps( false );
  8629. // flush dsp automatic nodes
  8630. g_bdas_init_nodes = 0;
  8631. g_bdas_room_init = 0;
  8632. }
  8633. //-----------------------------------------------------------------------------
  8634. // Purpose:
  8635. //-----------------------------------------------------------------------------
  8636. void DSP_ClearState()
  8637. {
  8638. // if we already cleared dsp state, and a restore is pending,
  8639. // don't clear again
  8640. if ( g_bNeedPresetRestore )
  8641. return;
  8642. // always save a cleared dsp automatic value to force reset of all adsp code
  8643. dsp_automatic.SetValue(0);
  8644. // 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
  8645. int i;
  8646. int c = ARRAYSIZE( g_PreserveDSP );
  8647. for ( i = 0 ; i < c; ++i )
  8648. {
  8649. PreserveDSP_t& slot = g_PreserveDSP[ i ];
  8650. ConVar *cv = slot.cvar;
  8651. Assert( cv );
  8652. if ( cv == &dsp_player )
  8653. {
  8654. slot.oldvalue = dsp_player_get();
  8655. dsp_player_set( 0 );
  8656. }
  8657. else
  8658. {
  8659. slot.oldvalue = cv->GetFloat();
  8660. cv->SetValue( 0 );
  8661. }
  8662. }
  8663. // force all dsp presets to end crossfades, end one-shot presets, & release and reset all resources
  8664. // immediately.
  8665. FreeDsps( false ); // free all dsp states, but don't discard preset templates
  8666. // This forces the ConVars which we set to zero above to be reloaded to their old values at the time we issue the CheckNewDspPresets
  8667. // command. This seems to happen early enough in level changes were we don't appear to be trying to stomp real settings...
  8668. g_bNeedPresetRestore = true;
  8669. }
  8670. // return true if dsp's preset is one-shot and it has expired
  8671. bool DSP_HasExpired( int idsp )
  8672. {
  8673. dsp_t *pdsp;
  8674. Assert( idsp < CDSPS );
  8675. if (idsp < 0 || idsp >= CDSPS)
  8676. return false;
  8677. pdsp = &dsps[idsp];
  8678. // if first preset has expired, dsp has expired
  8679. if ( PSET_IsOneShot( pdsp->ppset[0] ) )
  8680. return PSET_HasExpired( pdsp->ppset[0] );
  8681. else
  8682. return false;
  8683. }
  8684. // returns true if dsp is crossfading from previous dsp preset
  8685. bool DSP_IsCrossfading( int idsp, bool bUseMsTimeExpiration )
  8686. {
  8687. dsp_t *pdsp;
  8688. Assert( idsp < CDSPS );
  8689. if (idsp < 0 || idsp >= CDSPS)
  8690. return false;
  8691. pdsp = &dsps[idsp];
  8692. if ( bUseMsTimeExpiration && ( pdsp->ipsetprev != 0 ) )
  8693. {
  8694. if ( pdsp->xramp.nEndRampTimeInMs < Plat_MSTime() )
  8695. {
  8696. // This case happens often when we previously switched from one DSP (that was fading) to another.
  8697. // When we re-switch to the first DSP, the cross fading is still considered valid, except that the sounds in the delay are actually not valid anymore.
  8698. // Let's not indicate that we are cross-fading, that way we can switch to the new preset sooner rather than later.
  8699. if ( snd_dsp_spew_changes.GetBool() )
  8700. {
  8701. DevMsg( "[Sound DSP] For Dsp %d, don't consider cross fading from presets %d to %d as previous preset is expired.\n", idsp, pdsp->ipsetprev, pdsp->ipset );
  8702. }
  8703. return false;
  8704. }
  8705. }
  8706. return !RMP_HitEnd( &pdsp->xramp );
  8707. }
  8708. // returns previous preset # before oneshot preset was set
  8709. int DSP_OneShotPrevious( int idsp )
  8710. {
  8711. dsp_t *pdsp;
  8712. int idsp_prev;
  8713. Assert( idsp < CDSPS );
  8714. if (idsp < 0 || idsp >= CDSPS)
  8715. return 0;
  8716. pdsp = &dsps[idsp];
  8717. idsp_prev = pdsp->ipsetsav_oneshot;
  8718. return idsp_prev;
  8719. }
  8720. // given idsp (processor index), return true if
  8721. // both current and previous presets are 0 for this processor
  8722. bool DSP_PresetIsOff( int idsp )
  8723. {
  8724. dsp_t *pdsp;
  8725. if (idsp < 0 || idsp >= CDSPS)
  8726. return true;
  8727. Assert ( idsp < CDSPS ); // make sure idsp is valid
  8728. pdsp = &dsps[idsp];
  8729. // if current and previous preset 0, return - preset 0 is 'off'
  8730. return ( !pdsp->ipset && !pdsp->ipsetprev );
  8731. }
  8732. // returns true if dsp is off for room effects
  8733. bool DSP_RoomDSPIsOff()
  8734. {
  8735. return DSP_PresetIsOff( Get_idsp_room() );
  8736. }
  8737. // Main DSP processing routine:
  8738. // process samples in buffers using pdsp processor
  8739. // continue crossfade between 2 dsp processors if crossfading on switch
  8740. // pfront - front stereo buffer to process
  8741. // prear - rear stereo buffer to process (may be NULL)
  8742. // pcenter - front center mono buffer (may be NULL)
  8743. // sampleCount - number of samples in pbuf to process
  8744. // This routine also maps the # processing channels in the pdsp to the number of channels
  8745. // supplied. ie: if the pdsp has 4 channels and pbfront and pbrear are both non-null, the channels
  8746. // map 1:1 through the processors.
  8747. void DSP_Process( int idsp, portable_samplepair_t *pbfront, portable_samplepair_t *pbrear, portable_samplepair_t *pbcenter, int sampleCount )
  8748. {
  8749. bool bcrossfading;
  8750. int cchan_in; // input channels (2,4 or 5)
  8751. int cprocs; // output channels (1, 2 or 4)
  8752. dsp_t *pdsp;
  8753. if (idsp < 0 || idsp >= CDSPS)
  8754. return;
  8755. // Don't pull dsp data in if player is not connected (during load/level change)
  8756. if ( !g_pSoundServices->IsConnected() )
  8757. return;
  8758. Assert ( idsp < CDSPS ); // make sure idsp is valid
  8759. pdsp = &dsps[idsp];
  8760. Assert (pbfront);
  8761. // return right away if fx processing is turned off
  8762. if ( dsp_off.GetInt() )
  8763. return;
  8764. if ( pdsp->bEnabled == false )
  8765. {
  8766. return;
  8767. }
  8768. // if current and previous preset 0, return - preset 0 is 'off'
  8769. if ( !pdsp->ipset && !pdsp->ipsetprev )
  8770. return;
  8771. if ( sampleCount < 0 )
  8772. return;
  8773. bcrossfading = !RMP_HitEnd( &pdsp->xramp );
  8774. if ( pdsp->ipsetprev != 0 )
  8775. {
  8776. if ( pdsp->xramp.nEndRampTimeInMs < Plat_MSTime() )
  8777. {
  8778. // This case happens often when we previously switched from one DSP (that was fading) to another.
  8779. // When we re-switch to the first DSP, the cross-fading is still considered valid, except that the sounds in the delay are actually not valid anymore.
  8780. // By canceling the cross-fading, we only hear the new effect and not the old effect.
  8781. if ( snd_dsp_spew_changes.GetBool() )
  8782. {
  8783. DevMsg( "[Sound DSP] For Dsp %d, suppress cross fading from presets %d to %d as previous preset is expired.\n", idsp, pdsp->ipsetprev, pdsp->ipset );
  8784. }
  8785. RMP_SetEnd( &pdsp->xramp );
  8786. bcrossfading = false;
  8787. }
  8788. }
  8789. // if not crossfading, and previous channel is not null, free previous
  8790. if ( !bcrossfading )
  8791. {
  8792. DSP_FreePrevPreset( pdsp );
  8793. }
  8794. // if current and previous preset 0 (ie: just freed previous), return - preset 0 is 'off'
  8795. if ( !pdsp->ipset && !pdsp->ipsetprev )
  8796. return;
  8797. uint nCurrentTime = Plat_MSTime();
  8798. if ( snd_dsp_spew_changes.GetBool() )
  8799. {
  8800. if ( bcrossfading )
  8801. {
  8802. DevMsg("[Sound DSP] Dsp %d processed. Cross-fading presets from %d to %d.\n", idsp, pdsp->ipsetprev, pdsp->ipset );
  8803. }
  8804. else
  8805. {
  8806. static uint sLastDisplay = 0;
  8807. if ( nCurrentTime > sLastDisplay + 1000 )
  8808. {
  8809. DevMsg( "[Sound DSP] Dsp %d processed.\n", idsp ); // Displayed every second
  8810. sLastDisplay = nCurrentTime;
  8811. }
  8812. }
  8813. }
  8814. if ( pdsp->ipset != 0 )
  8815. {
  8816. pdsp->ppset[0]->nLastUpdatedTimeInMilliseconds = nCurrentTime;
  8817. }
  8818. if ( pdsp->ipsetprev != 0 )
  8819. {
  8820. pdsp->ppsetprev[0]->nLastUpdatedTimeInMilliseconds = nCurrentTime;
  8821. }
  8822. cchan_in = (pbrear ? 4 : 2) + (pbcenter ? 1 : 0);
  8823. cprocs = pdsp->cchan;
  8824. Assert(cchan_in == 2 || cchan_in == 4 || cchan_in == 5 );
  8825. // if oneshot preset, update the duration counter (only update front left counter)
  8826. PSET_UpdateDuration( pdsp->ppset[0], sampleCount );
  8827. // NOTE: when mixing between different channel sizes,
  8828. // always AVERAGE down to fewer channels and DUPLICATE up more channels.
  8829. // The following routines always process cchan_in channels.
  8830. // ie: QuadToMono still updates 4 values in buffer
  8831. // DSP_Process stereo in to mono out (ie: left and right are averaged)
  8832. if ( snd_spew_dsp_process.GetBool() )
  8833. {
  8834. Msg( "[Sound] DSP_Process() called. DSP index: %d - Sample cout: %d\n", idsp, sampleCount );
  8835. }
  8836. if ( cchan_in == 2 && cprocs == 1)
  8837. {
  8838. DSP_ProcessStereoToMono( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  8839. return;
  8840. }
  8841. // DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
  8842. if ( cchan_in == 2 && cprocs >= 2)
  8843. {
  8844. DSP_ProcessStereoToStereo( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  8845. return;
  8846. }
  8847. // DSP_Process quad in to mono out
  8848. if ( cchan_in == 4 && cprocs == 1)
  8849. {
  8850. DSP_ProcessQuadToMono( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  8851. return;
  8852. }
  8853. // DSP_Process quad in to stereo out (preserve stereo spatialization, loose front/rear)
  8854. if ( cchan_in == 4 && cprocs == 2)
  8855. {
  8856. DSP_ProcessQuadToStereo( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  8857. return;
  8858. }
  8859. // DSP_Process quad in to quad out
  8860. if ( cchan_in == 4 && cprocs == 4)
  8861. {
  8862. DSP_ProcessQuadToQuad( pdsp, pbfront, pbrear, sampleCount, bcrossfading );
  8863. return;
  8864. }
  8865. // DSP_Process quad + center in to mono out
  8866. if ( cchan_in == 5 && cprocs == 1)
  8867. {
  8868. DSP_Process5To1( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  8869. return;
  8870. }
  8871. if ( cchan_in == 5 && cprocs == 2)
  8872. {
  8873. // undone: not used in AllocDsps
  8874. Assert(false);
  8875. //DSP_Process5to2( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  8876. return;
  8877. }
  8878. if ( cchan_in == 5 && cprocs == 4)
  8879. {
  8880. // undone: not used in AllocDsps
  8881. Assert(false);
  8882. //DSP_Process5to4( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  8883. return;
  8884. }
  8885. // DSP_Process quad + center in to quad + center out
  8886. if ( cchan_in == 5 && cprocs == 5)
  8887. {
  8888. DSP_Process5To5( pdsp, pbfront, pbrear, pbcenter, sampleCount, bcrossfading );
  8889. return;
  8890. }
  8891. }
  8892. // DSP helpers
  8893. // free all dsp processors
  8894. void FreeDsps( bool bReleaseTemplateMemory )
  8895. {
  8896. DSP_Free(idsp_room);
  8897. DSP_Free(idsp_water);
  8898. DSP_Free(idsp_player);
  8899. DSP_Free(idsp_facingaway);
  8900. DSP_Free(idsp_speaker);
  8901. DSP_Free(idsp_spatial);
  8902. DSP_Free(idsp_automatic);
  8903. idsp_room = 0;
  8904. idsp_water = 0;
  8905. idsp_player = 0;
  8906. idsp_facingaway = 0;
  8907. idsp_speaker = 0;
  8908. idsp_spatial = 0;
  8909. idsp_automatic = 0;
  8910. DSP_FreeAll();
  8911. // only unlock and free psettemplate memory on engine shutdown
  8912. if ( bReleaseTemplateMemory )
  8913. DSP_ReleaseMemory();
  8914. }
  8915. // alloc dsp processors, load dsp preset array from file on engine init only
  8916. bool AllocDsps( bool bLoadPresetFile )
  8917. {
  8918. int csurround = (g_AudioDevice->IsSurround() ? 2: 0); // surround channels to allocate
  8919. int ccenter = (g_AudioDevice->IsSurroundCenter() ? 1 : 0); // center channels to allocate
  8920. DSP_InitAll( bLoadPresetFile );
  8921. idsp_room = -1;
  8922. idsp_water = -1;
  8923. idsp_player = -1;
  8924. idsp_facingaway = -1;
  8925. idsp_speaker = -1;
  8926. idsp_spatial = -1;
  8927. idsp_automatic = -1;
  8928. // alloc dsp room channel (mono, stereo if dsp_stereo is 1)
  8929. // dsp room is mono, 300ms default fade time
  8930. idsp_room = DSP_Alloc( dsp_room.GetInt(), 200, 1 );
  8931. // dsp automatic overrides dsp_room, if dsp_room set to DSP_AUTOMATIC (1)
  8932. idsp_automatic = DSP_Alloc( dsp_automatic.GetInt(), 200, 1 ) ;
  8933. // alloc stereo or quad series processors for player or water
  8934. // water and player presets are mono
  8935. idsp_water = DSP_Alloc( dsp_water.GetInt(), 100, 1 );
  8936. idsp_player = DSP_Alloc( dsp_player_get(), 100, 1 );
  8937. // alloc facing away filters (stereo, quad or 5ch)
  8938. idsp_facingaway = DSP_Alloc( dsp_facingaway.GetInt(), 100, 2 + csurround + ccenter );
  8939. // alloc speaker preset (mono)
  8940. idsp_speaker = DSP_Alloc( dsp_speaker.GetInt(), 300, 1 );
  8941. // alloc spatial preset (2-5 chan)
  8942. idsp_spatial = DSP_Alloc( dsp_spatial.GetInt(), 300, 2 + csurround + ccenter );
  8943. // init prev values
  8944. ipset_room_prev = dsp_room.GetInt();
  8945. ipset_water_prev = dsp_water.GetInt();
  8946. ipset_player_prev = dsp_player_get();
  8947. ipset_facingaway_prev = dsp_facingaway.GetInt();
  8948. ipset_room_typeprev = dsp_room_type.GetInt();
  8949. ipset_speaker_prev = dsp_speaker.GetInt();
  8950. ipset_spatial_prev = dsp_spatial.GetInt();
  8951. ipset_automatic_prev = dsp_automatic.GetInt();
  8952. if (idsp_room < 0 || idsp_water < 0 || idsp_player < 0 || idsp_facingaway < 0 || idsp_speaker < 0 || idsp_spatial < 0 || idsp_automatic < 0)
  8953. {
  8954. DevMsg ("WARNING: DSP processor failed to initialize! \n" );
  8955. FreeDsps( true );
  8956. return false;
  8957. }
  8958. return true;
  8959. }
  8960. // count number of dsp presets specified in preset file
  8961. // counts outer {} pairs, ignoring inner {} pairs.
  8962. int DSP_CountFilePresets( const char *pstart )
  8963. {
  8964. int cpresets = 0;
  8965. bool binpreset = false;
  8966. bool blookleft = false;
  8967. while ( 1 )
  8968. {
  8969. pstart = COM_Parse( pstart );
  8970. if ( strlen(com_token) <= 0)
  8971. break;
  8972. if ( com_token[0] == '{' ) // left paren
  8973. {
  8974. if (!binpreset)
  8975. {
  8976. cpresets++; // found preset:
  8977. blookleft = true; // look for another left
  8978. binpreset = true;
  8979. }
  8980. else
  8981. {
  8982. blookleft = false; // inside preset: next, look for matching right paren
  8983. }
  8984. continue;
  8985. }
  8986. if ( com_token[0] == '}' ) // right paren
  8987. {
  8988. if (binpreset)
  8989. {
  8990. if (!blookleft) // looking for right paren
  8991. {
  8992. blookleft = true; // found it, now look for another left
  8993. }
  8994. else
  8995. {
  8996. // expected inner left paren, found outer right - end of preset definition
  8997. binpreset = false;
  8998. blookleft = true;
  8999. }
  9000. }
  9001. else
  9002. {
  9003. // error - unexpected } paren
  9004. DevMsg("PARSE ERROR!!! dsp_presets.txt: unexpected '}' \n");
  9005. continue;
  9006. }
  9007. }
  9008. }
  9009. return cpresets;
  9010. }
  9011. struct dsp_stringmap_t
  9012. {
  9013. char sz[33];
  9014. int i;
  9015. };
  9016. // token map for dsp_preset.txt
  9017. dsp_stringmap_t gdsp_stringmap[] =
  9018. {
  9019. // PROCESSOR TYPE:
  9020. {"NULL", PRC_NULL},
  9021. {"DLY", PRC_DLY},
  9022. {"RVA", PRC_RVA},
  9023. {"FLT", PRC_FLT},
  9024. {"CRS", PRC_CRS},
  9025. {"PTC", PRC_PTC},
  9026. {"ENV", PRC_ENV},
  9027. {"LFO", PRC_LFO},
  9028. {"EFO", PRC_EFO},
  9029. {"MDY", PRC_MDY},
  9030. {"DFR", PRC_DFR},
  9031. {"AMP", PRC_AMP},
  9032. // FILTER TYPE:
  9033. {"LP", FLT_LP},
  9034. {"HP", FLT_HP},
  9035. {"BP", FLT_BP},
  9036. // FILTER QUALITY:
  9037. {"LO", QUA_LO},
  9038. {"MED", QUA_MED},
  9039. {"HI", QUA_HI},
  9040. {"VHI", QUA_VHI},
  9041. // DELAY TYPE:
  9042. {"PLAIN", DLY_PLAIN},
  9043. {"ALLPASS", DLY_ALLPASS},
  9044. {"LOWPASS", DLY_LOWPASS},
  9045. {"DLINEAR", DLY_LINEAR},
  9046. {"FLINEAR", DLY_FLINEAR},
  9047. {"LOWPASS_4TAP",DLY_LOWPASS_4TAP},
  9048. {"PLAIN_4TAP", DLY_PLAIN_4TAP},
  9049. // LFO TYPE:
  9050. {"SIN", LFO_SIN},
  9051. {"TRI", LFO_TRI},
  9052. {"SQR", LFO_SQR},
  9053. {"SAW", LFO_SAW},
  9054. {"RND", LFO_RND},
  9055. {"LOG_IN", LFO_LOG_IN},
  9056. {"LOG_OUT", LFO_LOG_OUT},
  9057. {"LIN_IN", LFO_LIN_IN},
  9058. {"LIN_OUT", LFO_LIN_OUT},
  9059. // ENVELOPE TYPE:
  9060. {"LIN", ENV_LIN},
  9061. {"EXP", ENV_EXP},
  9062. // PRESET CONFIGURATION TYPE:
  9063. {"SIMPLE", PSET_SIMPLE},
  9064. {"LINEAR", PSET_LINEAR},
  9065. {"PARALLEL2", PSET_PARALLEL2},
  9066. {"PARALLEL4", PSET_PARALLEL4},
  9067. {"PARALLEL5", PSET_PARALLEL5},
  9068. {"FEEDBACK", PSET_FEEDBACK},
  9069. {"FEEDBACK3", PSET_FEEDBACK3},
  9070. {"FEEDBACK4", PSET_FEEDBACK4},
  9071. {"MOD1", PSET_MOD},
  9072. {"MOD2", PSET_MOD2},
  9073. {"MOD3", PSET_MOD3}
  9074. };
  9075. int gcdsp_stringmap = sizeof(gdsp_stringmap) / sizeof (dsp_stringmap_t);
  9076. #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')\
  9077. // given ptr to null term. string, return integer or float value from g_dsp_stringmap
  9078. float DSP_LookupStringToken( char *psz, int ipset )
  9079. {
  9080. int i;
  9081. float fipset = (float)ipset;
  9082. if (isnumber(psz[0]))
  9083. return atof(psz);
  9084. for (i = 0; i < gcdsp_stringmap; i++)
  9085. {
  9086. if (!strcmpi(gdsp_stringmap[i].sz, psz))
  9087. return gdsp_stringmap[i].i;
  9088. }
  9089. // not found
  9090. DevMsg("DSP PARSE ERROR! token not found in dsp_presets.txt. Preset: %3.0f \n", fipset );
  9091. return 0;
  9092. }
  9093. // load dsp preset file, parse presets into g_psettemplate array
  9094. // format for each preset:
  9095. // { <preset #> <preset type> <#processors> <gain> { <processor type> <param0>...<param15> } {...} {...} }
  9096. #define CHAR_LEFT_PAREN '{'
  9097. #define CHAR_RIGHT_PAREN '}'
  9098. // free preset template memory
  9099. void DSP_ReleaseMemory( void )
  9100. {
  9101. if (g_psettemplates)
  9102. {
  9103. delete[] g_psettemplates;
  9104. g_psettemplates = NULL;
  9105. }
  9106. }
  9107. bool DSP_LoadPresetFile( void )
  9108. {
  9109. char szFile[ MAX_OSPATH ];
  9110. char *pbuffer;
  9111. const char *pstart;
  9112. bool bResult = false;
  9113. int cpresets;
  9114. int ipreset;
  9115. int itype;
  9116. int cproc;
  9117. float mix_min;
  9118. float mix_max;
  9119. float db_min;
  9120. float db_mixdrop;
  9121. int j;
  9122. bool fdone;
  9123. float duration;
  9124. float fadeout;
  9125. Q_snprintf( szFile, sizeof( szFile ), "scripts/dsp_presets.txt" );
  9126. MEM_ALLOC_CREDIT();
  9127. CUtlBuffer buf;
  9128. if ( !g_pFullFileSystem->ReadFile( szFile, "GAME", buf ) )
  9129. {
  9130. Error( "DSP_LoadPresetFile: unable to open '%s'\n", szFile );
  9131. return bResult;
  9132. }
  9133. pbuffer = (char *)buf.PeekGet(); // Use malloc - free at end of this routine
  9134. pstart = pbuffer;
  9135. // figure out how many presets we're loading - count outer parens.
  9136. cpresets = DSP_CountFilePresets( pstart );
  9137. g_cpsettemplates = cpresets;
  9138. g_psettemplates = new pset_t[cpresets];
  9139. if (!g_psettemplates)
  9140. {
  9141. Warning( "DSP Preset Loader: Out of memory.\n");
  9142. goto load_exit;
  9143. }
  9144. memset (g_psettemplates, 0, cpresets * sizeof(pset_t));
  9145. // parse presets into g_psettemplates array
  9146. pstart = pbuffer;
  9147. // for each preset...
  9148. for ( j = 0; j < cpresets; j++)
  9149. {
  9150. // check for end of file or next CHAR_LEFT_PAREN
  9151. while (1)
  9152. {
  9153. pstart = COM_Parse( pstart );
  9154. if ( strlen(com_token) <= 0)
  9155. break;
  9156. if ( com_token[0] != CHAR_LEFT_PAREN )
  9157. continue;
  9158. break;
  9159. }
  9160. // found start of a new preset definition
  9161. // get preset #, type, cprocessors, gain
  9162. pstart = COM_Parse( pstart );
  9163. ipreset = atoi( com_token );
  9164. pstart = COM_Parse( pstart );
  9165. itype = (int)DSP_LookupStringToken( com_token , ipreset);
  9166. pstart = COM_Parse( pstart );
  9167. mix_min = atof( com_token );
  9168. pstart = COM_Parse( pstart );
  9169. mix_max = atof( com_token );
  9170. pstart = COM_Parse( pstart );
  9171. duration = atof( com_token );
  9172. pstart = COM_Parse( pstart );
  9173. fadeout = atof( com_token );
  9174. pstart = COM_Parse( pstart );
  9175. db_min = atof( com_token );
  9176. pstart = COM_Parse( pstart );
  9177. db_mixdrop = atof( com_token );
  9178. g_psettemplates[ipreset].fused = true;
  9179. g_psettemplates[ipreset].mix_min = mix_min;
  9180. g_psettemplates[ipreset].mix_max = mix_max;
  9181. g_psettemplates[ipreset].duration = duration;
  9182. g_psettemplates[ipreset].fade = fadeout;
  9183. g_psettemplates[ipreset].db_min = db_min;
  9184. g_psettemplates[ipreset].db_mixdrop = db_mixdrop;
  9185. // parse each processor for this preset
  9186. fdone = false;
  9187. cproc = 0;
  9188. while (1)
  9189. {
  9190. // find CHAR_LEFT_PAREN - start of new processor
  9191. while (1)
  9192. {
  9193. pstart = COM_Parse( pstart );
  9194. if ( strlen(com_token) <= 0)
  9195. break;
  9196. if (com_token[0] == CHAR_LEFT_PAREN)
  9197. break;
  9198. if (com_token[0] == CHAR_RIGHT_PAREN)
  9199. {
  9200. // if found right paren, no more processors: done with this preset
  9201. fdone = true;
  9202. break;
  9203. }
  9204. }
  9205. if ( fdone )
  9206. break;
  9207. // get processor type
  9208. pstart = COM_Parse( pstart );
  9209. g_psettemplates[ipreset].prcs[cproc].type = (int)DSP_LookupStringToken( com_token, ipreset );
  9210. // get param 0..n or stop when hit closing CHAR_RIGHT_PAREN
  9211. int ip = 0;
  9212. while (1)
  9213. {
  9214. pstart = COM_Parse( pstart );
  9215. if ( strlen(com_token) <= 0)
  9216. break;
  9217. if ( com_token[0] == CHAR_RIGHT_PAREN )
  9218. break;
  9219. g_psettemplates[ipreset].prcs[cproc].prm[ip++] = DSP_LookupStringToken( com_token, ipreset );
  9220. // cap at max params
  9221. ip = MIN(ip, CPRCPARAMS);
  9222. }
  9223. cproc++;
  9224. if (cproc > CPSET_PRCS)
  9225. DevMsg("DSP PARSE ERROR!!! dsp_presets.txt: missing } or too many processors in preset #: %3.0f \n", (float)ipreset);
  9226. cproc = MIN(cproc, CPSET_PRCS); // don't overflow # procs
  9227. }
  9228. // if cproc == 1, type is always SIMPLE
  9229. if ( cproc == 1)
  9230. itype = PSET_SIMPLE;
  9231. g_psettemplates[ipreset].type = itype;
  9232. g_psettemplates[ipreset].cprcs = cproc;
  9233. }
  9234. bResult = true;
  9235. load_exit:
  9236. return bResult;
  9237. }
  9238. //-----------------------------------------------------------------------------
  9239. // Purpose: Called by client on level shutdown to clear ear ringing dsp effects
  9240. // could be extended to other stuff
  9241. //-----------------------------------------------------------------------------
  9242. void DSP_FastReset( int dspType )
  9243. {
  9244. int c = ARRAYSIZE( g_PreserveDSP );
  9245. // Restore
  9246. for ( int i = 0 ; i < c; ++i )
  9247. {
  9248. PreserveDSP_t& slot = g_PreserveDSP[ i ];
  9249. if ( slot.cvar == &dsp_player )
  9250. {
  9251. slot.oldvalue = dspType;
  9252. return;
  9253. }
  9254. }
  9255. }
  9256. bool HandlePresetChange( int nDspIndex, int & nPrevPreset, int nNewPreset, const char * pDspName )
  9257. {
  9258. if ( nPrevPreset == nNewPreset )
  9259. {
  9260. return false;
  9261. }
  9262. if ( !DSP_IsCrossfading( nDspIndex, true ) )
  9263. {
  9264. DSP_SetPreset( nDspIndex, nNewPreset, pDspName );
  9265. nPrevPreset = nNewPreset;
  9266. return true;
  9267. }
  9268. else
  9269. {
  9270. if ( snd_dsp_spew_changes.GetBool() )
  9271. {
  9272. DevMsg( "[Sound DSP] For Dsp %d, %s changed presets from %d to %d. Have to wait end of cross-fading.\n", nDspIndex, pDspName, nPrevPreset, nNewPreset );
  9273. }
  9274. return false;
  9275. }
  9276. }
  9277. // Helper to check for change in preset of any of 4 processors
  9278. // if switching to a new preset, alloc new preset, simulate both presets in DSP_Process & xfade,
  9279. // called a few times per frame.
  9280. void CheckNewDspPresets( void )
  9281. {
  9282. bool b_slow_cpu = dsp_slow_cpu.GetBool();
  9283. DSP_CheckRestorePresets();
  9284. // room fx are on only if cpu is not slow
  9285. int iroom = b_slow_cpu ? 0 : dsp_room.GetInt() ;
  9286. int ifacingaway = b_slow_cpu ? 0 : dsp_facingaway.GetInt();
  9287. int iroomtype = b_slow_cpu ? 0 : dsp_room_type.GetInt();
  9288. int ispatial = b_slow_cpu ? 0 : dsp_spatial.GetInt();
  9289. int iautomatic = b_slow_cpu ? 0 : dsp_automatic.GetInt();
  9290. // always use dsp to process these
  9291. int iwater = dsp_water.GetInt();
  9292. int iplayer = dsp_player_get();
  9293. int ispeaker = dsp_speaker.GetInt();
  9294. // check for expired one-shot presets on player and room.
  9295. // Only check if a) no new preset has been set and b) not crossfading from previous preset (ie; previous is null)
  9296. // Note that in this code we are testing several time against last updated time.
  9297. // The code could be optimized further but fortunately, most times, it not executed
  9298. if ( iplayer == ipset_player_prev && !DSP_IsCrossfading( idsp_player, false ) )
  9299. {
  9300. if ( DSP_HasExpired ( idsp_player ) )
  9301. {
  9302. iplayer = DSP_OneShotPrevious( idsp_player); // preset has expired - revert to previous preset before one-shot
  9303. dsp_player_set(iplayer);
  9304. }
  9305. }
  9306. if ( iroom == ipset_room_prev && !DSP_IsCrossfading( idsp_room, false ) )
  9307. {
  9308. if ( DSP_HasExpired ( idsp_room ) )
  9309. {
  9310. iroom = DSP_OneShotPrevious( idsp_room ); // preset has expired - revert to previous preset before one-shot
  9311. dsp_room.SetValue(iroom);
  9312. }
  9313. }
  9314. // legacy code support for "room_type" Cvar
  9315. if ( iroomtype != ipset_room_typeprev )
  9316. {
  9317. // force dsp_room = room_type
  9318. ipset_room_typeprev = iroomtype;
  9319. dsp_room.SetValue(iroomtype);
  9320. }
  9321. // NOTE: don't change presets if currently crossfading from a previous preset
  9322. if ( HandlePresetChange( idsp_room, ipset_room_prev, iroom, "room" ) )
  9323. {
  9324. // Force room_type = dsp_room
  9325. dsp_room_type.SetValue(iroom);
  9326. ipset_room_typeprev = iroom;
  9327. }
  9328. HandlePresetChange( idsp_water, ipset_water_prev, iwater, "water" );
  9329. HandlePresetChange( idsp_player, ipset_player_prev, iplayer, "player" );
  9330. HandlePresetChange( idsp_facingaway, ipset_facingaway_prev, ifacingaway, "facingaway" );
  9331. HandlePresetChange( idsp_speaker, ipset_speaker_prev, ispeaker, "speaker" );
  9332. HandlePresetChange( idsp_spatial, ipset_spatial_prev, ispatial, "spatial" );
  9333. HandlePresetChange( idsp_automatic, ipset_automatic_prev, iautomatic, "automatic" );
  9334. }
  9335. // create idsp_room preset from set of values, reload the preset.
  9336. // modifies psettemplates in place.
  9337. // ipreset is the preset # ie: 40
  9338. // iproc is the processor to modify within the preset (typically 0)
  9339. // pvalues is an array of floating point parameters
  9340. // cparams is the # of elements in pvalues
  9341. // USED FOR DEBUG ONLY.
  9342. void DSP_DEBUGSetParams(int ipreset, int iproc, float *pvalues, int cparams)
  9343. {
  9344. pset_t new_pset; // preset
  9345. int cparam = iclamp (cparams, 0, CPRCPARAMS);
  9346. prc_t *pprct;
  9347. // copy template preset from template array
  9348. new_pset = g_psettemplates[ipreset];
  9349. // get iproc processor
  9350. pprct = &(new_pset.prcs[iproc]);
  9351. // copy parameters in to processor
  9352. for (int i = 0; i < cparam; i++)
  9353. {
  9354. pprct->prm[i] = pvalues[i];
  9355. }
  9356. // copy constructed preset back into template location
  9357. g_psettemplates[ipreset] = new_pset;
  9358. // setup new preset
  9359. dsp_room.SetValue( 0 );
  9360. CheckNewDspPresets();
  9361. dsp_room.SetValue( ipreset );
  9362. CheckNewDspPresets();
  9363. }
  9364. // reload entire preset file, reset all current dsp presets
  9365. // NOTE: this is debug code only. It doesn't do all mem free work correctly!
  9366. void DSP_DEBUGReloadPresetFile( void )
  9367. {
  9368. int iroom = dsp_room.GetInt();
  9369. int iwater = dsp_water.GetInt();
  9370. int iplayer = dsp_player_get();
  9371. // int ifacingaway = dsp_facingaway.GetInt();
  9372. // int iroomtype = dsp_room_type.GetInt();
  9373. int ispeaker = dsp_speaker.GetInt();
  9374. int ispatial = dsp_spatial.GetInt();
  9375. // int iautomatic = dsp_automatic.GetInt();
  9376. // reload template array
  9377. DSP_ReleaseMemory();
  9378. DSP_LoadPresetFile();
  9379. // force presets to reload
  9380. dsp_room.SetValue( 0 );
  9381. dsp_water.SetValue( 0 );
  9382. dsp_player_set( 0 );
  9383. //dsp_facingaway.SetValue( 0 );
  9384. //dsp_room_type.SetValue( 0 );
  9385. dsp_speaker.SetValue( 0 );
  9386. dsp_spatial.SetValue( 0 );
  9387. //dsp_automatic.SetValue( 0 );
  9388. CheckNewDspPresets();
  9389. dsp_room.SetValue( iroom );
  9390. dsp_water.SetValue( iwater );
  9391. dsp_player_set( iplayer );
  9392. //dsp_facingaway.SetValue( ifacingaway );
  9393. //dsp_room_type.SetValue( iroomtype );
  9394. dsp_speaker.SetValue( ispeaker );
  9395. dsp_spatial.SetValue( ispatial );
  9396. //dsp_automatic.SetValue( iautomatic );
  9397. CheckNewDspPresets();
  9398. // flush dsp automatic nodes
  9399. g_bdas_init_nodes = 0;
  9400. g_bdas_room_init = 0;
  9401. }
  9402. // UNDONE: stock reverb presets:
  9403. // carpet hallway
  9404. // tile hallway
  9405. // wood hallway
  9406. // metal hallway
  9407. // train tunnel
  9408. // sewer main tunnel
  9409. // concrete access tunnel
  9410. // cave tunnel
  9411. // sand floor cave tunnel
  9412. // metal duct shaft
  9413. // elevator shaft
  9414. // large elevator shaft
  9415. // parking garage
  9416. // aircraft hangar
  9417. // cathedral
  9418. // train station
  9419. // small cavern
  9420. // large cavern
  9421. // huge cavern
  9422. // watery cavern
  9423. // long, low cavern
  9424. // wood warehouse
  9425. // metal warehouse
  9426. // concrete warehouse
  9427. // small closet room
  9428. // medium drywall room
  9429. // medium wood room
  9430. // medium metal room
  9431. // elevator
  9432. // small metal room
  9433. // medium metal room
  9434. // large metal room
  9435. // huge metal room
  9436. // small metal room dense
  9437. // medium metal room dense
  9438. // large metal room dense
  9439. // huge metal room dense
  9440. // small concrete room
  9441. // medium concrete room
  9442. // large concrete room
  9443. // huge concrete room
  9444. // small concrete room dense
  9445. // medium concrete room dense
  9446. // large concrete room dense
  9447. // huge concrete room dense
  9448. // soundproof room
  9449. // carpet lobby
  9450. // swimming pool
  9451. // open park
  9452. // open courtyard
  9453. // wide parkinglot
  9454. // narrow street
  9455. // wide street, short buildings
  9456. // wide street, tall buildings
  9457. // narrow canyon
  9458. // wide canyon
  9459. // huge canyon
  9460. // small valley
  9461. // wide valley
  9462. // wreckage & rubble
  9463. // small building cluster
  9464. // wide open plain
  9465. // high vista
  9466. // alien interior small
  9467. // alien interior medium
  9468. // alien interior large
  9469. // alien interior huge
  9470. // special fx presets:
  9471. // alien citadel
  9472. // teleport aftershock (these presets all ADSR timeout and reset the dsp_* to 0)
  9473. // on target teleport
  9474. // off target teleport
  9475. // death fade
  9476. // beam stasis
  9477. // scatterbrain
  9478. // pulse only
  9479. // slomo
  9480. // hypersensitive
  9481. // supershocker
  9482. // physwhacked
  9483. // forcefieldfry
  9484. // juiced
  9485. // zoomed in
  9486. // crabbed
  9487. // barnacle gut
  9488. // bad transmission
  9489. ////////////////////////
  9490. // Dynamics processing
  9491. ////////////////////////
  9492. // compressor defines
  9493. #define COMP_MAX_AMP 32767 // abs max amplitude
  9494. #define COMP_THRESH 20000 // start compressing at this threshold
  9495. // compress input value - smoothly limit output y to -32767 <= y <= 32767
  9496. // UNDONE: not tested or used
  9497. inline int S_Compress( int xin )
  9498. {
  9499. return iclip( xin >> 2 ); // DEBUG - disabled
  9500. float Yn, Xn, Cn, Fn;
  9501. float C0 = 20000; // threshold
  9502. float p = .3; // compression ratio
  9503. float g = 1; // gain after compression
  9504. Xn = (float)xin;
  9505. // Compressor formula:
  9506. // Cn = l*Cn-1 + (1-l)*|Xn| // peak detector with memory
  9507. // f(Cn) = (Cn/C0)^(p-1) for Cn > C0 // gain function above threshold
  9508. // f(Cn) = 1 for C <= C0 // unity gain below threshold
  9509. // Yn = f(Cn) * Xn // compressor output
  9510. // UNDONE: curves discontinuous at threshold, causes distortion, try catmul-rom
  9511. //float l = .5; // compressor memory
  9512. //Cn = l * (*pCnPrev) + (1 - l) * fabs((float)xin);
  9513. //*pCnPrev = Cn;
  9514. Cn = fabs((float)xin);
  9515. if (Cn < C0)
  9516. Fn = 1;
  9517. else
  9518. Fn = powf((Cn / C0),(p - 1));
  9519. Yn = Fn * Xn * g;
  9520. //if (Cn > 0)
  9521. // Msg("%d -> %d\n", xin, (int)Yn); // DEBUG
  9522. //if (fabs(Yn) > 32767)
  9523. // Yn = Yn; // DEBUG
  9524. return (iclip((int)Yn));
  9525. }
  9526. CON_COMMAND( snd_print_dsp_effect, "Prints the content of a dsp effect." )
  9527. {
  9528. if ( args.ArgC() != 2 )
  9529. {
  9530. Warning( "Incorrect usage of snd_print_dsp_effect. snd_print_dsp_effect <dspindex>.\n" );
  9531. return;
  9532. }
  9533. int nDspIndex = atoi( args.Arg( 1 ) );
  9534. if ( ( nDspIndex < 0) || ( nDspIndex >= CDSPS ) )
  9535. {
  9536. Warning( "DSP index is out of range. It should be between 0 and %d.\n", CDSPS );
  9537. return;
  9538. }
  9539. dsp_t *pDsp = &dsps[ nDspIndex ];
  9540. DSP_Print( *pDsp, 0 );
  9541. }