Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1250 lines
40 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Device Common Base Class.
  4. //
  5. //=====================================================================================//
  6. #include "audio_pch.h"
  7. #include "../../cl_splitscreen.h"
  8. #include "snd_dma.h"
  9. #include "../../debugoverlay.h"
  10. #include "server.h"
  11. #include "client.h"
  12. // NOTE: This has to be the last file included!
  13. #include "tier0/memdbgon.h"
  14. #define ISPEAKER_RIGHT_FRONT 0
  15. #define ISPEAKER_LEFT_FRONT 1
  16. #define ISPEAKER_RIGHT_REAR 2
  17. #define ISPEAKER_LEFT_REAR 3
  18. #define ISPEAKER_CENTER_FRONT 4
  19. #define ISPEAKER_DIR_STEREO 99
  20. extern Vector listener_right[ MAX_SPLITSCREEN_CLIENTS ];
  21. extern void DEBUG_StartSoundMeasure(int type, int samplecount );
  22. extern void DEBUG_StopSoundMeasure(int type, int samplecount );
  23. extern bool MIX_ScaleChannelVolume( paintbuffer_t *pPaint, channel_t *pChannel, float volume[CCHANVOLUMES], int mixchans );
  24. inline bool FVolumeFrontNonZero( float *pvol )
  25. {
  26. return (pvol[IFRONT_RIGHT] || pvol[IFRONT_LEFT]);
  27. }
  28. inline bool FVolumeRearNonZero( float *pvol )
  29. {
  30. return (pvol[IREAR_RIGHT] || pvol[IREAR_LEFT]);
  31. }
  32. inline bool FVolumeCenterNonZero( float *pvol )
  33. {
  34. return (pvol[IFRONT_CENTER] != 0);
  35. }
  36. // fade speaker volumes to mono, based on xfade value.
  37. // ie: xfade 1.0 is full mono.
  38. // ispeaker is speaker index, cspeaker is total # of speakers
  39. // fmix2channels causes mono mix for 4 channel mix to mix down to 2 channels
  40. // this is used for the 2 speaker outpu case, which uses recombined 4 channel front/rear mixing
  41. static float XfadeSpeakerVolToMono( float scale, float xfade, int ispeaker, int cspeaker, bool fmix2channels )
  42. {
  43. float scale_out;
  44. float scale_target;
  45. if (cspeaker == 4 )
  46. {
  47. // mono sound distribution:
  48. float scale_targets[] = {0.9, 0.9, 0.9, 0.9}; // RF, LF, RR, LR
  49. float scale_targets2ch[] = {0.9, 0.9, 0.0, 0.0}; // RF, LF, RR, LR
  50. if ( fmix2channels )
  51. scale_target = scale_targets2ch[(int)clamp(ispeaker, 0, 3)];
  52. else
  53. scale_target = scale_targets[(int)clamp(ispeaker, 0, 3)];
  54. goto XfadeExit;
  55. }
  56. if (cspeaker == 5 )
  57. {
  58. // mono sound distribution:
  59. float scale_targets[] = {0.9, 0.9, 0.5, 0.5, 0.9}; // RF, LF, RR, LR, FC
  60. scale_target = scale_targets[(int)clamp(ispeaker, 0, 4)];
  61. goto XfadeExit;
  62. }
  63. // if (cspeaker == 2 )
  64. scale_target = 0.9; // front 2 speakers in stereo each get 50% of total volume in mono case
  65. XfadeExit:
  66. scale_out = scale + (scale_target - scale) * xfade;
  67. return scale_out;
  68. }
  69. // given:
  70. // 2d yaw angle to sound source (0-360), where 0 is listener_right
  71. // pitch angle to source
  72. // angle to speaker position (0-360), where 0 is listener_right
  73. // speaker index
  74. // speaker total count,
  75. // return: scale from 0-1.0 for speaker volume.
  76. // NOTE: as pitch angle goes to +/- 90, sound goes to mono, all speakers.
  77. #define PITCH_ANGLE_THRESHOLD 45.0
  78. #define REAR_VOL_DROP 0.5
  79. #define VOLCURVEPOWER 1.5 // 1.0 is a linear crossfade of volume between speakers.
  80. // 1.5 provides a smoother, nonlinear volume transition - this is done
  81. // because a volume of 255 played in a single speaker is
  82. // percieved as louder than 128 + 128 in two speakers
  83. // separated by at least 45 degrees. The nonlinear curve
  84. // gives the volume boost needed.
  85. static float GetSpeakerVol( float yaw_source, float pitch_source, float mono, float yaw_speaker, int ispeaker, int cspeaker, bool fmix2channels )
  86. {
  87. float adif = fabs(yaw_source - yaw_speaker);
  88. float pitch_angle = pitch_source;
  89. float scale = 0.0;
  90. float xfade = 0.0;
  91. if (adif > 180)
  92. adif = 360 - adif;
  93. // mono goes from 0.0 to 1.0 as listener moves into 'mono' radius of sound source.
  94. // Also, as pitch_angle to sound source approaches 90 (sound above/below listener), sounds become mono.
  95. // convert pitch angle to 0-90 absolute pitch
  96. if (pitch_angle < 0)
  97. pitch_angle += 360;
  98. if (pitch_angle > 180)
  99. pitch_angle = 360 - pitch_angle;
  100. if (pitch_angle > 90)
  101. pitch_angle = 90 - (pitch_angle - 90);
  102. // calculate additional mono crossfade due to pitch angle
  103. if (pitch_angle > PITCH_ANGLE_THRESHOLD)
  104. {
  105. xfade = (pitch_angle - PITCH_ANGLE_THRESHOLD) / (90.0 - PITCH_ANGLE_THRESHOLD); // 0.0 -> 1.0 as angle 45->90
  106. mono += xfade;
  107. mono = clamp(mono, 0.0, 1.0);
  108. }
  109. if (cspeaker == 2)
  110. {
  111. // 2 speaker (headphone) mix: speakers opposing, at 0 & 180 degrees
  112. scale = (1.0 - FastPow(adif / 180.0, VOLCURVEPOWER));
  113. goto GetVolExit;
  114. }
  115. if (adif >= 90.0)
  116. goto GetVolExit; // 0.0 scale
  117. if (cspeaker == 4)
  118. {
  119. // 4 ch surround: all speakers on 90 degree angles,
  120. // scale ranges from 0.0 (at 90 degree difference between source and speaker)
  121. // to 1.0 (0 degree difference between source and speaker)
  122. if (ispeaker == ISPEAKER_DIR_STEREO)
  123. {
  124. scale = (1.0 - FastPow(adif / 135.0f, VOLCURVEPOWER));
  125. }
  126. else
  127. {
  128. scale = (1.0 - FastPow(adif / 90.0, VOLCURVEPOWER));
  129. }
  130. goto GetVolExit;
  131. }
  132. // 5 ch surround:
  133. // rear speakers are on 90 degree angles and return 0.0->1.0 range over +/- 90 degrees each
  134. // center speaker is on 45 degree angle to left/right front speaker
  135. // center speaker has 0.0->1.0 range over 45 degrees
  136. switch (ispeaker)
  137. {
  138. default:
  139. case ISPEAKER_RIGHT_REAR:
  140. case ISPEAKER_LEFT_REAR:
  141. {
  142. // rear speakers get +/- 90 degrees of linear scaling...
  143. scale = (1.0 - FastPow(adif / 90.0, VOLCURVEPOWER));
  144. break;
  145. }
  146. case ISPEAKER_CENTER_FRONT:
  147. {
  148. // center speaker gets +/- 45 degrees of linear scaling...
  149. if (adif > 45.0)
  150. goto GetVolExit; // 0.0 scale
  151. scale = (1.0 - FastPow(adif / 45.0, VOLCURVEPOWER));
  152. break;
  153. }
  154. case ISPEAKER_RIGHT_FRONT:
  155. {
  156. if (yaw_source > yaw_speaker)
  157. {
  158. // if sound source is between right front speaker and center speaker,
  159. // apply scaling over 75 degrees...
  160. if (adif > 75.0)
  161. goto GetVolExit; // 0.0 scale
  162. scale = (1.0 - FastPow(adif / 75.0, VOLCURVEPOWER));
  163. }
  164. /*
  165. if (yaw_source > yaw_speaker && yaw_source < (yaw_speaker + 90.0))
  166. {
  167. // if sound source is between right front speaker and center speaker,
  168. // apply scaling over 45 degrees...
  169. if (adif > 45.0)
  170. goto GetVolExit; // 0.0 scale
  171. scale = (1.0 - FastPow(adif/45.0, VOLCURVEPOWER));
  172. }
  173. */
  174. else
  175. {
  176. // sound source is CW from right speaker, apply scaling over 90 degrees...
  177. scale = (1.0 - FastPow(adif / 90.0, VOLCURVEPOWER));
  178. }
  179. break;
  180. }
  181. case ISPEAKER_LEFT_FRONT:
  182. {
  183. if (yaw_source < yaw_speaker)
  184. {
  185. // if sound source is between left front speaker and center speaker,
  186. // apply scaling over 75 degrees...
  187. if (adif > 75.0)
  188. goto GetVolExit; // 0.0 scale
  189. scale = (1.0 - FastPow(adif / 75.0, VOLCURVEPOWER));
  190. }
  191. /*
  192. if (yaw_source < yaw_speaker && yaw_source > (yaw_speaker - 90.0))
  193. {
  194. // if sound source is between left front speaker and center speaker,
  195. // apply scaling over 45 degrees...
  196. if (adif > 45.0)
  197. goto GetVolExit; // 0.0 scale
  198. scale = (1.0 - FastPow(adif/45.0, VOLCURVEPOWER));
  199. }
  200. */
  201. else
  202. {
  203. // sound source is CW from right speaker, apply scaling over 90 degrees...
  204. scale = (1.0 - FastPow(adif / 90.0, VOLCURVEPOWER));
  205. }
  206. break;
  207. }
  208. }
  209. GetVolExit:
  210. Assert(mono <= 1.0 && mono >= 0.0);
  211. Assert(scale <= 1.0 && scale >= 0.0);
  212. // crossfade speaker volumes towards mono with increased pitch angle of sound source
  213. scale = XfadeSpeakerVolToMono(scale, mono, ispeaker, cspeaker, fmix2channels);
  214. Assert(scale <= 1.0 && scale >= 0.0);
  215. return scale;
  216. }
  217. extern ConVar sv_cheats;
  218. // counterstrike options
  219. #define SND_SVACTIVE_CONCMD( VARIABLENAME, DEFAULTVALUE, DESCSTRING ) \
  220. float g_##VARIABLENAME = DEFAULTVALUE; \
  221. CON_COMMAND( VARIABLENAME , DESCSTRING ) \
  222. { \
  223. if ( args.ArgC () < 2 ) \
  224. { \
  225. ConMsg ("%s = %f\n", #VARIABLENAME, g_##VARIABLENAME ); \
  226. } \
  227. else if ( sv.IsActive() && !sv_cheats.GetBool() ) \
  228. { \
  229. ConMsg( "Cannot change %s while the server is running and sv_cheats = 0. To change settings set sv_cheats 1\n", #VARIABLENAME ); \
  230. return; \
  231. } \
  232. else \
  233. { \
  234. g_##VARIABLENAME = V_atof( args[1] ); \
  235. } \
  236. } \
  237. // headphones
  238. SND_SVACTIVE_CONCMD( snd_front_headphone_position, 90.0, "Specifies the position (in degrees) of the virtual front left/right headphones." )
  239. SND_SVACTIVE_CONCMD( snd_rear_headphone_position, 90.0, "Specifies the position (in degrees) of the virtual rear left/right headphones." )
  240. // speakers
  241. SND_SVACTIVE_CONCMD( snd_front_stereo_speaker_position, 90.0, "Specifies the position (in degrees) of the virtual front left/right speakers." );
  242. SND_SVACTIVE_CONCMD( snd_rear_stereo_speaker_position, 90.0, "Specifies the position (in degrees) of the virtual rear left/right speakers." );
  243. // speakers 4, 5 or 7
  244. SND_SVACTIVE_CONCMD( snd_front_surround_speaker_position, 45.0, "Specifies the position (in degrees) of the virtual front left/right speakers." );
  245. SND_SVACTIVE_CONCMD( snd_rear_surround_speaker_position, 135.0,"Specifies the position (in degrees) of the virtual rear left/right speakers." );
  246. // given unit vector from listener to sound source,
  247. // determine proportion of volume for sound in FL, FC, FR, RL, RR quadrants
  248. // Scale this proportion by the distance scalar 'gain'
  249. // If sound has 'mono' radius, blend sound to mono over 50% of radius.
  250. SND_SVACTIVE_CONCMD( snd_headphone_pan_exponent, 1.0, "Specifies the exponent for the pan xfade from phone to phone if the \"exp\" pan law is being used." );
  251. SND_SVACTIVE_CONCMD( snd_stereo_speaker_pan_exponent, 1.5, "Specifies the exponent for the pan xfade from speaker to speaker if the \"exp\" pan law is being used." );
  252. SND_SVACTIVE_CONCMD( snd_surround_speaker_pan_exponent, 1.5, "Specifies the exponent for the pan xfade from speaker to speaker if the \"exp\" pan law is being used." );
  253. SND_SVACTIVE_CONCMD( snd_headphone_pan_radial_weight, 1.0, "Apply cos(angle) * weight before pan law" );
  254. SND_SVACTIVE_CONCMD( snd_stereo_speaker_pan_radial_weight, 0.0, "Apply cos(angle) * weight before pan law" );
  255. SND_SVACTIVE_CONCMD( snd_surround_speaker_pan_radial_weight, 0.0, "Apply cos(angle) * weight before pan law" );
  256. enum snd_pan_mode_t
  257. {
  258. SND_PAN_EXP = 0,
  259. SND_PAN_EQ_POW,
  260. SND_PAN_GLDSRC
  261. };
  262. snd_pan_mode_t g_snd_headphone_pan_mode = SND_PAN_EXP;
  263. snd_pan_mode_t g_snd_stereo_speaker_pan_mode = SND_PAN_EXP;
  264. snd_pan_mode_t g_snd_surround_speaker_pan_mode = SND_PAN_EXP;
  265. // SND_SVACTIVE_CONCMD( snd_headphone_pan_mode, 0.0, "Specifies which pan law to use when monitoring through headphones. < 0 = exp >, < 1 = equal power >, < 2 = goldsrc >", int );
  266. // SND_SVACTIVE_CONCMD( snd_stereo_speaker_pan_mode, 0.0, "Specifies which pan law to use when monitoring through stereo speakers. < 0 = exp >, < 1 = equal power >, < 2 = goldsrc >", int );
  267. // SND_SVACTIVE_CONCMD( snd_surround_speaker_pan_mode, 0.0, "Specifies which pan law to use when monitoring through stereo speakers. < 0 = exp >, < 1 = equal power >, < 2 = goldsrc >", int );
  268. extern ConVar snd_debug_panlaw;
  269. void DEBUG_DrawPanCurvesLocation( float flYawSource, float flSpeakerMin, float flSpeakerMax, float flFactor, float flMinValue, float flMaxValue )
  270. {
  271. float startY = 0.66;
  272. float totalY = 0.25;
  273. float startX = 0.0;
  274. float endX = 0.25 * ( 9.0 / 16.0 );
  275. float stepX = (float)(endX / (float)180);
  276. float nSource = flFactor * 180;
  277. float flMinY = flMinValue * totalY;
  278. float flMaxY = flMaxValue * totalY;
  279. CDebugOverlay::AddScreenTextOverlay( startX + ( stepX * nSource ), startY - ( flMinY ) - .01, .01, 255, 0, 0, 255, "#" );
  280. CDebugOverlay::AddScreenTextOverlay( startX + ( stepX * nSource ), startY - ( flMinY ) - .02, .01, 255, 0, 0, 255, "#" );
  281. CDebugOverlay::AddScreenTextOverlay( startX + ( stepX * nSource ), startY - ( flMaxY ) + .01, .01, 255, 0, 0, 255, "#" );
  282. CDebugOverlay::AddScreenTextOverlay( startX + ( stepX * nSource ), startY - ( flMaxY ) + .02, .01, 255, 0, 0, 255, "#" );
  283. startX += (((float) 1.5 * endX) + 0.01 );
  284. float flMidX = startX + ( endX * 0.5 );
  285. float flMidY = startY - ( totalY * 0.5);
  286. float flSin, flCos;
  287. FastSinCos( flYawSource * 0.01745329251994329500 , &flSin, &flCos );
  288. CDebugOverlay::AddScreenTextOverlay(flMidX + flCos * endX *0.53, flMidY + -(flSin*totalY*0.53), .01, 255, 0, 0, 255, "#");
  289. }
  290. // given unit vector from listener to sound source,
  291. // determine proportion of volume for sound in FL, FC, FR, RL, RR quadrants
  292. // Scale this proportion by the distance scalar 'gain'
  293. // If sound has 'mono' radius, blend sound to mono over 50% of radius.
  294. void Device_SpatializeChannel( int nSlot, float volume[CCHANVOLUMES/2], int master_vol, const Vector& sourceDir, float gain, float mono, int nWaveType )
  295. {
  296. VPROF("Device_SpatializeChannel");
  297. float rfscale, rrscale, lfscale, lrscale, fcscale;
  298. fcscale = rfscale = lfscale = rrscale = lrscale = 0.0;
  299. bool bSurround = g_AudioDevice->IsSurround();
  300. bool bSurroundCenter = g_AudioDevice->IsSurroundCenter();
  301. bool bHeadphone = g_AudioDevice->IsHeadphone();
  302. // clear volumes
  303. for (int i = 0; i < CCHANVOLUMES/2; i++)
  304. volume[i] = 0;
  305. // linear crossfader for 2, 4 or 5 speakers, using polar coord. separation angle as linear basis
  306. // get pitch & yaw angle from listener origin to sound source
  307. QAngle angles;
  308. float pitch;
  309. float source_yaw;
  310. float yaw;
  311. VectorAngles(sourceDir, angles);
  312. pitch = angles[PITCH];
  313. source_yaw = angles[YAW];
  314. // get 2d listener yaw angle from listener right
  315. QAngle angles2d;
  316. Vector source2d;
  317. float listener_yaw;
  318. source2d.x = listener_right[ nSlot ].x;
  319. source2d.y = listener_right[ nSlot ].y;
  320. source2d.z = 0.0;
  321. VectorNormalize(source2d);
  322. // convert right vector to euler angles (yaw & pitch)
  323. VectorAngles(source2d, angles2d);
  324. listener_yaw = angles2d[YAW];
  325. // get yaw of sound source, with listener_yaw as reference 0.
  326. yaw = source_yaw - listener_yaw;
  327. if (yaw < 0)
  328. yaw += 360;
  329. if ( !bSurround )
  330. {
  331. // 2 ch stereo mixing
  332. if ( bHeadphone )
  333. {
  334. // headphone mix: (NO HRTF)
  335. rfscale = GetSpeakerVol( yaw, pitch, mono, 0.0, ISPEAKER_RIGHT_FRONT, 2, false);
  336. lfscale = GetSpeakerVol( yaw, pitch, mono, 180.0, ISPEAKER_LEFT_FRONT, 2, false );
  337. }
  338. else
  339. {
  340. // stereo speakers at 45 & 135 degrees: (mono sounds mix down to 2 channels)
  341. rfscale = GetSpeakerVol( yaw, pitch, mono, 45.0, ISPEAKER_RIGHT_FRONT, 4, true );
  342. lfscale = GetSpeakerVol( yaw, pitch, mono, 135.0, ISPEAKER_LEFT_FRONT, 4, true );
  343. rrscale = GetSpeakerVol( yaw, pitch, mono, 315.0, ISPEAKER_RIGHT_REAR, 4, true );
  344. lrscale = GetSpeakerVol( yaw, pitch, mono, 225.0, ISPEAKER_LEFT_REAR, 4, true );
  345. // add sounds coming from rear (quieter)
  346. rfscale = clamp((rfscale + rrscale * 0.75), 0.0, 1.0);
  347. lfscale = clamp((lfscale + lrscale * 0.75), 0.0, 1.0);
  348. rrscale = 0;
  349. lrscale = 0;
  350. //DevMsg("lfscale=%f rfscale=%f lrscale=%f rrscale=%f\n",lfscale,rfscale,lrscale,rrscale);
  351. //DevMsg("pitch=%f yaw=%f \n",pitch, yaw);
  352. }
  353. goto SpatialExit;
  354. }
  355. if ( bSurround && !bSurroundCenter )
  356. {
  357. // 4 ch surround
  358. // linearly scale with radial distance from asource to FR, FL, RR, RL
  359. // where FR = 45 degrees, FL = 135, RR = 315 (-45), RL = 225 (-135)
  360. if ( nWaveType == CHAR_DIRSTEREO )
  361. {
  362. // select a different speaker falloff curve specifically for this mode
  363. rfscale = GetSpeakerVol( yaw, pitch, mono, 45.0, ISPEAKER_DIR_STEREO, 4, false );
  364. lfscale = GetSpeakerVol( yaw, pitch, mono, 135.0, ISPEAKER_DIR_STEREO, 4, false );
  365. rrscale = GetSpeakerVol( yaw, pitch, mono, 315.0, ISPEAKER_DIR_STEREO, 4, false );
  366. lrscale = GetSpeakerVol( yaw, pitch, mono, 225.0, ISPEAKER_DIR_STEREO, 4, false );
  367. }
  368. else
  369. {
  370. rfscale = GetSpeakerVol( yaw, pitch, mono, 45.0, ISPEAKER_RIGHT_FRONT, 4, false );
  371. lfscale = GetSpeakerVol( yaw, pitch, mono, 135.0, ISPEAKER_LEFT_FRONT, 4, false );
  372. rrscale = GetSpeakerVol( yaw, pitch, mono, 315.0, ISPEAKER_RIGHT_REAR, 4, false );
  373. lrscale = GetSpeakerVol( yaw, pitch, mono, 225.0, ISPEAKER_LEFT_REAR, 4, false );
  374. }
  375. // DevMsg("lfscale=%f rfscale=%f lrscale=%f rrscale=%f\n",lfscale,rfscale,lrscale,rrscale);
  376. // DevMsg("pitch=%f yaw=%f \n",pitch, yaw);
  377. goto SpatialExit;
  378. }
  379. if ( bSurround && bSurroundCenter )
  380. {
  381. // 5 ch surround
  382. // linearly scale with radial distance from asource to FR, FC, FL, RR, RL
  383. // where FR = 45 degrees, FC = 90, FL = 135, RR = 315 (-45), RL = 225 (-135)
  384. rfscale = GetSpeakerVol( yaw, pitch, mono, 45.0, ISPEAKER_RIGHT_FRONT, 5, false );
  385. fcscale = GetSpeakerVol( yaw, pitch, mono, 90.0, ISPEAKER_CENTER_FRONT, 5, false );
  386. lfscale = GetSpeakerVol( yaw, pitch, mono, 135.0, ISPEAKER_LEFT_FRONT, 5, false );
  387. rrscale = GetSpeakerVol( yaw, pitch, mono, 315.0, ISPEAKER_RIGHT_REAR, 5, false );
  388. lrscale = GetSpeakerVol( yaw, pitch, mono, 225.0, ISPEAKER_LEFT_REAR, 5, false );
  389. //DevMsg("lfscale=%f center= %f rfscale=%f lrscale=%f rrscale=%f\n",lfscale,fcscale, rfscale,lrscale,rrscale);
  390. //DevMsg("pitch=%f yaw=%f \n",pitch, yaw);
  391. goto SpatialExit;
  392. }
  393. SpatialExit:
  394. // scale volumes in each quadrant by distance attenuation.
  395. // volumes are 0-255:
  396. // gain is 0.0->1.0, rscale is 0.0->1.0, so scale is 0.0->1.0
  397. // master_vol is 0->255, so rightvol is 0->255
  398. volume[IFRONT_RIGHT] = master_vol * gain * rfscale;
  399. volume[IFRONT_LEFT] = master_vol * gain * lfscale;
  400. volume[IFRONT_RIGHT] = clamp( volume[IFRONT_RIGHT], 0, 255 );
  401. volume[IFRONT_LEFT] = clamp( volume[IFRONT_LEFT], 0, 255 );
  402. if ( bSurround )
  403. {
  404. volume[IREAR_RIGHT] = master_vol * gain * rrscale;
  405. volume[IREAR_LEFT] = master_vol * gain * lrscale;
  406. volume[IREAR_RIGHT] = clamp( volume[IREAR_RIGHT], 0, 255 );
  407. volume[IREAR_LEFT] = clamp( volume[IREAR_LEFT], 0, 255 );
  408. if ( bSurroundCenter )
  409. {
  410. volume[IFRONT_CENTER] = master_vol * gain * fcscale;
  411. volume[IFRONT_CENTER0] = 0.0;
  412. volume[IFRONT_CENTER] = clamp( volume[IFRONT_CENTER], 0, 255);
  413. }
  414. }
  415. }
  416. void DEBUG_DrawSpeakerValues( float volume[CCHANVOLUMES/2] )
  417. {
  418. float startY = 0.66;
  419. float totalY = 0.25;
  420. float startX = 0.0;
  421. float endX = 0.25 * ( 9.0 / 16.0 );
  422. /* float stepX = (float)(endX / (float)180);*/
  423. char valueString[32];
  424. startX += (((float) 1.5 * endX) + 0.01 );
  425. float flMidX = startX + ( endX * 0.5 );
  426. /* float flMidY = startY - ( totalY * 0.5);*/
  427. CDebugOverlay::AddScreenTextOverlay(flMidX , startY - totalY -0.04, .01, 0, 0, 255, 255, "#");
  428. CDebugOverlay::AddScreenTextOverlay(flMidX , startY + 0.04, .01, 0, 0, 255, 255, "#");
  429. sprintf( valueString, "%.3f", volume[IFRONT_CENTER] );
  430. CDebugOverlay::AddScreenTextOverlay(flMidX -0.01 , startY - totalY -0.015, .01, 255, 255, 255, 255, valueString );
  431. int nCenterVol = volume[IFRONT_CENTER] * 15;
  432. for(int i = 1; i <= nCenterVol; i++ )
  433. {
  434. CDebugOverlay::AddScreenTextOverlay(flMidX, startY - totalY -0.04 - (float)i * 0.005, .01, 0, 255, 0, 255, "#");
  435. }
  436. sprintf( valueString, "%.3f", volume[IFRONT_RIGHT] );
  437. CDebugOverlay::AddScreenTextOverlay(flMidX + endX * 0.5, startY - totalY -0.015, .01, 255, 255, 255, 255, valueString );
  438. int nFrontRightVol = volume[IFRONT_RIGHT] * 15;
  439. for(int i = 1; i <= nFrontRightVol; i++ )
  440. {
  441. CDebugOverlay::AddScreenTextOverlay(flMidX + (float)i * 0.005, startY - totalY -0.04, .01, 0, 255, 0, 255, "#");
  442. }
  443. sprintf( valueString, "%.3f", volume[IFRONT_LEFT] );
  444. CDebugOverlay::AddScreenTextOverlay(flMidX - endX * 0.5, startY - totalY -0.015, .01, 255, 255, 255, 255, valueString );
  445. int nFrontLeftVol = volume[IFRONT_LEFT] * 15;
  446. for(int i = 1; i <= nFrontLeftVol; i++ )
  447. {
  448. CDebugOverlay::AddScreenTextOverlay(flMidX - (float)i * 0.005, startY - totalY -0.04, .01, 0, 255, 0, 255, "#");
  449. }
  450. sprintf( valueString, "%.3f", volume[IREAR_RIGHT] );
  451. CDebugOverlay::AddScreenTextOverlay(flMidX + endX * 0.5, startY + 0.015, .01, 255, 255, 255, 255, valueString );
  452. int nRearRightVol = volume[IREAR_RIGHT] * 15;
  453. for(int i = 1; i <= nRearRightVol; i++ )
  454. {
  455. CDebugOverlay::AddScreenTextOverlay(flMidX + (float)i * 0.005, startY + 0.04, .01, 0, 255, 0, 255, "#");
  456. }
  457. sprintf( valueString, "%.3f", volume[IREAR_LEFT] );
  458. CDebugOverlay::AddScreenTextOverlay(flMidX - endX * 0.5, startY + 0.015, .01, 255, 255, 255, 255, valueString );
  459. int nRearLeftVol = volume[IREAR_LEFT] * 15;
  460. for(int i = 1; i <= nRearLeftVol; i++ )
  461. {
  462. CDebugOverlay::AddScreenTextOverlay(flMidX - (float)i * 0.005, startY + 0.04, .01, 0, 255, 0, 255, "#");
  463. }
  464. }
  465. #define PI 3.14159265
  466. static void InterpSpeakerVol( float flRadialWeight, snd_pan_mode_t nPanMode, float flExponent, float flYawSource, float flSpeakerMin, float flSpeakerMax, float &flMinValue, float &flMaxValue, bool bDraw = true)
  467. {
  468. float flFactor = ( flYawSource - flSpeakerMin ) / (flSpeakerMax - flSpeakerMin );
  469. float flOriginalFactor = flFactor;
  470. if( flRadialWeight > 0.0 && nPanMode != SND_PAN_GLDSRC )
  471. {
  472. float flRadialFactor = 1.0 - ( FastCos( flFactor * PI ) + 1.0 ) * 0.5;
  473. float flRadialDiff = flRadialFactor - flFactor;
  474. flFactor = flFactor + ( flRadialDiff * flRadialWeight );
  475. }
  476. switch( nPanMode )
  477. {
  478. default:
  479. case SND_PAN_EXP:
  480. {
  481. flMinValue = 1.0 - FastPow( flFactor, flExponent );
  482. flMaxValue = 1.0 - FastPow( 1.0 - flFactor, flExponent );
  483. break;
  484. }
  485. case SND_PAN_EQ_POW:
  486. {
  487. // equal power pan
  488. float flFactorAngle = flFactor * ( PI * 0.5);
  489. FastSinCos( flFactorAngle, &flMaxValue, &flMinValue );
  490. break;
  491. }
  492. case SND_PAN_GLDSRC:
  493. {
  494. // goldsrc pan
  495. flMinValue = ( FastCos( flFactor * PI ) + 1.0 ) * 0.5;
  496. flMaxValue = 1.0 - flMinValue;
  497. break;
  498. }
  499. }
  500. flMinValue = clamp( flMinValue, 0.0, 1.0 );
  501. flMaxValue = clamp( flMaxValue, 0.0, 1.0 );
  502. if( snd_debug_panlaw.GetInt() && bDraw )
  503. {
  504. DEBUG_DrawPanCurvesLocation( flYawSource, flSpeakerMin, flSpeakerMax, flOriginalFactor, flMinValue, flMaxValue );
  505. }
  506. }
  507. void DEBUG_DrawPanCurves(void)
  508. {
  509. float startY = 0.66;
  510. float totalY = 0.25;
  511. float startX = 0.0;
  512. float endX = 0.25 * ( 9.0 / 16.0 );
  513. float stepX = (float)(endX / (float)180);
  514. float flMinValue, flMaxValue;
  515. // for( int nOption = 0; nOption < 2; nOption++ )
  516. // {
  517. snd_pan_mode_t nPanMode = (snd_pan_mode_t ) g_snd_headphone_pan_mode;
  518. float flExponent = g_snd_headphone_pan_exponent;
  519. float flRadialPan = g_snd_headphone_pan_radial_weight;
  520. float flFrontSpeakerPos = g_snd_front_headphone_position;
  521. float flRearSpeakerPos = g_snd_rear_headphone_position;
  522. if( snd_surround.GetInt() > 0 )
  523. {
  524. nPanMode = (snd_pan_mode_t ) g_snd_stereo_speaker_pan_mode;
  525. flExponent = g_snd_stereo_speaker_pan_exponent;
  526. flRadialPan = g_snd_stereo_speaker_pan_radial_weight;
  527. CDebugOverlay::AddScreenTextOverlay(startX + (endX * 0.2), startY + 0.01, .1, 250, 250, 200, 255, "Speaker Pan Law");
  528. if( snd_surround.GetInt() == 2 )
  529. {
  530. flFrontSpeakerPos = g_snd_front_stereo_speaker_position;
  531. flRearSpeakerPos = g_snd_rear_stereo_speaker_position;
  532. }
  533. else
  534. {
  535. flExponent = g_snd_surround_speaker_pan_exponent;
  536. flRadialPan = g_snd_surround_speaker_pan_radial_weight;
  537. flFrontSpeakerPos = g_snd_front_surround_speaker_position;
  538. flRearSpeakerPos = g_snd_rear_surround_speaker_position;
  539. nPanMode = (snd_pan_mode_t ) g_snd_surround_speaker_pan_mode;
  540. }
  541. }
  542. else
  543. {
  544. CDebugOverlay::AddScreenTextOverlay(startX + (endX * 0.2), startY + 0.01, .1, 250, 250, 200, 255, "Headphone Pan Law");
  545. }
  546. if(nPanMode == SND_PAN_EQ_POW )
  547. {
  548. CDebugOverlay::AddScreenTextOverlay(startX + (endX * 0.2), startY + 0.03, .1, 250, 250, 200, 255, "Equal Power");
  549. }
  550. else if(nPanMode == SND_PAN_EXP )
  551. {
  552. CDebugOverlay::AddScreenTextOverlay(startX + (endX * 0.2), startY + 0.03, .1, 250, 250, 200, 255, "Exponential");
  553. }
  554. else if(nPanMode == SND_PAN_GLDSRC )
  555. {
  556. CDebugOverlay::AddScreenTextOverlay(startX + (endX * 0.2), startY + 0.03, .1, 250, 250, 200, 255, "Gold Source");
  557. }
  558. //startX += (((float) nOption * endX) + 0.01 );
  559. for( int nSource = 0; nSource <= 180; nSource++ )
  560. {
  561. InterpSpeakerVol( flRadialPan, nPanMode, flExponent, (float) nSource, 0.0, 180.0, flMinValue, flMaxValue, false );
  562. CDebugOverlay::AddScreenTextOverlay(startX + (stepX * (float) nSource), startY - (flMinValue*totalY), .01, 0, 255, 0, 255, "+");
  563. CDebugOverlay::AddScreenTextOverlay(startX + (stepX * (float) nSource), startY - (flMaxValue*totalY), .01, 0, 255, 0, 255, "+");
  564. }
  565. startX += (((float) 1.5 * endX) + 0.01 );
  566. float flMidX = startX + ( endX * 0.5 );
  567. float flMidY = startY - ( totalY * 0.5);
  568. for( int nSource = 0; nSource <= 180; nSource++ )
  569. {
  570. FastSinCos( (float)nSource * 0.01745329251994329500 * 2.0, &flMaxValue, &flMinValue );
  571. CDebugOverlay::AddScreenTextOverlay(flMidX + flMaxValue * endX *0.5, flMidY + -(flMinValue*totalY*0.5), .01, 0, 255, 0, 255, "*");
  572. }
  573. CDebugOverlay::AddScreenTextOverlay(flMidX + 1.0 * endX * 0.38, flMidY + (0.0*totalY*0.38), .01, 0, 255, 0, 255, ">");
  574. CDebugOverlay::AddScreenTextOverlay(flMidX - 1.0 * endX * 0.38, flMidY + (0.0*totalY*0.38), .01, 0, 255, 0, 255, "<");
  575. CDebugOverlay::AddScreenTextOverlay(flMidX + 0.0 * endX *0.38, flMidY - (1.0*totalY*0.38), .01, 0, 255, 0, 255, "^");
  576. float flSin, flCos;
  577. FastSinCos( (flFrontSpeakerPos+90 ) * 0.01745329251994329500, &flSin, &flCos );
  578. CDebugOverlay::AddScreenTextOverlay(flMidX + flCos * (endX * 0.46), flMidY - (flSin*totalY*0.46), .01, 255, 255, 0, 255, "*");
  579. FastSinCos( -(flFrontSpeakerPos+270 ) * 0.01745329251994329500, &flSin, &flCos );
  580. CDebugOverlay::AddScreenTextOverlay(flMidX + flCos * (endX * 0.46), flMidY - (flSin*totalY*0.46), .01, 255, 255, 0, 255, "*");
  581. FastSinCos( (flRearSpeakerPos+90 ) * 0.01745329251994329500, &flSin, &flCos );
  582. CDebugOverlay::AddScreenTextOverlay(flMidX + flCos * (endX * 0.42), flMidY - (flSin*totalY * 0.42), .01, 0, 255, 255, 255, "*");
  583. FastSinCos( -(flRearSpeakerPos+270 ) * 0.01745329251994329500, &flSin, &flCos );
  584. CDebugOverlay::AddScreenTextOverlay(flMidX + flCos * (endX * 0.42), flMidY - (flSin*totalY * 0.42), .01, 0, 255, 255, 255, "*");
  585. // }
  586. }
  587. static float InterpPitchAngle( float flPitchAngle, float flMono )
  588. {
  589. float flNewMono = flMono;
  590. // mono goes from 0.0 to 1.0 as listener moves into 'mono' radius of sound source.
  591. // Also, as pitch_angle to sound source approaches 90 (sound above/below listener), sounds become mono.
  592. // convert pitch angle to 0-90 absolute pitch
  593. if ( flPitchAngle < 0)
  594. flPitchAngle += 360;
  595. if ( flPitchAngle > 180)
  596. flPitchAngle = 360 - flPitchAngle;
  597. if ( flPitchAngle > 90)
  598. flPitchAngle = 90 - (flPitchAngle - 90);
  599. // calculate additional mono crossfade due to pitch angle
  600. if ( flPitchAngle > PITCH_ANGLE_THRESHOLD )
  601. {
  602. float xfade = ( flPitchAngle - PITCH_ANGLE_THRESHOLD ) / ( 90.0 - PITCH_ANGLE_THRESHOLD ); // 0.0 -> 1.0 as angle 45->90
  603. flNewMono = clamp( flNewMono + xfade, 0.0, 1.0 );
  604. }
  605. return flNewMono;
  606. }
  607. static float InterpMonoSpread( float flMono, float flScale, int ispeaker, int cspeaker, bool fmix2channels )
  608. {
  609. Assert(flMono <= 1.0 && flMono >= 0.0);
  610. Assert( flScale <= 1.0 && flScale >= 0.0 );
  611. // crossfade speaker volumes towards mono with increased pitch angle of sound source
  612. float flNewScale = XfadeSpeakerVolToMono( flScale, flMono, ispeaker, cspeaker, fmix2channels );
  613. Assert( flScale <= 1.0 && flScale >= 0.0);
  614. return flNewScale;
  615. }
  616. //////////////////////////////////////////////////////////////////////////
  617. // float only version
  618. //////////////////////////////////////////////////////////////////////////
  619. void Device_SpatializeChannel( int nSlot, float volume[CCHANVOLUMES/2], const Vector& sourceDir, float mono, float flRearToStereoScale /* = 0.75 */ )
  620. {
  621. VPROF("CAudioDeviceBase::SpatializeChannel - 2");
  622. float rfscale, rrscale, lfscale, lrscale, fcscale;
  623. bool bSurround = g_AudioDevice->IsSurround();
  624. bool bSurroundCenter = g_AudioDevice->IsSurroundCenter();
  625. bool bHeadphone = g_AudioDevice->IsHeadphone();
  626. fcscale = rfscale = lfscale = rrscale = lrscale = 0.0;
  627. // clear volumes
  628. for (int i = 0; i < CCHANVOLUMES/2; i++)
  629. volume[i] = 0;
  630. // linear crossfader for 2, 4 or 5 speakers, using polar coord. separation angle as linear basis
  631. // get pitch & yaw angle from listener origin to sound source
  632. QAngle angles;
  633. float pitch;
  634. float source_yaw;
  635. float yaw;
  636. // sourceDir = sourcePos - playerPos
  637. VectorAngles(sourceDir, angles);
  638. pitch = angles[PITCH];
  639. source_yaw = angles[YAW];
  640. // adjust mono spread based on pitch angle
  641. float flMono = InterpPitchAngle( pitch, mono );
  642. // get 2d listener yaw angle from listener right
  643. QAngle angles2d;
  644. Vector source2d;
  645. float listener_yaw;
  646. source2d.x = listener_right[ nSlot ].x;
  647. source2d.y = listener_right[ nSlot ].y;
  648. source2d.z = 0.0;
  649. VectorNormalize(source2d);
  650. // convert right vector to euler angles (yaw & pitch)
  651. VectorAngles(source2d, angles2d);
  652. listener_yaw = angles2d[YAW];
  653. // get yaw of sound source, with listener_yaw as reference 0.
  654. yaw = AngleDiff( source_yaw, listener_yaw );
  655. if ( yaw < 0.0 )
  656. {
  657. yaw += 360;
  658. }
  659. // default to stereo
  660. float flFrontCenter = 90;
  661. // pre-rotation
  662. float flFront = 90;
  663. float flRear = 90;
  664. bool bMixToTwoChannels = true;
  665. int nSpkeakerCount = 4;
  666. snd_pan_mode_t nPanMode = ( snd_pan_mode_t ) g_snd_stereo_speaker_pan_mode;
  667. float flPanExponent = g_snd_stereo_speaker_pan_exponent;
  668. float flRadialPan = g_snd_stereo_speaker_pan_radial_weight;
  669. if ( bHeadphone )
  670. {
  671. // headphone mix: (NO HRTF)
  672. // override with phone settings
  673. flFront = clamp( g_snd_front_headphone_position, 0.0, 90.0 );
  674. flRear = clamp( g_snd_rear_headphone_position, flFront, 180.0 );
  675. bMixToTwoChannels = true;
  676. nSpkeakerCount = 4;
  677. nPanMode = ( snd_pan_mode_t ) g_snd_headphone_pan_mode;
  678. flPanExponent = g_snd_headphone_pan_exponent;
  679. flRadialPan = g_snd_headphone_pan_radial_weight;
  680. }
  681. else if( bSurround && !bSurroundCenter )
  682. {
  683. // override with quad settings
  684. flFront = clamp( g_snd_front_surround_speaker_position, 0.0, 90.0 );
  685. flRear = clamp( g_snd_rear_surround_speaker_position, flFront, 180.0 );
  686. flPanExponent = g_snd_surround_speaker_pan_exponent;
  687. flRadialPan = g_snd_surround_speaker_pan_radial_weight;
  688. nPanMode = ( snd_pan_mode_t ) g_snd_surround_speaker_pan_mode;
  689. bMixToTwoChannels = false;
  690. nSpkeakerCount = 4;
  691. }
  692. else if ( bSurround && bSurroundCenter )
  693. {
  694. // override with 5.1 settings
  695. flFront = clamp( g_snd_front_surround_speaker_position, 0.0, 90.0 );
  696. flRear = clamp( g_snd_rear_surround_speaker_position, flFront, 180.0 );
  697. flPanExponent = g_snd_surround_speaker_pan_exponent;
  698. flRadialPan = g_snd_surround_speaker_pan_radial_weight;
  699. nPanMode = ( snd_pan_mode_t ) g_snd_surround_speaker_pan_mode;
  700. bMixToTwoChannels = false;
  701. nSpkeakerCount = 5;
  702. }
  703. else // stereo
  704. {
  705. // override with stereo settings
  706. flFront = clamp( g_snd_front_stereo_speaker_position, 0.0, 90.0 );
  707. flRear = clamp( g_snd_rear_stereo_speaker_position, flFront, 180.0 );
  708. bMixToTwoChannels = true;
  709. nSpkeakerCount = 4; // stereo is processed as 4 speakers (just for backward compatibility
  710. }
  711. float flFrontRight = 90.0 - flFront;
  712. float flFrontLeft = 90.0 + flFront;
  713. float flRearRight = 450.0 - flRear;
  714. float flRearLeft= 90.0 + flRear;
  715. // if there's a center speaker we interp from right->center->left
  716. if( bSurroundCenter )
  717. {
  718. if( yaw >= flFrontRight && yaw < flFrontCenter )
  719. {
  720. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flFrontRight, flFrontCenter, rfscale, fcscale );
  721. }
  722. else if( yaw >= flFrontCenter && yaw < flFrontLeft )
  723. {
  724. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flFrontCenter, flFrontLeft, fcscale, lfscale );
  725. }
  726. } // otw directly right->left
  727. else
  728. {
  729. if( yaw >= flFrontRight && yaw < flFrontLeft )
  730. {
  731. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flFrontRight, flFrontLeft, rfscale, lfscale );
  732. }
  733. }
  734. if ( yaw >= flFrontLeft && yaw < flRearLeft )
  735. {
  736. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flFrontLeft, flRearLeft, lfscale, lrscale );
  737. }
  738. else if ( yaw >= flRearLeft && yaw < flRearRight )
  739. {
  740. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flRearLeft, flRearRight, lrscale, rrscale );
  741. }
  742. // the circle wraps between frontright and rearright
  743. else if ( yaw >= flRearRight ) // between RearRight & 0/360
  744. {
  745. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flRearRight, 360 + flFrontRight, rrscale, rfscale );
  746. }
  747. else if ( yaw < flFrontRight ) // between 0/360 and FrontRight
  748. {
  749. InterpSpeakerVol( flRadialPan, nPanMode, flPanExponent, yaw, flRearRight - 360, flFrontRight, rrscale, rfscale );
  750. }
  751. Assert( fcscale <= 1.0 && fcscale >= 0.0 );
  752. if( bSurroundCenter )
  753. {
  754. fcscale = InterpMonoSpread( flMono, fcscale, ISPEAKER_CENTER_FRONT, nSpkeakerCount, bMixToTwoChannels );
  755. }
  756. Assert( rfscale <= 1.0 && rfscale >= 0.0 );
  757. rfscale = InterpMonoSpread( flMono, rfscale, ISPEAKER_RIGHT_FRONT, nSpkeakerCount, bMixToTwoChannels );
  758. Assert( lfscale <= 1.0 && lfscale >= 0.0 );
  759. lfscale = InterpMonoSpread( flMono, lfscale, ISPEAKER_LEFT_FRONT, nSpkeakerCount, bMixToTwoChannels );
  760. Assert( rrscale <= 1.0 && rrscale >= 0.0 );
  761. rrscale = InterpMonoSpread( flMono, rrscale, ISPEAKER_RIGHT_REAR, nSpkeakerCount, bMixToTwoChannels );
  762. Assert( lrscale <= 1.0 && lrscale >= 0.0 );
  763. lrscale = InterpMonoSpread( flMono, lrscale, ISPEAKER_LEFT_REAR, nSpkeakerCount, bMixToTwoChannels );
  764. // add sounds coming from rear (potentially scaled)
  765. if( !bSurround )
  766. {
  767. rfscale = rfscale + ( rrscale * flRearToStereoScale );
  768. lfscale = lfscale + ( lrscale * flRearToStereoScale );
  769. rrscale = 0;
  770. lrscale = 0;
  771. }
  772. volume[IFRONT_RIGHT] = clamp( rfscale, 0.0, 1.0 );
  773. volume[IFRONT_LEFT] = clamp( lfscale, 0.0, 1.0 );
  774. if ( bSurround )
  775. {
  776. volume[IREAR_RIGHT] = clamp( rrscale, 0.0, 1.0 );
  777. volume[IREAR_LEFT] = clamp( lrscale, 0.0, 1.0 );
  778. if ( bSurroundCenter )
  779. {
  780. volume[IFRONT_CENTER] = clamp( fcscale, 0.0, 1.0 );
  781. volume[IFRONT_CENTER0] = 0.0;
  782. }
  783. }
  784. if(snd_debug_panlaw.GetInt())
  785. {
  786. DEBUG_DrawSpeakerValues( volume );
  787. }
  788. }
  789. // old skool integer version
  790. ConVar snd_rear_speaker_scale("snd_rear_speaker_scale", "1.0", FCVAR_CHEAT, "How much to scale rear speaker contribution to front stereo output" );
  791. void Device_ApplyDSPEffects( int idsp, portable_samplepair_t *pbuffront, portable_samplepair_t *pbufrear, portable_samplepair_t *pbufcenter, int samplecount)
  792. {
  793. VPROF("CAudioDeviceBase::ApplyDSPEffects");
  794. DEBUG_StartSoundMeasure( 1, samplecount );
  795. DSP_Process( idsp, pbuffront, pbufrear, pbufcenter, samplecount );
  796. DEBUG_StopSoundMeasure( 1, samplecount );
  797. }
  798. void Device_MixUpsample( int sampleCount, int filtertype )
  799. {
  800. VPROF( "CAudioDeviceBase::MixUpsample" );
  801. paintbuffer_t *pPaint = MIX_GetCurrentPaintbufferPtr();
  802. int ifilter = pPaint->ifilter;
  803. Assert (ifilter < CPAINTFILTERS);
  804. S_MixBufferUpsample2x( sampleCount, pPaint->pbuf, &(pPaint->fltmem[ifilter][0]), CPAINTFILTERMEM, filtertype );
  805. if ( pPaint->fsurround )
  806. {
  807. Assert( pPaint->pbufrear );
  808. S_MixBufferUpsample2x( sampleCount, pPaint->pbufrear, &(pPaint->fltmemrear[ifilter][0]), CPAINTFILTERMEM, filtertype );
  809. if ( pPaint->fsurround_center )
  810. {
  811. Assert( pPaint->pbufcenter );
  812. S_MixBufferUpsample2x( sampleCount, pPaint->pbufcenter, &(pPaint->fltmemcenter[ifilter][0]), CPAINTFILTERMEM, filtertype );
  813. }
  814. }
  815. // make sure on next upsample pass for this paintbuffer, new filter memory is used
  816. pPaint->ifilter++;
  817. }
  818. void Device_Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  819. {
  820. VPROF( "CAudioDeviceBase::Mix8Mono" );
  821. float volume[CCHANVOLUMES];
  822. paintbuffer_t *pPaint = MIX_GetCurrentPaintbufferPtr();
  823. if ( !MIX_ScaleChannelVolume( pPaint, pChannel, volume, 1) )
  824. return;
  825. if ( FVolumeFrontNonZero(volume) )
  826. {
  827. Mix8MonoWavtype( pChannel, pPaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount);
  828. }
  829. if ( pPaint->fsurround )
  830. {
  831. if ( FVolumeRearNonZero(volume) )
  832. {
  833. Assert( pPaint->pbufrear );
  834. Mix8MonoWavtype( pChannel, pPaint->pbufrear + outputOffset, &volume[IREAR_LEFT], (byte *)pData, inputOffset, rateScaleFix, outCount );
  835. }
  836. if ( pPaint->fsurround_center && FVolumeCenterNonZero(volume) )
  837. {
  838. Assert( pPaint->pbufcenter );
  839. Mix8MonoWavtype( pChannel, pPaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], (byte *)pData, inputOffset, rateScaleFix, outCount );
  840. }
  841. }
  842. }
  843. void Device_Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  844. {
  845. VPROF( "CAudioDeviceBase::Mix8Stereo" );
  846. float volume[CCHANVOLUMES];
  847. paintbuffer_t *pPaint = MIX_GetCurrentPaintbufferPtr();
  848. if ( !MIX_ScaleChannelVolume( pPaint, pChannel, volume, 2 ) )
  849. return;
  850. if ( FVolumeFrontNonZero(volume) )
  851. {
  852. Mix8StereoWavtype( pChannel, pPaint->pbuf + outputOffset, volume, (byte *)pData, inputOffset, rateScaleFix, outCount );
  853. }
  854. if ( pPaint->fsurround )
  855. {
  856. if ( FVolumeRearNonZero(volume) )
  857. {
  858. Assert( pPaint->pbufrear );
  859. Mix8StereoWavtype( pChannel, pPaint->pbufrear + outputOffset, &volume[IREAR_LEFT], (byte *)pData, inputOffset, rateScaleFix, outCount );
  860. }
  861. if ( pPaint->fsurround_center && FVolumeCenterNonZero(volume) )
  862. {
  863. Assert( pPaint->pbufcenter );
  864. Mix8StereoWavtype( pChannel, pPaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], (byte *)pData, inputOffset, rateScaleFix, outCount );
  865. }
  866. }
  867. }
  868. void Device_Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  869. {
  870. VPROF( "CAudioDeviceBase::Mix16Mono" );
  871. float volume[CCHANVOLUMES];
  872. paintbuffer_t *pPaint = MIX_GetCurrentPaintbufferPtr();
  873. if ( !MIX_ScaleChannelVolume( pPaint, pChannel, volume, 1 ) )
  874. return;
  875. if ( FVolumeFrontNonZero(volume) )
  876. {
  877. Mix16MonoWavtype( pChannel, pPaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
  878. }
  879. if ( pPaint->fsurround )
  880. {
  881. if ( FVolumeRearNonZero(volume) )
  882. {
  883. Assert( pPaint->pbufrear );
  884. Mix16MonoWavtype( pChannel, pPaint->pbufrear + outputOffset, &volume[IREAR_LEFT], pData, inputOffset, rateScaleFix, outCount );
  885. }
  886. if ( pPaint->fsurround_center && FVolumeCenterNonZero(volume) )
  887. {
  888. Assert( pPaint->pbufcenter );
  889. Mix16MonoWavtype( pChannel, pPaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], pData, inputOffset, rateScaleFix, outCount );
  890. }
  891. }
  892. }
  893. void Device_Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, fixedint rateScaleFix, int outCount, int timecompress )
  894. {
  895. VPROF( "CAudioDeviceBase::Mix16Stereo" );
  896. float volume[CCHANVOLUMES];
  897. paintbuffer_t *pPaint = MIX_GetCurrentPaintbufferPtr();
  898. if ( !MIX_ScaleChannelVolume( pPaint, pChannel, volume, 2 ) )
  899. return;
  900. if ( FVolumeFrontNonZero(volume) )
  901. {
  902. Mix16StereoWavtype( pChannel, pPaint->pbuf + outputOffset, volume, pData, inputOffset, rateScaleFix, outCount );
  903. }
  904. if ( pPaint->fsurround )
  905. {
  906. if ( FVolumeRearNonZero(volume) )
  907. {
  908. Assert( pPaint->pbufrear );
  909. Mix16StereoWavtype( pChannel, pPaint->pbufrear + outputOffset, &volume[IREAR_LEFT], pData, inputOffset, rateScaleFix, outCount );
  910. }
  911. if ( pPaint->fsurround_center && FVolumeCenterNonZero(volume) )
  912. {
  913. Assert( pPaint->pbufcenter );
  914. Mix16StereoWavtype( pChannel, pPaint->pbufcenter + outputOffset, &volume[IFRONT_CENTER], pData, inputOffset, rateScaleFix, outCount );
  915. }
  916. }
  917. }
  918. #if USE_AUDIO_DEVICE_V1
  919. // Null Audio Device
  920. class CAudioDeviceNull : public CAudioDeviceBase
  921. {
  922. public:
  923. CAudioDeviceNull()
  924. {
  925. m_pName = "Sound Disabled";
  926. m_nChannels = 2;
  927. m_nSampleBits = 16;
  928. m_nSampleRate = SOUND_DMA_SPEED;
  929. m_bIsActive = false;
  930. }
  931. bool IsActive( void ) { return false; }
  932. bool Init( void ) { return true; }
  933. void Shutdown( void ) {}
  934. void Pause( void ) {}
  935. void UnPause( void ) {}
  936. int64 PaintBegin( float, int64, int64 ) { return 0; }
  937. void PaintEnd( void ) {}
  938. int GetOutputPosition( void ) { return 0; }
  939. void ClearBuffer( void ) {}
  940. void TransferSamples( int end ) {}
  941. int DeviceSampleCount( void ) { return 0; }
  942. };
  943. IAudioDevice *Audio_GetNullDevice( void )
  944. {
  945. return new CAudioDeviceNull;
  946. }
  947. #else
  948. void IAudioDevice2::TransferSamples( uint32 )
  949. {
  950. CAudioMixBuffer mixBuffers[SOUND_DEVICE_MAX_CHANNELS];
  951. const portable_samplepair_t *pFront = PAINTBUFFER;
  952. const portable_samplepair_t *pRear = REARPAINTBUFFER;
  953. const portable_samplepair_t *pCenter = CENTERPAINTBUFFER;
  954. float flMasterVolume = S_GetMasterVolume();
  955. for ( int i = 0; i < MIX_BUFFER_SIZE; i++ )
  956. {
  957. mixBuffers[0].m_flData[i] = pFront[i].left;
  958. mixBuffers[1].m_flData[i] = pFront[i].right;
  959. }
  960. ScaleBuffer( mixBuffers[0].m_flData, mixBuffers[0].m_flData, flMasterVolume );
  961. ScaleBuffer( mixBuffers[1].m_flData, mixBuffers[1].m_flData, flMasterVolume );
  962. if ( IsSurroundCenter() )
  963. {
  964. for ( int i = 0; i < MIX_BUFFER_SIZE; i++ )
  965. {
  966. mixBuffers[2].m_flData[i] = pCenter[i].left;
  967. mixBuffers[3].m_flData[i] = 0;
  968. }
  969. ScaleBuffer( mixBuffers[2].m_flData, mixBuffers[2].m_flData, flMasterVolume );
  970. // this is all zeros, so scaling it to the master volume isn't necessary
  971. //ScaleBuffer( mixBuffers[3].m_flData, mixBuffers[3].m_flData, flMasterVolume );
  972. }
  973. if ( IsSurround() )
  974. {
  975. for ( int i = 0; i < MIX_BUFFER_SIZE; i++ )
  976. {
  977. mixBuffers[4].m_flData[i] = pRear[i].left;
  978. mixBuffers[5].m_flData[i] = pRear[i].right;
  979. }
  980. ScaleBuffer( mixBuffers[4].m_flData, mixBuffers[4].m_flData, flMasterVolume );
  981. ScaleBuffer( mixBuffers[5].m_flData, mixBuffers[5].m_flData, flMasterVolume );
  982. }
  983. if ( ChannelCount() > 6 )
  984. {
  985. for ( int i = 0; i < MIX_BUFFER_SIZE; i++ )
  986. {
  987. mixBuffers[6].m_flData[i] = 0;
  988. mixBuffers[7].m_flData[i] = 0;
  989. }
  990. }
  991. OutputBuffer( ChannelCount(), mixBuffers );
  992. }
  993. #endif