Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4293 lines
124 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Portable code to mix sounds for snd_dma.cpp.
  4. //
  5. //=============================================================================//
  6. #include "audio_pch.h"
  7. #include "mouthinfo.h"
  8. #include "../../cl_main.h"
  9. #include "icliententitylist.h"
  10. #include "icliententity.h"
  11. #include "../../sys_dll.h"
  12. #include "video/ivideoservices.h"
  13. #include "engine/IEngineSound.h"
  14. #if defined( REPLAY_ENABLED )
  15. #include "demo.h"
  16. #include "replay_internal.h"
  17. #endif
  18. #ifdef GNUC
  19. // we don't suport the ASM in this file right now under GCC, fallback to C libs
  20. #undef id386
  21. #endif
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. #if defined( REPLAY_ENABLED )
  25. extern IReplayMovieManager *g_pReplayMovieManager;
  26. #endif
  27. #if defined(_WIN32) && id386
  28. // warning C4731: frame pointer register 'ebp' modified by inline assembly code
  29. #pragma warning(disable : 4731)
  30. #endif
  31. // NOTE: !!!!!! YOU MUST UPDATE SND_MIXA.S IF THIS VALUE IS CHANGED !!!!!
  32. #define SND_SCALE_BITS 7
  33. #define SND_SCALE_SHIFT (8-SND_SCALE_BITS)
  34. #define SND_SCALE_LEVELS (1<<SND_SCALE_BITS)
  35. #define SND_SCALE_BITS16 8
  36. #define SND_SCALE_SHIFT16 (8-SND_SCALE_BITS16)
  37. #define SND_SCALE_LEVELS16 (1<<SND_SCALE_BITS16)
  38. void Snd_WriteLinearBlastStereo16(void);
  39. void SND_PaintChannelFrom8( portable_samplepair_t *pOutput, int *volume, byte *pData8, int count );
  40. bool Con_IsVisible( void );
  41. void SND_RecordBuffer( void );
  42. bool DSP_RoomDSPIsOff( void );
  43. bool BChannelLowVolume( channel_t *pch, int vol_min );
  44. void ChannelCopyVolumes( channel_t *pch, int *pvolume_dest, int ivol_start, int cvol );
  45. float ChannelLoudestCurVolume( const channel_t * RESTRICT pch );
  46. extern int g_soundtime;
  47. extern float host_frametime;
  48. extern float host_frametime_unbounded;
  49. #if !defined( NO_VOICE )
  50. extern int g_SND_VoiceOverdriveInt;
  51. #endif
  52. extern ConVar dsp_room;
  53. extern ConVar dsp_water;
  54. extern ConVar dsp_player;
  55. extern ConVar dsp_facingaway;
  56. extern ConVar snd_showstart;
  57. extern ConVar dsp_automatic;
  58. extern ConVar snd_pitchquality;
  59. extern float DSP_ROOM_MIX;
  60. extern float DSP_NOROOM_MIX;
  61. portable_samplepair_t *g_paintbuffer;
  62. // temp paintbuffer - not included in main list of paintbuffers
  63. // NOTE: this paintbuffer is also used as a copy buffer by interpolating pitch
  64. // shift routines. Decreasing TEMP_COPY_BUFFER_SIZE (or PAINTBUFFER_MEM_SIZE)
  65. // will decrease the maximum pitch level (current 4.0)!
  66. portable_samplepair_t *g_temppaintbuffer = NULL;
  67. CUtlVector< paintbuffer_t > g_paintBuffers;
  68. // pointer to current paintbuffer (front and reare), used by all mixing, upsampling and dsp routines
  69. portable_samplepair_t *g_curpaintbuffer = NULL;
  70. portable_samplepair_t *g_currearpaintbuffer = NULL;
  71. portable_samplepair_t *g_curcenterpaintbuffer = NULL;
  72. bool g_bdirectionalfx;
  73. bool g_bDspOff;
  74. float g_dsp_volume;
  75. // dsp performance timing
  76. unsigned g_snd_call_time_debug = 0;
  77. unsigned g_snd_time_debug = 0;
  78. unsigned g_snd_count_debug = 0;
  79. unsigned g_snd_samplecount = 0;
  80. unsigned g_snd_frametime = 0;
  81. unsigned g_snd_frametime_total = 0;
  82. int g_snd_profile_type = 0; // type 1 dsp, type 2 mixer, type 3 load sound, type 4 all sound
  83. #define FILTERTYPE_NONE 0
  84. #define FILTERTYPE_LINEAR 1
  85. #define FILTERTYPE_CUBIC 2
  86. // filter memory for upsampling
  87. portable_samplepair_t cubicfilter1[3] = {{0,0},{0,0},{0,0}};
  88. portable_samplepair_t cubicfilter2[3] = {{0,0},{0,0},{0,0}};
  89. portable_samplepair_t linearfilter1[1] = {{0,0}};
  90. portable_samplepair_t linearfilter2[1] = {{0,0}};
  91. portable_samplepair_t linearfilter3[1] = {{0,0}};
  92. portable_samplepair_t linearfilter4[1] = {{0,0}};
  93. portable_samplepair_t linearfilter5[1] = {{0,0}};
  94. portable_samplepair_t linearfilter6[1] = {{0,0}};
  95. portable_samplepair_t linearfilter7[1] = {{0,0}};
  96. portable_samplepair_t linearfilter8[1] = {{0,0}};
  97. int snd_scaletable[SND_SCALE_LEVELS][256]; // 32k*4 = 128K
  98. int *snd_p, snd_linear_count, snd_vol;
  99. short *snd_out;
  100. extern int DSP_Alloc( int ipset, float xfade, int cchan );
  101. bool DSP_CheckDspAutoEnabled( void );
  102. int Get_idsp_room ( void );
  103. int dsp_room_GetInt ( void );
  104. void DSP_SetDspAuto( int dsp_preset );
  105. bool DSP_CheckDspAutoEnabled( void );
  106. void MIX_ScalePaintBuffer( int bufferIndex, int count, float fgain );
  107. bool IsReplayRendering()
  108. {
  109. #if defined( REPLAY_ENABLED )
  110. return g_pReplayMovieManager && g_pReplayMovieManager->IsRendering();
  111. #else
  112. return false;
  113. #endif
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Free allocated memory buffers
  117. //-----------------------------------------------------------------------------
  118. void MIX_FreeAllPaintbuffers(void)
  119. {
  120. if ( g_paintBuffers.Count() )
  121. {
  122. if ( g_temppaintbuffer )
  123. {
  124. _aligned_free( g_temppaintbuffer );
  125. g_temppaintbuffer = NULL;
  126. }
  127. for ( int i = 0; i < g_paintBuffers.Count(); i++ )
  128. {
  129. if ( g_paintBuffers[i].pbuf )
  130. {
  131. _aligned_free( g_paintBuffers[i].pbuf );
  132. }
  133. if ( g_paintBuffers[i].pbufrear )
  134. {
  135. _aligned_free( g_paintBuffers[i].pbufrear );
  136. }
  137. if ( g_paintBuffers[i].pbufcenter )
  138. {
  139. _aligned_free( g_paintBuffers[i].pbufcenter );
  140. }
  141. }
  142. g_paintBuffers.RemoveAll();
  143. }
  144. }
  145. void MIX_InitializePaintbuffer( paintbuffer_t *pPaintBuffer, bool bSurround, bool bSurroundCenter )
  146. {
  147. V_memset( pPaintBuffer, 0, sizeof( *pPaintBuffer ) );
  148. pPaintBuffer->pbuf = (portable_samplepair_t *)_aligned_malloc( PAINTBUFFER_MEM_SIZE*sizeof(portable_samplepair_t), 16 );
  149. V_memset( pPaintBuffer->pbuf, 0, PAINTBUFFER_MEM_SIZE*sizeof(portable_samplepair_t) );
  150. if ( bSurround )
  151. {
  152. pPaintBuffer->pbufrear = (portable_samplepair_t *)_aligned_malloc( PAINTBUFFER_MEM_SIZE*sizeof(portable_samplepair_t), 16 );
  153. V_memset( pPaintBuffer->pbufrear, 0, PAINTBUFFER_MEM_SIZE*sizeof(portable_samplepair_t) );
  154. }
  155. if ( bSurroundCenter )
  156. {
  157. pPaintBuffer->pbufcenter = (portable_samplepair_t *)_aligned_malloc( PAINTBUFFER_MEM_SIZE*sizeof(portable_samplepair_t), 16 );
  158. V_memset( pPaintBuffer->pbufcenter, 0, PAINTBUFFER_MEM_SIZE*sizeof(portable_samplepair_t) );
  159. }
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Allocate memory buffers
  163. // Initialize paintbuffers array, set current paint buffer to main output buffer SOUND_BUFFER_PAINT
  164. //-----------------------------------------------------------------------------
  165. bool MIX_InitAllPaintbuffers(void)
  166. {
  167. bool bSurround;
  168. bool bSurroundCenter;
  169. bSurroundCenter = g_AudioDevice->IsSurroundCenter();
  170. bSurround = g_AudioDevice->IsSurround() || bSurroundCenter;
  171. g_temppaintbuffer = (portable_samplepair_t*)_aligned_malloc( TEMP_COPY_BUFFER_SIZE*sizeof(portable_samplepair_t), 16 );
  172. V_memset( g_temppaintbuffer, 0, TEMP_COPY_BUFFER_SIZE*sizeof(portable_samplepair_t) );
  173. while ( g_paintBuffers.Count() < SOUND_BUFFER_BASETOTAL )
  174. {
  175. int nIndex = g_paintBuffers.AddToTail();
  176. MIX_InitializePaintbuffer( &(g_paintBuffers[ nIndex ]), bSurround, bSurroundCenter );
  177. }
  178. g_paintbuffer = g_paintBuffers[SOUND_BUFFER_PAINT].pbuf;
  179. // buffer flags
  180. g_paintBuffers[SOUND_BUFFER_ROOM].flags = SOUND_BUSS_ROOM;
  181. g_paintBuffers[SOUND_BUFFER_FACING].flags = SOUND_BUSS_FACING;
  182. g_paintBuffers[SOUND_BUFFER_FACINGAWAY].flags = SOUND_BUSS_FACINGAWAY;
  183. g_paintBuffers[SOUND_BUFFER_SPEAKER].flags = SOUND_BUSS_SPEAKER;
  184. g_paintBuffers[SOUND_BUFFER_DRY].flags = SOUND_BUSS_DRY;
  185. // buffer surround sound flag
  186. g_paintBuffers[SOUND_BUFFER_PAINT].fsurround = bSurround;
  187. g_paintBuffers[SOUND_BUFFER_FACING].fsurround = bSurround;
  188. g_paintBuffers[SOUND_BUFFER_FACINGAWAY].fsurround = bSurround;
  189. g_paintBuffers[SOUND_BUFFER_DRY].fsurround = bSurround;
  190. // buffer 5 channel surround sound flag
  191. g_paintBuffers[SOUND_BUFFER_PAINT].fsurround_center = bSurroundCenter;
  192. g_paintBuffers[SOUND_BUFFER_FACING].fsurround_center = bSurroundCenter;
  193. g_paintBuffers[SOUND_BUFFER_FACINGAWAY].fsurround_center = bSurroundCenter;
  194. g_paintBuffers[SOUND_BUFFER_DRY].fsurround_center = bSurroundCenter;
  195. // room buffer mixes down to mono or stereo, never to 4 or 5 ch
  196. g_paintBuffers[SOUND_BUFFER_ROOM].fsurround = false;
  197. g_paintBuffers[SOUND_BUFFER_ROOM].fsurround_center = false;
  198. // speaker buffer mixes to mono
  199. g_paintBuffers[SOUND_BUFFER_SPEAKER].fsurround = false;
  200. g_paintBuffers[SOUND_BUFFER_SPEAKER].fsurround_center = false;
  201. MIX_SetCurrentPaintbuffer( SOUND_BUFFER_PAINT );
  202. return true;
  203. }
  204. // called before loading samples to mix - cap the mix rate (ie: pitch) so that
  205. // we never overflow the mix copy buffer.
  206. double MIX_GetMaxRate( double rate, int sampleCount )
  207. {
  208. if (rate <= 2.0)
  209. return rate;
  210. // copybuf_bytes = rate_max * samples_max * samplesize_max
  211. // so:
  212. // rate_max = copybuf_bytes / (samples_max * samplesize_max )
  213. double samplesize_max = 4.0; // stereo 16bit samples
  214. double copybuf_bytes = (double)(TEMP_COPY_BUFFER_SIZE * sizeof(portable_samplepair_t));
  215. double samples_max = (double)(PAINTBUFFER_SIZE);
  216. double rate_max = copybuf_bytes / (samples_max * samplesize_max);
  217. // make sure sampleCount is never greater than paintbuffer samples
  218. // (this should have been set up in MIX_PaintChannels)
  219. Assert (sampleCount <= PAINTBUFFER_SIZE);
  220. return fpmin( rate, rate_max );
  221. }
  222. // Transfer (endtime - lpaintedtime) stereo samples in pfront out to hardware
  223. // pfront - pointer to stereo paintbuffer - 32 bit samples, interleaved stereo
  224. // lpaintedtime - total number of 32 bit stereo samples previously output to hardware
  225. // endtime - total number of 32 bit stereo samples currently mixed in paintbuffer
  226. void S_TransferStereo16( void *pOutput, const portable_samplepair_t *pfront, int lpaintedtime, int endtime )
  227. {
  228. int lpos;
  229. if ( IsX360() )
  230. {
  231. // not the right path for 360
  232. Assert( 0 );
  233. return;
  234. }
  235. Assert( pOutput );
  236. snd_vol = S_GetMasterVolume()*256;
  237. snd_p = (int *)pfront;
  238. // get size of output buffer in full samples (LR pairs)
  239. int samplePairCount = g_AudioDevice->DeviceSampleCount() >> 1;
  240. int sampleMask = samplePairCount - 1;
  241. bool bShouldPlaySound = !cl_movieinfo.IsRecording() && !IsReplayRendering();
  242. while ( lpaintedtime < endtime )
  243. {
  244. // pbuf can hold 16384, 16 bit L/R samplepairs.
  245. // lpaintedtime - where to start painting into dma buffer.
  246. // (modulo size of dma buffer for current position).
  247. // handle recirculating buffer issues
  248. // lpos - samplepair index into dma buffer. First samplepair from paintbuffer to be xfered here.
  249. lpos = lpaintedtime & sampleMask;
  250. // snd_out is L/R sample index into dma buffer. First L sample from paintbuffer goes here.
  251. snd_out = (short *)pOutput + (lpos<<1);
  252. // snd_linear_count is number of samplepairs between end of dma buffer and xfer start index.
  253. snd_linear_count = samplePairCount - lpos;
  254. // clamp snd_linear_count to be only as many samplepairs premixed
  255. if ( snd_linear_count > endtime - lpaintedtime )
  256. {
  257. // endtime - lpaintedtime = number of premixed sample pairs ready for xfer.
  258. snd_linear_count = endtime - lpaintedtime;
  259. }
  260. // snd_linear_count is now number of mono 16 bit samples (L and R) to xfer.
  261. snd_linear_count <<= 1;
  262. // write a linear blast of samples
  263. SND_RecordBuffer();
  264. if ( bShouldPlaySound )
  265. {
  266. // transfer 16bit samples from snd_p into snd_out, multiplying each sample by volume.
  267. Snd_WriteLinearBlastStereo16();
  268. }
  269. // advance paintbuffer pointer
  270. snd_p += snd_linear_count;
  271. // advance lpaintedtime by number of samplepairs just xfered.
  272. lpaintedtime += (snd_linear_count>>1);
  273. }
  274. }
  275. // Transfer contents of main paintbuffer pfront out to
  276. // device. Perform volume multiply on each sample.
  277. void S_TransferPaintBuffer(void *pOutput, const portable_samplepair_t *pfront, int lpaintedtime, int endtime)
  278. {
  279. int out_idx; // mono sample index
  280. int count; // number of mono samples to output
  281. int out_mask;
  282. int step;
  283. int val;
  284. int nSoundVol;
  285. const int *p;
  286. if ( IsX360() )
  287. {
  288. // not the right path for 360
  289. Assert( 0 );
  290. return;
  291. }
  292. Assert( pOutput );
  293. p = (const int *) pfront;
  294. count = ((endtime - lpaintedtime) * g_AudioDevice->DeviceChannels());
  295. out_mask = g_AudioDevice->DeviceSampleCount() - 1;
  296. // 44k: remove old 22k sound support << HISPEED_DMA
  297. // out_idx = ((paintedtime << HISPEED_DMA) * g_AudioDevice->DeviceChannels()) & out_mask;
  298. out_idx = (lpaintedtime * g_AudioDevice->DeviceChannels()) & out_mask;
  299. step = 3 - g_AudioDevice->DeviceChannels(); // mono output buffer - step 2, stereo - step 1
  300. nSoundVol = S_GetMasterVolume()*256;
  301. if (g_AudioDevice->DeviceSampleBits() == 16)
  302. {
  303. short *out = (short *) pOutput;
  304. while (count--)
  305. {
  306. val = (*p * nSoundVol) >> 8;
  307. p+= step;
  308. val = CLIP(val);
  309. out[out_idx] = val;
  310. out_idx = (out_idx + 1) & out_mask;
  311. }
  312. }
  313. else if (g_AudioDevice->DeviceSampleBits() == 8)
  314. {
  315. unsigned char *out = (unsigned char *) pOutput;
  316. while (count--)
  317. {
  318. val = (*p * nSoundVol) >> 8;
  319. p+= step;
  320. val = CLIP(val);
  321. out[out_idx] = (val>>8) + 128;
  322. out_idx = (out_idx + 1) & out_mask;
  323. }
  324. }
  325. }
  326. /*
  327. ===============================================================================
  328. CHANNEL MIXING
  329. ===============================================================================
  330. */
  331. // free channel so that it may be allocated by the
  332. // next request to play a sound. If sound is a
  333. // word in a sentence, release the sentence.
  334. // Works for static, dynamic, sentence and stream sounds
  335. void S_FreeChannel(channel_t *ch)
  336. {
  337. // Don't reenter in here (can happen inside voice code).
  338. if ( ch->flags.m_bIsFreeingChannel )
  339. return;
  340. ch->flags.m_bIsFreeingChannel = true;
  341. SND_CloseMouth(ch);
  342. g_pSoundServices->OnSoundStopped( ch->guid, ch->soundsource, ch->entchannel, ch->sfx->getname() );
  343. ch->flags.isSentence = false;
  344. // Msg("End sound %s\n", ch->sfx->getname() );
  345. delete ch->pMixer;
  346. ch->pMixer = NULL;
  347. ch->sfx = NULL;
  348. // zero all data in channel
  349. g_ActiveChannels.Remove( ch );
  350. Q_memset(ch, 0, sizeof(channel_t));
  351. }
  352. // Mix all channels into active paintbuffers until paintbuffer is full or 'endtime' is reached.
  353. // endtime: time in 44khz samples to mix
  354. // rate: ignore samples which are not natively at this rate (for multipass mixing/filtering)
  355. // if rate == SOUND_ALL_RATES then mix all samples this pass
  356. // flags: if SOUND_MIX_DRY, then mix only samples with channel flagged as 'dry'
  357. // outputRate: target mix rate for all samples. Note, if outputRate = SOUND_DMA_SPEED, then
  358. // this routine will fill the paintbuffer to endtime. Otherwise, fewer samples are mixed.
  359. // if (endtime - paintedtime) is not aligned on boundaries of 4,
  360. // we'll miss data if outputRate < SOUND_DMA_SPEED!
  361. void MIX_MixChannelsToPaintbuffer( CChannelList &list, int endtime, int flags, int rate, int outputRate )
  362. {
  363. VPROF( "MixChannelsToPaintbuffer" );
  364. int i;
  365. int sampleCount;
  366. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s c:%d %d/%d", __FUNCTION__, list.Count(), rate, outputRate );
  367. // mix each channel into paintbuffer
  368. // validate parameters
  369. Assert( outputRate <= SOUND_DMA_SPEED );
  370. Assert( !((endtime - g_paintedtime) & 0x3) || (outputRate == SOUND_DMA_SPEED) ); // make sure we're not discarding data
  371. // 44k: try to mix this many samples at outputRate
  372. sampleCount = ( endtime - g_paintedtime ) / ( SOUND_DMA_SPEED / outputRate );
  373. if ( sampleCount <= 0 )
  374. return;
  375. // Apply a global pitch shift if we're playing back a time-scaled replay
  376. float flGlobalPitchScale = 1.0f;
  377. #if defined( REPLAY_ENABLED )
  378. extern IDemoPlayer *g_pReplayDemoPlayer;
  379. if ( demoplayer->IsPlayingBack() && demoplayer == g_pReplayDemoPlayer )
  380. {
  381. // adjust time scale if playing back demo
  382. flGlobalPitchScale = demoplayer->GetPlaybackTimeScale();
  383. }
  384. #endif
  385. for ( i = list.Count(); --i >= 0; )
  386. {
  387. channel_t *ch = list.GetChannel( i );
  388. Assert( ch->sfx );
  389. // must never have a 'dry' and 'speaker' set - causes double mixing & double data reading
  390. Assert ( !( ( ch->flags.bdry && ch->flags.bSpeaker ) || ( ch->flags.bdry && ch->special_dsp != 0 ) ) );
  391. // if mixing with SOUND_MIX_DRY flag, ignore (don't even load) all channels not flagged as 'dry'
  392. if ( flags == SOUND_MIX_DRY )
  393. {
  394. if ( !ch->flags.bdry )
  395. continue;
  396. }
  397. // if mixing with SOUND_MIX_WET flag, ignore (don't even load) all channels flagged as 'dry' or 'speaker'
  398. if ( flags == SOUND_MIX_WET )
  399. {
  400. if ( ch->flags.bdry || ch->flags.bSpeaker || ch->special_dsp != 0 )
  401. continue;
  402. }
  403. // if mixing with SOUND_MIX_SPEAKER flag, ignore (don't even load) all channels not flagged as 'speaker'
  404. if ( flags == SOUND_MIX_SPEAKER )
  405. {
  406. if ( !ch->flags.bSpeaker )
  407. continue;
  408. }
  409. // if mixing with SOUND_MIX_SPEAKER flag, ignore (don't even load) all channels not flagged as 'speaker'
  410. if ( flags == SOUND_MIX_SPECIAL_DSP )
  411. {
  412. if ( ch->special_dsp == 0 )
  413. continue;
  414. }
  415. // multipass mixing - only mix samples of specified sample rate
  416. switch ( rate )
  417. {
  418. case SOUND_11k:
  419. case SOUND_22k:
  420. case SOUND_44k:
  421. if ( rate != ch->sfx->pSource->SampleRate() )
  422. continue;
  423. break;
  424. default:
  425. case SOUND_ALL_RATES:
  426. break;
  427. }
  428. // Tracker 20771, if breen is speaking through the monitor, the client doesn't have an entity
  429. // for the "soundsource" but we still need the lipsync to pause if the game is paused. Therefore
  430. // I changed SND_IsMouth to look for any .wav on any channels which has sentence data
  431. bool bIsMouth = SND_IsMouth(ch);
  432. bool bShouldPause = IsX360() ? !ch->sfx->m_bIsUISound : bIsMouth;
  433. // Tracker 14637: Pausing the game pauses voice sounds, but not other sounds...
  434. if ( bShouldPause && g_pSoundServices->IsGamePaused() )
  435. {
  436. continue;
  437. }
  438. if ( bIsMouth )
  439. {
  440. if ( ( ch->soundsource == SOUND_FROM_UI_PANEL ) || entitylist->GetClientEntity(ch->soundsource) ||
  441. ( ch->flags.bSpeaker && entitylist->GetClientEntity( ch->speakerentity ) ) )
  442. {
  443. // UNDONE: recode this as a member function of CAudioMixer
  444. SND_MoveMouth8(ch, ch->sfx->pSource, sampleCount);
  445. }
  446. }
  447. // mix channel to all active paintbuffers:
  448. // mix 'dry' sounds only to dry paintbuffer.
  449. // mix 'speaker' sounds only to speaker paintbuffer.
  450. // mix all other sounds between room, facing & facingaway paintbuffers
  451. // NOTE: must be called once per channel only - consecutive calls retrieve additional data.
  452. float flPitch = ch->pitch;
  453. ch->pitch *= flGlobalPitchScale;
  454. if (list.IsQuashed(i))
  455. {
  456. // If the sound has been silenced as a performance heuristic, quash it.
  457. ch->pMixer->SkipSamples( ch, sampleCount, outputRate, 0 );
  458. // DevMsg("Quashed channel %d (%s)\n", i, ch->sfx->GetFileName());
  459. }
  460. else
  461. {
  462. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "MixDataToDevice" );
  463. ch->pMixer->MixDataToDevice( g_AudioDevice, ch, sampleCount, outputRate, 0 );
  464. }
  465. // restore to original pitch settings
  466. ch->pitch = flPitch;
  467. if ( !ch->pMixer->ShouldContinueMixing() )
  468. {
  469. S_FreeChannel( ch );
  470. list.RemoveChannelFromList(i);
  471. }
  472. if ( (ch->nFreeChannelAtSampleTime > 0 && (int)ch->nFreeChannelAtSampleTime <= endtime) )
  473. {
  474. S_FreeChannel( ch );
  475. list.RemoveChannelFromList(i);
  476. }
  477. }
  478. }
  479. // pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer
  480. inline portable_samplepair_t * S_GetNextpFilter(int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem)
  481. {
  482. // The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples
  483. if (i == -1)
  484. return (&(pfiltermem[0]));
  485. if (i == 0)
  486. return (&(pfiltermem[1]));
  487. if (i == 1)
  488. return (&(pfiltermem[2]));
  489. // return from paintbuffer, where samples are doubled.
  490. // even samples are to be replaced with interpolated value.
  491. return (&(pbuffer[(i-2)*2 + 1]));
  492. }
  493. // pass forward over passed in buffer and cubic interpolate all odd samples
  494. // pbuffer: buffer to filter (in place)
  495. // prevfilter: filter memory. NOTE: this must match the filtertype ie: filtercubic[] for FILTERTYPE_CUBIC
  496. // if NULL then perform no filtering. UNDONE: should have a filter memory array type
  497. // count: how many samples to upsample. will become count*2 samples in buffer, in place.
  498. void S_Interpolate2xCubic( portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem, int cfltmem, int count )
  499. {
  500. // implement cubic interpolation on 2x upsampled buffer. Effectively delays buffer contents by 2 samples.
  501. // pbuffer: contains samples at 0, 2, 4, 6...
  502. // temppaintbuffer is temp buffer, of same or larger size than a paintbuffer, used to store processed values
  503. // count: number of samples to process in buffer ie: how many samples at 0, 2, 4, 6...
  504. // finpos is the fractional, inpos the integer part.
  505. // finpos = 0.5 for upsampling by 2x
  506. // inpos is the position of the sample
  507. // xm1 = x [inpos - 1];
  508. // x0 = x [inpos + 0];
  509. // x1 = x [inpos + 1];
  510. // x2 = x [inpos + 2];
  511. // a = (3 * (x0-x1) - xm1 + x2) / 2;
  512. // b = 2*x1 + xm1 - (5*x0 + x2) / 2;
  513. // c = (x1 - xm1) / 2;
  514. // y [outpos] = (((a * finpos) + b) * finpos + c) * finpos + x0;
  515. int i, upCount = count << 1;
  516. int a, b, c;
  517. int xm1, x0, x1, x2;
  518. portable_samplepair_t *psamp0;
  519. portable_samplepair_t *psamp1;
  520. portable_samplepair_t *psamp2;
  521. portable_samplepair_t *psamp3;
  522. int outpos = 0;
  523. Assert (upCount <= PAINTBUFFER_SIZE);
  524. // pfiltermem holds 6 samples from previous buffer pass
  525. // process 'count' samples
  526. for ( i = 0; i < count; i++)
  527. {
  528. // get source sample pointer
  529. psamp0 = S_GetNextpFilter(i-1, pbuffer, pfiltermem);
  530. psamp1 = S_GetNextpFilter(i, pbuffer, pfiltermem);
  531. psamp2 = S_GetNextpFilter(i+1, pbuffer, pfiltermem);
  532. psamp3 = S_GetNextpFilter(i+2, pbuffer, pfiltermem);
  533. // write out original sample to interpolation buffer
  534. g_temppaintbuffer[outpos++] = *psamp1;
  535. // get all left samples for interpolation window
  536. xm1 = psamp0->left;
  537. x0 = psamp1->left;
  538. x1 = psamp2->left;
  539. x2 = psamp3->left;
  540. // interpolate
  541. a = (3 * (x0-x1) - xm1 + x2) / 2;
  542. b = 2*x1 + xm1 - (5*x0 + x2) / 2;
  543. c = (x1 - xm1) / 2;
  544. // write out interpolated sample
  545. g_temppaintbuffer[outpos].left = a/8 + b/4 + c/2 + x0;
  546. // get all right samples for window
  547. xm1 = psamp0->right;
  548. x0 = psamp1->right;
  549. x1 = psamp2->right;
  550. x2 = psamp3->right;
  551. // interpolate
  552. a = (3 * (x0-x1) - xm1 + x2) / 2;
  553. b = 2*x1 + xm1 - (5*x0 + x2) / 2;
  554. c = (x1 - xm1) / 2;
  555. // write out interpolated sample, increment output counter
  556. g_temppaintbuffer[outpos++].right = a/8 + b/4 + c/2 + x0;
  557. Assert( outpos <= TEMP_COPY_BUFFER_SIZE );
  558. }
  559. Assert(cfltmem >= 3);
  560. // save last 3 samples from paintbuffer
  561. pfiltermem[0] = pbuffer[upCount - 5];
  562. pfiltermem[1] = pbuffer[upCount - 3];
  563. pfiltermem[2] = pbuffer[upCount - 1];
  564. // copy temppaintbuffer back into paintbuffer
  565. for (i = 0; i < upCount; i++)
  566. pbuffer[i] = g_temppaintbuffer[i];
  567. }
  568. // pass forward over passed in buffer and linearly interpolate all odd samples
  569. // pbuffer: buffer to filter (in place)
  570. // prevfilter: filter memory. NOTE: this must match the filtertype ie: filterlinear[] for FILTERTYPE_LINEAR
  571. // if NULL then perform no filtering.
  572. // count: how many samples to upsample. will become count*2 samples in buffer, in place.
  573. void S_Interpolate2xLinear( portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem, int cfltmem, int count )
  574. {
  575. int i, upCount = count<<1;
  576. Assert (upCount <= PAINTBUFFER_SIZE);
  577. Assert (cfltmem >= 1);
  578. // use interpolation value from previous mix
  579. pbuffer[0].left = (pfiltermem->left + pbuffer[0].left) >> 1;
  580. pbuffer[0].right = (pfiltermem->right + pbuffer[0].right) >> 1;
  581. for ( i = 2; i < upCount; i+=2)
  582. {
  583. // use linear interpolation for upsampling
  584. pbuffer[i].left = (pbuffer[i].left + pbuffer[i-1].left) >> 1;
  585. pbuffer[i].right = (pbuffer[i].right + pbuffer[i-1].right) >> 1;
  586. }
  587. // save last value to be played out in buffer
  588. *pfiltermem = pbuffer[upCount - 1];
  589. }
  590. // Optimized routine. 2.27X faster than the above routine
  591. void S_Interpolate2xLinear_2( int count, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem, int cfltmem )
  592. {
  593. Assert (cfltmem >= 1);
  594. int sample = count-1;
  595. int end = (count*2)-1;
  596. portable_samplepair_t *pwrite = &pbuffer[end];
  597. portable_samplepair_t *pread = &pbuffer[sample];
  598. portable_samplepair_t last = pread[0];
  599. pread--;
  600. // PERFORMANCE: Unroll the loop 8 times. This improves speed quite a bit
  601. for ( ;sample >= 8; sample -= 8 )
  602. {
  603. pwrite[0] = last;
  604. pwrite[-1].left = (pread[0].left + last.left)>>1;
  605. pwrite[-1].right = (pread[0].right + last.right)>>1;
  606. last = pread[0];
  607. pwrite[-2] = last;
  608. pwrite[-3].left = (pread[-1].left + last.left)>>1;
  609. pwrite[-3].right = (pread[-1].right + last.right)>>1;
  610. last = pread[-1];
  611. pwrite[-4] = last;
  612. pwrite[-5].left = (pread[-2].left + last.left)>>1;
  613. pwrite[-5].right = (pread[-2].right + last.right)>>1;
  614. last = pread[-2];
  615. pwrite[-6] = last;
  616. pwrite[-7].left = (pread[-3].left + last.left)>>1;
  617. pwrite[-7].right = (pread[-3].right + last.right)>>1;
  618. last = pread[-3];
  619. pwrite[-8] = last;
  620. pwrite[-9].left = (pread[-4].left + last.left)>>1;
  621. pwrite[-9].right = (pread[-4].right + last.right)>>1;
  622. last = pread[-4];
  623. pwrite[-10] = last;
  624. pwrite[-11].left = (pread[-5].left + last.left)>>1;
  625. pwrite[-11].right = (pread[-5].right + last.right)>>1;
  626. last = pread[-5];
  627. pwrite[-12] = last;
  628. pwrite[-13].left = (pread[-6].left + last.left)>>1;
  629. pwrite[-13].right = (pread[-6].right + last.right)>>1;
  630. last = pread[-6];
  631. pwrite[-14] = last;
  632. pwrite[-15].left = (pread[-7].left + last.left)>>1;
  633. pwrite[-15].right = (pread[-7].right + last.right)>>1;
  634. last = pread[-7];
  635. pread -= 8;
  636. pwrite -= 16;
  637. }
  638. while ( pread >= pbuffer )
  639. {
  640. pwrite[0] = last;
  641. pwrite[-1].left = (pread[0].left + last.left)>>1;
  642. pwrite[-1].right = (pread[0].right + last.right)>>1;
  643. last = pread[0];
  644. pread--;
  645. pwrite-=2;
  646. }
  647. pbuffer[1] = last;
  648. pbuffer[0].left = (pfiltermem->left + last.left) >> 1;
  649. pbuffer[0].right = (pfiltermem->right + last.right) >> 1;
  650. *pfiltermem = pbuffer[end];
  651. }
  652. // upsample by 2x, optionally using interpolation
  653. // count: how many samples to upsample. will become count*2 samples in buffer, in place.
  654. // pbuffer: buffer to upsample into (in place)
  655. // pfiltermem: filter memory. NOTE: this must match the filtertype ie: filterlinear[] for FILTERTYPE_LINEAR
  656. // if NULL then perform no filtering.
  657. // cfltmem: max number of sample pairs filter can use
  658. // filtertype: FILTERTYPE_NONE, _LINEAR, _CUBIC etc. Must match prevfilter.
  659. void S_MixBufferUpsample2x( int count, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem, int cfltmem, int filtertype )
  660. {
  661. // JAY: Optimized this routine. Test then remove old routine.
  662. // NOTE: Has been proven equivalent by comparing output.
  663. if ( filtertype == FILTERTYPE_LINEAR )
  664. {
  665. S_Interpolate2xLinear_2( count, pbuffer, pfiltermem, cfltmem );
  666. return;
  667. }
  668. int i, j, upCount = count<<1;
  669. // reverse through buffer, duplicating contents for 'count' samples
  670. for (i = upCount - 1, j = count - 1; j >= 0; i-=2, j--)
  671. {
  672. pbuffer[i] = pbuffer[j];
  673. pbuffer[i-1] = pbuffer[j];
  674. }
  675. // pass forward through buffer, interpolate all even slots
  676. switch (filtertype)
  677. {
  678. default:
  679. break;
  680. case FILTERTYPE_LINEAR:
  681. S_Interpolate2xLinear(pbuffer, pfiltermem, cfltmem, count);
  682. break;
  683. case FILTERTYPE_CUBIC:
  684. S_Interpolate2xCubic(pbuffer, pfiltermem, cfltmem, count);
  685. break;
  686. }
  687. }
  688. //===============================================================================
  689. // PAINTBUFFER ROUTINES
  690. //===============================================================================
  691. // Set current paintbuffer to pbuf.
  692. // The set paintbuffer is used by all subsequent mixing, upsampling and dsp routines.
  693. // Also sets the rear paintbuffer if paintbuffer has fsurround true.
  694. // (otherwise, rearpaintbuffer is NULL)
  695. void MIX_SetCurrentPaintbuffer(int ipaintbuffer)
  696. {
  697. // set front and rear paintbuffer
  698. Assert(ipaintbuffer < g_paintBuffers.Count());
  699. g_curpaintbuffer = g_paintBuffers[ipaintbuffer].pbuf;
  700. if ( g_paintBuffers[ipaintbuffer].fsurround )
  701. {
  702. g_currearpaintbuffer = g_paintBuffers[ipaintbuffer].pbufrear;
  703. g_curcenterpaintbuffer = NULL;
  704. if ( g_paintBuffers[ipaintbuffer].fsurround_center )
  705. g_curcenterpaintbuffer = g_paintBuffers[ipaintbuffer].pbufcenter;
  706. }
  707. else
  708. {
  709. g_currearpaintbuffer = NULL;
  710. g_curcenterpaintbuffer = NULL;
  711. }
  712. Assert(g_curpaintbuffer != NULL);
  713. }
  714. // return index to current paintbuffer
  715. int MIX_GetCurrentPaintbufferIndex( void )
  716. {
  717. int i;
  718. for ( i = 0; i < g_paintBuffers.Count(); i++ )
  719. {
  720. if (g_curpaintbuffer == g_paintBuffers[i].pbuf)
  721. return i;
  722. }
  723. return 0;
  724. }
  725. // return pointer to current paintbuffer struct
  726. paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
  727. {
  728. int ipaint = MIX_GetCurrentPaintbufferIndex();
  729. Assert( ipaint < g_paintBuffers.Count() );
  730. return &g_paintBuffers[ipaint];
  731. }
  732. // return pointer to front paintbuffer pbuf, given index
  733. inline portable_samplepair_t *MIX_GetPFrontFromIPaint(int ipaintbuffer)
  734. {
  735. return g_paintBuffers[ipaintbuffer].pbuf;
  736. }
  737. paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaintbuffer )
  738. {
  739. Assert( ipaintbuffer < g_paintBuffers.Count() );
  740. return &g_paintBuffers[ipaintbuffer];
  741. }
  742. // return pointer to rear buffer, given index.
  743. // returns null if fsurround is false;
  744. inline portable_samplepair_t *MIX_GetPRearFromIPaint(int ipaintbuffer)
  745. {
  746. if ( g_paintBuffers[ipaintbuffer].fsurround )
  747. return g_paintBuffers[ipaintbuffer].pbufrear;
  748. return NULL;
  749. }
  750. // return pointer to center buffer, given index.
  751. // returns null if fsurround_center is false;
  752. inline portable_samplepair_t *MIX_GetPCenterFromIPaint(int ipaintbuffer)
  753. {
  754. if ( g_paintBuffers[ipaintbuffer].fsurround_center )
  755. return g_paintBuffers[ipaintbuffer].pbufcenter;
  756. return NULL;
  757. }
  758. // return index to paintbuffer, given buffer pointer
  759. inline int MIX_GetIPaintFromPFront( portable_samplepair_t *pbuf )
  760. {
  761. int i;
  762. for ( i = 0; i < g_paintBuffers.Count(); i++ )
  763. {
  764. if ( pbuf == g_paintBuffers[i].pbuf )
  765. return i;
  766. }
  767. return 0;
  768. }
  769. // return pointer to paintbuffer struct, given ptr to buffer data
  770. inline paintbuffer_t *MIX_GetPPaintFromPFront( portable_samplepair_t *pbuf )
  771. {
  772. int i;
  773. i = MIX_GetIPaintFromPFront( pbuf );
  774. return &g_paintBuffers[i];
  775. }
  776. // up convert mono buffer to full surround
  777. inline void MIX_ConvertBufferToSurround( int ipaintbuffer )
  778. {
  779. paintbuffer_t *ppaint = &g_paintBuffers[ipaintbuffer];
  780. // duplicate channel data as needed
  781. if ( g_AudioDevice->IsSurround() )
  782. {
  783. // set buffer flags
  784. ppaint->fsurround = g_AudioDevice->IsSurround();
  785. ppaint->fsurround_center = g_AudioDevice->IsSurroundCenter();
  786. portable_samplepair_t *pfront = MIX_GetPFrontFromIPaint( ipaintbuffer );
  787. portable_samplepair_t *prear = MIX_GetPRearFromIPaint( ipaintbuffer );
  788. portable_samplepair_t *pcenter = MIX_GetPCenterFromIPaint( ipaintbuffer );
  789. // copy front to rear
  790. Q_memcpy(prear, pfront, sizeof(portable_samplepair_t) * PAINTBUFFER_SIZE);
  791. // copy front to center
  792. if ( g_AudioDevice->IsSurroundCenter() )
  793. Q_memcpy(pcenter, pfront, sizeof(portable_samplepair_t) * PAINTBUFFER_SIZE);
  794. }
  795. }
  796. // Activate a paintbuffer. All active paintbuffers are mixed in parallel within
  797. // MIX_MixChannelsToPaintbuffer, according to flags
  798. inline void MIX_ActivatePaintbuffer(int ipaintbuffer)
  799. {
  800. Assert( ipaintbuffer < g_paintBuffers.Count() );
  801. g_paintBuffers[ipaintbuffer].factive = true;
  802. }
  803. // Don't mix into this paintbuffer
  804. inline void MIX_DeactivatePaintbuffer(int ipaintbuffer)
  805. {
  806. Assert( ipaintbuffer < g_paintBuffers.Count() );
  807. g_paintBuffers[ipaintbuffer].factive = false;
  808. }
  809. // Don't mix into any paintbuffers
  810. inline void MIX_DeactivateAllPaintbuffers(void)
  811. {
  812. int i;
  813. for ( i = 0; i < g_paintBuffers.Count(); i++ )
  814. g_paintBuffers[i].factive = false;
  815. }
  816. // set upsampling filter indexes back to 0
  817. inline void MIX_ResetPaintbufferFilterCounters( void )
  818. {
  819. int i;
  820. for ( i = 0; i < g_paintBuffers.Count(); i++ )
  821. g_paintBuffers[i].ifilter = 0;
  822. }
  823. inline void MIX_ResetPaintbufferFilterCounter( int ipaintbuffer )
  824. {
  825. Assert ( ipaintbuffer < g_paintBuffers.Count() );
  826. g_paintBuffers[ipaintbuffer].ifilter = 0;
  827. }
  828. // Change paintbuffer's flags
  829. inline void MIX_SetPaintbufferFlags(int ipaintbuffer, int flags)
  830. {
  831. Assert( ipaintbuffer < g_paintBuffers.Count() );
  832. g_paintBuffers[ipaintbuffer].flags = flags;
  833. }
  834. // zero out all paintbuffers
  835. void MIX_ClearAllPaintBuffers( int SampleCount, bool clearFilters )
  836. {
  837. // g_paintBuffers can be NULL with -nosound
  838. if ( g_paintBuffers.Count() <= 0 )
  839. {
  840. return;
  841. }
  842. int i;
  843. int count = min(SampleCount, PAINTBUFFER_SIZE);
  844. // zero out all paintbuffer data (ignore sampleCount)
  845. for ( i = 0; i < g_paintBuffers.Count(); i++ )
  846. {
  847. if (g_paintBuffers[i].pbuf != NULL)
  848. Q_memset(g_paintBuffers[i].pbuf, 0, (count+1) * sizeof(portable_samplepair_t));
  849. if (g_paintBuffers[i].pbufrear != NULL)
  850. Q_memset(g_paintBuffers[i].pbufrear, 0, (count+1) * sizeof(portable_samplepair_t));
  851. if (g_paintBuffers[i].pbufcenter != NULL)
  852. Q_memset(g_paintBuffers[i].pbufcenter, 0, (count+1) * sizeof(portable_samplepair_t));
  853. if ( clearFilters )
  854. {
  855. Q_memset( g_paintBuffers[i].fltmem, 0, sizeof(g_paintBuffers[i].fltmem) );
  856. Q_memset( g_paintBuffers[i].fltmemrear, 0, sizeof(g_paintBuffers[i].fltmemrear) );
  857. Q_memset( g_paintBuffers[i].fltmemcenter, 0, sizeof(g_paintBuffers[i].fltmemcenter) );
  858. }
  859. }
  860. if ( clearFilters )
  861. {
  862. MIX_ResetPaintbufferFilterCounters();
  863. }
  864. }
  865. #define SWAP(a,b,t) {(t) = (a); (a) = (b); (b) = (t);}
  866. #define AVG(a,b) (((a) + (b)) >> 1 )
  867. #define AVG4(a,b,c,d) (((a) + (b) + (c) + (d)) >> 2 )
  868. // Synthesize center channel from left/right values (average).
  869. // Currently just averages, but could actually remove
  870. // the center signal from the l/r channels...
  871. inline void MIX_CenterFromLeftRight( int *pl, int *pr, int *pc )
  872. {
  873. int l = *pl;
  874. int r = *pr;
  875. int c = 0;
  876. c = (l + r) / 2;
  877. /*
  878. l = l - c/2;
  879. r = r - c/2;
  880. if (l < 0)
  881. {
  882. l = 0;
  883. r += (-l);
  884. c += (-l);
  885. }
  886. else if (r < 0)
  887. {
  888. r = 0;
  889. l += (-r);
  890. c += (-r);
  891. }
  892. */
  893. *pc = c;
  894. // *pl = l;
  895. // *pr = r;
  896. }
  897. // mixes pbuf1 + pbuf2 into pbuf3, count samples
  898. // fgain is output gain 0-1.0
  899. // NOTE: pbuf3 may equal pbuf1 or pbuf2!
  900. // mixing algorithms:
  901. // destination 2ch:
  902. // pb1 2ch + pb2 2ch -> pb3 2ch
  903. // pb1 (4ch->2ch) + pb2 2ch -> pb3 2ch
  904. // pb1 2ch + pb2 (4ch->2ch) -> pb3 2ch
  905. // pb1 (4ch->2ch) + pb2 (4ch->2ch) -> pb3 2ch
  906. // destination 4ch:
  907. // pb1 4ch + pb2 4ch -> pb3 4ch
  908. // pb1 (2ch->4ch) + pb2 4ch -> pb3 4ch
  909. // pb1 4ch + pb2 (2ch->4ch) -> pb3 4ch
  910. // pb1 (2ch->4ch) + pb2 (2ch->4ch) -> pb3 4ch
  911. // if all buffers are 4 or 5 ch surround, mix rear & center channels into ibuf3 as well.
  912. // NOTE: for performance, conversion and mixing are done in a single pass instead of
  913. // a two pass channel convert + mix scheme.
  914. void MIX_MixPaintbuffers(int ibuf1, int ibuf2, int ibuf3, int count, float fgain_out)
  915. {
  916. VPROF("Mixpaintbuffers");
  917. int i;
  918. portable_samplepair_t *pbuf1, *pbuf2, *pbuf3, *pbuft;
  919. portable_samplepair_t *pbufrear1, *pbufrear2, *pbufrear3, *pbufreart;
  920. portable_samplepair_t *pbufcenter1, *pbufcenter2, *pbufcenter3, *pbufcentert;
  921. int cchan1, cchan2, cchan3, cchant;
  922. int xl,xr;
  923. int l,r,l2,r2,c, c2;
  924. int gain_out;
  925. gain_out = 256 * fgain_out;
  926. Assert (count <= PAINTBUFFER_SIZE);
  927. Assert (ibuf1 < g_paintBuffers.Count());
  928. Assert (ibuf2 < g_paintBuffers.Count());
  929. Assert (ibuf3 < g_paintBuffers.Count());
  930. pbuf1 = g_paintBuffers[ibuf1].pbuf;
  931. pbuf2 = g_paintBuffers[ibuf2].pbuf;
  932. pbuf3 = g_paintBuffers[ibuf3].pbuf;
  933. pbufrear1 = g_paintBuffers[ibuf1].pbufrear;
  934. pbufrear2 = g_paintBuffers[ibuf2].pbufrear;
  935. pbufrear3 = g_paintBuffers[ibuf3].pbufrear;
  936. pbufcenter1 = g_paintBuffers[ibuf1].pbufcenter;
  937. pbufcenter2 = g_paintBuffers[ibuf2].pbufcenter;
  938. pbufcenter3 = g_paintBuffers[ibuf3].pbufcenter;
  939. cchan1 = 2 + (g_paintBuffers[ibuf1].fsurround ? 2 : 0) + (g_paintBuffers[ibuf1].fsurround_center ? 1 : 0);
  940. cchan2 = 2 + (g_paintBuffers[ibuf2].fsurround ? 2 : 0) + (g_paintBuffers[ibuf2].fsurround_center ? 1 : 0);
  941. cchan3 = 2 + (g_paintBuffers[ibuf3].fsurround ? 2 : 0) + (g_paintBuffers[ibuf3].fsurround_center ? 1 : 0);
  942. // make sure pbuf1 always has fewer or equal channels than pbuf2
  943. // NOTE: pbuf3 may equal pbuf1 or pbuf2!
  944. if ( cchan2 < cchan1 )
  945. {
  946. SWAP( cchan1, cchan2, cchant );
  947. SWAP( pbuf1, pbuf2, pbuft );
  948. SWAP( pbufrear1, pbufrear2, pbufreart );
  949. SWAP( pbufcenter1, pbufcenter2, pbufcentert);
  950. }
  951. // UNDONE: implement fast mixing routines for each of the following sections
  952. // destination buffer stereo - average n chans down to stereo
  953. if ( cchan3 == 2 )
  954. {
  955. // destination 2ch:
  956. // pb1 2ch + pb2 2ch -> pb3 2ch
  957. // pb1 2ch + pb2 (4ch->2ch) -> pb3 2ch
  958. // pb1 (4ch->2ch) + pb2 (4ch->2ch) -> pb3 2ch
  959. if ( cchan1 == 2 && cchan2 == 2 )
  960. {
  961. // mix front channels
  962. for (i = 0; i < count; i++)
  963. {
  964. pbuf3[i].left = pbuf1[i].left + pbuf2[i].left;
  965. pbuf3[i].right = pbuf1[i].right + pbuf2[i].right;
  966. }
  967. goto gain2ch;
  968. }
  969. if ( cchan1 == 2 && cchan2 == 4 )
  970. {
  971. // avg rear chan l/r
  972. for (i = 0; i < count; i++)
  973. {
  974. pbuf3[i].left = pbuf1[i].left + AVG( pbuf2[i].left, pbufrear2[i].left );
  975. pbuf3[i].right = pbuf1[i].right + AVG( pbuf2[i].right, pbufrear2[i].right );
  976. }
  977. goto gain2ch;
  978. }
  979. if ( cchan1 == 4 && cchan2 == 4 )
  980. {
  981. // avg rear chan l/r
  982. for (i = 0; i < count; i++)
  983. {
  984. pbuf3[i].left = AVG( pbuf1[i].left, pbufrear1[i].left) + AVG( pbuf2[i].left, pbufrear2[i].left );
  985. pbuf3[i].right = AVG( pbuf1[i].right, pbufrear1[i].right) + AVG( pbuf2[i].right, pbufrear2[i].right );
  986. }
  987. goto gain2ch;
  988. }
  989. if ( cchan1 == 2 && cchan2 == 5 )
  990. {
  991. // avg rear chan l/r + center split into left/right
  992. for (i = 0; i < count; i++)
  993. {
  994. l = pbuf2[i].left + ((pbufcenter2[i].left) >> 1);
  995. r = pbuf2[i].right + ((pbufcenter2[i].left) >> 1);
  996. pbuf3[i].left = pbuf1[i].left + AVG( l, pbufrear2[i].left );
  997. pbuf3[i].right = pbuf1[i].right + AVG( r, pbufrear2[i].right );
  998. }
  999. goto gain2ch;
  1000. }
  1001. if ( cchan1 == 4 && cchan2 == 5)
  1002. {
  1003. for (i = 0; i < count; i++)
  1004. {
  1005. l = pbuf2[i].left + ((pbufcenter2[i].left) >> 1);
  1006. r = pbuf2[i].right + ((pbufcenter2[i].left) >> 1);
  1007. pbuf3[i].left = AVG( pbuf1[i].left, pbufrear1[i].left) + AVG( l, pbufrear2[i].left );
  1008. pbuf3[i].right = AVG( pbuf1[i].right, pbufrear1[i].right) + AVG( r, pbufrear2[i].right );
  1009. }
  1010. goto gain2ch;
  1011. }
  1012. if ( cchan1 == 5 && cchan2 == 5)
  1013. {
  1014. for (i = 0; i < count; i++)
  1015. {
  1016. l = pbuf1[i].left + ((pbufcenter1[i].left) >> 1);
  1017. r = pbuf1[i].right + ((pbufcenter1[i].left) >> 1);
  1018. l2 = pbuf2[i].left + ((pbufcenter2[i].left) >> 1);
  1019. r2 = pbuf2[i].right + ((pbufcenter2[i].left) >> 1);
  1020. pbuf3[i].left = AVG( l, pbufrear1[i].left) + AVG( l2, pbufrear2[i].left );
  1021. pbuf3[i].right = AVG( r, pbufrear1[i].right) + AVG( r2, pbufrear2[i].right );
  1022. } goto gain2ch;
  1023. }
  1024. }
  1025. // destination buffer quad - duplicate n chans up to quad
  1026. if ( cchan3 == 4 )
  1027. {
  1028. // pb1 4ch + pb2 4ch -> pb3 4ch
  1029. // pb1 (2ch->4ch) + pb2 4ch -> pb3 4ch
  1030. // pb1 (2ch->4ch) + pb2 (2ch->4ch) -> pb3 4ch
  1031. if ( cchan1 == 4 && cchan2 == 4)
  1032. {
  1033. // mix front -> front, rear -> rear
  1034. for (i = 0; i < count; i++)
  1035. {
  1036. pbuf3[i].left = pbuf1[i].left + pbuf2[i].left;
  1037. pbuf3[i].right = pbuf1[i].right + pbuf2[i].right;
  1038. pbufrear3[i].left = pbufrear1[i].left + pbufrear2[i].left;
  1039. pbufrear3[i].right = pbufrear1[i].right + pbufrear2[i].right;
  1040. }
  1041. goto gain4ch;
  1042. }
  1043. if ( cchan1 == 2 && cchan2 == 4)
  1044. {
  1045. for (i = 0; i < count; i++)
  1046. {
  1047. // split 2 ch left -> front left, rear left
  1048. // split 2 ch right -> front right, rear right
  1049. xl = pbuf1[i].left;
  1050. xr = pbuf1[i].right;
  1051. pbuf3[i].left = xl + pbuf2[i].left;
  1052. pbuf3[i].right = xr + pbuf2[i].right;
  1053. pbufrear3[i].left = xl + pbufrear2[i].left;
  1054. pbufrear3[i].right = xr + pbufrear2[i].right;
  1055. }
  1056. goto gain4ch;
  1057. }
  1058. if ( cchan1 == 2 && cchan2 == 2)
  1059. {
  1060. // mix l,r, split into front l, front r
  1061. for (i = 0; i < count; i++)
  1062. {
  1063. xl = pbuf1[i].left + pbuf2[i].left;
  1064. xr = pbuf1[i].right + pbuf2[i].right;
  1065. pbufrear3[i].left = pbuf3[i].left = xl;
  1066. pbufrear3[i].right = pbuf3[i].right = xr;
  1067. }
  1068. goto gain4ch;
  1069. }
  1070. if ( cchan1 == 2 && cchan2 == 5 )
  1071. {
  1072. for (i = 0; i < count; i++)
  1073. {
  1074. // split center of chan2 into left/right
  1075. l2 = pbuf2[i].left + ((pbufcenter2[i].left) >> 1);
  1076. r2 = pbuf2[i].right + ((pbufcenter2[i].left) >> 1);
  1077. xl = pbuf1[i].left;
  1078. xr = pbuf1[i].right;
  1079. pbuf3[i].left = xl + l2;
  1080. pbuf3[i].right = xr + r2;
  1081. pbufrear3[i].left = xl + pbufrear2[i].left;
  1082. pbufrear3[i].right = xr + pbufrear2[i].right;
  1083. }
  1084. goto gain4ch;
  1085. }
  1086. if ( cchan1 == 4 && cchan2 == 5)
  1087. {
  1088. for (i = 0; i < count; i++)
  1089. {
  1090. l2 = pbuf2[i].left + ((pbufcenter2[i].left) >> 1);
  1091. r2 = pbuf2[i].right + ((pbufcenter2[i].left) >> 1);
  1092. pbuf3[i].left = pbuf1[i].left + l2;
  1093. pbuf3[i].right = pbuf1[i].right + r2;
  1094. pbufrear3[i].left = pbufrear1[i].left + pbufrear2[i].left;
  1095. pbufrear3[i].right = pbufrear1[i].right + pbufrear2[i].right;
  1096. }
  1097. goto gain4ch;
  1098. }
  1099. if ( cchan1 == 5 && cchan2 == 5 )
  1100. {
  1101. for (i = 0; i < count; i++)
  1102. {
  1103. l = pbuf1[i].left + ((pbufcenter1[i].left) >> 1);
  1104. r = pbuf1[i].right + ((pbufcenter1[i].left) >> 1);
  1105. l2 = pbuf2[i].left + ((pbufcenter2[i].left) >> 1);
  1106. r2 = pbuf2[i].right + ((pbufcenter2[i].left) >> 1);
  1107. pbuf3[i].left = l + l2;
  1108. pbuf3[i].right = r + r2;
  1109. pbufrear3[i].left = pbufrear1[i].left + pbufrear2[i].left;
  1110. pbufrear3[i].right = pbufrear1[i].right + pbufrear2[i].right;
  1111. }
  1112. goto gain4ch;
  1113. }
  1114. }
  1115. // 5 channel destination
  1116. if (cchan3 == 5)
  1117. {
  1118. // up convert from 2 or 4 ch buffer to 5 ch buffer:
  1119. // center channel is synthesized from front left, front right
  1120. if (cchan1 == 2 && cchan2 == 2)
  1121. {
  1122. for (i = 0; i < count; i++)
  1123. {
  1124. // split 2 ch left -> front left, center, rear left
  1125. // split 2 ch right -> front right, center, rear right
  1126. l = pbuf1[i].left;
  1127. r = pbuf1[i].right;
  1128. MIX_CenterFromLeftRight(&l, &r, &c);
  1129. l2 = pbuf2[i].left;
  1130. r2 = pbuf2[i].right;
  1131. MIX_CenterFromLeftRight(&l2, &r2, &c2);
  1132. pbuf3[i].left = l + l2;
  1133. pbuf3[i].right = r + r2;
  1134. pbufrear3[i].left = pbuf1[i].left + pbuf2[i].left;
  1135. pbufrear3[i].right = pbuf1[i].right + pbuf2[i].right;
  1136. pbufcenter3[i].left = c + c2;
  1137. }
  1138. goto gain5ch;
  1139. }
  1140. if (cchan1 == 2 && cchan2 == 4)
  1141. {
  1142. for (i = 0; i < count; i++)
  1143. {
  1144. l = pbuf1[i].left;
  1145. r = pbuf1[i].right;
  1146. MIX_CenterFromLeftRight(&l, &r, &c);
  1147. l2 = pbuf2[i].left;
  1148. r2 = pbuf2[i].right;
  1149. MIX_CenterFromLeftRight(&l2, &r2, &c2);
  1150. pbuf3[i].left = l + l2;
  1151. pbuf3[i].right = r + r2;
  1152. pbufrear3[i].left = pbuf1[i].left + pbufrear2[i].left;
  1153. pbufrear3[i].right = pbuf1[i].right + pbufrear2[i].right;
  1154. pbufcenter3[i].left = c + c2;
  1155. }
  1156. goto gain5ch;
  1157. }
  1158. if (cchan1 == 2 && cchan2 == 5)
  1159. {
  1160. for (i = 0; i < count; i++)
  1161. {
  1162. l = pbuf1[i].left;
  1163. r = pbuf1[i].right;
  1164. MIX_CenterFromLeftRight(&l, &r, &c);
  1165. pbuf3[i].left = l + pbuf2[i].left;
  1166. pbuf3[i].right = r + pbuf2[i].right;
  1167. pbufrear3[i].left = pbuf1[i].left + pbufrear2[i].left;
  1168. pbufrear3[i].right = pbuf1[i].right + pbufrear2[i].right;
  1169. pbufcenter3[i].left = c + pbufcenter2[i].left;
  1170. }
  1171. goto gain5ch;
  1172. }
  1173. if (cchan1 == 4 && cchan2 == 4)
  1174. {
  1175. for (i = 0; i < count; i++)
  1176. {
  1177. l = pbuf1[i].left;
  1178. r = pbuf1[i].right;
  1179. MIX_CenterFromLeftRight(&l, &r, &c);
  1180. l2 = pbuf2[i].left;
  1181. r2 = pbuf2[i].right;
  1182. MIX_CenterFromLeftRight(&l2, &r2, &c2);
  1183. pbuf3[i].left = l + l2;
  1184. pbuf3[i].right = r + r2;
  1185. pbufrear3[i].left = pbufrear1[i].left + pbufrear2[i].left;
  1186. pbufrear3[i].right = pbufrear1[i].right + pbufrear2[i].right;
  1187. pbufcenter3[i].left = c + c2;
  1188. }
  1189. goto gain5ch;
  1190. }
  1191. if (cchan1 == 4 && cchan2 == 5)
  1192. {
  1193. for (i = 0; i < count; i++)
  1194. {
  1195. l = pbuf1[i].left;
  1196. r = pbuf1[i].right;
  1197. MIX_CenterFromLeftRight(&l, &r, &c);
  1198. pbuf3[i].left = l + pbuf2[i].left;
  1199. pbuf3[i].right = r + pbuf2[i].right;
  1200. pbufrear3[i].left = pbufrear1[i].left + pbufrear2[i].left;
  1201. pbufrear3[i].right = pbufrear1[i].right + pbufrear2[i].right;
  1202. pbufcenter3[i].left = c + pbufcenter2[i].left;
  1203. }
  1204. goto gain5ch;
  1205. }
  1206. if ( cchan2 == 5 && cchan1 == 5 )
  1207. {
  1208. for (i = 0; i < count; i++)
  1209. {
  1210. pbuf3[i].left = pbuf1[i].left + pbuf2[i].left;
  1211. pbuf3[i].right = pbuf1[i].right + pbuf2[i].right;
  1212. pbufrear3[i].left = pbufrear1[i].left + pbufrear2[i].left;
  1213. pbufrear3[i].right = pbufrear1[i].right + pbufrear2[i].right;
  1214. pbufcenter3[i].left = pbufcenter1[i].left + pbufcenter2[i].left;
  1215. }
  1216. goto gain5ch;
  1217. }
  1218. }
  1219. gain2ch:
  1220. if ( gain_out == 256) // KDB: perf
  1221. return;
  1222. for (i = 0; i < count; i++)
  1223. {
  1224. pbuf3[i].left = (pbuf3[i].left * gain_out) >> 8;
  1225. pbuf3[i].right = (pbuf3[i].right * gain_out) >> 8;
  1226. }
  1227. return;
  1228. gain4ch:
  1229. if ( gain_out == 256) // KDB: perf
  1230. return;
  1231. for (i = 0; i < count; i++)
  1232. {
  1233. pbuf3[i].left = (pbuf3[i].left * gain_out) >> 8;
  1234. pbuf3[i].right = (pbuf3[i].right * gain_out) >> 8;
  1235. pbufrear3[i].left = (pbufrear3[i].left * gain_out) >> 8;
  1236. pbufrear3[i].right = (pbufrear3[i].right * gain_out) >> 8;
  1237. }
  1238. return;
  1239. gain5ch:
  1240. if ( gain_out == 256) // KDB: perf
  1241. return;
  1242. for (i = 0; i < count; i++)
  1243. {
  1244. pbuf3[i].left = (pbuf3[i].left * gain_out) >> 8;
  1245. pbuf3[i].right = (pbuf3[i].right * gain_out) >> 8;
  1246. pbufrear3[i].left = (pbufrear3[i].left * gain_out) >> 8;
  1247. pbufrear3[i].right = (pbufrear3[i].right * gain_out) >> 8;
  1248. pbufcenter3[i].left = (pbufcenter3[i].left * gain_out) >> 8;
  1249. }
  1250. return;
  1251. }
  1252. // multiply all values in paintbuffer by fgain
  1253. void MIX_ScalePaintBuffer( int bufferIndex, int count, float fgain )
  1254. {
  1255. portable_samplepair_t *pbuf = g_paintBuffers[bufferIndex].pbuf;
  1256. portable_samplepair_t *pbufrear = g_paintBuffers[bufferIndex].pbufrear;
  1257. portable_samplepair_t *pbufcenter = g_paintBuffers[bufferIndex].pbufcenter;
  1258. int gain = 256 * fgain;
  1259. int i;
  1260. if (gain == 256)
  1261. return;
  1262. if ( !g_paintBuffers[bufferIndex].fsurround )
  1263. {
  1264. for (i = 0; i < count; i++)
  1265. {
  1266. pbuf[i].left = (pbuf[i].left * gain) >> 8;
  1267. pbuf[i].right = (pbuf[i].right * gain) >> 8;
  1268. }
  1269. }
  1270. else
  1271. {
  1272. for (i = 0; i < count; i++)
  1273. {
  1274. pbuf[i].left = (pbuf[i].left * gain) >> 8;
  1275. pbuf[i].right = (pbuf[i].right * gain) >> 8;
  1276. pbufrear[i].left = (pbufrear[i].left * gain) >> 8;
  1277. pbufrear[i].right = (pbufrear[i].right * gain) >> 8;
  1278. }
  1279. if (g_paintBuffers[bufferIndex].fsurround_center)
  1280. {
  1281. for (i = 0; i < count; i++)
  1282. {
  1283. pbufcenter[i].left = (pbufcenter[i].left * gain) >> 8;
  1284. // pbufcenter[i].right = (pbufcenter[i].right * gain) >> 8; mono center channel
  1285. }
  1286. }
  1287. }
  1288. }
  1289. // DEBUG peak detection values
  1290. #define _SDEBUG 1
  1291. #ifdef _SDEBUG
  1292. float sdebug_avg_in = 0.0;
  1293. float sdebug_in_count = 0.0;
  1294. float sdebug_avg_out = 0.0;
  1295. float sdebug_out_count = 0.0;
  1296. #define SDEBUG_TOTAL_COUNT (3*44100)
  1297. #endif // DEBUG
  1298. // DEBUG code - get and show peak value of specified paintbuffer
  1299. // DEBUG code - ibuf is buffer index, count is # samples to test, pppeakprev stores peak
  1300. void SDEBUG_GetAvgValue( int ibuf, int count, float *pav )
  1301. {
  1302. #ifdef _SDEBUG
  1303. if (snd_showstart.GetInt() != 4 )
  1304. return;
  1305. float av = 0.0;
  1306. for (int i = 0; i < count; i++)
  1307. av += (float)(abs(g_paintBuffers[ibuf].pbuf->left) + abs(g_paintBuffers[ibuf].pbuf->right))/2.0;
  1308. *pav = av / count;
  1309. #endif // DEBUG
  1310. }
  1311. void SDEBUG_GetAvgIn( int ibuf, int count)
  1312. {
  1313. float av = 0.0;
  1314. SDEBUG_GetAvgValue( ibuf, count, &av );
  1315. sdebug_avg_in = ((av * count ) + (sdebug_avg_in * sdebug_in_count)) / (count + sdebug_in_count);
  1316. sdebug_in_count += count;
  1317. }
  1318. void SDEBUG_GetAvgOut( int ibuf, int count)
  1319. {
  1320. float av = 0.0;
  1321. SDEBUG_GetAvgValue( ibuf, count, &av );
  1322. sdebug_avg_out = ((av * count ) + (sdebug_avg_out * sdebug_out_count)) / (count + sdebug_out_count);
  1323. sdebug_out_count += count;
  1324. }
  1325. void SDEBUG_ShowAvgValue()
  1326. {
  1327. #ifdef _SDEBUG
  1328. if (sdebug_in_count > SDEBUG_TOTAL_COUNT)
  1329. {
  1330. if ((int)sdebug_avg_in > 20.0 && (int)sdebug_avg_out > 20.0)
  1331. DevMsg("dsp avg gain:%1.2f in:%1.2f out:%1.2f 1/gain:%1.2f\n", sdebug_avg_out/sdebug_avg_in, sdebug_avg_in, sdebug_avg_out, sdebug_avg_in/sdebug_avg_out);
  1332. sdebug_avg_in = 0.0;
  1333. sdebug_avg_out = 0.0;
  1334. sdebug_in_count = 0.0;
  1335. sdebug_out_count = 0.0;
  1336. }
  1337. #endif // DEBUG
  1338. }
  1339. // clip all values in paintbuffer to 16bit.
  1340. // if fsurround is set for paintbuffer, also process rear buffer samples
  1341. void MIX_CompressPaintbuffer(int ipaint, int count)
  1342. {
  1343. VPROF("CompressPaintbuffer");
  1344. int i;
  1345. paintbuffer_t *ppaint = MIX_GetPPaintFromIPaint(ipaint);
  1346. portable_samplepair_t *pbf;
  1347. portable_samplepair_t *pbr;
  1348. portable_samplepair_t *pbc;
  1349. pbf = ppaint->pbuf;
  1350. pbr = ppaint->pbufrear;
  1351. pbc = ppaint->pbufcenter;
  1352. for (i = 0; i < count; i++)
  1353. {
  1354. pbf->left = CLIP(pbf->left);
  1355. pbf->right = CLIP(pbf->right);
  1356. pbf++;
  1357. }
  1358. if ( ppaint->fsurround )
  1359. {
  1360. Assert (pbr);
  1361. for (i = 0; i < count; i++)
  1362. {
  1363. pbr->left = CLIP(pbr->left);
  1364. pbr->right = CLIP(pbr->right);
  1365. pbr++;
  1366. }
  1367. }
  1368. if ( ppaint->fsurround_center )
  1369. {
  1370. Assert (pbc);
  1371. for (i = 0; i < count; i++)
  1372. {
  1373. pbc->left = CLIP(pbc->left);
  1374. //pbc->right = CLIP(pbc->right); mono center channel
  1375. pbc++;
  1376. }
  1377. }
  1378. }
  1379. // mix and upsample channels to 44khz 'ipaintbuffer'
  1380. // mix channels matching 'flags' (SOUND_MIX_DRY, SOUND_MIX_WET, SOUND_MIX_SPEAKER) into specified paintbuffer
  1381. // upsamples 11khz, 22khz channels to 44khz.
  1382. // NOTE: only call this on channels that will be mixed into only 1 paintbuffer
  1383. // and that will not be mixed until the next mix pass! otherwise, MIX_MixChannelsToPaintbuffer
  1384. // will advance any internal pointers on mixed channels; subsequent calls will be at
  1385. // incorrect offset.
  1386. void MIX_MixUpsampleBuffer( CChannelList &list, int ipaintbuffer, int end, int count, int flags )
  1387. {
  1388. VPROF("MixUpsampleBuffer");
  1389. int ipaintcur = MIX_GetCurrentPaintbufferIndex(); // save current paintbuffer
  1390. // reset paintbuffer upsampling filter index
  1391. MIX_ResetPaintbufferFilterCounter( ipaintbuffer );
  1392. // prevent other paintbuffers from being mixed
  1393. MIX_DeactivateAllPaintbuffers();
  1394. MIX_ActivatePaintbuffer( ipaintbuffer ); // operates on MIX_MixChannelsToPaintbuffer
  1395. MIX_SetCurrentPaintbuffer( ipaintbuffer ); // operates on MixUpSample
  1396. // mix 11khz channels to buffer
  1397. if ( list.m_has11kChannels )
  1398. {
  1399. MIX_MixChannelsToPaintbuffer( list, end, flags, SOUND_11k, SOUND_11k );
  1400. // upsample 11khz buffer by 2x
  1401. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_11k), FILTERTYPE_LINEAR );
  1402. }
  1403. if ( list.m_has22kChannels || list.m_has11kChannels )
  1404. {
  1405. // mix 22khz channels to buffer
  1406. MIX_MixChannelsToPaintbuffer( list, end, flags, SOUND_22k, SOUND_22k );
  1407. #if (SOUND_DMA_SPEED > SOUND_22k)
  1408. // upsample 22khz buffer by 2x
  1409. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_22k), FILTERTYPE_LINEAR );
  1410. #endif
  1411. }
  1412. // mix 44khz channels to buffer
  1413. MIX_MixChannelsToPaintbuffer( list, end, flags, SOUND_44k, SOUND_DMA_SPEED);
  1414. MIX_DeactivateAllPaintbuffers();
  1415. // restore previous paintbuffer
  1416. MIX_SetCurrentPaintbuffer( ipaintcur );
  1417. }
  1418. // upsample and mix sounds into final 44khz versions of the following paintbuffers:
  1419. // SOUND_BUFFER_ROOM, SOUND_BUFFER_FACING, IFACINGAWAY, SOUND_BUFFER_DRY, SOUND_BUFFER_SPEAKER, SOUND_BUFFER_SPECIALs
  1420. // dsp fx are then applied to these buffers by the caller.
  1421. // caller also remixes all into final SOUND_BUFFER_PAINT output.
  1422. void MIX_UpsampleAllPaintbuffers( CChannelList &list, int end, int count )
  1423. {
  1424. VPROF( "MixUpsampleAll" );
  1425. // 'dry' and 'speaker' channel sounds mix 100% into their corresponding buffers
  1426. // mix and upsample all 'dry' sounds (channels) to 44khz SOUND_BUFFER_DRY paintbuffer
  1427. if ( list.m_hasDryChannels )
  1428. MIX_MixUpsampleBuffer( list, SOUND_BUFFER_DRY, end, count, SOUND_MIX_DRY );
  1429. // mix and upsample all 'speaker' sounds (channels) to 44khz SOUND_BUFFER_SPEAKER paintbuffer
  1430. if ( list.m_hasSpeakerChannels )
  1431. MIX_MixUpsampleBuffer( list, SOUND_BUFFER_SPEAKER, end, count, SOUND_MIX_SPEAKER );
  1432. // mix and upsample all 'special dsp' sounds (channels) to 44khz SOUND_BUFFER_SPECIALs paintbuffer
  1433. for ( int iDSP = 0; iDSP < list.m_nSpecialDSPs.Count(); ++iDSP )
  1434. {
  1435. for ( int i = SOUND_BUFFER_SPECIAL_START; i < g_paintBuffers.Count(); ++i )
  1436. {
  1437. paintbuffer_t *pSpecialBuffer = MIX_GetPPaintFromIPaint( i );
  1438. if ( pSpecialBuffer->nSpecialDSP == list.m_nSpecialDSPs[ iDSP ] && pSpecialBuffer->idsp_specialdsp != -1 )
  1439. {
  1440. MIX_MixUpsampleBuffer( list, i, end, count, SOUND_MIX_SPECIAL_DSP );
  1441. break;
  1442. }
  1443. }
  1444. }
  1445. // 'room', 'facing' 'facingaway' sounds are mixed into up to 3 buffers:
  1446. // 11khz sounds are mixed into 3 buffers based on distance from listener, and facing direction
  1447. // These buffers are room, facing, facingaway
  1448. // These 3 mixed buffers are then each upsampled to 22khz.
  1449. // 22khz sounds are mixed into the 3 buffers based on distance from listener, and facing direction
  1450. // These 3 mixed buffers are then each upsampled to 44khz.
  1451. // 44khz sounds are mixed into the 3 buffers based on distance from listener, and facing direction
  1452. MIX_DeactivateAllPaintbuffers();
  1453. // set paintbuffer upsample filter indices to 0
  1454. MIX_ResetPaintbufferFilterCounters();
  1455. if ( !g_bDspOff )
  1456. {
  1457. // only mix to roombuffer if dsp fx are on KDB: perf
  1458. MIX_ActivatePaintbuffer(SOUND_BUFFER_ROOM); // operates on MIX_MixChannelsToPaintbuffer
  1459. }
  1460. MIX_ActivatePaintbuffer(SOUND_BUFFER_FACING);
  1461. if ( g_bdirectionalfx )
  1462. {
  1463. // mix to facing away buffer only if directional presets are set
  1464. MIX_ActivatePaintbuffer(SOUND_BUFFER_FACINGAWAY);
  1465. }
  1466. // mix 11khz sounds:
  1467. // pan sounds between 3 busses: facing, facingaway and room buffers
  1468. MIX_MixChannelsToPaintbuffer( list, end, SOUND_MIX_WET, SOUND_11k, SOUND_11k);
  1469. // upsample all 11khz buffers by 2x
  1470. if ( !g_bDspOff )
  1471. {
  1472. // only upsample roombuffer if dsp fx are on KDB: perf
  1473. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_ROOM); // operates on MixUpSample
  1474. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_11k), FILTERTYPE_LINEAR );
  1475. }
  1476. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_FACING);
  1477. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_11k), FILTERTYPE_LINEAR );
  1478. if ( g_bdirectionalfx )
  1479. {
  1480. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_FACINGAWAY);
  1481. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_11k), FILTERTYPE_LINEAR );
  1482. }
  1483. // mix 22khz sounds:
  1484. // pan sounds between 3 busses: facing, facingaway and room buffers
  1485. MIX_MixChannelsToPaintbuffer( list, end, SOUND_MIX_WET, SOUND_22k, SOUND_22k);
  1486. // upsample all 22khz buffers by 2x
  1487. #if ( SOUND_DMA_SPEED > SOUND_22k )
  1488. if ( !g_bDspOff )
  1489. {
  1490. // only upsample roombuffer if dsp fx are on KDB: perf
  1491. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_ROOM);
  1492. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_22k), FILTERTYPE_LINEAR );
  1493. }
  1494. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_FACING);
  1495. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_22k), FILTERTYPE_LINEAR );
  1496. if ( g_bdirectionalfx )
  1497. {
  1498. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_FACINGAWAY);
  1499. g_AudioDevice->MixUpsample( count / (SOUND_DMA_SPEED / SOUND_22k), FILTERTYPE_LINEAR );
  1500. }
  1501. #endif
  1502. // mix all 44khz sounds to all active paintbuffers
  1503. MIX_MixChannelsToPaintbuffer( list, end, SOUND_MIX_WET, SOUND_44k, SOUND_DMA_SPEED);
  1504. MIX_DeactivateAllPaintbuffers();
  1505. MIX_SetCurrentPaintbuffer(SOUND_BUFFER_PAINT);
  1506. }
  1507. ConVar snd_cull_duplicates("snd_cull_duplicates","0",FCVAR_ALLOWED_IN_COMPETITIVE,"If nonzero, aggressively cull duplicate sounds during mixing. The number specifies the number of duplicates allowed to be played.");
  1508. // Helper class for determining whether a given channel number should be culled from
  1509. // mixing, if snd_cull_duplicates is enabled (psychoacoustic quashing).
  1510. class CChannelCullList
  1511. {
  1512. public:
  1513. // default constructor
  1514. CChannelCullList() : m_numChans(0) {};
  1515. // call if you plan on culling channels - and not otherwise, it's a little expensive
  1516. // (that's why it's not in the constructor)
  1517. void Initialize( CChannelList &list );
  1518. // returns true if a given channel number has been marked for culling
  1519. inline bool ShouldCull( int channelNum )
  1520. {
  1521. return (m_numChans > channelNum) ? m_bShouldCull[channelNum] : false;
  1522. }
  1523. // an array of sound names and their volumes
  1524. // TODO: there may be a way to do this faster on 360 (eg, pad to 128bit, use SIMD)
  1525. struct sChannelVolData
  1526. {
  1527. int m_channelNum;
  1528. int m_vol; // max volume of sound. -1 means "do not cull, ever, do not even do the math"
  1529. unsigned int m_nameHash; // a unique id for a sound file
  1530. };
  1531. protected:
  1532. sChannelVolData m_channelInfo[MAX_CHANNELS];
  1533. bool m_bShouldCull[MAX_CHANNELS]; // in ChannelList order, not sorted order
  1534. int m_numChans;
  1535. };
  1536. // comparator for qsort as used below (eg a lambda)
  1537. // returns < 0 if a should come before b, > 0 if a should come after, 0 otherwise
  1538. static int __cdecl ChannelVolComparator ( const void * a, const void * b )
  1539. {
  1540. // greater numbers come first.
  1541. return static_cast<const CChannelCullList::sChannelVolData *>(b)->m_vol - static_cast<const CChannelCullList::sChannelVolData *>(a)->m_vol;
  1542. }
  1543. void CChannelCullList::Initialize( CChannelList &list )
  1544. {
  1545. VPROF("CChannelCullList::Initialize");
  1546. // First, build a sorted list of channels by decreasing volume, and by a hash of their wavname.
  1547. m_numChans = list.Count();
  1548. for ( int i = m_numChans - 1 ; i >= 0 ; --i )
  1549. {
  1550. channel_t *ch = list.GetChannel(i);
  1551. m_channelInfo[i].m_channelNum = i;
  1552. if ( ch && ch->pMixer->IsReadyToMix() )
  1553. {
  1554. m_channelInfo[i].m_vol = ChannelLoudestCurVolume(ch);
  1555. AssertMsg(m_channelInfo[i].m_vol >= 0, "Sound channel has a negative volume?");
  1556. m_channelInfo[i].m_nameHash = (unsigned int) ch->sfx;
  1557. }
  1558. else
  1559. {
  1560. m_channelInfo[i].m_vol = -1;
  1561. m_channelInfo[i].m_nameHash = NULL; // doesn't matter
  1562. }
  1563. }
  1564. // set the unused channels to invalid data
  1565. for ( int i = m_numChans ; i < MAX_CHANNELS ; ++i )
  1566. {
  1567. m_channelInfo[i].m_channelNum = -1;
  1568. m_channelInfo[i].m_vol = -1;
  1569. }
  1570. // Sort the list.
  1571. qsort( m_channelInfo, MAX_CHANNELS, sizeof(sChannelVolData), ChannelVolComparator );
  1572. // Then, determine if the given sound is less than the nth loudest of its hash. If so, mark its flag
  1573. // for removal.
  1574. // TODO: use an actual algorithm rather than this bogus quadratic technique.
  1575. // (I'm using it for now because we don't have convenient/fast hash table
  1576. // classes, which would be the linear-time way to deal with this).
  1577. const int cutoff = snd_cull_duplicates.GetInt();
  1578. for ( int i = 0 ; i < m_numChans ; ++i ) // i is index in original channel list
  1579. {
  1580. channel_t *ch = list.GetChannel(i);
  1581. // for each sound, determine where it ranks in loudness
  1582. int howManyLouder = 0;
  1583. for ( int j = 0 ;
  1584. m_channelInfo[j].m_channelNum != i && m_channelInfo[j].m_vol >= 0 && j < MAX_CHANNELS ;
  1585. ++j )
  1586. {
  1587. // j steps through the sorted list until we find ourselves:
  1588. if (m_channelInfo[j].m_nameHash == (unsigned int)(ch->sfx))
  1589. {
  1590. // that's another channel playing this sound but louder than me
  1591. ++howManyLouder;
  1592. }
  1593. }
  1594. if (howManyLouder >= cutoff)
  1595. {
  1596. // this sound should be culled
  1597. m_bShouldCull[i] = true;
  1598. }
  1599. else
  1600. {
  1601. // this sound should not be culled
  1602. m_bShouldCull[i] = false;
  1603. }
  1604. }
  1605. }
  1606. ConVar snd_mute_losefocus("snd_mute_losefocus", "1", FCVAR_ARCHIVE);
  1607. // build a list of channels that will actually do mixing in this update
  1608. // remove all active channels that won't mix for some reason
  1609. void MIX_BuildChannelList( CChannelList &list )
  1610. {
  1611. VPROF("MIX_BuildChannelList");
  1612. g_ActiveChannels.GetActiveChannels( list );
  1613. list.m_nSpecialDSPs.RemoveAll();
  1614. list.m_hasDryChannels = false;
  1615. list.m_hasSpeakerChannels = false;
  1616. list.m_has11kChannels = false;
  1617. list.m_has22kChannels = false;
  1618. list.m_has44kChannels = false;
  1619. bool delayStartServer = false;
  1620. bool delayStartClient = false;
  1621. bool bPaused = g_pSoundServices->IsGamePaused();
  1622. #ifdef POSIX
  1623. bool bActive = g_pSoundServices->IsGameActive();
  1624. bool bStopOnFocusLoss = !bActive && snd_mute_losefocus.GetBool();
  1625. #endif
  1626. CChannelCullList cullList;
  1627. if (snd_cull_duplicates.GetInt() > 0)
  1628. {
  1629. cullList.Initialize(list);
  1630. }
  1631. // int numQuashed = 0;
  1632. for ( int i = list.Count(); --i >= 0; )
  1633. {
  1634. channel_t *ch = list.GetChannel(i);
  1635. bool bRemove = false;
  1636. // Certain async loaded sounds lazily load into memory in the background, use this to determine
  1637. // if the sound is ready for mixing
  1638. CAudioSource *pSource = NULL;
  1639. if ( ch->pMixer->IsReadyToMix() )
  1640. {
  1641. pSource = S_LoadSound( ch->sfx, ch );
  1642. // Don't mix sound data for sounds with 'zero' volume. If it's a non-looping sound,
  1643. // just remove the sound when its volume goes to zero. If it's a 'dry' channel sound (ie: music)
  1644. // then assume bZeroVolume is fade in - don't restart
  1645. // To be 'zero' volume, all target volume and current volume values must all be less than 5
  1646. bool bZeroVolume = BChannelLowVolume( ch, 1 );
  1647. if ( !pSource || ( bZeroVolume && !pSource->IsLooped() && !ch->flags.bdry ) )
  1648. {
  1649. // NOTE: Since we've loaded the sound, check to see if it's a sentence. Play them at zero anyway
  1650. // to keep the character's lips moving and the captions happening.
  1651. if ( !pSource || pSource->GetSentence() == NULL )
  1652. {
  1653. S_FreeChannel( ch );
  1654. bRemove = true;
  1655. }
  1656. }
  1657. else if ( bZeroVolume )
  1658. {
  1659. bRemove = true;
  1660. }
  1661. // If the sound wants to stop when the game pauses, do so
  1662. if ( bPaused && SND_ShouldPause(ch) )
  1663. {
  1664. bRemove = true;
  1665. }
  1666. #ifdef POSIX
  1667. // If we aren't the active app and the option for background audio isn't on, mute the audio
  1668. // Windows has it's own system for background muting
  1669. if ( !bRemove && bStopOnFocusLoss )
  1670. {
  1671. bRemove = true;
  1672. // Free up the sound channels otherwise they start filling up
  1673. if ( pSource && ( !pSource->IsLooped() && !pSource->IsStreaming() ) )
  1674. {
  1675. S_FreeChannel( ch );
  1676. }
  1677. }
  1678. #endif
  1679. // On lowend, aggressively cull duplicate sounds.
  1680. if ( !bRemove && snd_cull_duplicates.GetInt() > 0 )
  1681. {
  1682. // We can't simply remove them, because then sounds will pile up waiting to finish later.
  1683. // We need to flag them for not mixing.
  1684. list.m_quashed[i] = cullList.ShouldCull(i);
  1685. /*
  1686. if (list.m_quashed[i])
  1687. {
  1688. numQuashed++;
  1689. // Msg("removed %i\n", i);
  1690. }
  1691. */
  1692. }
  1693. else
  1694. {
  1695. list.m_quashed[i] = false;
  1696. }
  1697. }
  1698. else
  1699. {
  1700. bRemove = true;
  1701. }
  1702. if ( bRemove )
  1703. {
  1704. list.RemoveChannelFromList(i);
  1705. continue;
  1706. }
  1707. if ( ch->flags.bSpeaker )
  1708. {
  1709. list.m_hasSpeakerChannels = true;
  1710. }
  1711. if ( ch->special_dsp != 0 )
  1712. {
  1713. if ( list.m_nSpecialDSPs.Find( ch->special_dsp ) == -1 )
  1714. {
  1715. list.m_nSpecialDSPs.AddToTail( ch->special_dsp );
  1716. }
  1717. }
  1718. if ( ch->flags.bdry )
  1719. {
  1720. list.m_hasDryChannels = true;
  1721. }
  1722. int rate = pSource->SampleRate();
  1723. if ( rate == SOUND_11k )
  1724. {
  1725. list.m_has11kChannels = true;
  1726. }
  1727. else if ( rate == SOUND_22k )
  1728. {
  1729. list.m_has22kChannels = true;
  1730. }
  1731. else if ( rate == SOUND_44k )
  1732. {
  1733. list.m_has44kChannels = true;
  1734. }
  1735. if ( ch->flags.delayed_start && !SND_IsMouth(ch) )
  1736. {
  1737. if ( ch->flags.fromserver )
  1738. {
  1739. delayStartServer = true;
  1740. }
  1741. else
  1742. {
  1743. delayStartClient = true;
  1744. }
  1745. }
  1746. // get playback pitch
  1747. ch->pitch = ch->pMixer->ModifyPitch( ch->basePitch * 0.01f );
  1748. }
  1749. // DevMsg( "%d channels quashed.\n", numQuashed );
  1750. // This code will resync the delay calculation clock really often
  1751. // any time there are no scheduled waves or the game is paused
  1752. // we go ahead and reset the clock
  1753. // That way the clock is only used for short periods of time
  1754. // and we need no solution for drift
  1755. if ( bPaused || (host_frametime_unbounded > host_frametime) )
  1756. {
  1757. delayStartClient = false;
  1758. delayStartServer = false;
  1759. }
  1760. if (!delayStartServer)
  1761. {
  1762. S_SyncClockAdjust(CLOCK_SYNC_SERVER);
  1763. }
  1764. if (!delayStartClient)
  1765. {
  1766. S_SyncClockAdjust(CLOCK_SYNC_CLIENT);
  1767. }
  1768. }
  1769. // main mixing rountine - mix up to 'endtime' samples.
  1770. // All channels are mixed in a paintbuffer and then sent to
  1771. // hardware.
  1772. // A mix pass is performed, resulting in mixed sounds in SOUND_BUFFER_ROOM, SOUND_BUFFER_FACING, SOUND_BUFFER_FACINGAWAY, SOUND_BUFFER_DRY, SOUND_BUFFER_SPEAKER, SOUND_BUFFER_SPECIALs
  1773. // directional sounds are panned and mixed between SOUND_BUFFER_FACING and SOUND_BUFFER_FACINGAWAY
  1774. // omnidirectional sounds are panned 100% into SOUND_BUFFER_FACING
  1775. // sound sources far from player (ie: near back of room ) are mixed in proportion to this distance
  1776. // into SOUND_BUFFER_ROOM
  1777. // sounds with ch->bSpeaker set are mixed in mono into SOUND_BUFFER_SPEAKER
  1778. // sounds with ch->bSpecialDSP set are mixed in mono into SOUND_BUFFER_SPECIALs
  1779. // dsp_facingaway fx (2 or 4ch filtering) are then applied to the SOUND_BUFFER_FACINGAWAY
  1780. // dsp_speaker fx (1ch) are then applied to the SOUND_BUFFER_SPEAKER
  1781. // dsp_specialdsp fx (1ch) are then applied to the SOUND_BUFFER_SPECIALs
  1782. // dsp_room fx (1ch reverb) are then applied to the SOUND_BUFFER_ROOM
  1783. // All buffers are recombined into the SOUND_BUFFER_PAINT
  1784. // The dsp_water and dsp_player fx are applied in series to the SOUND_BUFFER_PAINT
  1785. // Finally, the SOUND_BUFFER_DRY buffer is mixed into the SOUND_BUFFER_PAINT
  1786. extern ConVar dsp_off;
  1787. extern ConVar snd_profile;
  1788. extern void DEBUG_StartSoundMeasure(int type, int samplecount );
  1789. extern void DEBUG_StopSoundMeasure(int type, int samplecount );
  1790. extern ConVar dsp_enhance_stereo;
  1791. extern ConVar dsp_volume;
  1792. extern ConVar dsp_vol_5ch;
  1793. extern ConVar dsp_vol_4ch;
  1794. extern ConVar dsp_vol_2ch;
  1795. extern void MXR_SetCurrentSoundMixer( const char *szsoundmixer );
  1796. extern ConVar snd_soundmixer;
  1797. void MIX_PaintChannels( int endtime, bool bIsUnderwater )
  1798. {
  1799. VPROF("MIX_PaintChannels");
  1800. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1801. int end;
  1802. int count;
  1803. bool b_spatial_delays = dsp_enhance_stereo.GetInt() != 0 ? true : false;
  1804. bool room_fsurround_sav;
  1805. bool room_fsurround_center_sav;
  1806. paintbuffer_t *proom = MIX_GetPPaintFromIPaint(SOUND_BUFFER_ROOM);
  1807. CheckNewDspPresets();
  1808. MXR_SetCurrentSoundMixer( snd_soundmixer.GetString() );
  1809. // dsp performance tuning
  1810. g_snd_profile_type = snd_profile.GetInt();
  1811. // dsp_off is true if no dsp processing is to run
  1812. // directional dsp processing is enabled if dsp_facingaway is non-zero
  1813. g_bDspOff = dsp_off.GetInt() ? 1 : 0;
  1814. CChannelList list;
  1815. MIX_BuildChannelList(list);
  1816. // get master dsp volume
  1817. g_dsp_volume = dsp_volume.GetFloat();
  1818. // attenuate master dsp volume by 2,4 or 5 ch settings
  1819. if ( g_AudioDevice->IsSurround() )
  1820. {
  1821. g_dsp_volume *= ( g_AudioDevice->IsSurroundCenter() ? dsp_vol_5ch.GetFloat() : dsp_vol_4ch.GetFloat() );
  1822. }
  1823. else
  1824. {
  1825. g_dsp_volume *= dsp_vol_2ch.GetFloat();
  1826. }
  1827. if ( !g_bDspOff )
  1828. {
  1829. g_bdirectionalfx = dsp_facingaway.GetInt() ? 1 : 0;
  1830. }
  1831. else
  1832. {
  1833. g_bdirectionalfx = 0;
  1834. }
  1835. // get dsp preset gain values, update gain crossfaders, used when mixing dsp processed buffers into paintbuffer
  1836. SDEBUG_ShowAvgValue();
  1837. // the cache needs to hold the audio in memory during mixing, so tell it that mixing is starting
  1838. wavedatacache->OnMixBegin();
  1839. while ( g_paintedtime < endtime )
  1840. {
  1841. VPROF("MIX_PaintChannels inner loop");
  1842. // mix a full 'paintbuffer' of sound
  1843. // clamp at paintbuffer size
  1844. end = endtime;
  1845. if (endtime - g_paintedtime > PAINTBUFFER_SIZE)
  1846. {
  1847. end = g_paintedtime + PAINTBUFFER_SIZE;
  1848. }
  1849. // number of 44khz samples to mix into paintbuffer, up to paintbuffer size
  1850. count = end - g_paintedtime;
  1851. // clear all mix buffers
  1852. g_AudioDevice->MixBegin( count );
  1853. // upsample all mix buffers.
  1854. // results in 44khz versions of:
  1855. // SOUND_BUFFER_ROOM, SOUND_BUFFER_FACING, SOUND_BUFFER_FACINGAWAY, SOUND_BUFFER_DRY, SOUND_BUFFER_SPEAKER, SOUND_BUFFER_SPECIALs
  1856. MIX_UpsampleAllPaintbuffers( list, end, count );
  1857. // apply appropriate dsp fx to each buffer, remix buffers into single quad output buffer
  1858. // apply 2 or 4ch filtering to IFACINGAWAY buffer
  1859. if ( g_bdirectionalfx )
  1860. {
  1861. g_AudioDevice->ApplyDSPEffects( idsp_facingaway, MIX_GetPFrontFromIPaint(SOUND_BUFFER_FACINGAWAY), MIX_GetPRearFromIPaint(SOUND_BUFFER_FACINGAWAY), MIX_GetPCenterFromIPaint(SOUND_BUFFER_FACINGAWAY), count );
  1862. }
  1863. if ( !g_bDspOff && list.m_hasSpeakerChannels )
  1864. {
  1865. // apply 1ch filtering to SOUND_BUFFER_SPEAKER
  1866. g_AudioDevice->ApplyDSPEffects( idsp_speaker, MIX_GetPFrontFromIPaint(SOUND_BUFFER_SPEAKER), MIX_GetPRearFromIPaint(SOUND_BUFFER_SPEAKER), MIX_GetPCenterFromIPaint(SOUND_BUFFER_SPEAKER), count );
  1867. // mix SOUND_BUFFER_SPEAKER with SOUND_BUFFER_ROOM and SOUND_BUFFER_FACING
  1868. MIX_ScalePaintBuffer( SOUND_BUFFER_SPEAKER, count, 0.7 );
  1869. MIX_MixPaintbuffers( SOUND_BUFFER_SPEAKER, SOUND_BUFFER_FACING, SOUND_BUFFER_FACING, count, 1.0 ); // +70% dry speaker
  1870. MIX_ScalePaintBuffer( SOUND_BUFFER_SPEAKER, count, 0.43 );
  1871. MIX_MixPaintbuffers( SOUND_BUFFER_SPEAKER, SOUND_BUFFER_ROOM, SOUND_BUFFER_ROOM, count, 1.0 ); // +30% wet speaker
  1872. }
  1873. if ( !g_bDspOff )
  1874. {
  1875. // apply 1ch filtering to SOUND_BUFFER_SPECIALs
  1876. for ( int iDSP = 0; iDSP < list.m_nSpecialDSPs.Count(); ++iDSP )
  1877. {
  1878. bool bFoundMixer = false;
  1879. for ( int i = SOUND_BUFFER_SPECIAL_START; i < g_paintBuffers.Count(); ++i )
  1880. {
  1881. paintbuffer_t *pSpecialBuffer = MIX_GetPPaintFromIPaint( i );
  1882. if ( pSpecialBuffer->nSpecialDSP == list.m_nSpecialDSPs[ iDSP ] && pSpecialBuffer->idsp_specialdsp != -1 )
  1883. {
  1884. g_AudioDevice->ApplyDSPEffects( pSpecialBuffer->idsp_specialdsp, MIX_GetPFrontFromIPaint( i ), MIX_GetPRearFromIPaint( i ), MIX_GetPCenterFromIPaint( i ), count );
  1885. // mix SOUND_BUFFER_SPECIALs with SOUND_BUFFER_ROOM and SOUND_BUFFER_FACING
  1886. MIX_ScalePaintBuffer( i, count, 0.7 );
  1887. MIX_MixPaintbuffers( i, SOUND_BUFFER_FACING, SOUND_BUFFER_FACING, count, 1.0 ); // +70% dry speaker
  1888. MIX_ScalePaintBuffer( i, count, 0.43 );
  1889. MIX_MixPaintbuffers( i, SOUND_BUFFER_ROOM, SOUND_BUFFER_ROOM, count, 1.0 ); // +30% wet speaker
  1890. bFoundMixer = true;
  1891. break;
  1892. }
  1893. }
  1894. // Couldn't find a mixer with the correct DSP, so make a new one!
  1895. if ( !bFoundMixer )
  1896. {
  1897. bool bSurroundCenter = g_AudioDevice->IsSurroundCenter();
  1898. bool bSurround = g_AudioDevice->IsSurround() || bSurroundCenter;
  1899. int nIndex = g_paintBuffers.AddToTail();
  1900. MIX_InitializePaintbuffer( &(g_paintBuffers[ nIndex ]), bSurround, bSurroundCenter );
  1901. g_paintBuffers[ nIndex ].flags = SOUND_BUSS_SPECIAL_DSP;
  1902. // special dsp buffer mixes to mono
  1903. g_paintBuffers[ nIndex ].fsurround = false;
  1904. g_paintBuffers[ nIndex ].fsurround_center = false;
  1905. g_paintBuffers[ nIndex ].idsp_specialdsp = -1;
  1906. g_paintBuffers[ nIndex ].nSpecialDSP = list.m_nSpecialDSPs[ iDSP ];
  1907. g_paintBuffers[ nIndex ].nPrevSpecialDSP = g_paintBuffers[ nIndex ].nSpecialDSP;
  1908. g_paintBuffers[ nIndex ].idsp_specialdsp = DSP_Alloc( g_paintBuffers[ nIndex ].nSpecialDSP, 300, 1 );
  1909. }
  1910. }
  1911. }
  1912. // apply dsp_room effects to room buffer
  1913. g_AudioDevice->ApplyDSPEffects( Get_idsp_room(), MIX_GetPFrontFromIPaint(SOUND_BUFFER_ROOM), MIX_GetPRearFromIPaint(SOUND_BUFFER_ROOM), MIX_GetPCenterFromIPaint(SOUND_BUFFER_ROOM), count );
  1914. // save room buffer surround status, in case we upconvert it
  1915. room_fsurround_sav = proom->fsurround;
  1916. room_fsurround_center_sav = proom->fsurround_center;
  1917. // apply left/center/right/lrear/rrear spatial delays to room buffer
  1918. if ( b_spatial_delays && !g_bDspOff && !DSP_RoomDSPIsOff() )
  1919. {
  1920. // upgrade mono room buffer to surround status so we can apply spatial delays to all channels
  1921. MIX_ConvertBufferToSurround( SOUND_BUFFER_ROOM );
  1922. g_AudioDevice->ApplyDSPEffects( idsp_spatial, MIX_GetPFrontFromIPaint(SOUND_BUFFER_ROOM), MIX_GetPRearFromIPaint(SOUND_BUFFER_ROOM), MIX_GetPCenterFromIPaint(SOUND_BUFFER_ROOM), count );
  1923. }
  1924. if ( g_bdirectionalfx ) // KDB: perf
  1925. {
  1926. // Recombine IFACING and IFACINGAWAY buffers into SOUND_BUFFER_PAINT
  1927. MIX_MixPaintbuffers( SOUND_BUFFER_FACING, SOUND_BUFFER_FACINGAWAY, SOUND_BUFFER_PAINT, count, DSP_NOROOM_MIX );
  1928. // Add in dsp room fx to paintbuffer, mix at 75%
  1929. MIX_MixPaintbuffers( SOUND_BUFFER_ROOM, SOUND_BUFFER_PAINT, SOUND_BUFFER_PAINT, count, DSP_ROOM_MIX );
  1930. }
  1931. else
  1932. {
  1933. // Mix IFACING buffer with SOUND_BUFFER_ROOM
  1934. // (SOUND_BUFFER_FACINGAWAY contains no data, IFACINGBBUFFER has full dry mix based on distance from listener)
  1935. // if dsp disabled, mix 100% facingbuffer, otherwise, mix 75% facingbuffer + roombuffer
  1936. float mix = g_bDspOff ? 1.0 : DSP_ROOM_MIX;
  1937. MIX_MixPaintbuffers( SOUND_BUFFER_ROOM, SOUND_BUFFER_FACING, SOUND_BUFFER_PAINT, count, mix );
  1938. }
  1939. // restore room buffer surround status, in case we upconverted it
  1940. proom->fsurround = room_fsurround_sav;
  1941. proom->fsurround_center = room_fsurround_center_sav;
  1942. // Apply underwater fx dsp_water (serial in-line)
  1943. if ( bIsUnderwater )
  1944. {
  1945. // BUG: if out of water, previous delays will be heard. must clear dly buffers.
  1946. g_AudioDevice->ApplyDSPEffects( idsp_water, MIX_GetPFrontFromIPaint(SOUND_BUFFER_PAINT), MIX_GetPRearFromIPaint(SOUND_BUFFER_PAINT), MIX_GetPCenterFromIPaint(SOUND_BUFFER_PAINT), count );
  1947. }
  1948. // find dsp gain
  1949. SDEBUG_GetAvgIn(SOUND_BUFFER_PAINT, count);
  1950. // Apply player fx dsp_player (serial in-line) - does nothing if dsp fx are disabled
  1951. g_AudioDevice->ApplyDSPEffects( idsp_player, MIX_GetPFrontFromIPaint(SOUND_BUFFER_PAINT), MIX_GetPRearFromIPaint(SOUND_BUFFER_PAINT), MIX_GetPCenterFromIPaint(SOUND_BUFFER_PAINT), count );
  1952. // display dsp gain
  1953. SDEBUG_GetAvgOut(SOUND_BUFFER_PAINT, count);
  1954. /*
  1955. // apply left/center/right/lrear/rrear spatial delays to paint buffer
  1956. if ( b_spatial_delays )
  1957. g_AudioDevice->ApplyDSPEffects( idsp_spatial, MIX_GetPFrontFromIPaint(SOUND_BUFFER_PAINT), MIX_GetPRearFromIPaint(SOUND_BUFFER_PAINT), MIX_GetPCenterFromIPaint(SOUND_BUFFER_PAINT), count );
  1958. */
  1959. // Add dry buffer, set output gain to water * player dsp gain (both 1.0 if not active)
  1960. MIX_MixPaintbuffers( SOUND_BUFFER_PAINT, SOUND_BUFFER_DRY, SOUND_BUFFER_PAINT, count, 1.0);
  1961. // clip all values > 16 bit down to 16 bit
  1962. // NOTE: This is required - the hardware buffer transfer routines no longer perform clipping.
  1963. MIX_CompressPaintbuffer( SOUND_BUFFER_PAINT, count );
  1964. // transfer SOUND_BUFFER_PAINT paintbuffer out to DMA buffer
  1965. MIX_SetCurrentPaintbuffer( SOUND_BUFFER_PAINT );
  1966. g_AudioDevice->TransferSamples( end );
  1967. g_paintedtime = end;
  1968. }
  1969. // the cache needs to hold the audio in memory during mixing, so tell it that mixing is complete
  1970. wavedatacache->OnMixEnd();
  1971. }
  1972. // Applies volume scaling (evenly) to all fl,fr,rl,rr volumes
  1973. // used for voice ducking and panning between various mix busses
  1974. // Ensures if mixing to speaker buffer, only speaker sounds pass through
  1975. // Called just before mixing wav data to current paintbuffer.
  1976. // a) if another player in a multiplayer game is speaking, scale all volumes down.
  1977. // b) if mixing to SOUND_BUFFER_ROOM, scale all volumes by ch.dspmix and dsp_room gain
  1978. // c) if mixing to SOUND_BUFFER_FACINGAWAY, scale all volumes by ch.dspface and dsp_facingaway gain
  1979. // d) If SURROUND_ON, but buffer is not surround, recombined front/rear volumes
  1980. // returns false if channel is to be entirely skipped.
  1981. bool MIX_ScaleChannelVolume( paintbuffer_t *ppaint, channel_t *pChannel, int volume[CCHANVOLUMES], int mixchans )
  1982. {
  1983. int i;
  1984. int mixflag = ppaint->flags;
  1985. float scale;
  1986. char wavtype = pChannel->wavtype;
  1987. float dspmix;
  1988. // copy current channel volumes into output array
  1989. ChannelCopyVolumes( pChannel, volume, 0, CCHANVOLUMES );
  1990. dspmix = pChannel->dspmix;
  1991. // if dsp is off, or room dsp is off, mix 0% to mono room buffer, 100% to facing buffer
  1992. if ( g_bDspOff || DSP_RoomDSPIsOff() )
  1993. dspmix = 0.0;
  1994. // duck all sound volumes except speaker's voice
  1995. #if !defined( NO_VOICE )
  1996. int duckScale = min((int)(g_DuckScale * 256), g_SND_VoiceOverdriveInt);
  1997. #else
  1998. int duckScale = (int)(g_DuckScale * 256);
  1999. #endif
  2000. if( duckScale < 256 )
  2001. {
  2002. if( pChannel->pMixer )
  2003. {
  2004. CAudioSource *pSource = pChannel->pMixer->GetSource();
  2005. if( !pSource->IsVoiceSource() )
  2006. {
  2007. // Apply voice overdrive..
  2008. for (i = 0; i < CCHANVOLUMES; i++)
  2009. volume[i] = (volume[i] * duckScale) >> 8;
  2010. }
  2011. }
  2012. }
  2013. // If mixing to the room buss, adjust volume based on channel's dspmix setting.
  2014. // dspmix is DSP_MIX_MAX (~0.78) if sound is far from player, DSP_MIX_MIN (~0.24) if sound is near player
  2015. if ( mixflag & SOUND_BUSS_ROOM )
  2016. {
  2017. // set dsp mix volume, scaled by global dsp_volume
  2018. float dspmixvol = fpmin(dspmix * g_dsp_volume, 1.0f);
  2019. // if dspmix is 1.0, 100% of sound goes to SOUND_BUFFER_ROOM and 0% to SOUND_BUFFER_FACING
  2020. for (i = 0; i < CCHANVOLUMES; i++)
  2021. volume[i] = (int)((float)(volume[i]) * dspmixvol);
  2022. }
  2023. // If global dsp volume is less than 1, reduce dspmix (ie: increase dry volume)
  2024. // If gloabl dsp volume is greater than 1, do not reduce dspmix
  2025. if (g_dsp_volume < 1.0)
  2026. dspmix *= g_dsp_volume;
  2027. // If mixing to facing/facingaway buss, adjust volume based on sound entity's facing direction.
  2028. // If sound directly faces player, ch->dspface = 1.0. If facing directly away, ch->dspface = -1.0.
  2029. // mix to lowpass buffer if facing away, to allpass if facing
  2030. // scale 1.0 - facing player, scale 0, facing away
  2031. scale = (pChannel->dspface + 1.0) / 2.0;
  2032. // UNDONE: get front cone % from channel to set this.
  2033. // bias scale such that 1.0 to 'cone' is considered facing. Facing cone narrows as cone -> 1.0
  2034. // and 'cone' -> 0.0 becomes 1.0 -> 0.0
  2035. float cone = 0.6f;
  2036. scale = scale * (1/cone);
  2037. scale = clamp( scale, 0.0f, 1.0f );
  2038. // pan between facing and facing away buffers
  2039. // if ( !g_bdirectionalfx || wavtype == CHAR_DOPPLER || wavtype == CHAR_OMNI || (wavtype == CHAR_DIRECTIONAL && mixchans == 2) )
  2040. if ( !g_bdirectionalfx || wavtype != CHAR_DIRECTIONAL )
  2041. {
  2042. // if no directional fx mix 0% to facingaway buffer
  2043. // if wavtype is DOPPLER, mix 0% to facingaway buffer - DOPPLER wavs have a custom mixer
  2044. // if wavtype is OMNI, mix 0% to facingaway buffer - OMNI wavs have no directionality
  2045. // if wavtype is DIRECTIONAL and stereo encoded, mix 0% to facingaway buffer - DIRECTIONAL STEREO wavs have a custom mixer
  2046. scale = 1.0;
  2047. }
  2048. if ( mixflag & SOUND_BUSS_FACING )
  2049. {
  2050. // facing player
  2051. // if dspface is 1.0, 100% of sound goes to SOUND_BUFFER_FACING
  2052. for (i = 0; i < CCHANVOLUMES; i++)
  2053. volume[i] = (int)((float)(volume[i]) * scale * (1.0 - dspmix));
  2054. }
  2055. else if ( mixflag & SOUND_BUSS_FACINGAWAY )
  2056. {
  2057. // facing away from player
  2058. // if dspface is 0.0, 100% of sound goes to SOUND_BUFFER_FACINGAWAY
  2059. for (i = 0; i < CCHANVOLUMES; i++)
  2060. volume[i] = (int)((float)(volume[i]) * (1.0 - scale) * (1.0 - dspmix));
  2061. }
  2062. // NOTE: this must occur last in this routine:
  2063. if ( g_AudioDevice->IsSurround() && !ppaint->fsurround )
  2064. {
  2065. // if 4ch or 5ch spatialization on, but current mix buffer is 2ch,
  2066. // recombine front + rear volumes (revert to 2ch spatialization)
  2067. volume[IFRONT_RIGHT] += volume[IREAR_RIGHT];
  2068. volume[IFRONT_LEFT] += volume[IREAR_LEFT];
  2069. volume[IFRONT_RIGHTD] += volume[IREAR_RIGHTD];
  2070. volume[IFRONT_LEFTD] += volume[IREAR_LEFTD];
  2071. // if 5 ch, recombine center channel vol
  2072. if ( g_AudioDevice->IsSurroundCenter() )
  2073. {
  2074. volume[IFRONT_RIGHT] += volume[IFRONT_CENTER] / 2;
  2075. volume[IFRONT_LEFT] += volume[IFRONT_CENTER] / 2;
  2076. volume[IFRONT_RIGHTD] += volume[IFRONT_CENTERD] / 2;
  2077. volume[IFRONT_LEFTD] += volume[IFRONT_CENTERD] / 2;
  2078. }
  2079. // clear rear & center volumes
  2080. volume[IREAR_RIGHT] = 0;
  2081. volume[IREAR_LEFT] = 0;
  2082. volume[IFRONT_CENTER] = 0;
  2083. volume[IREAR_RIGHTD] = 0;
  2084. volume[IREAR_LEFTD] = 0;
  2085. volume[IFRONT_CENTERD] = 0;
  2086. }
  2087. bool fzerovolume = true;
  2088. for (i = 0; i < CCHANVOLUMES; i++)
  2089. {
  2090. volume[i] = clamp(volume[i], 0, 255);
  2091. if (volume[i])
  2092. fzerovolume = false;
  2093. }
  2094. if ( fzerovolume )
  2095. {
  2096. // DevMsg ("Skipping mix of 0 volume sound! \n");
  2097. return false;
  2098. }
  2099. return true;
  2100. }
  2101. //===============================================================================
  2102. // Low level mixing routines
  2103. //===============================================================================
  2104. void Snd_WriteLinearBlastStereo16( void )
  2105. {
  2106. #if !id386
  2107. int i;
  2108. int val;
  2109. for ( i=0; i<snd_linear_count; i+=2 )
  2110. {
  2111. // scale and clamp left 16bit signed: [0x8000, 0x7FFF]
  2112. val = ( snd_p[i] * snd_vol )>>8;
  2113. if ( val > 32767 )
  2114. snd_out[i] = 32767;
  2115. else if ( val < -32768 )
  2116. snd_out[i] = -32768;
  2117. else
  2118. snd_out[i] = val;
  2119. // scale and clamp right 16bit signed: [0x8000, 0x7FFF]
  2120. val = ( snd_p[i+1] * snd_vol )>>8;
  2121. if ( val > 32767 )
  2122. snd_out[i+1] = 32767;
  2123. else if ( val < -32768 )
  2124. snd_out[i+1] = -32768;
  2125. else
  2126. snd_out[i+1] = val;
  2127. }
  2128. #else
  2129. __asm
  2130. {
  2131. // input data
  2132. mov ebx,snd_p
  2133. // output data
  2134. mov edi,snd_out
  2135. // iterate from end to beginning
  2136. mov ecx,snd_linear_count
  2137. // scale table
  2138. mov esi,snd_vol
  2139. // scale and clamp 16bit signed lsw: [0x8000, 0x7FFF]
  2140. WLBS16_LoopTop:
  2141. mov eax,[ebx+ecx*4-8]
  2142. imul eax,esi
  2143. sar eax,0x08
  2144. cmp eax,0x7FFF
  2145. jg WLBS16_ClampHigh
  2146. cmp eax,0xFFFF8000
  2147. jnl WLBS16_ClampDone
  2148. mov eax,0xFFFF8000
  2149. jmp WLBS16_ClampDone
  2150. WLBS16_ClampHigh:
  2151. mov eax,0x7FFF
  2152. WLBS16_ClampDone:
  2153. // scale and clamp 16bit signed msw: [0x8000, 0x7FFF]
  2154. mov edx,[ebx+ecx*4-4]
  2155. imul edx,esi
  2156. sar edx,0x08
  2157. cmp edx,0x7FFF
  2158. jg WLBS16_ClampHigh2
  2159. cmp edx,0xFFFF8000
  2160. jnl WLBS16_ClampDone2
  2161. mov edx,0xFFFF8000
  2162. jmp WLBS16_ClampDone2
  2163. WLBS16_ClampHigh2:
  2164. mov edx,0x7FFF
  2165. WLBS16_ClampDone2:
  2166. shl edx,0x10
  2167. and eax,0xFFFF
  2168. or edx,eax
  2169. mov [edi+ecx*2-4],edx
  2170. // two shorts per iteration
  2171. sub ecx,0x02
  2172. jnz WLBS16_LoopTop
  2173. }
  2174. #endif
  2175. }
  2176. void SND_InitScaletable (void)
  2177. {
  2178. int i, j;
  2179. for (i=0 ; i<SND_SCALE_LEVELS; i++)
  2180. for (j=0 ; j<256 ; j++)
  2181. snd_scaletable[i][j] = ((signed char)j) * i * (1<<SND_SCALE_SHIFT);
  2182. }
  2183. void SND_PaintChannelFrom8(portable_samplepair_t *pOutput, int *volume, byte *pData8, int count)
  2184. {
  2185. #if !id386
  2186. int data;
  2187. int *lscale, *rscale;
  2188. int i;
  2189. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2190. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2191. for (i=0 ; i<count ; i++)
  2192. {
  2193. data = pData8[i];
  2194. pOutput[i].left += lscale[data];
  2195. pOutput[i].right += rscale[data];
  2196. }
  2197. #else
  2198. // portable_samplepair_t structure
  2199. #define psp_left 0
  2200. #define psp_right 4
  2201. #define psp_size 8
  2202. static int tempStore;
  2203. __asm
  2204. {
  2205. // prologue
  2206. push ebp
  2207. // esp = pOutput
  2208. mov eax, pOutput
  2209. mov tempStore, eax
  2210. xchg esp,tempStore
  2211. // ebx = volume
  2212. mov ebx,volume
  2213. // esi = pData8
  2214. mov esi,pData8
  2215. // ecx = count
  2216. mov ecx,count
  2217. // These values depend on the setting of SND_SCALE_BITS
  2218. // The mask must mask off all the lower bits you aren't using in the multiply
  2219. // so for 7 bits, the mask is 0xFE, 6 bits 0xFC, etc.
  2220. // The shift must multiply by the table size. There are 256 4-byte values in the table at each level.
  2221. // So each index must be shifted left by 10, but since the bits we use are in the MSB rather than LSB
  2222. // they must be shifted right by 8 - SND_SCALE_BITS. e.g., for a 7 bit number the left shift is:
  2223. // 10 - (8-7) = 9. For a 5 bit number it's 10 - (8-5) = 7.
  2224. mov eax,[ebx]
  2225. mov edx,[ebx + 4]
  2226. and eax,0xFE
  2227. and edx,0xFE
  2228. // shift up by 10 to index table, down by 1 to make the 7 MSB of the bytes an index
  2229. // eax = lscale
  2230. // edx = rscale
  2231. shl eax,0x09
  2232. shl edx,0x09
  2233. add eax,OFFSET snd_scaletable
  2234. add edx,OFFSET snd_scaletable
  2235. // ebx = data byte
  2236. sub ebx,ebx
  2237. mov bl,[esi+ecx-1]
  2238. // odd or even number of L/R samples
  2239. test ecx,0x01
  2240. jz PCF8_Loop
  2241. // process odd L/R sample
  2242. mov edi,[eax+ebx*4]
  2243. mov ebp,[edx+ebx*4]
  2244. add edi,[esp+ecx*psp_size-psp_size+psp_left]
  2245. add ebp,[esp+ecx*psp_size-psp_size+psp_right]
  2246. mov [esp+ecx*psp_size-psp_size+psp_left],edi
  2247. mov [esp+ecx*psp_size-psp_size+psp_right],ebp
  2248. mov bl,[esi+ecx-1-1]
  2249. dec ecx
  2250. jz PCF8_Done
  2251. PCF8_Loop:
  2252. // process L/R sample N
  2253. mov edi,[eax+ebx*4]
  2254. mov ebp,[edx+ebx*4]
  2255. add edi,[esp+ecx*psp_size-psp_size+psp_left]
  2256. add ebp,[esp+ecx*psp_size-psp_size+psp_right]
  2257. mov [esp+ecx*psp_size-psp_size+psp_left],edi
  2258. mov [esp+ecx*psp_size-psp_size+psp_right],ebp
  2259. mov bl,[esi+ecx-1-1]
  2260. // process L/R sample N-1
  2261. mov edi,[eax+ebx*4]
  2262. mov ebp,[edx+ebx*4]
  2263. add edi,[esp+ecx*psp_size-psp_size*2+psp_left]
  2264. add ebp,[esp+ecx*psp_size-psp_size*2+psp_right]
  2265. mov [esp+ecx*psp_size-psp_size*2+psp_left],edi
  2266. mov [esp+ecx*psp_size-psp_size*2+psp_right],ebp
  2267. mov bl,[esi+ecx-1-2]
  2268. // two L/R samples per iteration
  2269. sub ecx,0x02
  2270. jnz PCF8_Loop
  2271. PCF8_Done:
  2272. // epilogue
  2273. xchg esp,tempStore
  2274. pop ebp
  2275. }
  2276. #endif
  2277. }
  2278. //===============================================================================
  2279. // SOFTWARE MIXING ROUTINES
  2280. //===============================================================================
  2281. // UNDONE: optimize these
  2282. // grab samples from left source channel only and mix as if mono.
  2283. // volume array contains appropriate spatialization volumes for doppler left (incoming sound)
  2284. void SW_Mix8StereoDopplerLeft( portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2285. {
  2286. int sampleIndex = 0;
  2287. fixedint sampleFrac = inputOffset;
  2288. int *lscale, *rscale;
  2289. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2290. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2291. for ( int i = 0; i < outCount; i++ )
  2292. {
  2293. pOutput[i].left += lscale[pData[sampleIndex]];
  2294. pOutput[i].right += rscale[pData[sampleIndex]];
  2295. sampleFrac += rateScaleFix;
  2296. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2297. sampleFrac = FIX_FRACPART(sampleFrac);
  2298. }
  2299. }
  2300. // grab samples from right source channel only and mix as if mono.
  2301. // volume array contains appropriate spatialization volumes for doppler right (outgoing sound)
  2302. void SW_Mix8StereoDopplerRight( portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2303. {
  2304. int sampleIndex = 0;
  2305. fixedint sampleFrac = inputOffset;
  2306. int *lscale, *rscale;
  2307. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2308. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2309. for ( int i = 0; i < outCount; i++ )
  2310. {
  2311. pOutput[i].left += lscale[pData[sampleIndex+1]];
  2312. pOutput[i].right += rscale[pData[sampleIndex+1]];
  2313. sampleFrac += rateScaleFix;
  2314. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2315. sampleFrac = FIX_FRACPART(sampleFrac);
  2316. }
  2317. }
  2318. // grab samples from left source channel only and mix as if mono.
  2319. // volume array contains appropriate spatialization volumes for doppler left (incoming sound)
  2320. void SW_Mix16StereoDopplerLeft( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2321. {
  2322. int sampleIndex = 0;
  2323. fixedint sampleFrac = inputOffset;
  2324. for ( int i = 0; i < outCount; i++ )
  2325. {
  2326. pOutput[i].left += (volume[0] * (int)(pData[sampleIndex]))>>8;
  2327. pOutput[i].right += (volume[1] * (int)(pData[sampleIndex]))>>8;
  2328. sampleFrac += rateScaleFix;
  2329. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2330. sampleFrac = FIX_FRACPART(sampleFrac);
  2331. }
  2332. }
  2333. // grab samples from right source channel only and mix as if mono.
  2334. // volume array contains appropriate spatialization volumes for doppler right (outgoing sound)
  2335. void SW_Mix16StereoDopplerRight( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2336. {
  2337. int sampleIndex = 0;
  2338. fixedint sampleFrac = inputOffset;
  2339. for ( int i = 0; i < outCount; i++ )
  2340. {
  2341. pOutput[i].left += (volume[0] * (int)(pData[sampleIndex+1]))>>8;
  2342. pOutput[i].right += (volume[1] * (int)(pData[sampleIndex+1]))>>8;
  2343. sampleFrac += rateScaleFix;
  2344. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2345. sampleFrac = FIX_FRACPART(sampleFrac);
  2346. }
  2347. }
  2348. // mix left wav (front facing) with right wav (rear facing) based on soundfacing direction
  2349. void SW_Mix8StereoDirectional( float soundfacing, portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2350. {
  2351. int sampleIndex = 0;
  2352. fixedint sampleFrac = inputOffset;
  2353. int x;
  2354. int l,r;
  2355. signed char lb,rb;
  2356. int *lscale, *rscale;
  2357. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2358. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2359. // if soundfacing -1.0, sound source is facing away from player
  2360. // if soundfacing 0.0, sound source is perpendicular to player
  2361. // if soundfacing 1.0, sound source is facing player
  2362. int frontmix = (int)(256.0f * ((1.f + soundfacing) / 2.f)); // 0 -> 256
  2363. for ( int i = 0; i < outCount; i++ )
  2364. {
  2365. lb = (pData[sampleIndex]); // get left byte
  2366. rb = (pData[sampleIndex+1]); // get right byte
  2367. l = ((int)lb);
  2368. r = ((int)rb);
  2369. x = ( r + ((( l - r ) * frontmix) >> 8) );
  2370. pOutput[i].left += lscale[x & 0xFF]; // multiply by volume and convert to 16 bit
  2371. pOutput[i].right += rscale[x & 0xFF];
  2372. sampleFrac += rateScaleFix;
  2373. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2374. sampleFrac = FIX_FRACPART(sampleFrac);
  2375. }
  2376. }
  2377. // mix left wav (front facing) with right wav (rear facing) based on soundfacing direction
  2378. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2379. // pData buffer, ensuring we can always provide 'outCount' samples.
  2380. void SW_Mix8StereoDirectional_Interp( float soundfacing, portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2381. {
  2382. fixedint sampleIndex = 0;
  2383. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2384. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2385. int first, second, interpl, interpr;
  2386. int *lscale, *rscale;
  2387. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2388. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2389. int x;
  2390. // if soundfacing -1.0, sound source is facing away from player
  2391. // if soundfacing 0.0, sound source is perpendicular to player
  2392. // if soundfacing 1.0, sound source is facing player
  2393. int frontmix = (int)(256.0f * ((1.f + soundfacing) / 2.f)); // 0 -> 256
  2394. for ( int i = 0; i < outCount; i++ )
  2395. {
  2396. // interpolate between first & second sample (the samples bordering sampleFrac12 fraction)
  2397. first = (int)((signed char)(pData[sampleIndex])); // left byte
  2398. second = (int)((signed char)(pData[sampleIndex+2]));
  2399. interpl = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2400. first = (int)((signed char)(pData[sampleIndex+1])); // right byte
  2401. second = (int)((signed char)(pData[sampleIndex+3]));
  2402. interpr = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2403. // crossfade between right/left based on directional mix
  2404. x = ( interpr + ((( interpl - interpr ) * frontmix) >> 8) );
  2405. pOutput[i].left += lscale[x & 0xFF]; // scale and convert to 16 bit
  2406. pOutput[i].right += rscale[x & 0xFF];
  2407. sampleFrac14 += rateScaleFix14;
  2408. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2409. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2410. }
  2411. }
  2412. // mix left wav (front facing) with right wav (rear facing) based on soundfacing direction
  2413. void SW_Mix16StereoDirectional( float soundfacing, portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2414. {
  2415. fixedint sampleIndex = 0;
  2416. fixedint sampleFrac = inputOffset;
  2417. int x;
  2418. int l, r;
  2419. // if soundfacing -1.0, sound source is facing away from player
  2420. // if soundfacing 0.0, sound source is perpendicular to player
  2421. // if soundfacing 1.0, sound source is facing player
  2422. int frontmix = (int)(256.0f * ((1.f + soundfacing) / 2.f)); // 0 -> 256
  2423. for ( int i = 0; i < outCount; i++ )
  2424. {
  2425. // get left, right samples
  2426. l = (int)(pData[sampleIndex]);
  2427. r = (int)(pData[sampleIndex+1]);
  2428. // crossfade between left & right based on front/rear facing
  2429. x = ( r + ((( l - r ) * frontmix) >> 8) );
  2430. pOutput[i].left += (volume[0] * x) >> 8;
  2431. pOutput[i].right += (volume[1] * x) >> 8;
  2432. sampleFrac += rateScaleFix;
  2433. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2434. sampleFrac = FIX_FRACPART(sampleFrac);
  2435. }
  2436. }
  2437. // mix left wav (front facing) with right wav (rear facing) based on soundfacing direction
  2438. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2439. // pData buffer, ensuring we can always provide 'outCount' samples.
  2440. void SW_Mix16StereoDirectional_Interp( float soundfacing, portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2441. {
  2442. fixedint sampleIndex = 0;
  2443. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2444. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2445. int x;
  2446. int first, second, interpl, interpr;
  2447. // if soundfacing -1.0, sound source is facing away from player
  2448. // if soundfacing 0.0, sound source is perpendicular to player
  2449. // if soundfacing 1.0, sound source is facing player
  2450. int frontmix = (int)(256.0f * ((1.f + soundfacing) / 2.f)); // 0 -> 256
  2451. for ( int i = 0; i < outCount; i++ )
  2452. {
  2453. // get interpolated left, right samples
  2454. first = (int)(pData[sampleIndex]);
  2455. second = (int)(pData[sampleIndex+2]);
  2456. interpl = first + (((second - first) * (int)sampleFrac14) >> 14);
  2457. first = (int)(pData[sampleIndex+1]);
  2458. second = (int)(pData[sampleIndex+3]);
  2459. interpr = first + (((second - first) * (int)sampleFrac14) >> 14);
  2460. // crossfade between left & right based on front/rear facing
  2461. x = ( interpr + ((( interpl - interpr ) * frontmix) >> 8) );
  2462. pOutput[i].left += (volume[0] * x) >> 8;
  2463. pOutput[i].right += (volume[1] * x) >> 8;
  2464. sampleFrac14 += rateScaleFix14;
  2465. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2466. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2467. }
  2468. }
  2469. // distance variant wav (left is close, right is far)
  2470. void SW_Mix8StereoDistVar( float distmix, portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2471. {
  2472. int sampleIndex = 0;
  2473. fixedint sampleFrac = inputOffset;
  2474. int x;
  2475. int l,r;
  2476. signed char lb, rb;
  2477. int *lscale, *rscale;
  2478. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2479. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2480. // distmix 0 - sound is near player (100% wav left)
  2481. // distmix 1.0 - sound is far from player (100% wav right)
  2482. int nearmix = (int)(256.0f * (1.0f - distmix));
  2483. int farmix = (int)(256.0f * distmix);
  2484. // if mixing at max or min range, skip crossfade (KDB: perf)
  2485. if (!nearmix)
  2486. {
  2487. for ( int i = 0; i < outCount; i++ )
  2488. {
  2489. rb = (pData[sampleIndex+1]); // get right byte
  2490. x = (int) rb;
  2491. pOutput[i].left += lscale[x & 0xFF]; // multiply by volume and convert to 16 bit
  2492. pOutput[i].right += rscale[x & 0xFF];
  2493. sampleFrac += rateScaleFix;
  2494. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2495. sampleFrac = FIX_FRACPART(sampleFrac);
  2496. }
  2497. return;
  2498. }
  2499. if (!farmix)
  2500. {
  2501. for ( int i = 0; i < outCount; i++ )
  2502. {
  2503. lb = (pData[sampleIndex]); // get left byte
  2504. x = (int) lb;
  2505. pOutput[i].left += lscale[x & 0xFF]; // multiply by volume and convert to 16 bit
  2506. pOutput[i].right += rscale[x & 0xFF];
  2507. sampleFrac += rateScaleFix;
  2508. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2509. sampleFrac = FIX_FRACPART(sampleFrac);
  2510. }
  2511. return;
  2512. }
  2513. // crossfade left/right
  2514. for ( int i = 0; i < outCount; i++ )
  2515. {
  2516. lb = (pData[sampleIndex]); // get left byte
  2517. rb = (pData[sampleIndex+1]); // get right byte
  2518. l = (int)lb;
  2519. r = (int)rb;
  2520. x = ( l + (((r - l) * farmix ) >> 8) );
  2521. pOutput[i].left += lscale[x & 0xFF]; // multiply by volume and convert to 16 bit
  2522. pOutput[i].right += rscale[x & 0xFF];
  2523. sampleFrac += rateScaleFix;
  2524. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2525. sampleFrac = FIX_FRACPART(sampleFrac);
  2526. }
  2527. }
  2528. // distance variant wav (left is close, right is far)
  2529. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2530. // pData buffer, ensuring we can always provide 'outCount' samples.
  2531. void SW_Mix8StereoDistVar_Interp( float distmix, portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2532. {
  2533. int x;
  2534. // distmix 0 - sound is near player (100% wav left)
  2535. // distmix 1.0 - sound is far from player (100% wav right)
  2536. int nearmix = (int)(256.0f * (1.0f - distmix));
  2537. int farmix = (int)(256.0f * distmix);
  2538. fixedint sampleIndex = 0;
  2539. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2540. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2541. int first, second, interpl, interpr;
  2542. int *lscale, *rscale;
  2543. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2544. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2545. // if mixing at max or min range, skip crossfade (KDB: perf)
  2546. if (!nearmix)
  2547. {
  2548. for ( int i = 0; i < outCount; i++ )
  2549. {
  2550. first = (int)((signed char)(pData[sampleIndex+1])); // right sample
  2551. second = (int)((signed char)(pData[sampleIndex+3]));
  2552. interpr = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2553. pOutput[i].left += lscale[interpr & 0xFF]; // scale and convert to 16 bit
  2554. pOutput[i].right += rscale[interpr & 0xFF];
  2555. sampleFrac14 += rateScaleFix14;
  2556. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2557. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2558. }
  2559. return;
  2560. }
  2561. if (!farmix)
  2562. {
  2563. for ( int i = 0; i < outCount; i++ )
  2564. {
  2565. first = (int)((signed char)(pData[sampleIndex])); // left sample
  2566. second = (int)((signed char)(pData[sampleIndex+2]));
  2567. interpl = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2568. pOutput[i].left += lscale[interpl & 0xFF]; // scale and convert to 16 bit
  2569. pOutput[i].right += rscale[interpl & 0xFF];
  2570. sampleFrac14 += rateScaleFix14;
  2571. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2572. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2573. }
  2574. return;
  2575. }
  2576. // crossfade left/right
  2577. for ( int i = 0; i < outCount; i++ )
  2578. {
  2579. // interpolate between first & second sample (the samples bordering sampleFrac14 fraction)
  2580. first = (int)((signed char)(pData[sampleIndex]));
  2581. second = (int)((signed char)(pData[sampleIndex+2]));
  2582. interpl = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2583. first = (int)((signed char)(pData[sampleIndex+1]));
  2584. second = (int)((signed char)(pData[sampleIndex+3]));
  2585. interpr = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2586. // crossfade between left and right based on distance mix
  2587. x = ( interpl + (((interpr - interpl) * farmix ) >> 8) );
  2588. pOutput[i].left += lscale[x & 0xFF]; // scale and convert to 16 bit
  2589. pOutput[i].right += rscale[x & 0xFF];
  2590. sampleFrac14 += rateScaleFix14;
  2591. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2592. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2593. }
  2594. }
  2595. // distance variant wav (left is close, right is far)
  2596. void SW_Mix16StereoDistVar( float distmix, portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2597. {
  2598. int sampleIndex = 0;
  2599. fixedint sampleFrac = inputOffset;
  2600. int x;
  2601. int l,r;
  2602. // distmix 0 - sound is near player (100% wav left)
  2603. // distmix 1.0 - sound is far from player (100% wav right)
  2604. int nearmix = Float2Int(256.0f * (1.f - distmix));
  2605. int farmix = Float2Int(256.0f * distmix);
  2606. // if mixing at max or min range, skip crossfade (KDB: perf)
  2607. if (!nearmix)
  2608. {
  2609. for ( int i = 0; i < outCount; i++ )
  2610. {
  2611. x = pData[sampleIndex+1]; // right sample
  2612. pOutput[i].left += (volume[0] * x)>>8;
  2613. pOutput[i].right += (volume[1] * x)>>8;
  2614. sampleFrac += rateScaleFix;
  2615. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2616. sampleFrac = FIX_FRACPART(sampleFrac);
  2617. }
  2618. return;
  2619. }
  2620. if (!farmix)
  2621. {
  2622. for ( int i = 0; i < outCount; i++ )
  2623. {
  2624. x = pData[sampleIndex]; // left sample
  2625. pOutput[i].left += (volume[0] * x)>>8;
  2626. pOutput[i].right += (volume[1] * x)>>8;
  2627. sampleFrac += rateScaleFix;
  2628. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2629. sampleFrac = FIX_FRACPART(sampleFrac);
  2630. }
  2631. return;
  2632. }
  2633. // crossfade left/right
  2634. for ( int i = 0; i < outCount; i++ )
  2635. {
  2636. l = pData[sampleIndex];
  2637. r = pData[sampleIndex+1];
  2638. x = ( l + (((r - l) * farmix) >> 8) );
  2639. pOutput[i].left += (volume[0] * x)>>8;
  2640. pOutput[i].right += (volume[1] * x)>>8;
  2641. sampleFrac += rateScaleFix;
  2642. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2643. sampleFrac = FIX_FRACPART(sampleFrac);
  2644. }
  2645. }
  2646. // distance variant wav (left is close, right is far)
  2647. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2648. // pData buffer, ensuring we can always provide 'outCount' samples.
  2649. void SW_Mix16StereoDistVar_Interp( float distmix, portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2650. {
  2651. int x;
  2652. fixedint sampleIndex = 0;
  2653. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2654. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2655. int first, second, interpl, interpr;
  2656. // distmix 0 - sound is near player (100% wav left)
  2657. // distmix 1.0 - sound is far from player (100% wav right)
  2658. int nearmix = Float2Int(256.0f * (1.f - distmix));
  2659. int farmix = Float2Int(256.0f * distmix);
  2660. // if mixing at max or min range, skip crossfade (KDB: perf)
  2661. if (!nearmix)
  2662. {
  2663. for ( int i = 0; i < outCount; i++ )
  2664. {
  2665. first = (int)(pData[sampleIndex+1]); // right sample
  2666. second = (int)(pData[sampleIndex+3]);
  2667. interpr = first + (((second - first) * (int)sampleFrac14) >> 14);
  2668. pOutput[i].left += (volume[0] * interpr)>>8;
  2669. pOutput[i].right += (volume[1] * interpr)>>8;
  2670. sampleFrac14 += rateScaleFix14;
  2671. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2672. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2673. }
  2674. return;
  2675. }
  2676. if (!farmix)
  2677. {
  2678. for ( int i = 0; i < outCount; i++ )
  2679. {
  2680. first = (int)(pData[sampleIndex]); // left sample
  2681. second = (int)(pData[sampleIndex+2]);
  2682. interpl = first + (((second - first) * (int)sampleFrac14) >> 14);
  2683. pOutput[i].left += (volume[0] * interpl)>>8;
  2684. pOutput[i].right += (volume[1] * interpl)>>8;
  2685. sampleFrac14 += rateScaleFix14;
  2686. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2687. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2688. }
  2689. return;
  2690. }
  2691. // crossfade left/right
  2692. for ( int i = 0; i < outCount; i++ )
  2693. {
  2694. first = (int)(pData[sampleIndex]);
  2695. second = (int)(pData[sampleIndex+2]);
  2696. interpl = first + (((second - first) * (int)sampleFrac14) >> 14);
  2697. first = (int)(pData[sampleIndex+1]);
  2698. second = (int)(pData[sampleIndex+3]);
  2699. interpr = first + (((second - first) * (int)sampleFrac14) >> 14);
  2700. // crossfade between left & right samples
  2701. x = ( interpl + (((interpr - interpl) * farmix) >> 8) );
  2702. pOutput[i].left += (volume[0] * x) >> 8;
  2703. pOutput[i].right += (volume[1] * x) >> 8;
  2704. sampleFrac14 += rateScaleFix14;
  2705. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2706. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2707. }
  2708. }
  2709. void SW_Mix8Mono( portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2710. {
  2711. // Not using pitch shift?
  2712. if ( rateScaleFix == FIX(1) )
  2713. {
  2714. // native code
  2715. SND_PaintChannelFrom8( pOutput, volume, (byte *)pData, outCount );
  2716. return;
  2717. }
  2718. int sampleIndex = 0;
  2719. fixedint sampleFrac = inputOffset;
  2720. int *lscale, *rscale;
  2721. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2722. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2723. for ( int i = 0; i < outCount; i++ )
  2724. {
  2725. pOutput[i].left += lscale[pData[sampleIndex]];
  2726. pOutput[i].right += rscale[pData[sampleIndex]];
  2727. sampleFrac += rateScaleFix;
  2728. sampleIndex += FIX_INTPART(sampleFrac);
  2729. sampleFrac = FIX_FRACPART(sampleFrac);
  2730. }
  2731. }
  2732. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2733. // pData buffer, ensuring we can always provide 'outCount' samples.
  2734. void SW_Mix8Mono_Interp( portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount)
  2735. {
  2736. fixedint sampleIndex = 0;
  2737. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2738. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2739. int first, second, interp;
  2740. int *lscale, *rscale;
  2741. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2742. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2743. // iterate 0th sample to outCount-1 sample
  2744. for (int i = 0; i < outCount; i++ )
  2745. {
  2746. // interpolate between first & second sample (the samples bordering sampleFrac12 fraction)
  2747. first = (int)((signed char)(pData[sampleIndex]));
  2748. second = (int)((signed char)(pData[sampleIndex+1]));
  2749. interp = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2750. pOutput[i].left += lscale[interp & 0xFF]; // multiply by volume and convert to 16 bit
  2751. pOutput[i].right += rscale[interp & 0xFF];
  2752. sampleFrac14 += rateScaleFix14;
  2753. sampleIndex += FIX_INTPART14(sampleFrac14);
  2754. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2755. }
  2756. }
  2757. void SW_Mix8Stereo( portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2758. {
  2759. int sampleIndex = 0;
  2760. fixedint sampleFrac = inputOffset;
  2761. int *lscale, *rscale;
  2762. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2763. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2764. for ( int i = 0; i < outCount; i++ )
  2765. {
  2766. pOutput[i].left += lscale[pData[sampleIndex]];
  2767. pOutput[i].right += rscale[pData[sampleIndex+1]];
  2768. sampleFrac += rateScaleFix;
  2769. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2770. sampleFrac = FIX_FRACPART(sampleFrac);
  2771. }
  2772. }
  2773. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2774. // pData buffer, ensuring we can always provide 'outCount' samples.
  2775. void SW_Mix8Stereo_Interp( portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount)
  2776. {
  2777. fixedint sampleIndex = 0;
  2778. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2779. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2780. int first, second, interpl, interpr;
  2781. int *lscale, *rscale;
  2782. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  2783. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  2784. // iterate 0th sample to outCount-1 sample
  2785. for (int i = 0; i < outCount; i++ )
  2786. {
  2787. // interpolate between first & second sample (the samples bordering sampleFrac12 fraction)
  2788. first = (int)((signed char)(pData[sampleIndex])); // left
  2789. second = (int)((signed char)(pData[sampleIndex+2]));
  2790. interpl = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2791. first = (int)((signed char)(pData[sampleIndex+1])); // right
  2792. second = (int)((signed char)(pData[sampleIndex+3]));
  2793. interpr = first + ( ((second - first) * (int)sampleFrac14) >> 14 );
  2794. pOutput[i].left += lscale[interpl & 0xFF]; // multiply by volume and convert to 16 bit
  2795. pOutput[i].right += rscale[interpr & 0xFF];
  2796. sampleFrac14 += rateScaleFix14;
  2797. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2798. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2799. }
  2800. }
  2801. void SW_Mix16Mono_Shift( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2802. {
  2803. int vol0 = volume[0];
  2804. int vol1 = volume[1];
  2805. #if !id386
  2806. int sampleIndex = 0;
  2807. fixedint sampleFrac = inputOffset;
  2808. for ( int i = 0; i < outCount; i++ )
  2809. {
  2810. pOutput[i].left += (vol0 * (int)(pData[sampleIndex]))>>8;
  2811. pOutput[i].right += (vol1 * (int)(pData[sampleIndex]))>>8;
  2812. sampleFrac += rateScaleFix;
  2813. sampleIndex += FIX_INTPART(sampleFrac);
  2814. sampleFrac = FIX_FRACPART(sampleFrac);
  2815. }
  2816. #else
  2817. // in assembly, you can make this 32.32 instead of 4.28 and use the carry flag instead of masking
  2818. int rateScaleInt = FIX_INTPART(rateScaleFix);
  2819. unsigned int rateScaleFrac = FIX_FRACPART(rateScaleFix) << (32-FIX_BITS);
  2820. __asm
  2821. {
  2822. mov eax, volume ;
  2823. movq mm0, DWORD PTR [eax] ; vol1, vol0 (32-bits each)
  2824. packssdw mm0, mm0 ; pack and replicate... vol1, vol0, vol1, vol0 (16-bits each)
  2825. //pxor mm7, mm7 ; mm7 is my zero register...
  2826. xor esi, esi
  2827. mov eax, DWORD PTR [pOutput] ; store initial output ptr
  2828. mov edx, DWORD PTR [pData] ; store initial input ptr
  2829. mov ebx, inputOffset;
  2830. mov ecx, outCount;
  2831. BEGINLOAD:
  2832. movd mm2, WORD PTR [edx+2*esi] ; load first piece of data from pData
  2833. punpcklwd mm2, mm2 ; 0, 0, pData_1st, pData_1st
  2834. add ebx, rateScaleFrac ; do the crazy fixed integer math
  2835. adc esi, rateScaleInt
  2836. movd mm3, WORD PTR [edx+2*esi] ; load second piece of data from pData
  2837. punpcklwd mm3, mm3 ; 0, 0, pData_2nd, pData_2nd
  2838. punpckldq mm2, mm3 ; pData_2nd, pData_2nd, pData_2nd, pData_2nd
  2839. add ebx, rateScaleFrac ; do the crazy fixed integer math
  2840. adc esi, rateScaleInt
  2841. movq mm3, mm2 ; copy the goods
  2842. pmullw mm2, mm0 ; pData_2nd*vol1, pData_2nd*vol0, pData_1st*vol1, pData_1st*vol0 (bits 0-15)
  2843. pmulhw mm3, mm0 ; pData_2nd*vol1, pData_2nd*vol0, pData_1st*vol1, pData_1st*vol0 (bits 16-31)
  2844. movq mm4, mm2 ; copy
  2845. movq mm5, mm3 ; copy
  2846. punpcklwd mm2, mm3 ; pData_1st*vol1, pData_1st*vol0 (bits 0-31)
  2847. punpckhwd mm4, mm5 ; pData_2nd*vol1, pData_2nd*vol0 (bits 0-31)
  2848. psrad mm2, 8 ; shift right by 8
  2849. psrad mm4, 8 ; shift right by 8
  2850. add ecx, -2 ; decrement i-value
  2851. paddd mm2, QWORD PTR [eax] ; add to existing vals
  2852. paddd mm4, QWORD PTR [eax+8] ;
  2853. movq QWORD PTR [eax], mm2 ; store back
  2854. movq QWORD PTR [eax+8], mm4 ;
  2855. add eax, 10h ;
  2856. cmp ecx, 01h ; see if we can quit
  2857. jg BEGINLOAD ; Kipp Owens is a doof...
  2858. jl END ; Nick Shaffner is killing me...
  2859. movsx edi, WORD PTR [edx+2*esi] ; load first 16 bit val and zero-extend
  2860. imul edi, vol0 ; multiply pData[sampleIndex] by volume[0]
  2861. sar edi, 08h ; divide by 256
  2862. add DWORD PTR [eax], edi ; add to pOutput[i].left
  2863. movsx edi, WORD PTR [edx+2*esi] ; load same 16 bit val and zero-extend (cuz I thrashed the reg)
  2864. imul edi, vol1 ; multiply pData[sampleIndex] by volume[1]
  2865. sar edi, 08h ; divide by 256
  2866. add DWORD PTR [eax+04h], edi ; add to pOutput[i].right
  2867. END:
  2868. emms;
  2869. }
  2870. #endif
  2871. }
  2872. void SW_Mix16Mono_NoShift( portable_samplepair_t *pOutput, int *volume, short *pData, int outCount )
  2873. {
  2874. int vol0 = volume[0];
  2875. int vol1 = volume[1];
  2876. #if !id386
  2877. for ( int i = 0; i < outCount; i++ )
  2878. {
  2879. int x = *pData++;
  2880. pOutput[i].left += (x * vol0) >> 8;
  2881. pOutput[i].right += (x * vol1) >> 8;
  2882. }
  2883. #else
  2884. __asm
  2885. {
  2886. mov eax, volume ;
  2887. movq mm0, DWORD PTR [eax] ; vol1, vol0 (32-bits each)
  2888. packssdw mm0, mm0 ; pack and replicate... vol1, vol0, vol1, vol0 (16-bits each)
  2889. //pxor mm7, mm7 ; mm7 is my zero register...
  2890. mov eax, DWORD PTR [pOutput] ; store initial output ptr
  2891. mov edx, DWORD PTR [pData] ; store initial input ptr
  2892. mov ecx, outCount;
  2893. BEGINLOAD:
  2894. movd mm2, WORD PTR [edx] ; load first piece o data from pData
  2895. punpcklwd mm2, mm2 ; 0, 0, pData_1st, pData_1st
  2896. add edx,2 ; move to the next sample
  2897. movd mm3, WORD PTR [edx] ; load second piece o data from pData
  2898. punpcklwd mm3, mm3 ; 0, 0, pData_2nd, pData_2nd
  2899. punpckldq mm2, mm3 ; pData_2nd, pData_2nd, pData_2nd, pData_2nd
  2900. add edx,2 ; move to the next sample
  2901. movq mm3, mm2 ; copy the goods
  2902. pmullw mm2, mm0 ; pData_2nd*vol1, pData_2nd*vol0, pData_1st*vol1, pData_1st*vol0 (bits 0-15)
  2903. pmulhw mm3, mm0 ; pData_2nd*vol1, pData_2nd*vol0, pData_1st*vol1, pData_1st*vol0 (bits 16-31)
  2904. movq mm4, mm2 ; copy
  2905. movq mm5, mm3 ; copy
  2906. punpcklwd mm2, mm3 ; pData_1st*vol1, pData_1st*vol0 (bits 0-31)
  2907. punpckhwd mm4, mm5 ; pData_2nd*vol1, pData_2nd*vol0 (bits 0-31)
  2908. psrad mm2, 8 ; shift right by 8
  2909. psrad mm4, 8 ; shift right by 8
  2910. add ecx, -2 ; decrement i-value
  2911. paddd mm2, QWORD PTR [eax] ; add to existing vals
  2912. paddd mm4, QWORD PTR [eax+8] ;
  2913. movq QWORD PTR [eax], mm2 ; store back
  2914. movq QWORD PTR [eax+8], mm4 ;
  2915. add eax, 10h ;
  2916. cmp ecx, 01h ; see if we can quit
  2917. jg BEGINLOAD ; I can cut and paste code!
  2918. jl END ;
  2919. movsx edi, WORD PTR [edx] ; load first 16 bit val and zero-extend
  2920. mov esi,edi ; save a copy for the other channel
  2921. imul edi, vol0 ; multiply pData[sampleIndex] by volume[0]
  2922. sar edi, 08h ; divide by 256
  2923. add DWORD PTR [eax], edi ; add to pOutput[i].left
  2924. ; esi has a copy, use it now
  2925. imul esi, vol1 ; multiply pData[sampleIndex] by volume[1]
  2926. sar esi, 08h ; divide by 256
  2927. add DWORD PTR [eax+04h], esi ; add to pOutput[i].right
  2928. END:
  2929. emms;
  2930. }
  2931. #endif
  2932. }
  2933. void SW_Mix16Mono( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2934. {
  2935. if ( rateScaleFix == FIX(1) )
  2936. {
  2937. SW_Mix16Mono_NoShift( pOutput, volume, pData, outCount );
  2938. }
  2939. else
  2940. {
  2941. SW_Mix16Mono_Shift( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  2942. }
  2943. }
  2944. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2945. // pData buffer, ensuring we can always provide 'outCount' samples.
  2946. void SW_Mix16Mono_Interp( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2947. {
  2948. fixedint sampleIndex = 0;
  2949. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2950. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2951. int first, second, interp;
  2952. for ( int i = 0; i < outCount; i++ )
  2953. {
  2954. first = (int)(pData[sampleIndex]);
  2955. second = (int)(pData[sampleIndex+1]);
  2956. interp = first + (((second - first) * (int)sampleFrac14) >> 14);
  2957. pOutput[i].left += (volume[0] * interp) >> 8;
  2958. pOutput[i].right += (volume[1] * interp) >> 8;
  2959. sampleFrac14 += rateScaleFix14;
  2960. sampleIndex += FIX_INTPART14(sampleFrac14);
  2961. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2962. }
  2963. }
  2964. void SW_Mix16Stereo( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2965. {
  2966. int sampleIndex = 0;
  2967. fixedint sampleFrac = inputOffset;
  2968. for ( int i = 0; i < outCount; i++ )
  2969. {
  2970. pOutput[i].left += (volume[0] * (int)(pData[sampleIndex]))>>8;
  2971. pOutput[i].right += (volume[1] * (int)(pData[sampleIndex+1]))>>8;
  2972. sampleFrac += rateScaleFix;
  2973. sampleIndex += FIX_INTPART(sampleFrac)<<1;
  2974. sampleFrac = FIX_FRACPART(sampleFrac);
  2975. }
  2976. }
  2977. // interpolating pitch shifter - sample(s) from preceding buffer are preloaded in
  2978. // pData buffer, ensuring we can always provide 'outCount' samples.
  2979. void SW_Mix16Stereo_Interp( portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  2980. {
  2981. fixedint sampleIndex = 0;
  2982. fixedint rateScaleFix14 = FIX_28TO14(rateScaleFix); // convert 28 bit fixed point to 14 bit fixed point
  2983. fixedint sampleFrac14 = FIX_28TO14(inputOffset);
  2984. int first, second, interpl, interpr;
  2985. for ( int i = 0; i < outCount; i++ )
  2986. {
  2987. first = (int)(pData[sampleIndex]);
  2988. second = (int)(pData[sampleIndex+2]);
  2989. interpl = first + (((second - first) * (int)sampleFrac14) >> 14);
  2990. first = (int)(pData[sampleIndex+1]);
  2991. second = (int)(pData[sampleIndex+3]);
  2992. interpr = first + (((second - first) * (int)sampleFrac14) >> 14);
  2993. pOutput[i].left += (volume[0] * interpl) >> 8;
  2994. pOutput[i].right += (volume[1] * interpr) >> 8;
  2995. sampleFrac14 += rateScaleFix14;
  2996. sampleIndex += FIX_INTPART14(sampleFrac14)<<1;
  2997. sampleFrac14 = FIX_FRACPART14(sampleFrac14);
  2998. }
  2999. }
  3000. // return true if mixer should use high quality pitch interpolation for this sound
  3001. bool FUseHighQualityPitch( channel_t *pChannel )
  3002. {
  3003. // do not use interpolating pitch shifter if:
  3004. // low quality flag set on sound (ie: wave name is prepended with CHAR_FAST_PITCH)
  3005. // or pitch has no fractional part
  3006. // or snd_pitchquality is 0
  3007. if ( !snd_pitchquality.GetInt() || pChannel->flags.bfast_pitch )
  3008. return false;
  3009. return ( (pChannel->pitch != floor(pChannel->pitch)) );
  3010. }
  3011. //===============================================================================
  3012. // DISPATCHERS FOR MIXING ROUTINES
  3013. //===============================================================================
  3014. void Mix8MonoWavtype( channel_t *pChannel, portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  3015. {
  3016. if ( FUseHighQualityPitch( pChannel ) )
  3017. SW_Mix8Mono_Interp( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3018. else
  3019. SW_Mix8Mono( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3020. }
  3021. void Mix16MonoWavtype( channel_t *pChannel, portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  3022. {
  3023. if ( FUseHighQualityPitch( pChannel ) )
  3024. SW_Mix16Mono_Interp( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3025. else
  3026. // fast native coded mixers with lower quality pitch shift
  3027. SW_Mix16Mono( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3028. }
  3029. void Mix8StereoWavtype( channel_t *pChannel, portable_samplepair_t *pOutput, int *volume, byte *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  3030. {
  3031. switch ( pChannel->wavtype )
  3032. {
  3033. case CHAR_DOPPLER:
  3034. SW_Mix8StereoDopplerLeft( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3035. SW_Mix8StereoDopplerRight( pOutput, &volume[IFRONT_LEFTD], pData, inputOffset, rateScaleFix, outCount );
  3036. break;
  3037. case CHAR_DIRECTIONAL:
  3038. if ( FUseHighQualityPitch( pChannel ) )
  3039. SW_Mix8StereoDirectional_Interp( pChannel->dspface, pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3040. else
  3041. SW_Mix8StereoDirectional( pChannel->dspface, pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3042. break;
  3043. case CHAR_DISTVARIANT:
  3044. if ( FUseHighQualityPitch( pChannel ) )
  3045. SW_Mix8StereoDistVar_Interp( pChannel->distmix, pOutput, volume, pData, inputOffset, rateScaleFix, outCount);
  3046. else
  3047. SW_Mix8StereoDistVar( pChannel->distmix, pOutput, volume, pData, inputOffset, rateScaleFix, outCount);
  3048. break;
  3049. case CHAR_OMNI:
  3050. // non directional stereo - all channel volumes are the same
  3051. if ( FUseHighQualityPitch( pChannel ) )
  3052. SW_Mix8Stereo_Interp( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3053. else
  3054. SW_Mix8Stereo( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3055. break;
  3056. default:
  3057. case CHAR_SPATIALSTEREO:
  3058. if ( FUseHighQualityPitch( pChannel ) )
  3059. SW_Mix8Stereo_Interp( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3060. else
  3061. SW_Mix8Stereo( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3062. break;
  3063. }
  3064. }
  3065. void Mix16StereoWavtype( channel_t *pChannel, portable_samplepair_t *pOutput, int *volume, short *pData, int inputOffset, fixedint rateScaleFix, int outCount )
  3066. {
  3067. switch ( pChannel->wavtype )
  3068. {
  3069. case CHAR_DOPPLER:
  3070. SW_Mix16StereoDopplerLeft( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3071. SW_Mix16StereoDopplerRight( pOutput, &volume[IFRONT_LEFTD], pData, inputOffset, rateScaleFix, outCount );
  3072. break;
  3073. case CHAR_DIRECTIONAL:
  3074. if ( FUseHighQualityPitch( pChannel ) )
  3075. SW_Mix16StereoDirectional_Interp( pChannel->dspface, pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3076. else
  3077. SW_Mix16StereoDirectional( pChannel->dspface, pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3078. break;
  3079. case CHAR_DISTVARIANT:
  3080. if ( FUseHighQualityPitch( pChannel ) )
  3081. SW_Mix16StereoDistVar_Interp( pChannel->distmix, pOutput, volume, pData, inputOffset, rateScaleFix, outCount);
  3082. else
  3083. SW_Mix16StereoDistVar( pChannel->distmix, pOutput, volume, pData, inputOffset, rateScaleFix, outCount);
  3084. break;
  3085. case CHAR_OMNI:
  3086. // non directional stereo - all channel volumes are same
  3087. if ( FUseHighQualityPitch( pChannel ) )
  3088. SW_Mix16Stereo_Interp( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3089. else
  3090. SW_Mix16Stereo( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3091. break;
  3092. default:
  3093. case CHAR_SPATIALSTEREO:
  3094. if ( FUseHighQualityPitch( pChannel ) )
  3095. SW_Mix16Stereo_Interp( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3096. else
  3097. SW_Mix16Stereo( pOutput, volume, pData, inputOffset, rateScaleFix, outCount );
  3098. break;
  3099. }
  3100. }
  3101. //===============================================================================
  3102. // Client entity mouth movement code. Set entity mouthopen variable, based
  3103. // on the sound envelope of the voice channel playing.
  3104. // KellyB 10/22/97
  3105. //===============================================================================
  3106. extern IBaseClientDLL *g_ClientDLL;
  3107. // called when voice channel is first opened on this entity
  3108. static CMouthInfo *GetMouthInfoForChannel( channel_t *pChannel )
  3109. {
  3110. #ifndef DEDICATED
  3111. // If it's a sound inside the client UI, ask the client for the mouthinfo
  3112. if ( pChannel->soundsource == SOUND_FROM_UI_PANEL )
  3113. return g_ClientDLL ? g_ClientDLL->GetClientUIMouthInfo() : NULL;
  3114. #endif
  3115. int mouthentity = pChannel->speakerentity == -1 ? pChannel->soundsource : pChannel->speakerentity;
  3116. IClientEntity *pClientEntity = entitylist->GetClientEntity( mouthentity );
  3117. if( !pClientEntity )
  3118. return NULL;
  3119. return pClientEntity->GetMouth();
  3120. }
  3121. void SND_InitMouth( channel_t *pChannel )
  3122. {
  3123. if ( SND_IsMouth( pChannel ) )
  3124. {
  3125. CMouthInfo *pMouth = GetMouthInfoForChannel(pChannel);
  3126. // init mouth movement vars
  3127. if ( pMouth )
  3128. {
  3129. pMouth->mouthopen = 0;
  3130. pMouth->sndavg = 0;
  3131. pMouth->sndcount = 0;
  3132. if ( pChannel->sfx->pSource && pChannel->sfx->pSource->GetSentence() )
  3133. {
  3134. pMouth->AddSource( pChannel->sfx->pSource, pChannel->flags.m_bIgnorePhonemes );
  3135. }
  3136. }
  3137. }
  3138. }
  3139. // called when channel stops
  3140. void SND_CloseMouth(channel_t *pChannel)
  3141. {
  3142. if ( SND_IsMouth( pChannel ) )
  3143. {
  3144. CMouthInfo *pMouth = GetMouthInfoForChannel(pChannel);
  3145. if ( pMouth )
  3146. {
  3147. // shut mouth
  3148. int idx = pMouth->GetIndexForSource( pChannel->sfx->pSource );
  3149. if ( idx != UNKNOWN_VOICE_SOURCE )
  3150. {
  3151. pMouth->RemoveSourceByIndex(idx);
  3152. }
  3153. else
  3154. {
  3155. pMouth->ClearVoiceSources();
  3156. }
  3157. pMouth->mouthopen = 0;
  3158. }
  3159. }
  3160. }
  3161. #define CAVGSAMPLES 10
  3162. // need this to make the debug code below work.
  3163. //#include "snd_wave_source.h"
  3164. void SND_MoveMouth8( channel_t *ch, CAudioSource *pSource, int count )
  3165. {
  3166. int data;
  3167. char *pdata = NULL;
  3168. int i;
  3169. int savg;
  3170. int scount;
  3171. CMouthInfo *pMouth = GetMouthInfoForChannel( ch );
  3172. if ( !pMouth )
  3173. return;
  3174. if ( pSource->GetSentence() )
  3175. {
  3176. int idx = pMouth->GetIndexForSource( pSource );
  3177. if ( idx == UNKNOWN_VOICE_SOURCE )
  3178. {
  3179. if ( pMouth->AddSource( pSource, ch->flags.m_bIgnorePhonemes ) == NULL )
  3180. {
  3181. DevMsg( 1, "out of voice sources, won't lipsync %s\n", ch->sfx->getname() );
  3182. #if 0
  3183. for ( int i = 0; i < pMouth->GetNumVoiceSources(); i++ )
  3184. {
  3185. CVoiceData *pVoice = pMouth->GetVoiceSource(i);
  3186. CAudioSourceWave *pWave = dynamic_cast<CAudioSourceWave *>(pVoice->GetSource());
  3187. const char *pName = "unknown";
  3188. if ( pWave && pWave->GetName() )
  3189. pName = pWave->GetName();
  3190. Msg("Playing %s...\n", pName );
  3191. }
  3192. #endif
  3193. }
  3194. }
  3195. else
  3196. {
  3197. // Update elapsed time from mixer
  3198. CVoiceData *vd = pMouth->GetVoiceSource( idx );
  3199. Assert( vd );
  3200. if ( vd )
  3201. {
  3202. Assert( pSource->SampleRate() > 0 );
  3203. float elapsed = ( float )ch->pMixer->GetSamplePosition() / ( float )pSource->SampleRate();
  3204. vd->SetElapsedTime( elapsed );
  3205. }
  3206. }
  3207. }
  3208. if ( IsX360() )
  3209. {
  3210. // not supporting because data is assumed to be 8 bit and bypasses mixer (decoding)
  3211. return;
  3212. }
  3213. if ( pMouth->NeedsEnvelope() )
  3214. {
  3215. int availableSamples = pSource->GetOutputData((void**)&pdata, ch->pMixer->GetSamplePosition(), count, NULL );
  3216. if( pdata == NULL )
  3217. return;
  3218. i = 0;
  3219. scount = pMouth->sndcount;
  3220. savg = 0;
  3221. while ( i < availableSamples && scount < CAVGSAMPLES )
  3222. {
  3223. data = pdata[i];
  3224. savg += abs(data);
  3225. i += 80 + ((byte)data & 0x1F);
  3226. scount++;
  3227. }
  3228. pMouth->sndavg += savg;
  3229. pMouth->sndcount = (byte) scount;
  3230. if ( pMouth->sndcount >= CAVGSAMPLES )
  3231. {
  3232. pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
  3233. pMouth->sndavg = 0;
  3234. pMouth->sndcount = 0;
  3235. }
  3236. }
  3237. else
  3238. {
  3239. pMouth->mouthopen = 0;
  3240. }
  3241. }
  3242. void SND_UpdateMouth( channel_t *pChannel )
  3243. {
  3244. CMouthInfo *m = GetMouthInfoForChannel( pChannel );
  3245. if ( !m )
  3246. return;
  3247. if ( pChannel->sfx )
  3248. {
  3249. m->AddSource( pChannel->sfx->pSource, pChannel->flags.m_bIgnorePhonemes );
  3250. }
  3251. }
  3252. void SND_ClearMouth( channel_t *pChannel )
  3253. {
  3254. CMouthInfo *m = GetMouthInfoForChannel( pChannel );
  3255. if ( !m )
  3256. return;
  3257. if ( pChannel->sfx )
  3258. {
  3259. m->RemoveSource( pChannel->sfx->pSource );
  3260. }
  3261. }
  3262. //-----------------------------------------------------------------------------
  3263. // Purpose:
  3264. // Input : *pChannel -
  3265. // Output : Returns true on success, false on failure.
  3266. //-----------------------------------------------------------------------------
  3267. bool SND_IsMouth( channel_t *pChannel )
  3268. {
  3269. #ifndef DEDICATED
  3270. if ( pChannel->soundsource == SOUND_FROM_UI_PANEL )
  3271. return true;
  3272. #endif
  3273. if ( !entitylist )
  3274. {
  3275. return false;
  3276. }
  3277. if ( pChannel->entchannel == CHAN_VOICE || pChannel->entchannel == CHAN_VOICE2 )
  3278. {
  3279. return true;
  3280. }
  3281. if ( pChannel->sfx &&
  3282. pChannel->sfx->pSource &&
  3283. pChannel->sfx->pSource->GetSentence() )
  3284. {
  3285. return true;
  3286. }
  3287. return false;
  3288. }
  3289. //-----------------------------------------------------------------------------
  3290. // Purpose:
  3291. // Input : *pChannel -
  3292. // Output : Returns true on success, false on failure.
  3293. //-----------------------------------------------------------------------------
  3294. bool SND_ShouldPause( channel_t *pChannel )
  3295. {
  3296. return pChannel->flags.m_bShouldPause;
  3297. }
  3298. //===============================================================================
  3299. // Movie recording support
  3300. //===============================================================================
  3301. void SND_RecordInit()
  3302. {
  3303. g_paintedtime = 0;
  3304. g_soundtime = 0;
  3305. // TMP Wave file supports stereo only, so force stereo
  3306. if ( snd_surround.GetInt() != 2 )
  3307. {
  3308. snd_surround.SetValue( 2 );
  3309. }
  3310. }
  3311. void SND_MovieStart( void )
  3312. {
  3313. if ( IsX360() )
  3314. return;
  3315. if ( !cl_movieinfo.IsRecording() )
  3316. return;
  3317. SND_RecordInit();
  3318. // 44k: engine playback rate is now 44100...changed from 22050
  3319. if ( cl_movieinfo.DoWav() )
  3320. {
  3321. WaveCreateTmpFile( cl_movieinfo.moviename, SOUND_DMA_SPEED, 16, 2 );
  3322. }
  3323. }
  3324. void SND_MovieEnd( void )
  3325. {
  3326. if ( IsX360() )
  3327. return;
  3328. if ( !cl_movieinfo.IsRecording() )
  3329. {
  3330. return;
  3331. }
  3332. if ( cl_movieinfo.DoWav() )
  3333. {
  3334. WaveFixupTmpFile( cl_movieinfo.moviename );
  3335. }
  3336. }
  3337. bool SND_IsRecording()
  3338. {
  3339. return ( ( IsReplayRendering() || cl_movieinfo.IsRecording() ) && !Con_IsVisible() );
  3340. }
  3341. extern IVideoRecorder *g_pVideoRecorder;
  3342. void SND_RecordBuffer( void )
  3343. {
  3344. if ( IsX360() )
  3345. return;
  3346. if ( !SND_IsRecording() )
  3347. return;
  3348. int i;
  3349. int val;
  3350. int bufferSize = snd_linear_count * sizeof(short);
  3351. short *tmp = (short *)_alloca( bufferSize );
  3352. for (i=0 ; i<snd_linear_count ; i+=2)
  3353. {
  3354. val = (snd_p[i]*snd_vol)>>8;
  3355. tmp[i] = CLIP(val);
  3356. val = (snd_p[i+1]*snd_vol)>>8;
  3357. tmp[i+1] = CLIP(val);
  3358. }
  3359. if ( IsReplayRendering() )
  3360. {
  3361. #if defined( REPLAY_ENABLED )
  3362. extern IClientReplayContext *g_pClientReplayContext;
  3363. IReplayMovieRenderer *pMovieRenderer = g_pClientReplayContext->GetMovieRenderer();
  3364. if ( IsReplayRendering() && pMovieRenderer && pMovieRenderer->IsAudioSyncFrame() )
  3365. {
  3366. pMovieRenderer->RenderAudio( (unsigned char *)tmp, bufferSize, snd_linear_count );
  3367. }
  3368. #endif
  3369. }
  3370. else
  3371. {
  3372. if ( cl_movieinfo.DoWav() )
  3373. {
  3374. WaveAppendTmpFile( cl_movieinfo.moviename, tmp, 16, snd_linear_count );
  3375. }
  3376. if ( cl_movieinfo.DoVideoSound() )
  3377. {
  3378. g_pVideoRecorder->AppendAudioSamples( tmp, bufferSize );
  3379. }
  3380. }
  3381. }