Sound.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  1. #include "SoundService.h"
  2. #include "SoundsEngine.h"
  3. #include "SoundScene.h"
  4. #include "Sound.h"
  5. Sound::Sound(SoundScene & scene, bool is3D, bool isAutodelete, SoundBankFileSound & snd, const char * bankName, const char * _cppFile, long _cppLine) : soundScene(scene), sbfSound(snd)
  6. {
  7. cppFile = _cppFile;
  8. cppLine = _cppLine;
  9. channel = null;
  10. soundBankName = bankName;
  11. states = 0;
  12. if(is3D) states |= att_is3D;
  13. if(isAutodelete) states |= att_isAutoDelete;
  14. if(sbfSound.setup.GetModeLoop() != SoundBankFileSetup::mode_loop_diasble)
  15. {
  16. Assert(!isAutodelete); //Не должно быть флага автоудаления
  17. states |= att_isLoop;
  18. }
  19. currentTime = 0.0f;
  20. wave = null;
  21. phonemes = null;
  22. phonemesFrame = 0;
  23. currentVolume = 1.0f;
  24. globalPos = 0.0f;
  25. fadeTime = 0.0f;
  26. playPrev = null;
  27. playNext = null;
  28. pullCode = -1;
  29. }
  30. Sound::~Sound()
  31. {
  32. //В списках уже не значимся, осталось только вычистить себя
  33. StopNow(true);
  34. }
  35. //Удалить звук
  36. void Sound::Release()
  37. {
  38. //Сцена удалит из своих списков и вызовет деструктор
  39. soundScene.ReleaseSound(this);
  40. }
  41. //Проиграть
  42. void Sound::Play()
  43. {
  44. //Запустим проигрывание в конце кадра
  45. if(!(states & s_play))
  46. {
  47. SetCommand(cmd_play);
  48. }
  49. }
  50. //Остановить
  51. void Sound::Stop()
  52. {
  53. //Остановим в конце кадра
  54. if(states & s_play)
  55. {
  56. SetCommand(cmd_stop);
  57. }
  58. }
  59. //Узнать текущее состояние
  60. bool Sound::IsPlay()
  61. {
  62. //Если играем или ждём запуска, считаем что играем
  63. if(states & s_play) return true;
  64. if((states & cmd_mask) == cmd_play) return true;
  65. if((states & cmd_mask) == cmd_fadein) return true;
  66. return false;
  67. }
  68. //Установить громкость звука
  69. void Sound::SetVolume(float volume)
  70. {
  71. currentVolume = volume;
  72. UpdateVolume();
  73. }
  74. //Получить громкость звука
  75. float Sound::GetVolume()
  76. {
  77. return currentVolume;
  78. }
  79. //Получить имя звука
  80. const char * Sound::GetName()
  81. {
  82. return sbfSound.name;
  83. }
  84. //Получить имя звукового банка
  85. const char * Sound::GetSoundBankName()
  86. {
  87. return soundBankName;
  88. }
  89. //Запустить звук проигрываться и плавно увеличить громкость за time секунд
  90. void Sound::FadeIn(float time)
  91. {
  92. //Фейдиться начнём в конце кадра
  93. if(!(states & s_play))
  94. {
  95. if(time > 0.001f)
  96. {
  97. fadeTime = time;
  98. SetCommand(cmd_fadein);
  99. }else{
  100. SetCommand(cmd_play);
  101. }
  102. }
  103. }
  104. //Плавно уменьшить громкость до 0 за time секунд и остановить проигрывание звука
  105. void Sound::FadeOut(float time)
  106. {
  107. //Фейдиться начнём в конце кадра
  108. if(states & s_play)
  109. {
  110. if(time > 0.001f)
  111. {
  112. fadeTime = time;
  113. SetCommand(cmd_fadeout);
  114. }else{
  115. SetCommand(cmd_stop);
  116. }
  117. }
  118. }
  119. //Узнать, зациклен звук или нет
  120. bool Sound::IsLoop()
  121. {
  122. return (states & att_isLoop) != 0;
  123. }
  124. //Вернуть идентификатор фонемы. Если отрицательный результат - фонемы нет, 0 - тишина
  125. long Sound::GetPhonemeId(ErrorCode * ecode)
  126. {
  127. //Если нет указателя на фонемы, попробуем его получить
  128. if(!phonemes)
  129. {
  130. phonemesFrame = 0;
  131. if(!wave)
  132. {
  133. if(ecode)
  134. {
  135. *ecode = ec_phonemes_sound_not_play;
  136. }
  137. return -1;
  138. }
  139. SoundBankFileWave * w = wave->wave;
  140. if(!w)
  141. {
  142. if(ecode)
  143. {
  144. *ecode = ec_phonemes_sound_not_play;
  145. }
  146. return -1;
  147. }
  148. for(dword i = 0; i < w->extraCount; i++)
  149. {
  150. if(w->extraData[i].id == sbf_extra_phonemes)
  151. {
  152. phonemes = (SoundBankFilePhonemes *)w->extraData[i].data;
  153. break;
  154. }
  155. }
  156. if(!phonemes)
  157. {
  158. if(ecode)
  159. {
  160. *ecode = ec_phonemes_no_data;
  161. }
  162. return -1;
  163. }
  164. if(phonemes->framesCount == 0)
  165. {
  166. phonemes = null;
  167. if(ecode)
  168. {
  169. *ecode = ec_phonemes_data_is_empty;
  170. }
  171. return -1;
  172. }
  173. }
  174. //Получаем текущее время волны
  175. dword timeInMs;
  176. /*
  177. if(channel && !channel->IsLost(this) && channel->GetPlayPosition(timeInMs))
  178. {
  179. dword sample = timeInMs;
  180. timeInMs = long(1000.0f*timeInMs/float(wave->wave->format & SoundBankFileWave::f_freq_mask));
  181. }else{
  182. timeInMs = long(currentTime*1000.0f);
  183. }
  184. Assert(fabsf(timeInMs*0.001f - currentTime) < 2.0f);
  185. */
  186. timeInMs = long(currentTime*1000.0f);
  187. phonemesFrame = phonemes->FindFrame(timeInMs, phonemesFrame);
  188. dword phoneme = (long)phonemes->GetPhonemeId(phonemesFrame);
  189. if(ecode)
  190. {
  191. *ecode = ec_ok;
  192. }
  193. //api->Trace("^^^ GetPhonemeId() = %i", phoneme);
  194. return phoneme;
  195. }
  196. //Установить позицию источника звука
  197. void Sound::SetPosition(const Vector & position)
  198. {
  199. globalPos = position;
  200. }
  201. //Получить позицию источника звука
  202. Vector Sound::GetPosition()
  203. {
  204. return globalPos;
  205. }
  206. //Приостоновить звук
  207. void Sound::ScenePause()
  208. {
  209. //Если уже на паузе, ничего не делаем
  210. if(states & s_pause)
  211. {
  212. return;
  213. }
  214. //Молчащий звук тоже не играем
  215. if((states & s_play) == 0 || !channel || channel->IsLost(this))
  216. {
  217. return;
  218. }
  219. //Запоминаем позицию проигрывания
  220. if(channel->GetPlayPosition(pausePosition))
  221. {
  222. states |= s_pause;
  223. }
  224. //Освобождаем канал
  225. soundScene.GetSoundsEngine().ReleaseSoundChannel(channel, this);
  226. channel = null;
  227. }
  228. //Продолжить проигрывать звук
  229. void Sound::SceneResume()
  230. {
  231. if((states & s_pause) == 0)
  232. {
  233. return;
  234. }
  235. if(states & s_play)
  236. {
  237. states &= ~s_play;
  238. //Востанавливаем канал
  239. PlayNow(false);
  240. states &= ~s_pause;
  241. }
  242. }
  243. //Продолжить проигрывание звука с потерянным каналом
  244. bool Sound::ContinueLost()
  245. {
  246. //Проверяем что условия запуска не изменились
  247. if(!(states & s_play) || !wave || wave->playTime <= 0.0f || wave->playTime - currentTime <= c_time_to_skip_lost_ms*0.001f)
  248. {
  249. return true;
  250. }
  251. if(states & s_pause)
  252. {
  253. return false;
  254. }
  255. states |= s_pause;
  256. Assert(wave->wave);
  257. Assert(wave->wave->samplesCount > 0);
  258. float kPos = Clampf(currentTime/wave->playTime);
  259. long pos = long(kPos*wave->wave->samplesCount);
  260. if(pos < 0) pos = 0;
  261. if((dword)pos >= wave->wave->samplesCount)
  262. {
  263. return true;
  264. }
  265. pausePosition = (dword)pos;
  266. if(states & att_is3D)
  267. {
  268. float att = Update3DPosition(false);
  269. fadeTime = Clampf(att, 0.0f, c_fade_time_to_restore*0.001f);
  270. }else{
  271. fadeTime = c_fade_time_to_restore*0.001f;
  272. }
  273. states &= ~s_play;
  274. PlayNow(true);
  275. pausePosition = 0;
  276. states &= ~s_pause;
  277. return true;
  278. }
  279. //Исполнить команду
  280. void Sound::ExecuteCommand()
  281. {
  282. //Отложенная до конца кадра команда
  283. dword cmd = states & cmd_mask;
  284. SetCommand(cmd_none);
  285. switch(cmd)
  286. {
  287. case cmd_play:
  288. if(states & s_play)
  289. {
  290. StopNow();
  291. }
  292. PlayNow(false);
  293. break;
  294. case cmd_stop:
  295. StopNow();
  296. break;
  297. case cmd_fadein:
  298. if(states & s_play)
  299. {
  300. StopNow();
  301. }
  302. PlayNow(true);
  303. break;
  304. case cmd_fadeout:
  305. if(channel && !channel->IsLost(this))
  306. {
  307. channel->FadeOut(fadeTime);
  308. }else{
  309. StopNow();
  310. }
  311. break;
  312. }
  313. }
  314. //Обновить звук
  315. void Sound::Update(float dltTime)
  316. {
  317. if(!wave)
  318. {
  319. StopNow();
  320. return;
  321. }
  322. //Счётчик времени
  323. bool isLoop = (sbfSound.setup.GetModeLoop() != SoundBankFileSetup::mode_loop_diasble);
  324. currentTime += dltTime;
  325. if(!wave->wave)
  326. {
  327. //Если играем тишину, то только проверяем счётчик и занимаем очередь
  328. if(currentTime >= wave->playTime)
  329. {
  330. StopNow();
  331. }
  332. return;
  333. }
  334. //Зацикливаем счётчик времени
  335. if(isLoop)
  336. {
  337. while(currentTime >= wave->playTime)
  338. {
  339. currentTime -= wave->playTime;
  340. }
  341. if(currentTime < 0.0f) currentTime = 0.0f;
  342. }
  343. //Следим за состоянием канала
  344. if(channel)
  345. {
  346. if(!channel->IsLost(this))
  347. {
  348. if(channel->IsPlay())
  349. {
  350. //Обновим позицию 3D звука
  351. Update3DPosition(true);
  352. channel->SetLowPriority((states & s_outofrange) != 0);
  353. //Хот фикс зависшего канала
  354. if(currentTime > wave->playTime + 1.0f)
  355. {
  356. if(!channel->IsPause())
  357. {
  358. channel->FadeOut(1.0f);
  359. }else{
  360. StopNow();
  361. }
  362. }
  363. return;
  364. }else{
  365. StopNow();
  366. return;
  367. }
  368. }else{
  369. channel = null;
  370. }
  371. }
  372. //Время на доигрывание звука
  373. float tailTime = wave->playTime - currentTime;
  374. if(tailTime <= 0.0f)
  375. {
  376. StopNow();
  377. return;
  378. }
  379. //Решаем что делать с отсутствующим каналом
  380. Update3DPosition(false);
  381. if((states & s_outofrange) != 0)
  382. {
  383. //3D звук за пределами радиуса, ничего не делаем
  384. return;
  385. }
  386. //Смотрим сколько осталось доигрывать звуку
  387. Assert(wave->wave);
  388. if(!isLoop)
  389. {
  390. if(tailTime <= c_time_to_skip_lost_ms*0.001f || tailTime <= wave->wave->unimportantTime)
  391. {
  392. //Фэйковое доигрывание без попытки востановить канал
  393. return;
  394. }
  395. }
  396. //Встаём/обновляем очередь на востановление канала
  397. dword priority = sbfSound.setup.GetPriority();
  398. Assert(!channel);
  399. soundScene.SetToContinueQueue(this, tailTime, priority, isLoop);
  400. }
  401. //Написать в лог сообщение об неудалённом звуке
  402. void Sound::UnReleaseMessage(const char * sceneOvner)
  403. {
  404. if(!(states & att_isAutoDelete))
  405. {
  406. api->Trace("Unrelease sound: %s, (scene: \"%s\", cpp: %s, %i, sbank: %s)", sbfSound.name, sceneOvner, cppFile, cppLine, soundBankName);
  407. }
  408. }
  409. //Установить команду на исполнение
  410. __forceinline void Sound::SetCommand(States cmd)
  411. {
  412. if((states & cmd_mask) == cmd_none)
  413. {
  414. if(cmd != cmd_none)
  415. {
  416. //Если не пустая команда, то подпишемся на разовое исполнение
  417. soundScene.ExecuteSoundCommand(this);
  418. }
  419. }
  420. //Замещаем текущую команду новой
  421. states = (states & ~cmd_mask) | cmd;
  422. }
  423. //Запустить звук на проигрывание немедленно
  424. void Sound::PlayNow(bool isFadeIn)
  425. {
  426. Assert(!(states & s_play));
  427. //Канала активного быть не должно сейчас и играть не должны
  428. Assert(!channel);
  429. //Волна для проигрывания
  430. if((states & s_pause) == 0)
  431. {
  432. //Новая волна
  433. dword waveIndex = sbfSound.SelectWaveIndex();
  434. wave = &sbfSound.waves[waveIndex];
  435. phonemes = null;
  436. currentTime = 0.0f;
  437. pausePosition = 0;
  438. if(!wave->wave && wave->playTime < 1e-3f)
  439. {
  440. //Просто пропускаем проигрывание
  441. return;
  442. }
  443. //Проверяем очередь
  444. if(sbfSound.setup.maxCount > 0)
  445. {
  446. if(sbfSound.playSoundsCount >= sbfSound.setup.maxCount)
  447. {
  448. //Надо завершить самый давний звук в пользу текущего
  449. Sound * s = (Sound *)sbfSound.playSoundsList;
  450. Assert(s);
  451. for(; s->playNext; s = s->playNext);
  452. s->Replase();
  453. }
  454. }
  455. //Добавляемся в список проигрываемых
  456. playPrev = null;
  457. playNext = (Sound *)sbfSound.playSoundsList;
  458. sbfSound.playSoundsList = this;
  459. if(playNext)
  460. {
  461. playNext->playPrev = this;
  462. }
  463. }
  464. Assert(wave);
  465. Assert(wave->playTime > 0.0f);
  466. //Настраиваем флажки
  467. states |= s_play;
  468. states &= ~s_outofrange;
  469. //Скажем сцене обновлять звук
  470. soundScene.StartUpdate(this);
  471. //Проверяем дистанцию, если звук 3D
  472. Update3DPosition(false);
  473. if(states & s_outofrange)
  474. {
  475. //Пока нет необходимости заводить канал
  476. return;
  477. }
  478. //Создаём канал для волны
  479. channel = soundScene.GetSoundsEngine().GetSoundChannel(sbfSound, wave, pausePosition, soundScene.GetSceneMaster(), this);
  480. if(channel)
  481. {
  482. //Канал удалось создать, работаем в нормальном режиме
  483. UpdateVolume();
  484. Update3DPosition(true);
  485. if(isFadeIn)
  486. {
  487. channel->FadeIn(fadeTime);
  488. }else{
  489. channel->Play();
  490. }
  491. }
  492. }
  493. //Остановить звук немедленно
  494. void Sound::StopNow(bool noRelease)
  495. {
  496. wave = null;
  497. phonemes = null;
  498. pausePosition = 0;
  499. if(states & s_play)
  500. {
  501. //Исключаем из списка проигрываемых
  502. if(playPrev)
  503. {
  504. playPrev->playNext = playNext;
  505. }else{
  506. sbfSound.playSoundsList = playNext;
  507. }
  508. if(playNext)
  509. {
  510. playNext->playPrev = playPrev;
  511. }
  512. //Останавливаем обновление
  513. soundScene.StopUpdate(this);
  514. }
  515. //Устанавливаем текущее состояние
  516. states &= ~s_mask;
  517. //Освобождаем канал, если использовали
  518. if(channel)
  519. {
  520. soundScene.GetSoundsEngine().ReleaseSoundChannel(channel, this);
  521. channel = null;
  522. }
  523. soundScene.RemoveFromContinueQueue(this);
  524. //Смотрим атрибут самоудаления
  525. if(states & att_isAutoDelete)
  526. {
  527. if(!noRelease)
  528. {
  529. Release();
  530. }
  531. }
  532. }
  533. //Заместить этот звук новым
  534. void Sound::Replase()
  535. {
  536. //Удалим канал с быстрым фэйдом
  537. if(channel)
  538. {
  539. channel->FadeOut(SoundsEngine::c_replaceFadeTimeInMs*0.001f);
  540. channel = null;
  541. }
  542. StopNow();
  543. }
  544. //Обновить громкость звука
  545. __forceinline void Sound::UpdateVolume()
  546. {
  547. if(channel)
  548. {
  549. #ifndef NO_TOOLS
  550. if(wave)
  551. {
  552. channel->FixWaveVolume(wave->volume);
  553. }
  554. #endif
  555. if(sbfSound.setup.GetFxMode() != SoundBankFileSetup::mode_fx_music)
  556. {
  557. channel->SetVolume(currentVolume*soundScene.GetVolumeSounds());
  558. }else{
  559. channel->SetVolume(currentVolume*soundScene.GetVolumeMusic());
  560. }
  561. }
  562. }
  563. //Обновить позицию звука
  564. __forceinline float Sound::Update3DPosition(bool isUpdateChannel)
  565. {
  566. if(states & att_is3D)
  567. {
  568. //Квадрат дистанции до слушателя
  569. FxVoice::Locator loc;
  570. Vector localPos(0.0f);
  571. float dist2 = 0.0f;
  572. bool inRange = soundScene.ListenerTransfromPosition(globalPos, sbfSound.att.maxDist2, localPos, dist2);
  573. if(!inRange)
  574. {
  575. //Ничего не слышно, обрубаем звук
  576. if(isUpdateChannel)
  577. {
  578. Assert(channel);
  579. Assert(!channel->IsLost(this));
  580. channel->SetLocators(&loc, 1);
  581. }
  582. states |= s_outofrange;
  583. return 0.0f;
  584. }
  585. //Дистанция от слушателя до звука
  586. float distXZ = localPos.GetLengthXZ();
  587. //Прямой звук. Определяем затухание
  588. loc.attenuation = sbfSound.att.Attenuation(dist2);
  589. if(loc.attenuation < 1e-10f)
  590. {
  591. //Слишком тихо, отражения даже и не пытаемся считать
  592. loc.attenuation = 0.0f;
  593. if(isUpdateChannel)
  594. {
  595. Assert(channel);
  596. Assert(!channel->IsLost(this));
  597. channel->SetLocators(&loc, 1);
  598. }
  599. states |= s_outofrange;
  600. return 0.0f;
  601. }
  602. states &= ~s_outofrange;
  603. if(!isUpdateChannel) return loc.attenuation;
  604. Assert(channel);
  605. Assert(!channel->IsLost(this));
  606. //Определяем направление от слушателя до звука
  607. const float headRad = 1.0f;
  608. const float headDirThreshold = 0.35f;
  609. if(distXZ > headRad)
  610. {
  611. //За пределами головы направление указываем обычно
  612. float kNorm = 1.0f/distXZ;
  613. loc.dirFront = localPos.z*kNorm;
  614. loc.dirRight = localPos.x*kNorm;
  615. }else
  616. if(distXZ > headRad*headDirThreshold)
  617. {
  618. //Внутри головы начинаем терять направление
  619. float kLen = (distXZ - headDirThreshold)/(1.0f - headDirThreshold); //1 на внешнем радиусе и 0 на внутренем
  620. float kNorm = kLen*1.0f/distXZ;
  621. loc.dirFront = localPos.z*kNorm;
  622. loc.dirRight = localPos.x*kNorm;
  623. }else{
  624. //С какого то порога направления нет
  625. loc.dirFront = 0.0f;
  626. loc.dirRight = 0.0f;
  627. }
  628. channel->SetLocators(&loc, 1);
  629. return loc.attenuation;
  630. }
  631. return 0.0f;
  632. }
  633. #ifndef STOP_DEBUG
  634. #include "..\..\common_h\render.h"
  635. #endif
  636. //Отобразить отладочную информацию
  637. void Sound::DebugDraw(dword debugStates, long & line, const char * sceneOvner)
  638. {
  639. #ifndef STOP_DEBUG
  640. if(states & s_play)
  641. {
  642. if(states & att_is3D)
  643. {
  644. if(debugStates & SoundsEngine::dbg_draw3d)
  645. {
  646. DebugDraw3D(debugStates & SoundsEngine::dbg_drawlevel_mask, sceneOvner);
  647. }
  648. }else{
  649. if(debugStates & SoundsEngine::dbg_draw2d)
  650. {
  651. DebugDraw2D(debugStates & SoundsEngine::dbg_drawlevel_mask, line, sceneOvner);
  652. }
  653. }
  654. }
  655. #endif
  656. }
  657. //Нарисовать слушателя
  658. void Sound::DebugDrawListener(dword debugStates, const Matrix & listener, const char * sceneOvner)
  659. {
  660. #ifndef STOP_DEBUG
  661. if(debugStates & SoundsEngine::dbg_drawlistener)
  662. {
  663. dword drawLevel = debugStates & SoundsEngine::dbg_drawlevel_mask;
  664. //Рендер для вывода информации
  665. static IRender * render = null;
  666. if(!render)
  667. {
  668. render = (IRender *)api->GetService("DX9Render");
  669. if(!render) return;
  670. }
  671. //Рисуем слушателя
  672. if(drawLevel == SoundsEngine::dbg_drawlevel_max)
  673. {
  674. render->DrawCapsule(0.3f, 0.8f, 0x80808080, Matrix().RotateZ(PI*0.5f)*listener);
  675. render->DrawMatrix(listener);
  676. render->Print(listener.pos, 40.0f, 0.0f, 0xffffffff, "Sound listener");
  677. render->Print(listener.pos, 40.0f, 1.1f, 0xffffffff, "\"%s\"", sceneOvner);
  678. }else{
  679. render->DrawMatrix(listener);
  680. }
  681. }
  682. #endif
  683. }
  684. //Написать о параметрах эффекта среды окружения
  685. void Sound::DebugDrawEnvironment(dword debugStates, long & line, const char * sceneOvner, const FxScene::EnvParams & env)
  686. {
  687. #ifndef STOP_DEBUG
  688. if(debugStates & (SoundsEngine::dbg_drawlistener | SoundsEngine::dbg_draw2d | SoundsEngine::dbg_draw3d))
  689. {
  690. //Рендер для вывода информации
  691. static IRender * render = null;
  692. if(!render)
  693. {
  694. render = (IRender *)api->GetService("DX9Render");
  695. if(!render) return;
  696. }
  697. //Рисуем слушателя
  698. float eps = 0.001f;
  699. if(!((fabs(env.dry - 1.0f) < eps) && (fabs(env.wet) < eps)))
  700. {
  701. render->Print(10.0f, 30.0f + line*20.0f, 0xcfffffff, "* Env. Scene: \"%s\", params: dry=%f, wet=%f, predelay=%f, early=%f, damping=%f, dispersion=%f",
  702. sceneOvner,
  703. env.dry, env.wet, env.predelayTime, env.earlyTime, env.earlyAttenuation, env.damping, env.dispersion);
  704. line++;
  705. }
  706. }
  707. #endif
  708. }
  709. //Вывести глобальные параметры
  710. void Sound::DebugDrawGlobals(dword debugStates, SoundService & service)
  711. {
  712. #ifndef STOP_DEBUG
  713. SoundsEngine & engine = service.Engine();
  714. dword drawLevel = debugStates & SoundsEngine::dbg_drawlevel_mask;
  715. //Рендер для вывода информации
  716. static IRender * render = null;
  717. if(!render)
  718. {
  719. render = (IRender *)api->GetService("DX9Render");
  720. if(!render) return;
  721. }
  722. //Пишем общую статистику
  723. render->Print(10.0f, 10.0f, 0xcfffffff, "Play channels %3u of %3u, reserved play: %3u of %3u, continue waiting: %3u",
  724. engine.GetPlayChannels(), engine.GetMaxChannels(),
  725. engine.GetPlayReservedChannels(), engine.GetMaxReservedChannels(), service.GetContinueWaiting());
  726. #endif
  727. }
  728. #ifndef STOP_DEBUG
  729. //Вывести отладочную информацию для 3D звука
  730. void Sound::DebugDraw3D(dword drawLevel, const char * sceneOvner)
  731. {
  732. //Рендер для вывода информации
  733. static IRender * render = null;
  734. if(!render)
  735. {
  736. render = (IRender *)api->GetService("DX9Render");
  737. if(!render) return;
  738. }
  739. //Текущая реальная громкость
  740. char buf[64];
  741. if(channel)
  742. {
  743. if(!channel->IsPause())
  744. {
  745. crt_snprintf(buf, sizeof(buf) - 1, "vol = %2.3f", channel->DebugGetCurrentVolume());
  746. }else{
  747. crt_snprintf(buf, sizeof(buf) - 1, "channel on pause", channel->DebugGetCurrentVolume());
  748. }
  749. }else{
  750. crt_strcpy(buf, sizeof(buf) - 1, "silence mode");
  751. }
  752. //Общии параметры
  753. const float minDist = sqrtf(sbfSound.att.minDist2);
  754. const float maxDist = sqrtf(sbfSound.att.maxDist2);
  755. const float textViewDist = coremax(50.0f, maxDist + 10.0f);
  756. //Крестовина
  757. render->DrawLine(globalPos - Vector(minDist, 0.0f, 0.0f), 0xffff0000, globalPos + Vector(minDist, 0.0f, 0.0f), 0xffff0000);
  758. render->DrawLine(globalPos - Vector(minDist, 0.0f, 0.0f), 0xffff0000, globalPos - Vector(maxDist, 0.0f, 0.0f), 0xff0000ff);
  759. render->DrawLine(globalPos + Vector(minDist, 0.0f, 0.0f), 0xffff0000, globalPos + Vector(maxDist, 0.0f, 0.0f), 0xff0000ff);
  760. render->DrawLine(globalPos - Vector(0.0f, 0.0f, minDist), 0xffff0000, globalPos + Vector(0.0f, 0.0f, minDist), 0xffff0000);
  761. render->DrawLine(globalPos - Vector(0.0f, 0.0f, minDist), 0xffff0000, globalPos - Vector(0.0f, 0.0f, maxDist), 0xff0000ff);
  762. render->DrawLine(globalPos + Vector(0.0f, 0.0f, minDist), 0xffff0000, globalPos + Vector(0.0f, 0.0f, maxDist), 0xff0000ff);
  763. //Круги обозначающие границу в горизонтальной плоскости проходящей через позицию звука
  764. render->DrawXZCircle(globalPos, minDist, 0xffff0000);
  765. render->DrawXZCircle(globalPos, maxDist, 0xff0000ff);
  766. dword textColor = 0xffffffff;
  767. if(wave && currentTime > wave->playTime)
  768. {
  769. textColor = 0xffff2020;
  770. }
  771. if(drawLevel == SoundsEngine::dbg_drawlevel_max)
  772. {
  773. //Рисуем график затухания
  774. const float height = 4.0f;
  775. const dword color = 0xffc0ffc0;
  776. //Графики затухания
  777. for(long i = 0; i < 50; i++)
  778. {
  779. float k1 = i/50.0f;
  780. float k2 = (i + 1.0f)/50.0f;
  781. float d1 = minDist + (maxDist - minDist)*k1;
  782. float d2 = minDist + (maxDist - minDist)*k2;
  783. float y1 = sbfSound.att.Attenuation(d1*d1)*height;
  784. float y2 = sbfSound.att.Attenuation(d2*d2)*height;
  785. render->DrawLine(globalPos + Vector(0.0f, y1, d1), color, globalPos + Vector(0.0f, y2, d2), color);
  786. render->DrawLine(globalPos + Vector(d1, y1, 0.0f), color, globalPos + Vector(d2, y2, 0.0f), color);
  787. render->DrawLine(globalPos + Vector(0.0f, y1, -d1), color, globalPos + Vector(0.0f, y2, -d2), color);
  788. render->DrawLine(globalPos + Vector(-d1, y1, 0.0f), color, globalPos + Vector(-d2, y2, 0.0f), color);
  789. }
  790. //Кольца показывающие гравик в пространстве
  791. for(long i = 0; i < 10; i++)
  792. {
  793. float k = i/10.0f;
  794. float d = minDist + (maxDist - minDist)*k;
  795. float y = sbfSound.att.Attenuation(d*d)*height;
  796. render->DrawXZCircle(globalPos + Vector(0.0f, y, 0.0f), d, i ? 0x1fc0ffc0 : color);
  797. render->DrawXZCircle(globalPos, d, 0x1f0000ff);
  798. }
  799. //Текущая проекция позиции камеры на графике затухания
  800. Vector camPos = render->GetView().GetCamPos();
  801. Vector delta = globalPos - camPos;
  802. float d2 = delta.GetLength2();
  803. if(d2 <= sbfSound.att.maxDist2)
  804. {
  805. float y = sbfSound.att.Attenuation(d2)*height;
  806. float d = sqrtf(d2);
  807. render->DrawXZCircle(globalPos + Vector(0.0f, y, 0.0f), d, 0xff20ff20);
  808. render->DrawXZCircle(globalPos + Vector(0.0f, 0.0f, 0.0f), d, 0xff00cf00);
  809. }
  810. //Пишем расширенную информацию
  811. render->Print(globalPos, textViewDist, -2.0f, textColor, "%s", GetName());
  812. render->Print(globalPos, textViewDist, -1.0f, textColor, "scene: \"%s\"", sceneOvner);
  813. render->Print(globalPos, textViewDist, 0.0f, textColor, "%s", buf);
  814. render->Print(globalPos, textViewDist, 1.0f, textColor, "[%.1f of %.1f sec]", currentTime, wave ? wave->playTime : 0.0f);
  815. render->Print(globalPos, textViewDist, 2.0f, textColor, "prty = %i", sbfSound.setup.mode & SoundBankFileSetup::mode_priority_mask);
  816. render->Print(globalPos, textViewDist, 3.0f, textColor, "loop = %s", (states & att_isLoop) ? "true" : "false");
  817. }else{
  818. //Только подписываем некоторую текстовую информацию
  819. render->Print(globalPos, textViewDist, -1.0f, textColor, "%s", GetName());
  820. render->Print(globalPos, textViewDist, 0.0f, textColor, "%s", buf);
  821. render->Print(globalPos, textViewDist, 1.0f, textColor, "scene: \"%s\"", sceneOvner);
  822. }
  823. }
  824. //Вывести отладочную информацию для 2D звука
  825. void Sound::DebugDraw2D(dword drawLevel, long & line, const char * sceneOvner)
  826. {
  827. //Рендер для вывода информации
  828. static IRender * render = null;
  829. if(!render)
  830. {
  831. render = (IRender *)api->GetService("DX9Render");
  832. if(!render) return;
  833. }
  834. //Текущая реальная громкость
  835. char buf[64];
  836. if(channel)
  837. {
  838. if(!channel->IsPause())
  839. {
  840. crt_snprintf(buf, sizeof(buf) - 1, "vol = %2.3f", channel->DebugGetCurrentVolume());
  841. }else{
  842. crt_snprintf(buf, sizeof(buf) - 1, "channel on pause", channel->DebugGetCurrentVolume());
  843. }
  844. }else{
  845. crt_strcpy(buf, sizeof(buf) - 1, "silence mode");
  846. }
  847. //Вывод информации в зависимости от уровня
  848. dword textColor = 0xcfffffff;
  849. if(wave && currentTime > wave->playTime)
  850. {
  851. textColor = 0xcfff2020;
  852. }
  853. if(drawLevel == SoundsEngine::dbg_drawlevel_max)
  854. {
  855. render->Print(10.0f, 30.0f + line*20.0f, textColor, "S2d: %s, scene: \"%s\", [%.1f of %.1f sec], %s, prty = %i, loop = %s", GetName(), sceneOvner, currentTime, wave ? wave->playTime : 0.0f, buf, sbfSound.setup.mode & SoundBankFileSetup::mode_priority_mask, (states & att_isLoop) ? "true" : "false");
  856. }else{
  857. render->Print(10.0f, 30.0f + line*20.0f, textColor, "S2d: %s, scene: \"%s\", %s", GetName(), sceneOvner, buf);
  858. }
  859. line++;
  860. }
  861. #endif