SoundSource.cpp 34 KB

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