SoundSource.cpp 33 KB

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