SoundMixer.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Sound/SoundProfile.h>
  14. #include <Engine/Sound/SoundDecoder.h>
  15. #include <Engine/Sound/SoundLibrary.h>
  16. #include <Engine/Sound/SoundData.h>
  17. #include <Engine/Sound/SoundObject.h>
  18. #include <Engine/Base/Statistics_Internal.h>
  19. #include <Engine/Base/Console.h>
  20. // asm shortcuts
  21. #define O offset
  22. #define Q qword ptr
  23. #define D dword ptr
  24. #define W word ptr
  25. #define B byte ptr
  26. #define ASMOPT 1
  27. // console variables for volume
  28. extern FLOAT snd_fSoundVolume;
  29. extern FLOAT snd_fMusicVolume;
  30. extern INDEX snd_bMono;
  31. // a bunch of local vars coming up
  32. static SLONG slMixerBufferSampleRate; // quality of destination buffer
  33. static SLONG slMixerBufferSize; // size in samples per channel of the destination buffers
  34. static void *pvMixerBuffer; // pointer to the start of the destination buffers
  35. static CSoundData *psd;
  36. static SWORD *pswSrcBuffer;
  37. static SLONG slLeftVolume, slRightVolume, slLeftFilter, slRightFilter;
  38. static SLONG slLastLeftSample, slLastRightSample, slSoundBufferSize;
  39. static FLOAT fSoundSampleRate, fPhase;
  40. static FLOAT fOfsDelta, fStep, fLeftStep, fRightStep, fLeftOfs, fRightOfs;
  41. static __int64 fixLeftOfs, fixRightOfs; // fixed integers 32:32
  42. static __int64 mmSurroundFactor, mmLeftStep, mmRightStep, mmVolumeGain;
  43. static BOOL bNotLoop, bEndOfSound;
  44. static const FLOAT f65536 = 65536.0f;
  45. static const FLOAT f4G = 4294967296.0f;
  46. static __int64 mmInvFactor = 0x00007FFF00007FFF;
  47. static __int64 mmMaskLD = 0x00000000FFFFFFFF;
  48. static __int64 mmUnsign2Sign = 0x8000800080008000;
  49. // reset mixer buffer (wipes it with zeroes and remembers pointers in static mixer variables)
  50. void ResetMixer( const SLONG *pslBuffer, const SLONG slBufferSize)
  51. {
  52. // clamp master volumes
  53. snd_fSoundVolume = Clamp(snd_fSoundVolume, 0.0f, 1.0f);
  54. snd_fMusicVolume = Clamp(snd_fMusicVolume, 0.0f, 1.0f);
  55. // cache local variables
  56. ASSERT( slBufferSize%4==0);
  57. pvMixerBuffer = (void*)pslBuffer;
  58. slMixerBufferSize = slBufferSize /2/2; // because it's stereo and 16-bit dst format
  59. slMixerBufferSampleRate = _pSound->sl_SwfeFormat.nSamplesPerSec;
  60. // wipe destination mixer buffer
  61. __asm {
  62. cld
  63. xor eax,eax
  64. mov edi,D [pvMixerBuffer]
  65. mov ecx,D [slMixerBufferSize]
  66. shl ecx,1 // *2 because of 32-bit src format
  67. rep stosd
  68. }
  69. }
  70. // copy mixer buffer to the output buffer(s)
  71. void CopyMixerBuffer_stereo( const SLONG slSrcOffset, const void *pDstBuffer, const SLONG slBytes)
  72. {
  73. ASSERT( pDstBuffer!=NULL);
  74. ASSERT( slBytes%4==0);
  75. if( slBytes<4) return;
  76. __asm {
  77. cld
  78. mov esi,D [slSrcOffset]
  79. add esi,D [pvMixerBuffer]
  80. mov edi,D [pDstBuffer]
  81. mov ecx,D [slBytes]
  82. shr ecx,2 // bytes to samples per channel
  83. rep movsd
  84. }
  85. }
  86. // copy one channel from mixer buffer to the output buffer(s)
  87. void CopyMixerBuffer_mono( const SLONG slSrcOffset, const void *pDstBuffer, const SLONG slBytes)
  88. {
  89. ASSERT( pDstBuffer!=NULL);
  90. ASSERT( slBytes%2==0);
  91. if( slBytes<4) return;
  92. __asm {
  93. mov esi,D [slSrcOffset]
  94. add esi,D [pvMixerBuffer]
  95. mov edi,D [pDstBuffer]
  96. mov ecx,D [slBytes]
  97. shr ecx,2 // bytes to samples
  98. copyLoop:
  99. movzx eax,W [esi]
  100. mov W [edi],ax
  101. add esi,4
  102. add edi,2
  103. dec ecx
  104. jnz copyLoop
  105. }
  106. }
  107. // plain conversion of mixer buffer from 32-bit to 16-bit clamped
  108. static void ConvertMixerBuffer( const SLONG slBytes)
  109. {
  110. ASSERT( slBytes%4==0);
  111. if( slBytes<4) return;
  112. __asm {
  113. cld
  114. mov esi,D [pvMixerBuffer]
  115. mov edi,D [pvMixerBuffer]
  116. mov ecx,D [slBytes]
  117. shr ecx,2 // bytes to samples (2 channels)
  118. copyLoop:
  119. movq mm0,Q [esi]
  120. packssdw mm0,mm0
  121. movd D [edi],mm0
  122. add esi,8
  123. add edi,4
  124. dec ecx
  125. jnz copyLoop
  126. emms
  127. }
  128. }
  129. // normalize mixer buffer
  130. void NormalizeMixerBuffer( const FLOAT fNormStrength, const SLONG slBytes, FLOAT &fLastNormValue)
  131. {
  132. // just convert to 16-bit if normalization isn't required
  133. ASSERT( slBytes%4==0);
  134. if( slBytes<8) return;
  135. if( fNormStrength<0.01f) {
  136. ConvertMixerBuffer(slBytes);
  137. return;
  138. }
  139. // well, I guess we'll might need to normalize a bit, so first - find maximum
  140. INDEX i;
  141. SLONG slPeak = 0;
  142. SLONG *pslSrc = (SLONG*)pvMixerBuffer;
  143. const INDEX iSamples = slBytes/2; // 16-bit was assumed -> samples (treat as mono)
  144. for( i=0; i<iSamples; i++) slPeak = Max( Abs(pslSrc[i]), slPeak);
  145. // determine normalize value and skip normalization if maximize is required (do not increase volume!)
  146. FLOAT fNormValue = 32767.0f / (FLOAT)slPeak;
  147. if( fNormValue>0.99f && fLastNormValue>0.99f) { // should be enough to tolerate
  148. fLastNormValue = 1.0f;
  149. ConvertMixerBuffer(slBytes);
  150. return;
  151. }
  152. // adjust normalize value by strength
  153. ASSERT( fNormStrength>=0 && fNormStrength<=1);
  154. fNormValue = Lerp( 1.0f, fNormValue, fNormStrength);
  155. const FLOAT fNormAdd = (fNormValue-fLastNormValue) / (iSamples/4);
  156. // normalize (and convert to 16-bit)
  157. SWORD *pswDst = (SWORD*)pvMixerBuffer;
  158. FLOAT fCurrentNormValue = fLastNormValue;
  159. for( i=0; i<iSamples; i++) {
  160. SLONG slSample = FloatToInt(pslSrc[i]*fCurrentNormValue);
  161. pswDst[i] = (SWORD)Clamp( slSample, -32767L, +32767L);
  162. fCurrentNormValue = fCurrentNormValue+fNormAdd; // interpolate normalizer
  163. if( fCurrentNormValue<fNormValue && fNormAdd<0) fCurrentNormValue = fNormValue; // clamp interpolated value
  164. else if( fCurrentNormValue>fNormValue && fNormAdd>0) fCurrentNormValue = fNormValue;
  165. }
  166. // CPrintF( "%.5f -> %.5f (%.5f) @ %.9f / %d\n", fLastNormValue, fCurrentNormValue, fNormValue, fNormAdd, iSamples);
  167. // remember normalization value
  168. fLastNormValue = fCurrentNormValue;
  169. }
  170. // mixes one mono 16-bit signed sound to destination buffer
  171. inline void MixMono( CSoundObject *pso)
  172. {
  173. _pfSoundProfile.StartTimer(CSoundProfile::PTI_RAWMIXER);
  174. #if ASMOPT == 1
  175. __asm {
  176. // convert from floats to fixints 32:16
  177. fld D [fLeftOfs]
  178. fmul D [f65536]
  179. fld D [fRightOfs]
  180. fmul D [f65536]
  181. fld D [fLeftStep]
  182. fmul D [f65536]
  183. fld D [fRightStep]
  184. fmul D [f4G]
  185. fistp Q [mmRightStep] // fixint 32:32
  186. fistp Q [mmLeftStep] // fixint 32:16
  187. fistp Q [fixRightOfs] // fixint 32:16
  188. fistp Q [fixLeftOfs] // fixint 32:16
  189. // get last played sample (for filtering purposes)
  190. movzx eax,W [slLastRightSample]
  191. movzx edx,W [slLastLeftSample]
  192. shl eax,16
  193. or eax,edx
  194. movd mm6,eax // MM6 = 0 | 0 || lastRightSample | lastLeftSample
  195. // get volume
  196. movd mm5,D [slRightVolume]
  197. movd mm0,D [slLeftVolume]
  198. psllq mm5,32
  199. por mm5,mm0 // MM5 = rightVolume || leftVolume
  200. // get filter
  201. mov eax,D [slRightFilter]
  202. mov edx,D [slLeftFilter]
  203. shl eax,16
  204. or eax,edx
  205. movd mm7,eax // MM7 = 0 | 0 || rightFilter | leftFilter
  206. // get offset of each channel inside sound and loop thru destination buffer
  207. mov W [mmRightStep],0
  208. movzx eax,W [fixLeftOfs]
  209. movzx edx,W [fixRightOfs]
  210. shl edx,16
  211. or eax,edx // EAX = right ofs frac | left ofs frac
  212. mov ebx,D [fixLeftOfs+2] // EBX = left ofs int
  213. mov edx,D [fixRightOfs+2] // EDX = right ofs int
  214. mov esi,D [pswSrcBuffer] // ESI = source sound buffer start ptr
  215. mov edi,D [pvMixerBuffer] // EDI = mixer buffer ptr
  216. mov ecx,D [slMixerBufferSize] // ECX = samples counter
  217. sampleLoop:
  218. // check if source offsets came to the end of source sound buffer
  219. cmp ebx,D [slSoundBufferSize]
  220. jl lNotEnd
  221. sub ebx,D [slSoundBufferSize]
  222. push D [bNotLoop]
  223. pop D [bEndOfSound]
  224. lNotEnd:
  225. // same for right channel
  226. cmp edx,D [slSoundBufferSize]
  227. jl rNotEnd
  228. sub edx,D [slSoundBufferSize]
  229. push D [bNotLoop]
  230. pop D [bEndOfSound]
  231. rNotEnd:
  232. // check end of sample
  233. cmp ecx,0
  234. jle loopEnd
  235. cmp D [bEndOfSound],TRUE
  236. je loopEnd
  237. // get sound samples
  238. movd mm1,D [esi+ ebx*2] // MM1 = 0 | 0 || nextLeftSample | leftSample
  239. movd mm2,D [esi+ edx*2] // MM2 = 0 | 0 || nextRightSample | RightSample
  240. psllq mm2,32
  241. por mm1,mm2 // MM1 = nextRightSample | rightSample || nextLeftSample | leftSample
  242. // calc linear interpolation factor (strength)
  243. movd mm3,eax // MM3 = 0 | 0 || right frac | left frac
  244. punpcklwd mm3,mm3
  245. psrlw mm3,1 // MM3 = rightFrac | rightFrac || leftFrac | leftFrac
  246. pxor mm3,Q [mmInvFactor] // MM3 = rightFrac | 1-rightFrac || leftFrac | 1-leftFrac
  247. // apply linear interpolation
  248. pmaddwd mm1,mm3
  249. psrad mm1,15
  250. packssdw mm1,mm1 // MM1 = ? | ? || linearRightSample | linearLeftSample
  251. // apply filter
  252. psubsw mm1,mm6
  253. pmulhw mm1,mm7
  254. psllw mm1,1
  255. paddsw mm1,mm6
  256. movq mm6,mm1
  257. // apply volume adjustment
  258. movq mm0,mm5
  259. psrad mm0,16
  260. packssdw mm0,mm0
  261. pmulhw mm1,mm0
  262. psllw mm1,1
  263. pxor mm1,Q [mmSurroundFactor]
  264. paddd mm5,Q [mmVolumeGain] // modify volume
  265. // unpack to 32bit and mix it into destination buffer
  266. punpcklwd mm1,mm1
  267. psrad mm1,16 // MM1 = finalRightSample || finalLeftSample
  268. paddd mm1,Q [edi]
  269. movq Q [edi],mm1
  270. // advance to next samples in source sound
  271. add eax,D [mmRightStep+0]
  272. adc edx,D [mmRightStep+4]
  273. add ax,W [mmLeftStep +0]
  274. adc ebx,D [mmLeftStep +2]
  275. add edi,8
  276. dec ecx
  277. jmp sampleLoop
  278. loopEnd:
  279. // store modified asm local vars
  280. mov D [fixLeftOfs +0],eax
  281. shr eax,16
  282. mov D [fixRightOfs+0],eax
  283. mov D [fixLeftOfs +2],ebx
  284. mov D [fixRightOfs+2],edx
  285. movd eax,mm6
  286. mov edx,eax
  287. and eax,0x0000FFFF
  288. shr edx,16
  289. mov D [slLastLeftSample],eax
  290. mov D [slLastRightSample],edx
  291. emms
  292. }
  293. #else
  294. // initialize some local vars
  295. SLONG slLeftSample, slRightSample, slNextSample;
  296. SLONG *pslDstBuffer = (SLONG*)pvMixerBuffer;
  297. fixLeftOfs = (__int64)(fLeftOfs * 65536.0);
  298. fixRightOfs = (__int64)(fRightOfs * 65536.0);
  299. __int64 fixLeftStep = (__int64)(fLeftStep * 65536.0);
  300. __int64 fixRightStep = (__int64)(fRightStep * 65536.0);
  301. __int64 fixSoundBufferSize = ((__int64)slSoundBufferSize)<<16;
  302. mmSurroundFactor = (__int64)(SWORD)mmSurroundFactor;
  303. // loop thru source buffer
  304. INDEX iCt = slMixerBufferSize;
  305. FOREVER
  306. {
  307. // if left channel source sample came to end of sample buffer
  308. if( fixLeftOfs >= fixSoundBufferSize) {
  309. fixLeftOfs -= fixSoundBufferSize;
  310. // if has no loop, end it
  311. bEndOfSound = bNotLoop;
  312. }
  313. // if right channel source sample came to end of sample buffer
  314. if( fixRightOfs >= fixSoundBufferSize) {
  315. fixRightOfs -= fixSoundBufferSize;
  316. // if has no loop, end it
  317. bEndOfSound = bNotLoop;
  318. }
  319. // end of buffer?
  320. if( iCt<=0 || bEndOfSound) break;
  321. // fetch one lineary interpolated sample on left channel
  322. slLeftSample = pswSrcBuffer[(fixLeftOfs>>16)+0];
  323. slNextSample = pswSrcBuffer[(fixLeftOfs>>16)+1];
  324. slLeftSample = (slLeftSample*(65535-(fixLeftOfs&65535)) + slNextSample*(fixLeftOfs&65535)) >>16;
  325. // fetch one lineary interpolated sample on right channel
  326. slRightSample = pswSrcBuffer[(fixRightOfs>>16)+0];
  327. slNextSample = pswSrcBuffer[(fixRightOfs>>16)+1];
  328. slRightSample = (slRightSample*(65535-(fixRightOfs&65535)) + slNextSample*(fixRightOfs&65535)) >>16;
  329. // filter samples
  330. slLastLeftSample += ((slLeftSample -slLastLeftSample) *slLeftFilter) >>15;
  331. slLastRightSample += ((slRightSample-slLastRightSample)*slRightFilter)>>15;
  332. // apply stereo volume to current sample
  333. slLeftSample = (slLastLeftSample * slLeftVolume) >>15;
  334. slRightSample = (slLastRightSample * slRightVolume)>>15;
  335. slRightSample = slRightSample ^ mmSurroundFactor;
  336. // mix in current sample
  337. slLeftSample += pslDstBuffer[0];
  338. slRightSample += pslDstBuffer[1];
  339. // upper clamp
  340. if( slLeftSample > MAX_SWORD) slLeftSample = MAX_SWORD;
  341. if( slRightSample > MAX_SWORD) slRightSample = MAX_SWORD;
  342. // lower clamp
  343. if( slLeftSample < MIN_SWORD) slLeftSample = MIN_SWORD;
  344. if( slRightSample < MIN_SWORD) slRightSample = MIN_SWORD;
  345. // store samples (both channels)
  346. pslDstBuffer[0] = slLeftSample;
  347. pslDstBuffer[1] = slRightSample;
  348. // modify volume `
  349. slLeftVolume += (SWORD)((mmVolumeGain>> 0)&0xFFFF);
  350. slRightVolume += (SWORD)((mmVolumeGain>>16)&0xFFFF);
  351. // advance to next sample
  352. fixLeftOfs += fixLeftStep;
  353. fixRightOfs += fixRightStep;
  354. pslDstBuffer += 4;
  355. iCt--;
  356. }
  357. #endif
  358. _pfSoundProfile.StopTimer(CSoundProfile::PTI_RAWMIXER);
  359. }
  360. // mixes one stereo 16-bit signed sound to destination buffer
  361. inline void MixStereo( CSoundObject *pso)
  362. {
  363. _pfSoundProfile.StartTimer(CSoundProfile::PTI_RAWMIXER);
  364. #if ASMOPT == 1
  365. __asm {
  366. // convert from floats to fixints 32:16
  367. fld D [fLeftOfs]
  368. fmul D [f65536]
  369. fld D [fRightOfs]
  370. fmul D [f65536]
  371. fld D [fLeftStep]
  372. fmul D [f65536]
  373. fld D [fRightStep]
  374. fmul D [f4G]
  375. fistp Q [mmRightStep] // fixint 32:32
  376. fistp Q [mmLeftStep] // fixint 32:16
  377. fistp Q [fixRightOfs] // fixint 32:16
  378. fistp Q [fixLeftOfs] // fixint 32:16
  379. // get last played sample (for filtering purposes)
  380. movzx eax,W [slLastRightSample]
  381. movzx edx,W [slLastLeftSample]
  382. shl eax,16
  383. or eax,edx
  384. movd mm6,eax // MM6 = 0 | 0 || lastRightSample | lastLeftSample
  385. // get volume
  386. movd mm5,D [slRightVolume]
  387. movd mm0,D [slLeftVolume]
  388. psllq mm5,32
  389. por mm5,mm0 // MM5 = rightVolume || leftVolume
  390. // get filter
  391. mov eax,D [slRightFilter]
  392. mov edx,D [slLeftFilter]
  393. shl eax,16
  394. or eax,edx
  395. movd mm7,eax // MM7 = 0 | 0 || rightFilter | leftFilter
  396. // get offset of each channel inside sound and loop thru destination buffer
  397. mov W [mmRightStep],0
  398. movzx eax,W [fixLeftOfs]
  399. movzx edx,W [fixRightOfs]
  400. shl edx,16
  401. or eax,edx // EAX = right ofs frac | left ofs frac
  402. mov ebx,D [fixLeftOfs+2] // EBX = left ofs int
  403. mov edx,D [fixRightOfs+2] // EDX = right ofs int
  404. mov esi,D [pswSrcBuffer] // ESI = source sound buffer start ptr
  405. mov edi,D [pvMixerBuffer] // EDI = mixer buffer ptr
  406. mov ecx,D [slMixerBufferSize] // ECX = samples counter
  407. sampleLoop:
  408. // check if source offsets came to the end of source sound buffer
  409. cmp ebx,D [slSoundBufferSize]
  410. jl lNotEnd
  411. sub ebx,D [slSoundBufferSize]
  412. push D [bNotLoop]
  413. pop D [bEndOfSound]
  414. lNotEnd:
  415. // same for right channel
  416. cmp edx,D [slSoundBufferSize]
  417. jl rNotEnd
  418. sub edx,D [slSoundBufferSize]
  419. push D [bNotLoop]
  420. pop D [bEndOfSound]
  421. rNotEnd:
  422. // check end of sample
  423. cmp ecx,0
  424. jle loopEnd
  425. cmp D [bEndOfSound],TRUE
  426. je loopEnd
  427. // get sound samples
  428. movq mm1,Q [esi+ ebx*4]
  429. movq mm2,Q [esi+ edx*4]
  430. pslld mm1,16
  431. psrad mm1,16 // MM1 = 0 | nextLeftSample || 0 | leftSample
  432. psrad mm2,16 // MM2 = 0 | nextRightSample || 0 | rightSample
  433. packssdw mm1,mm2 // MM1 = nextRightSample | rightSample || nextLeftSample | leftSample
  434. // calc linear interpolation factor (strength)
  435. movd mm3,eax // MM3 = 0 | 0 || right frac | left frac
  436. punpcklwd mm3,mm3
  437. psrlw mm3,1 // MM3 = rightFrac | rightFrac || leftFrac | leftFrac
  438. pxor mm3,Q [mmInvFactor] // MM3 = rightFrac | 1-rightFrac || leftFrac | 1-leftFrac
  439. // apply linear interpolation
  440. pmaddwd mm1,mm3
  441. psrad mm1,15
  442. packssdw mm1,mm1 // MM1 = ? | ? || linearRightSample | linearLeftSample
  443. // apply filter
  444. psubsw mm1,mm6
  445. pmulhw mm1,mm7
  446. psllw mm1,1
  447. paddsw mm1,mm6
  448. movq mm6,mm1
  449. // apply volume adjustment
  450. movq mm0,mm5
  451. psrad mm0,16
  452. packssdw mm0,mm0
  453. pmulhw mm1,mm0
  454. psllw mm1,1
  455. pxor mm1,Q [mmSurroundFactor]
  456. paddd mm5,Q [mmVolumeGain] // modify volume
  457. // unpack to 32bit and mix it into destination buffer
  458. punpcklwd mm1,mm1
  459. psrad mm1,16 // MM1 = finalRightSample || finalLeftSample
  460. paddd mm1,Q [edi]
  461. movq Q [edi],mm1
  462. // advance to next samples in source sound
  463. add eax,D [mmRightStep+0]
  464. adc edx,D [mmRightStep+4]
  465. add ax,W [mmLeftStep +0]
  466. adc ebx,D [mmLeftStep +2]
  467. add edi,8
  468. dec ecx
  469. jmp sampleLoop
  470. loopEnd:
  471. // store modified asm local vars
  472. mov D [fixLeftOfs +0],eax
  473. shr eax,16
  474. mov D [fixRightOfs+0],eax
  475. mov D [fixLeftOfs +2],ebx
  476. mov D [fixRightOfs+2],edx
  477. movd eax,mm6
  478. mov edx,eax
  479. and eax,0x0000FFFF
  480. shr edx,16
  481. mov D [slLastLeftSample],eax
  482. mov D [slLastRightSample],edx
  483. emms
  484. }
  485. #endif
  486. _pfSoundProfile.StopTimer(CSoundProfile::PTI_RAWMIXER);
  487. }
  488. // mixes one sound to destination buffer
  489. void MixSound( CSoundObject *pso)
  490. {
  491. psd = pso->so_pCsdLink;
  492. // if don't mix encoded sounds if they are not opened properly
  493. if((psd->sd_ulFlags&SDF_ENCODED) &&
  494. (pso->so_psdcDecoder==NULL || !pso->so_psdcDecoder->IsOpen()) ) {
  495. return;
  496. }
  497. // check for supported sound formats
  498. const SLONG slChannels = pso->so_pCsdLink->sd_wfeFormat.nChannels;
  499. const SLONG slBytes = pso->so_pCsdLink->sd_wfeFormat.wBitsPerSample/8;
  500. // unsupported sound formats will be ignored
  501. if( (slChannels!=1 && slChannels!=2) || slBytes!=2) return;
  502. // check for delay
  503. const FLOAT f1oMixerBufferSampleRate = 1.0f / slMixerBufferSampleRate;
  504. const FLOAT fSecondsToMix = (FLOAT)slMixerBufferSize * f1oMixerBufferSampleRate;
  505. pso->so_fDelayed += fSecondsToMix;
  506. if( pso->so_fDelayed < pso->so_sp.sp_fDelay) {
  507. _pfSoundProfile.IncrementCounter(CSoundProfile::PCI_SOUNDSDELAYED, 1);
  508. return;
  509. }
  510. // playing started, so skip further delays
  511. pso->so_fDelayed = 9999.9999f;
  512. // reach sound data and determine sound step, sound buffer and buffer size
  513. pswSrcBuffer = psd->sd_pswBuffer;
  514. fSoundSampleRate = psd->sd_wfeFormat.nSamplesPerSec * pso->so_sp.sp_fPitchShift;
  515. fStep = fSoundSampleRate * f1oMixerBufferSampleRate;
  516. fLeftStep = fStep;
  517. fRightStep = fStep;
  518. slSoundBufferSize = psd->sd_slBufferSampleSize;
  519. // eliminate potentional "puck" at the of sample that hasn't loop
  520. if( !(pso->so_slFlags&SOF_LOOP) && slSoundBufferSize>1) slSoundBufferSize--;
  521. // get old and new volumes
  522. FLOAT fLeftVolume = ClampDn( pso->so_fLastLeftVolume, 0.0f);
  523. FLOAT fRightVolume = ClampDn( pso->so_fLastRightVolume, 0.0f);
  524. FLOAT fNewLeftVolume = ClampDn( pso->so_sp.sp_fLeftVolume, 0.0f);
  525. FLOAT fNewRightVolume = ClampDn( pso->so_sp.sp_fRightVolume, 0.0f);
  526. // adjust for master volume
  527. if(pso->so_slFlags&SOF_MUSIC) {
  528. fNewLeftVolume *= snd_fMusicVolume;
  529. fNewRightVolume *= snd_fMusicVolume;
  530. } else {
  531. fNewLeftVolume *= snd_fSoundVolume;
  532. fNewRightVolume *= snd_fSoundVolume;
  533. }
  534. // if both channel volumes are too low
  535. if( fLeftVolume<0.001f && fRightVolume<0.001f && fNewLeftVolume<0.001f && fNewRightVolume<0.001f)
  536. {
  537. // if this is not an encoded sound
  538. if( !(psd->sd_ulFlags&SDF_ENCODED) ) {
  539. // skip mixing of this sample segment
  540. fOfsDelta = fStep*slMixerBufferSampleRate*fSecondsToMix;
  541. pso->so_fLeftOffset += fOfsDelta;
  542. pso->so_fRightOffset += fOfsDelta;
  543. const FLOAT fMinOfs = Min( pso->so_fLeftOffset, pso->so_fRightOffset);
  544. ASSERT( fMinOfs>=0);
  545. if( fMinOfs<0) CPrintF( "BUG: negative offset (%.2g) encountered in sound: '%s' !\n", fMinOfs, (CTString&)psd->GetName());
  546. // if looping
  547. if (pso->so_slFlags & SOF_LOOP) {
  548. // adjust offset ptrs inside sound
  549. while( pso->so_fLeftOffset < 0) pso->so_fLeftOffset += slSoundBufferSize;
  550. while( pso->so_fRightOffset < 0) pso->so_fRightOffset += slSoundBufferSize;
  551. while( pso->so_fLeftOffset >= slSoundBufferSize) pso->so_fLeftOffset -= slSoundBufferSize;
  552. while( pso->so_fRightOffset >= slSoundBufferSize) pso->so_fRightOffset -= slSoundBufferSize;
  553. // if not looping
  554. } else {
  555. // no more playing
  556. pso->so_slFlags &= ~SOF_PLAY;
  557. pso->so_fDelayed = 0.0f;
  558. pso->so_sp.sp_fDelay = 0.0f;
  559. }
  560. }
  561. // reset last samples
  562. pso->so_swLastLeftSample = 0;
  563. pso->so_swLastRightSample = 0;
  564. // update volume
  565. pso->so_fLastLeftVolume = fNewLeftVolume;
  566. pso->so_fLastRightVolume = fNewRightVolume;
  567. _pfSoundProfile.IncrementCounter(CSoundProfile::PCI_SOUNDSSKIPPED, 1);
  568. return;
  569. }
  570. _sfStats.IncrementCounter(CStatForm::SCI_SOUNDSMIXING);
  571. // cache sound object vars
  572. fPhase = pso->so_sp.sp_fPhaseShift;
  573. fLeftOfs = pso->so_fLeftOffset;
  574. fRightOfs = pso->so_fRightOffset;
  575. fOfsDelta = pso->so_fOffsetDelta;
  576. slLeftVolume = FloatToInt(fLeftVolume * 65536*32767.0f);
  577. slRightVolume = FloatToInt(fRightVolume * 65536*32767.0f);
  578. const FLOAT fMixBufSize = 65536*32767.0f / slMixerBufferSize;
  579. const SLONG slLeftGain = FloatToInt( (fNewLeftVolume -fLeftVolume) *fMixBufSize);
  580. const SLONG slRightGain = FloatToInt( (fNewRightVolume-fRightVolume) *fMixBufSize);
  581. mmVolumeGain = ((__int64)(slRightGain)<<32) | ((__int64)(slLeftGain)&0xFFFFFFFF);
  582. // extrapolate back new volumes because of not enough precision in interpolation!
  583. // (otherwise we might hear occasional pucks)
  584. if( fNewLeftVolume >0.001f) fNewLeftVolume = (slLeftVolume + slLeftGain *slMixerBufferSize) /(65536*32767.0f);
  585. if( fNewRightVolume>0.001f) fNewRightVolume = (slRightVolume + slRightGain*slMixerBufferSize) /(65536*32767.0f);
  586. //ASSERT( fNewLeftVolume>=0 && fNewRightVolume>=0);
  587. //CPrintF( "NV: %.4f / %.4f, GV: %.4f / %.4f\n", fNewLeftVolume,fNewRightVolume, fLeftGainedVolume,fRightGainedVolume);
  588. // determine filtering and surround
  589. slLeftFilter = pso->so_sp.sp_slLeftFilter;
  590. slRightFilter = pso->so_sp.sp_slRightFilter;
  591. bNotLoop = !(pso->so_slFlags & SOF_LOOP);
  592. mmSurroundFactor = 0;
  593. if( pso->so_slFlags & SOF_SURROUND) mmSurroundFactor = 0x0000FFFF;
  594. // if this is an encoded sound
  595. BOOL bDecodingFinished = FALSE;
  596. if( psd->sd_ulFlags&SDF_ENCODED) {
  597. _pfSoundProfile.StartTimer(CSoundProfile::PTI_DECODESOUND);
  598. // decode some samples from it
  599. SLONG slWantedBytes = FloatToInt(slMixerBufferSize*fStep*pso->so_pCsdLink->sd_wfeFormat.nChannels) *2;
  600. void *pvDecodeBuffer = _pSound->sl_pswDecodeBuffer;
  601. ASSERT(slWantedBytes<=_pSound->sl_slDecodeBufferSize);
  602. SLONG slDecodedBytes = pso->so_psdcDecoder->Decode( pvDecodeBuffer, slWantedBytes);
  603. ASSERT(slDecodedBytes<=slWantedBytes);
  604. // if it has a loop
  605. if (!bNotLoop) {
  606. // if sound is shorter than buffer
  607. while(slDecodedBytes<slWantedBytes) {
  608. // decode it again and again
  609. pso->so_psdcDecoder->Reset();
  610. slDecodedBytes += pso->so_psdcDecoder->Decode( ((UBYTE*)pvDecodeBuffer) +
  611. slDecodedBytes, slWantedBytes-slDecodedBytes);
  612. }
  613. // if it doesn't have a loop
  614. } else {
  615. // if sound is shorter than buffer
  616. if(slDecodedBytes<slWantedBytes) {
  617. // mark that it is finished
  618. bDecodingFinished = TRUE;
  619. }
  620. }
  621. // copy first sample to the last one (this is needed for linear interpolation)
  622. (ULONG&)(((UBYTE*)pvDecodeBuffer)[slDecodedBytes]) = *(ULONG*)pvDecodeBuffer;
  623. // fix some mixer variables to play temporary decode buffer instead of real sound
  624. pswSrcBuffer = (SWORD*)pvDecodeBuffer;
  625. slSoundBufferSize = slDecodedBytes>>2; // convert to samples
  626. fLeftOfs = 0.0f;
  627. fRightOfs = 0.0f;
  628. fPhase = 0.0f;
  629. _pfSoundProfile.StopTimer(CSoundProfile::PTI_DECODESOUND);
  630. }
  631. _pfSoundProfile.IncrementCounter(CSoundProfile::PCI_SOUNDSMIXED, 1);
  632. _pfSoundProfile.IncrementCounter(CSoundProfile::PCI_SAMPLES, slMixerBufferSize);
  633. _pfSoundProfile.StartTimer(CSoundProfile::PTI_MIXSOUND);
  634. slLastLeftSample = pso->so_swLastLeftSample;
  635. slLastRightSample = pso->so_swLastRightSample;
  636. // calculate eventual new offsets from phase shift
  637. FLOAT fLastPhase = fOfsDelta / fSoundSampleRate;
  638. FLOAT fPhaseDelta = fPhase - fLastPhase;
  639. FLOAT fStepDelta = Abs( fPhaseDelta*fSoundSampleRate / slMixerBufferSize);
  640. FLOAT fStepDeltaL, fStepDeltaR;
  641. if( fPhaseDelta>0) {
  642. fStepDeltaL = fStepDelta/2;
  643. if( fStepDeltaL>fLeftStep/2) fStepDeltaL = fLeftStep/2;
  644. fStepDeltaL = -fStepDeltaL;
  645. fStepDeltaR = fStepDelta + fStepDeltaL;
  646. } else {
  647. fStepDeltaR = fStepDelta/2;
  648. if( fStepDeltaR>fLeftStep/2) fStepDeltaR = fLeftStep/2;
  649. fStepDeltaR = -fStepDeltaR;
  650. fStepDeltaL = fStepDelta + fStepDeltaR;
  651. }
  652. fLeftStep += fStepDeltaL;
  653. fRightStep += fStepDeltaR;
  654. fStepDelta = fStepDeltaR-fStepDeltaL;
  655. // if there is anything to mix (could be nothing when encoded file just finished)
  656. if( slSoundBufferSize>0) {
  657. // safety check (needed because of bad-bug!)
  658. FLOAT fMinOfs = Min( fLeftOfs, fRightOfs);
  659. ASSERT( fMinOfs>=0);
  660. if( fMinOfs<0) CPrintF( "BUG: negative offset (%.2g) encountered in sound: '%s' !\n", fMinOfs, (CTString&)psd->GetName());
  661. // adjust offset ptrs inside sound to match those of phase shift
  662. while( fLeftOfs < 0) fLeftOfs += slSoundBufferSize;
  663. while( fRightOfs < 0) fRightOfs += slSoundBufferSize;
  664. while( fLeftOfs >= slSoundBufferSize) fLeftOfs -= slSoundBufferSize;
  665. while( fRightOfs >= slSoundBufferSize) fRightOfs -= slSoundBufferSize;
  666. // if mono output is required
  667. if( snd_bMono) {
  668. // monomize channels (cool word:)
  669. fLeftOfs = (fLeftOfs+fRightOfs)/2;
  670. fRightOfs = fLeftOfs;
  671. fLeftStep = (fLeftStep+fRightStep)/2;
  672. fRightStep = fLeftStep;
  673. slLeftVolume = (slLeftVolume+slRightVolume)/2;
  674. slRightVolume = slLeftVolume;
  675. slLeftFilter = (slLeftFilter+slRightFilter)/2;
  676. slRightFilter = slLeftFilter;
  677. }
  678. // call corresponding mixer routine for current sound format
  679. bEndOfSound = FALSE;
  680. if( slChannels==2) {
  681. // mix as 16-bit stereo
  682. MixStereo( pso);
  683. } else {
  684. // mix as 16-bit mono
  685. MixMono( pso);
  686. }
  687. }
  688. // if encoded sound
  689. if( psd->sd_ulFlags&SDF_ENCODED) {
  690. // ignore mixing finished flag, but use decoding finished flag
  691. bEndOfSound = bDecodingFinished;
  692. }
  693. // if sound ended, not buffer
  694. if( bEndOfSound) {
  695. // reset some sound vars
  696. slLastLeftSample = 0;
  697. slLastRightSample = 0;
  698. pso->so_slFlags &= ~SOF_PLAY;
  699. pso->so_fDelayed = 0.0f;
  700. pso->so_sp.sp_fDelay = 0.0f;
  701. }
  702. // rememer last samples for the next mix in
  703. pso->so_swLastLeftSample = (SWORD)slLastLeftSample;
  704. pso->so_swLastRightSample = (SWORD)slLastRightSample;
  705. // determine new phase shift offset
  706. pso->so_fOffsetDelta += fStepDelta*slMixerBufferSize;
  707. // update play offset for the next mix iteration
  708. pso->so_fLeftOffset = fixLeftOfs * (1.0f/65536.0f);
  709. pso->so_fRightOffset = fixRightOfs * (1.0f/65536.0f);
  710. // update volume
  711. pso->so_fLastLeftVolume = fNewLeftVolume;
  712. pso->so_fLastRightVolume = fNewRightVolume;
  713. //if( pso->so_fLastLeftVolume>0 || pso->so_fLastRightVolume>0 || fNewLeftVolume>0 || fNewRightVolume>0) {
  714. // CPrintF( "SO: 0x%8X; OV: %.4f / %.4f, NV: %.4f / %.4f\n", pso,
  715. // pso->so_fLastLeftVolume,pso->so_fLastRightVolume, fNewLeftVolume,fNewRightVolume);
  716. //}
  717. _pfSoundProfile.StopTimer(CSoundProfile::PTI_MIXSOUND);
  718. }