2
0

SoundSource.cpp 33 KB

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