SoundSource.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Audio/Audio.h"
  24. #include "../Audio/Sound.h"
  25. #include "../Audio/SoundSource.h"
  26. #include "../Audio/SoundStream.h"
  27. #include "../Core/Context.h"
  28. #include "../Resource/ResourceCache.h"
  29. #include "../DebugNew.h"
  30. namespace Atomic
  31. {
  32. #define INC_POS_LOOPED() \
  33. pos += intAdd; \
  34. fractPos += fractAdd; \
  35. if (fractPos > 65535) \
  36. { \
  37. fractPos &= 65535; \
  38. ++pos; \
  39. } \
  40. while (pos >= end) \
  41. pos -= (end - repeat); \
  42. #define INC_POS_ONESHOT() \
  43. pos += intAdd; \
  44. fractPos += fractAdd; \
  45. if (fractPos > 65535) \
  46. { \
  47. fractPos &= 65535; \
  48. ++pos; \
  49. } \
  50. if (pos >= end) \
  51. { \
  52. pos = 0; \
  53. break; \
  54. } \
  55. #define INC_POS_STEREO_LOOPED() \
  56. pos += (intAdd << 1); \
  57. fractPos += fractAdd; \
  58. if (fractPos > 65535) \
  59. { \
  60. fractPos &= 65535; \
  61. pos += 2; \
  62. } \
  63. while (pos >= end) \
  64. pos -= (end - repeat); \
  65. #define INC_POS_STEREO_ONESHOT() \
  66. pos += (intAdd << 1); \
  67. fractPos += fractAdd; \
  68. if (fractPos > 65535) \
  69. { \
  70. fractPos &= 65535; \
  71. pos += 2; \
  72. } \
  73. if (pos >= end) \
  74. { \
  75. pos = 0; \
  76. break; \
  77. } \
  78. #define GET_IP_SAMPLE() (((((int)pos[1] - (int)pos[0]) * fractPos) / 65536) + (int)pos[0])
  79. #define GET_IP_SAMPLE_LEFT() (((((int)pos[2] - (int)pos[0]) * fractPos) / 65536) + (int)pos[0])
  80. #define GET_IP_SAMPLE_RIGHT() (((((int)pos[3] - (int)pos[1]) * fractPos) / 65536) + (int)pos[1])
  81. static const float AUTOREMOVE_DELAY = 0.25f;
  82. static const int STREAM_SAFETY_SAMPLES = 4;
  83. extern const char* AUDIO_CATEGORY;
  84. SoundSource::SoundSource(Context* context) :
  85. Component(context),
  86. soundType_(SOUND_EFFECT),
  87. frequency_(0.0f),
  88. gain_(1.0f),
  89. attenuation_(1.0f),
  90. panning_(0.0f),
  91. autoRemoveTimer_(0.0f),
  92. autoRemove_(false),
  93. position_(0),
  94. fractPosition_(0),
  95. timePosition_(0.0f),
  96. unusedStreamSize_(0)
  97. {
  98. audio_ = GetSubsystem<Audio>();
  99. if (audio_)
  100. audio_->AddSoundSource(this);
  101. UpdateMasterGain();
  102. }
  103. SoundSource::~SoundSource()
  104. {
  105. if (audio_)
  106. audio_->RemoveSoundSource(this);
  107. }
  108. void SoundSource::RegisterObject(Context* context)
  109. {
  110. context->RegisterFactory<SoundSource>(AUDIO_CATEGORY);
  111. ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  112. MIXED_ACCESSOR_ATTRIBUTE("Sound", GetSoundAttr, SetSoundAttr, ResourceRef, ResourceRef(Sound::GetTypeStatic()), AM_DEFAULT);
  113. MIXED_ACCESSOR_ATTRIBUTE("Type", GetSoundType, SetSoundType, String, SOUND_EFFECT, AM_DEFAULT);
  114. ATTRIBUTE("Frequency", float, frequency_, 0.0f, AM_DEFAULT);
  115. ATTRIBUTE("Gain", float, gain_, 1.0f, AM_DEFAULT);
  116. ATTRIBUTE("Attenuation", float, attenuation_, 1.0f, AM_DEFAULT);
  117. ATTRIBUTE("Panning", float, panning_, 0.0f, AM_DEFAULT);
  118. ACCESSOR_ATTRIBUTE("Is Playing", IsPlaying, SetPlayingAttr, bool, false, AM_DEFAULT);
  119. ATTRIBUTE("Autoremove on Stop", bool, autoRemove_, false, AM_FILE);
  120. ACCESSOR_ATTRIBUTE("Play Position", GetPositionAttr, SetPositionAttr, int, 0, AM_FILE);
  121. }
  122. void SoundSource::Play(Sound* sound)
  123. {
  124. if (!audio_)
  125. return;
  126. // If no frequency set yet, set from the sound's default
  127. if (frequency_ == 0.0f && sound)
  128. SetFrequency(sound->GetFrequency());
  129. // If sound source is currently playing, have to lock the audio mutex
  130. if (position_)
  131. {
  132. MutexLock lock(audio_->GetMutex());
  133. PlayLockless(sound);
  134. }
  135. else
  136. PlayLockless(sound);
  137. MarkNetworkUpdate();
  138. }
  139. void SoundSource::Play(Sound* sound, float frequency)
  140. {
  141. SetFrequency(frequency);
  142. Play(sound);
  143. }
  144. void SoundSource::Play(Sound* sound, float frequency, float gain)
  145. {
  146. SetFrequency(frequency);
  147. SetGain(gain);
  148. Play(sound);
  149. }
  150. void SoundSource::Play(Sound* sound, float frequency, float gain, float panning)
  151. {
  152. SetFrequency(frequency);
  153. SetGain(gain);
  154. SetPanning(panning);
  155. Play(sound);
  156. }
  157. void SoundSource::Play(SoundStream* stream)
  158. {
  159. if (!audio_)
  160. return;
  161. // If no frequency set yet, set from the stream's default
  162. if (frequency_ == 0.0f && stream)
  163. SetFrequency(stream->GetFrequency());
  164. SharedPtr<SoundStream> streamPtr(stream);
  165. // If sound source is currently playing, have to lock the audio mutex. When stream playback is explicitly
  166. // requested, clear the existing sound if any
  167. if (position_)
  168. {
  169. MutexLock lock(audio_->GetMutex());
  170. sound_.Reset();
  171. PlayLockless(streamPtr);
  172. }
  173. else
  174. {
  175. sound_.Reset();
  176. PlayLockless(streamPtr);
  177. }
  178. // Stream playback is not supported for network replication, no need to mark network dirty
  179. }
  180. void SoundSource::Stop()
  181. {
  182. if (!audio_)
  183. return;
  184. // If sound source is currently playing, have to lock the audio mutex
  185. if (position_)
  186. {
  187. MutexLock lock(audio_->GetMutex());
  188. StopLockless();
  189. }
  190. else
  191. StopLockless();
  192. MarkNetworkUpdate();
  193. }
  194. void SoundSource::SetSoundType(const String& type)
  195. {
  196. if (type == SOUND_MASTER)
  197. return;
  198. soundType_ = type;
  199. soundTypeHash_ = StringHash(type);
  200. UpdateMasterGain();
  201. MarkNetworkUpdate();
  202. }
  203. void SoundSource::SetFrequency(float frequency)
  204. {
  205. frequency_ = Clamp(frequency, 0.0f, 535232.0f);
  206. MarkNetworkUpdate();
  207. }
  208. void SoundSource::SetGain(float gain)
  209. {
  210. gain_ = Max(gain, 0.0f);
  211. MarkNetworkUpdate();
  212. }
  213. void SoundSource::SetAttenuation(float attenuation)
  214. {
  215. attenuation_ = Clamp(attenuation, 0.0f, 1.0f);
  216. MarkNetworkUpdate();
  217. }
  218. void SoundSource::SetPanning(float panning)
  219. {
  220. panning_ = Clamp(panning, -1.0f, 1.0f);
  221. MarkNetworkUpdate();
  222. }
  223. void SoundSource::SetAutoRemove(bool enable)
  224. {
  225. autoRemove_ = enable;
  226. }
  227. bool SoundSource::IsPlaying() const
  228. {
  229. return (sound_ || soundStream_) && position_ != 0;
  230. }
  231. void SoundSource::SetPlayPosition(signed char* pos)
  232. {
  233. // Setting play position on a stream is not supported
  234. if (!audio_ || !sound_ || soundStream_)
  235. return;
  236. MutexLock lock(audio_->GetMutex());
  237. SetPlayPositionLockless(pos);
  238. }
  239. void SoundSource::Update(float timeStep)
  240. {
  241. if (!audio_ || !IsEnabledEffective())
  242. return;
  243. // If there is no actual audio output, perform fake mixing into a nonexistent buffer to check stopping/looping
  244. if (!audio_->IsInitialized())
  245. MixNull(timeStep);
  246. // Free the stream if playback has stopped
  247. if (soundStream_ && !position_)
  248. StopLockless();
  249. // Check for autoremove
  250. if (autoRemove_)
  251. {
  252. if (!IsPlaying())
  253. {
  254. autoRemoveTimer_ += timeStep;
  255. if (autoRemoveTimer_ > AUTOREMOVE_DELAY)
  256. {
  257. Remove();
  258. // Note: this object is now deleted, so only returning immediately is safe
  259. return;
  260. }
  261. }
  262. else
  263. autoRemoveTimer_ = 0.0f;
  264. }
  265. }
  266. void SoundSource::Mix(int* dest, unsigned samples, int mixRate, bool stereo, bool interpolation)
  267. {
  268. if (!position_ || (!sound_ && !soundStream_) || !IsEnabledEffective())
  269. return;
  270. int streamFilledSize, outBytes;
  271. if (soundStream_ && streamBuffer_)
  272. {
  273. int streamBufferSize = streamBuffer_->GetDataSize();
  274. // Calculate how many bytes of stream sound data is needed
  275. int neededSize = (int)((float)samples * frequency_ / (float)mixRate);
  276. // Add a little safety buffer. Subtract previous unused data
  277. neededSize += STREAM_SAFETY_SAMPLES;
  278. neededSize *= soundStream_->GetSampleSize();
  279. neededSize -= unusedStreamSize_;
  280. neededSize = Clamp(neededSize, 0, streamBufferSize - unusedStreamSize_);
  281. // Always start play position at the beginning of the stream buffer
  282. position_ = streamBuffer_->GetStart();
  283. // Request new data from the stream
  284. signed char* destination = streamBuffer_->GetStart() + unusedStreamSize_;
  285. outBytes = neededSize ? soundStream_->GetData(destination, (unsigned)neededSize) : 0;
  286. destination += outBytes;
  287. // Zero-fill rest if stream did not produce enough data
  288. if (outBytes < neededSize)
  289. memset(destination, 0, (size_t)(neededSize - outBytes));
  290. // Calculate amount of total bytes of data in stream buffer now, to know how much went unused after mixing
  291. streamFilledSize = neededSize + unusedStreamSize_;
  292. }
  293. // If streaming, play the stream buffer. Otherwise play the original sound
  294. Sound* sound = soundStream_ ? streamBuffer_ : sound_;
  295. if (!sound)
  296. return;
  297. // Choose the correct mixing routine
  298. if (!sound->IsStereo())
  299. {
  300. if (interpolation)
  301. {
  302. if (stereo)
  303. MixMonoToStereoIP(sound, dest, samples, mixRate);
  304. else
  305. MixMonoToMonoIP(sound, dest, samples, mixRate);
  306. }
  307. else
  308. {
  309. if (stereo)
  310. MixMonoToStereo(sound, dest, samples, mixRate);
  311. else
  312. MixMonoToMono(sound, dest, samples, mixRate);
  313. }
  314. }
  315. else
  316. {
  317. if (interpolation)
  318. {
  319. if (stereo)
  320. MixStereoToStereoIP(sound, dest, samples, mixRate);
  321. else
  322. MixStereoToMonoIP(sound, dest, samples, mixRate);
  323. }
  324. else
  325. {
  326. if (stereo)
  327. MixStereoToStereo(sound, dest, samples, mixRate);
  328. else
  329. MixStereoToMono(sound, dest, samples, mixRate);
  330. }
  331. }
  332. // Update the time position. In stream mode, copy unused data back to the beginning of the stream buffer
  333. if (soundStream_)
  334. {
  335. timePosition_ += ((float)samples / (float)mixRate) * frequency_ / soundStream_->GetFrequency();
  336. unusedStreamSize_ = Max(streamFilledSize - (int)(size_t)(position_ - streamBuffer_->GetStart()), 0);
  337. if (unusedStreamSize_)
  338. memcpy(streamBuffer_->GetStart(), (const void*)position_, (size_t)unusedStreamSize_);
  339. // If stream did not produce any data, stop if applicable
  340. if (!outBytes && soundStream_->GetStopAtEnd())
  341. {
  342. position_ = 0;
  343. return;
  344. }
  345. }
  346. else if (sound_)
  347. timePosition_ = ((float)(int)(size_t)(position_ - sound_->GetStart())) / (sound_->GetSampleSize() * sound_->GetFrequency());
  348. }
  349. void SoundSource::UpdateMasterGain()
  350. {
  351. if (audio_)
  352. masterGain_ = audio_->GetSoundSourceMasterGain(soundType_);
  353. }
  354. void SoundSource::SetSoundAttr(const ResourceRef& value)
  355. {
  356. ResourceCache* cache = GetSubsystem<ResourceCache>();
  357. Sound* newSound = cache->GetResource<Sound>(value.name_);
  358. if (IsPlaying())
  359. Play(newSound);
  360. else
  361. {
  362. // When changing the sound and not playing, free previous sound stream and stream buffer (if any)
  363. soundStream_.Reset();
  364. streamBuffer_.Reset();
  365. sound_ = newSound;
  366. }
  367. }
  368. void SoundSource::SetPlayingAttr(bool value)
  369. {
  370. if (value)
  371. {
  372. if (!IsPlaying())
  373. Play(sound_);
  374. }
  375. else
  376. Stop();
  377. }
  378. void SoundSource::SetPositionAttr(int value)
  379. {
  380. if (sound_)
  381. SetPlayPosition(sound_->GetStart() + value);
  382. }
  383. ResourceRef SoundSource::GetSoundAttr() const
  384. {
  385. return GetResourceRef(sound_, Sound::GetTypeStatic());
  386. }
  387. int SoundSource::GetPositionAttr() const
  388. {
  389. if (sound_ && position_)
  390. return (int)(GetPlayPosition() - sound_->GetStart());
  391. else
  392. return 0;
  393. }
  394. void SoundSource::PlayLockless(Sound* sound)
  395. {
  396. // Reset the time position in any case
  397. timePosition_ = 0.0f;
  398. if (sound)
  399. {
  400. if (!sound->IsCompressed())
  401. {
  402. // Uncompressed sound start
  403. signed char* start = sound->GetStart();
  404. if (start)
  405. {
  406. // Free existing stream & stream buffer if any
  407. soundStream_.Reset();
  408. streamBuffer_.Reset();
  409. sound_ = sound;
  410. position_ = start;
  411. fractPosition_ = 0;
  412. return;
  413. }
  414. }
  415. else
  416. {
  417. // Compressed sound start
  418. PlayLockless(sound->GetDecoderStream());
  419. sound_ = sound;
  420. return;
  421. }
  422. }
  423. // If sound pointer is null or if sound has no data, stop playback
  424. StopLockless();
  425. sound_.Reset();
  426. }
  427. void SoundSource::PlayLockless(SharedPtr<SoundStream> stream)
  428. {
  429. // Reset the time position in any case
  430. timePosition_ = 0.0f;
  431. if (stream)
  432. {
  433. // Setup the stream buffer
  434. unsigned sampleSize = stream->GetSampleSize();
  435. unsigned streamBufferSize = sampleSize * stream->GetIntFrequency() * STREAM_BUFFER_LENGTH / 1000;
  436. streamBuffer_ = new Sound(context_);
  437. streamBuffer_->SetSize(streamBufferSize);
  438. streamBuffer_->SetFormat(stream->GetIntFrequency(), stream->IsSixteenBit(), stream->IsStereo());
  439. streamBuffer_->SetLooped(true);
  440. soundStream_ = stream;
  441. unusedStreamSize_ = 0;
  442. position_ = streamBuffer_->GetStart();
  443. fractPosition_ = 0;
  444. return;
  445. }
  446. // If stream pointer is null, stop playback
  447. StopLockless();
  448. }
  449. void SoundSource::StopLockless()
  450. {
  451. position_ = 0;
  452. timePosition_ = 0.0f;
  453. // Free the sound stream and decode buffer if a stream was playing
  454. soundStream_.Reset();
  455. streamBuffer_.Reset();
  456. }
  457. void SoundSource::SetPlayPositionLockless(signed char* pos)
  458. {
  459. // Setting position on a stream is not supported
  460. if (!sound_ || soundStream_)
  461. return;
  462. signed char* start = sound_->GetStart();
  463. signed char* end = sound_->GetEnd();
  464. if (pos < start)
  465. pos = start;
  466. if (sound_->IsSixteenBit() && (pos - start) & 1)
  467. ++pos;
  468. if (pos > end)
  469. pos = end;
  470. position_ = pos;
  471. timePosition_ = ((float)(int)(size_t)(pos - sound_->GetStart())) / (sound_->GetSampleSize() * sound_->GetFrequency());
  472. }
  473. void SoundSource::MixMonoToMono(Sound* sound, int* dest, unsigned samples, int mixRate)
  474. {
  475. float totalGain = masterGain_ * attenuation_ * gain_;
  476. int vol = (int)(256.0f * totalGain + 0.5f);
  477. if (!vol)
  478. {
  479. MixZeroVolume(sound, samples, mixRate);
  480. return;
  481. }
  482. float add = frequency_ / (float)mixRate;
  483. int intAdd = (int)add;
  484. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  485. int fractPos = fractPosition_;
  486. if (sound->IsSixteenBit())
  487. {
  488. short* pos = (short*)position_;
  489. short* end = (short*)sound->GetEnd();
  490. short* repeat = (short*)sound->GetRepeat();
  491. if (sound->IsLooped())
  492. {
  493. while (samples--)
  494. {
  495. *dest = *dest + (*pos * vol) / 256;
  496. ++dest;
  497. INC_POS_LOOPED();
  498. }
  499. position_ = (signed char*)pos;
  500. }
  501. else
  502. {
  503. while (samples--)
  504. {
  505. *dest = *dest + (*pos * vol) / 256;
  506. ++dest;
  507. INC_POS_ONESHOT();
  508. }
  509. position_ = (signed char*)pos;
  510. }
  511. }
  512. else
  513. {
  514. signed char* pos = (signed char*)position_;
  515. signed char* end = sound->GetEnd();
  516. signed char* repeat = sound->GetRepeat();
  517. if (sound->IsLooped())
  518. {
  519. while (samples--)
  520. {
  521. *dest = *dest + *pos * vol;
  522. ++dest;
  523. INC_POS_LOOPED();
  524. }
  525. position_ = pos;
  526. }
  527. else
  528. {
  529. while (samples--)
  530. {
  531. *dest = *dest + *pos * vol;
  532. ++dest;
  533. INC_POS_ONESHOT();
  534. }
  535. position_ = pos;
  536. }
  537. }
  538. fractPosition_ = fractPos;
  539. }
  540. void SoundSource::MixMonoToStereo(Sound* sound, int* dest, unsigned samples, int mixRate)
  541. {
  542. float totalGain = masterGain_ * attenuation_ * gain_;
  543. int leftVol = (int)((-panning_ + 1.0f) * (256.0f * totalGain + 0.5f));
  544. int rightVol = (int)((panning_ + 1.0f) * (256.0f * totalGain + 0.5f));
  545. if (!leftVol && !rightVol)
  546. {
  547. MixZeroVolume(sound, samples, mixRate);
  548. return;
  549. }
  550. float add = frequency_ / (float)mixRate;
  551. int intAdd = (int)add;
  552. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  553. int fractPos = fractPosition_;
  554. if (sound->IsSixteenBit())
  555. {
  556. short* pos = (short*)position_;
  557. short* end = (short*)sound->GetEnd();
  558. short* repeat = (short*)sound->GetRepeat();
  559. if (sound->IsLooped())
  560. {
  561. while (samples--)
  562. {
  563. *dest = *dest + (*pos * leftVol) / 256;
  564. ++dest;
  565. *dest = *dest + (*pos * rightVol) / 256;
  566. ++dest;
  567. INC_POS_LOOPED();
  568. }
  569. position_ = (signed char*)pos;
  570. }
  571. else
  572. {
  573. while (samples--)
  574. {
  575. *dest = *dest + (*pos * leftVol) / 256;
  576. ++dest;
  577. *dest = *dest + (*pos * rightVol) / 256;
  578. ++dest;
  579. INC_POS_ONESHOT();
  580. }
  581. position_ = (signed char*)pos;
  582. }
  583. }
  584. else
  585. {
  586. signed char* pos = (signed char*)position_;
  587. signed char* end = sound->GetEnd();
  588. signed char* repeat = sound->GetRepeat();
  589. if (sound->IsLooped())
  590. {
  591. while (samples--)
  592. {
  593. *dest = *dest + *pos * leftVol;
  594. ++dest;
  595. *dest = *dest + *pos * rightVol;
  596. ++dest;
  597. INC_POS_LOOPED();
  598. }
  599. position_ = pos;
  600. }
  601. else
  602. {
  603. while (samples--)
  604. {
  605. *dest = *dest + *pos * leftVol;
  606. ++dest;
  607. *dest = *dest + *pos * rightVol;
  608. ++dest;
  609. INC_POS_ONESHOT();
  610. }
  611. position_ = pos;
  612. }
  613. }
  614. fractPosition_ = fractPos;
  615. }
  616. void SoundSource::MixMonoToMonoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
  617. {
  618. float totalGain = masterGain_ * attenuation_ * gain_;
  619. int vol = (int)(256.0f * totalGain + 0.5f);
  620. if (!vol)
  621. {
  622. MixZeroVolume(sound, samples, mixRate);
  623. return;
  624. }
  625. float add = frequency_ / (float)mixRate;
  626. int intAdd = (int)add;
  627. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  628. int fractPos = fractPosition_;
  629. if (sound->IsSixteenBit())
  630. {
  631. short* pos = (short*)position_;
  632. short* end = (short*)sound->GetEnd();
  633. short* repeat = (short*)sound->GetRepeat();
  634. if (sound->IsLooped())
  635. {
  636. while (samples--)
  637. {
  638. *dest = *dest + (GET_IP_SAMPLE() * vol) / 256;
  639. ++dest;
  640. INC_POS_LOOPED();
  641. }
  642. position_ = (signed char*)pos;
  643. }
  644. else
  645. {
  646. while (samples--)
  647. {
  648. *dest = *dest + (GET_IP_SAMPLE() * vol) / 256;
  649. ++dest;
  650. INC_POS_ONESHOT();
  651. }
  652. position_ = (signed char*)pos;
  653. }
  654. }
  655. else
  656. {
  657. signed char* pos = (signed char*)position_;
  658. signed char* end = sound->GetEnd();
  659. signed char* repeat = sound->GetRepeat();
  660. if (sound->IsLooped())
  661. {
  662. while (samples--)
  663. {
  664. *dest = *dest + GET_IP_SAMPLE() * vol;
  665. ++dest;
  666. INC_POS_LOOPED();
  667. }
  668. position_ = pos;
  669. }
  670. else
  671. {
  672. while (samples--)
  673. {
  674. *dest = *dest + GET_IP_SAMPLE() * vol;
  675. ++dest;
  676. INC_POS_ONESHOT();
  677. }
  678. position_ = pos;
  679. }
  680. }
  681. fractPosition_ = fractPos;
  682. }
  683. void SoundSource::MixMonoToStereoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
  684. {
  685. float totalGain = masterGain_ * attenuation_ * gain_;
  686. int leftVol = (int)((-panning_ + 1.0f) * (256.0f * totalGain + 0.5f));
  687. int rightVol = (int)((panning_ + 1.0f) * (256.0f * totalGain + 0.5f));
  688. if (!leftVol && !rightVol)
  689. {
  690. MixZeroVolume(sound, samples, mixRate);
  691. return;
  692. }
  693. float add = frequency_ / (float)mixRate;
  694. int intAdd = (int)add;
  695. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  696. int fractPos = fractPosition_;
  697. if (sound->IsSixteenBit())
  698. {
  699. short* pos = (short*)position_;
  700. short* end = (short*)sound->GetEnd();
  701. short* repeat = (short*)sound->GetRepeat();
  702. if (sound->IsLooped())
  703. {
  704. while (samples--)
  705. {
  706. int s = GET_IP_SAMPLE();
  707. *dest = *dest + (s * leftVol) / 256;
  708. ++dest;
  709. *dest = *dest + (s * rightVol) / 256;
  710. ++dest;
  711. INC_POS_LOOPED();
  712. }
  713. position_ = (signed char*)pos;
  714. }
  715. else
  716. {
  717. while (samples--)
  718. {
  719. int s = GET_IP_SAMPLE();
  720. *dest = *dest + (s * leftVol) / 256;
  721. ++dest;
  722. *dest = *dest + (s * rightVol) / 256;
  723. ++dest;
  724. INC_POS_ONESHOT();
  725. }
  726. position_ = (signed char*)pos;
  727. }
  728. }
  729. else
  730. {
  731. signed char* pos = (signed char*)position_;
  732. signed char* end = sound->GetEnd();
  733. signed char* repeat = sound->GetRepeat();
  734. if (sound->IsLooped())
  735. {
  736. while (samples--)
  737. {
  738. int s = GET_IP_SAMPLE();
  739. *dest = *dest + s * leftVol;
  740. ++dest;
  741. *dest = *dest + s * rightVol;
  742. ++dest;
  743. INC_POS_LOOPED();
  744. }
  745. position_ = pos;
  746. }
  747. else
  748. {
  749. while (samples--)
  750. {
  751. int s = GET_IP_SAMPLE();
  752. *dest = *dest + s * leftVol;
  753. ++dest;
  754. *dest = *dest + s * rightVol;
  755. ++dest;
  756. INC_POS_ONESHOT();
  757. }
  758. position_ = pos;
  759. }
  760. }
  761. fractPosition_ = fractPos;
  762. }
  763. void SoundSource::MixStereoToMono(Sound* sound, int* dest, unsigned samples, int mixRate)
  764. {
  765. float totalGain = masterGain_ * attenuation_ * gain_;
  766. int vol = (int)(256.0f * totalGain + 0.5f);
  767. if (!vol)
  768. {
  769. MixZeroVolume(sound, samples, mixRate);
  770. return;
  771. }
  772. float add = frequency_ / (float)mixRate;
  773. int intAdd = (int)add;
  774. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  775. int fractPos = fractPosition_;
  776. if (sound->IsSixteenBit())
  777. {
  778. short* pos = (short*)position_;
  779. short* end = (short*)sound->GetEnd();
  780. short* repeat = (short*)sound->GetRepeat();
  781. if (sound->IsLooped())
  782. {
  783. while (samples--)
  784. {
  785. int s = ((int)pos[0] + (int)pos[1]) / 2;
  786. *dest = *dest + (s * vol) / 256;
  787. ++dest;
  788. INC_POS_STEREO_LOOPED();
  789. }
  790. position_ = (signed char*)pos;
  791. }
  792. else
  793. {
  794. while (samples--)
  795. {
  796. int s = ((int)pos[0] + (int)pos[1]) / 2;
  797. *dest = *dest + (s * vol) / 256;
  798. ++dest;
  799. INC_POS_STEREO_ONESHOT();
  800. }
  801. position_ = (signed char*)pos;
  802. }
  803. }
  804. else
  805. {
  806. signed char* pos = (signed char*)position_;
  807. signed char* end = sound->GetEnd();
  808. signed char* repeat = sound->GetRepeat();
  809. if (sound->IsLooped())
  810. {
  811. while (samples--)
  812. {
  813. int s = ((int)pos[0] + (int)pos[1]) / 2;
  814. *dest = *dest + s * vol;
  815. ++dest;
  816. INC_POS_STEREO_LOOPED();
  817. }
  818. position_ = pos;
  819. }
  820. else
  821. {
  822. while (samples--)
  823. {
  824. int s = ((int)pos[0] + (int)pos[1]) / 2;
  825. *dest = *dest + s * vol;
  826. ++dest;
  827. INC_POS_STEREO_ONESHOT();
  828. }
  829. position_ = pos;
  830. }
  831. }
  832. fractPosition_ = fractPos;
  833. }
  834. void SoundSource::MixStereoToStereo(Sound* sound, int* dest, unsigned samples, int mixRate)
  835. {
  836. float totalGain = masterGain_ * attenuation_ * gain_;
  837. int vol = (int)(256.0f * totalGain + 0.5f);
  838. if (!vol)
  839. {
  840. MixZeroVolume(sound, samples, mixRate);
  841. return;
  842. }
  843. float add = frequency_ / (float)mixRate;
  844. int intAdd = (int)add;
  845. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  846. int fractPos = fractPosition_;
  847. if (sound->IsSixteenBit())
  848. {
  849. short* pos = (short*)position_;
  850. short* end = (short*)sound->GetEnd();
  851. short* repeat = (short*)sound->GetRepeat();
  852. if (sound->IsLooped())
  853. {
  854. while (samples--)
  855. {
  856. *dest = *dest + (pos[0] * vol) / 256;
  857. ++dest;
  858. *dest = *dest + (pos[1] * vol) / 256;
  859. ++dest;
  860. INC_POS_STEREO_LOOPED();
  861. }
  862. position_ = (signed char*)pos;
  863. }
  864. else
  865. {
  866. while (samples--)
  867. {
  868. *dest = *dest + (pos[0] * vol) / 256;
  869. ++dest;
  870. *dest = *dest + (pos[1] * vol) / 256;
  871. ++dest;
  872. INC_POS_STEREO_ONESHOT();
  873. }
  874. position_ = (signed char*)pos;
  875. }
  876. }
  877. else
  878. {
  879. signed char* pos = (signed char*)position_;
  880. signed char* end = sound->GetEnd();
  881. signed char* repeat = sound->GetRepeat();
  882. if (sound->IsLooped())
  883. {
  884. while (samples--)
  885. {
  886. *dest = *dest + pos[0] * vol;
  887. ++dest;
  888. *dest = *dest + pos[1] * vol;
  889. ++dest;
  890. INC_POS_STEREO_LOOPED();
  891. }
  892. position_ = pos;
  893. }
  894. else
  895. {
  896. while (samples--)
  897. {
  898. *dest = *dest + pos[0] * vol;
  899. ++dest;
  900. *dest = *dest + pos[1] * vol;
  901. ++dest;
  902. INC_POS_STEREO_ONESHOT();
  903. }
  904. position_ = pos;
  905. }
  906. }
  907. fractPosition_ = fractPos;
  908. }
  909. void SoundSource::MixStereoToMonoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
  910. {
  911. float totalGain = masterGain_ * attenuation_ * gain_;
  912. int vol = (int)(256.0f * totalGain + 0.5f);
  913. if (!vol)
  914. {
  915. MixZeroVolume(sound, samples, mixRate);
  916. return;
  917. }
  918. float add = frequency_ / (float)mixRate;
  919. int intAdd = (int)add;
  920. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  921. int fractPos = fractPosition_;
  922. if (sound->IsSixteenBit())
  923. {
  924. short* pos = (short*)position_;
  925. short* end = (short*)sound->GetEnd();
  926. short* repeat = (short*)sound->GetRepeat();
  927. if (sound->IsLooped())
  928. {
  929. while (samples--)
  930. {
  931. int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
  932. *dest = *dest + (s * vol) / 256;
  933. ++dest;
  934. INC_POS_STEREO_LOOPED();
  935. }
  936. position_ = (signed char*)pos;
  937. }
  938. else
  939. {
  940. while (samples--)
  941. {
  942. int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
  943. *dest = *dest + (s * vol) / 256;
  944. ++dest;
  945. INC_POS_STEREO_ONESHOT();
  946. }
  947. position_ = (signed char*)pos;
  948. }
  949. }
  950. else
  951. {
  952. signed char* pos = (signed char*)position_;
  953. signed char* end = sound->GetEnd();
  954. signed char* repeat = sound->GetRepeat();
  955. if (sound->IsLooped())
  956. {
  957. while (samples--)
  958. {
  959. int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
  960. *dest = *dest + s * vol;
  961. ++dest;
  962. INC_POS_STEREO_LOOPED();
  963. }
  964. position_ = pos;
  965. }
  966. else
  967. {
  968. while (samples--)
  969. {
  970. int s = (GET_IP_SAMPLE_LEFT() + GET_IP_SAMPLE_RIGHT()) / 2;
  971. *dest = *dest + s * vol;
  972. ++dest;
  973. INC_POS_STEREO_ONESHOT();
  974. }
  975. position_ = pos;
  976. }
  977. }
  978. fractPosition_ = fractPos;
  979. }
  980. void SoundSource::MixStereoToStereoIP(Sound* sound, int* dest, unsigned samples, int mixRate)
  981. {
  982. float totalGain = masterGain_ * attenuation_ * gain_;
  983. int vol = (int)(256.0f * totalGain + 0.5f);
  984. if (!vol)
  985. {
  986. MixZeroVolume(sound, samples, mixRate);
  987. return;
  988. }
  989. float add = frequency_ / (float)mixRate;
  990. int intAdd = (int)add;
  991. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  992. int fractPos = fractPosition_;
  993. if (sound->IsSixteenBit())
  994. {
  995. short* pos = (short*)position_;
  996. short* end = (short*)sound->GetEnd();
  997. short* repeat = (short*)sound->GetRepeat();
  998. if (sound->IsLooped())
  999. {
  1000. while (samples--)
  1001. {
  1002. *dest = *dest + (GET_IP_SAMPLE_LEFT() * vol) / 256;
  1003. ++dest;
  1004. *dest = *dest + (GET_IP_SAMPLE_RIGHT() * vol) / 256;
  1005. ++dest;
  1006. INC_POS_STEREO_LOOPED();
  1007. }
  1008. position_ = (signed char*)pos;
  1009. }
  1010. else
  1011. {
  1012. while (samples--)
  1013. {
  1014. *dest = *dest + (GET_IP_SAMPLE_LEFT() * vol) / 256;
  1015. ++dest;
  1016. *dest = *dest + (GET_IP_SAMPLE_RIGHT() * vol) / 256;
  1017. ++dest;
  1018. INC_POS_STEREO_ONESHOT();
  1019. }
  1020. position_ = (signed char*)pos;
  1021. }
  1022. }
  1023. else
  1024. {
  1025. signed char* pos = (signed char*)position_;
  1026. signed char* end = sound->GetEnd();
  1027. signed char* repeat = sound->GetRepeat();
  1028. if (sound->IsLooped())
  1029. {
  1030. while (samples--)
  1031. {
  1032. *dest = *dest + GET_IP_SAMPLE_LEFT() * vol;
  1033. ++dest;
  1034. *dest = *dest + GET_IP_SAMPLE_RIGHT() * vol;
  1035. ++dest;
  1036. INC_POS_STEREO_LOOPED();
  1037. }
  1038. position_ = pos;
  1039. }
  1040. else
  1041. {
  1042. while (samples--)
  1043. {
  1044. *dest = *dest + GET_IP_SAMPLE_LEFT() * vol;
  1045. ++dest;
  1046. *dest = *dest + GET_IP_SAMPLE_RIGHT() * vol;
  1047. ++dest;
  1048. INC_POS_STEREO_ONESHOT();
  1049. }
  1050. position_ = pos;
  1051. }
  1052. }
  1053. fractPosition_ = fractPos;
  1054. }
  1055. void SoundSource::MixZeroVolume(Sound* sound, unsigned samples, int mixRate)
  1056. {
  1057. float add = frequency_ * (float)samples / (float)mixRate;
  1058. int intAdd = (int)add;
  1059. int fractAdd = (int)((add - floorf(add)) * 65536.0f);
  1060. unsigned sampleSize = sound->GetSampleSize();
  1061. fractPosition_ += fractAdd;
  1062. if (fractPosition_ > 65535)
  1063. {
  1064. fractPosition_ &= 65535;
  1065. position_ += sampleSize;
  1066. }
  1067. position_ += intAdd * sampleSize;
  1068. if (position_ > sound->GetEnd())
  1069. {
  1070. if (sound->IsLooped())
  1071. {
  1072. while (position_ >= sound->GetEnd())
  1073. {
  1074. position_ -= (sound->GetEnd() - sound->GetRepeat());
  1075. }
  1076. }
  1077. else
  1078. position_ = 0;
  1079. }
  1080. }
  1081. void SoundSource::MixNull(float timeStep)
  1082. {
  1083. if (!position_ || !sound_ || !IsEnabledEffective())
  1084. return;
  1085. // Advance only the time position
  1086. timePosition_ += timeStep * frequency_ / sound_->GetFrequency();
  1087. if (sound_->IsLooped())
  1088. {
  1089. // For simulated playback, simply reset the time position to zero when the sound loops
  1090. if (timePosition_ >= sound_->GetLength())
  1091. timePosition_ -= sound_->GetLength();
  1092. }
  1093. else
  1094. {
  1095. if (timePosition_ >= sound_->GetLength())
  1096. {
  1097. position_ = 0;
  1098. timePosition_ = 0.0f;
  1099. }
  1100. }
  1101. }
  1102. }