SoundSource.cpp 35 KB

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