SoundSource.cpp 33 KB

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