SoundSource.cpp 35 KB

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