SoundScene.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. #include "Sound.h"
  2. #include "SoundScene.h"
  3. #include "SoundService.h"
  4. #include "SoundsEngine.h"
  5. #include "..\..\common_h\templates\pulls.h"
  6. SoundScene::SoundScene(SoundService & service, const char * ovnerName, const char * cppFile, long cppLine) :
  7. soundService(service),
  8. sounds(_FL_, 256),
  9. soundCommands(_FL_, 256),
  10. soundUpdates(_FL_, 256),
  11. continueQueue(_FL_, 256)
  12. {
  13. Assert(sizeof(FxScene::EnvParams) == sizeof(Enveronment));
  14. ovnerNameSaved = ovnerName;
  15. cppFileSaved = cppFile;
  16. cppLineSaved = cppLine;
  17. volume = 1.0f;
  18. volumeSounds = 1.0f;
  19. volumeMusic = 1.0f;
  20. isPause = false;
  21. isQueueSorted = false;
  22. isEvtBlend = false;
  23. sm = soundService.Engine().CreateSceneMaster();
  24. Assert(sm);
  25. memset(&envCurrent, 0, sizeof(envCurrent));
  26. envCurrent.dry = 1.0f;
  27. envSet = envCurrent;
  28. envBlendWeight = 0.0f;
  29. envBlendSpeed = 0.0f;
  30. UpdateVolumes();
  31. if(soundService.IsTraceCreates())
  32. {
  33. api->Trace("SoundsService debug message: SoundScene::SoundScene(%s, %s, %i)", ovnerName, cppFile, cppLine);
  34. }
  35. }
  36. SoundScene::~SoundScene()
  37. {
  38. //Удаляем все звуки
  39. while(sounds)
  40. {
  41. sounds[sounds - 1]->UnReleaseMessage(ovnerNameSaved.c_str());
  42. sounds[sounds - 1]->Release();
  43. }
  44. //Удаляемся из списка сцен
  45. soundService.RemoveScene(this);
  46. //Удалить мастера сцены
  47. sm->Release();
  48. if(soundService.IsTraceCreates())
  49. {
  50. api->Trace("SoundsService debug message: SoundScene::~SoundScene(%s)", ovnerNameSaved.c_str());
  51. }
  52. }
  53. //Удалить сцену
  54. void SoundScene::Release()
  55. {
  56. delete this;
  57. }
  58. //Создать непозиционированный звук, если звук не создался - вернётся null
  59. ISound * SoundScene::Create(const ConstString & soundName, const char * _cppFile, long _cppLine, bool isStartPlay, bool autoDelete, float vol)
  60. {
  61. if(soundService.IsTraceCreates())
  62. {
  63. api->Trace("SoundsService debug message: SoundScene::Create(\"%s\", %s, %i, isStartPlay=%s, autoDelete=%s, %f)", soundName.c_str(), _cppFile, _cppLine, isStartPlay ? "true" : "false", autoDelete ? "true" : "false", vol);
  64. }
  65. return (ISound *)CreateSound(soundName, _cppFile, _cppLine, isStartPlay, autoDelete, null, vol);
  66. }
  67. //Создать позиционированный в 3D звук, если звук не создался - вернётся null
  68. ISound3D * SoundScene::Create3D(const ConstString & soundName, const Vector & worldPos, const char * _cppFile, long _cppLine, bool isStartPlay, bool autoDelete, float vol)
  69. {
  70. if(soundService.IsTraceCreates())
  71. {
  72. api->Trace("SoundsService debug message: SoundScene::Create(\"%s\", (%f, %f, %f), %s, %i, isStartPlay=%s, autoDelete=%s, %f)", soundName.c_str(), worldPos.x, worldPos.y, worldPos.z, _cppFile, _cppLine, isStartPlay ? "true" : "false", autoDelete ? "true" : "false", vol);
  73. }
  74. return (ISound3D *)CreateSound(soundName, _cppFile, _cppLine, isStartPlay, autoDelete, &worldPos, vol);
  75. }
  76. //Создать звук
  77. Sound * SoundScene::CreateSound(const ConstString & soundName, const char * _cppFile, long _cppLine, bool isStartPlay, bool autoDelete, const Vector * worldPos, float vol)
  78. {
  79. //Ищем звук в звуковом банке
  80. const char * bankName = null;
  81. SoundBankFileSound * sbfs = soundService.FindSound(soundName, &bankName);
  82. if(!sbfs)
  83. {
  84. if(soundService.IsLogOut())
  85. {
  86. api->Error("SoundService: sound \"%s\" not found!", soundName.c_str());
  87. }
  88. return null;
  89. }
  90. Assert(bankName);
  91. //Проверяем допустимую комбинацию флагов и режимов
  92. if(autoDelete)
  93. {
  94. if(!isStartPlay)
  95. {
  96. if(soundService.IsLogOut())
  97. {
  98. api->Error("SoundService error: Can't create paused sound with autoDelete flag, [%s, line %i], sound name = \"%s\" error in function ISoundScene::Create", _cppFile, _cppLine, soundName.c_str());
  99. }
  100. return null;
  101. }
  102. if(sbfs->setup.GetModeLoop() != SoundBankFileSetup::mode_loop_diasble)
  103. {
  104. if(soundService.IsLogOut())
  105. {
  106. api->Error("SoundService error: Can't create loop sound with autoDelete flag, [%s, line %i], sound name = \"%s\" error in function ISoundScene::Create", _cppFile, _cppLine, soundName.c_str());
  107. }
  108. return null;
  109. }
  110. }
  111. //Создаём своё представление звука
  112. Sound * sound = SoundNew(*this, worldPos != null, autoDelete, *sbfs, bankName, _cppFile, _cppLine);
  113. sound->SetVolume(vol);
  114. sounds.Add(sound);
  115. if(worldPos)
  116. {
  117. sound->SetPosition(*worldPos);
  118. }
  119. if(isStartPlay)
  120. {
  121. sound->Play();
  122. }
  123. return autoDelete ? null : sound;
  124. }
  125. //Продолжить звучание сцены
  126. void SoundScene::Resume()
  127. {
  128. if(!isPause) return;
  129. isPause = false;
  130. for(long i = 0; i < sounds; i++)
  131. {
  132. sounds[i]->SceneResume();
  133. }
  134. }
  135. //Приостановить звучание сцены
  136. void SoundScene::Pause()
  137. {
  138. if(isPause) return;
  139. for(long i = 0; i < sounds; i++)
  140. {
  141. sounds[i]->ScenePause();
  142. }
  143. isPause = true;
  144. }
  145. //Узнать текущее состояние сцены
  146. bool SoundScene::IsPause()
  147. {
  148. return isPause;
  149. }
  150. //Установить общую громкость звучание всей сцены
  151. void SoundScene::SetVolume(float volume)
  152. {
  153. this->volume = volume;
  154. UpdateVolumes();
  155. }
  156. //Получить общую громкость звучание всей сцены
  157. float SoundScene::GetVolume()
  158. {
  159. return volume;
  160. }
  161. //Установить позицию слушателя
  162. void SoundScene::SetListenerMatrix(const Matrix & mtx)
  163. {
  164. listener = mtx;
  165. }
  166. //Получить позицию слушателя
  167. void SoundScene::GetListenerMatrix(Matrix & mtx)
  168. {
  169. mtx = listener;
  170. }
  171. //Установить текущую окружающую сцену с временем перехода в секундах
  172. void SoundScene::SetSoundEnvironmentScene(const Enveronment * envPeset, float blendTime)
  173. {
  174. if(isEvtBlend)
  175. {
  176. float kSet = Clampf(envBlendWeight);
  177. float kCur = 1.0f - kSet;
  178. for(dword i = 0; i < ARRSIZE(envCurrent.val); i++)
  179. {
  180. envCurrent.val[i] = envCurrent.val[i]*kCur + envSet.val[i]*kSet;
  181. }
  182. }
  183. isEvtBlend = true;
  184. if(envPeset)
  185. {
  186. for(dword i = 0; i < ARRSIZE(envSet.val); i++)
  187. {
  188. envSet.val[i] = envPeset->val[i];
  189. }
  190. }else{
  191. envSet = envCurrent;
  192. envSet.wet = 0.0f;
  193. envSet.dry = 1.0f;
  194. }
  195. if(blendTime > 0.005f)
  196. {
  197. envBlendWeight = 0.0f;
  198. envBlendSpeed = 1.0f/blendTime;
  199. }else{
  200. envBlendWeight = 1.0f;
  201. envBlendSpeed = 1000.0f;
  202. }
  203. }
  204. //Получить текущую окружающую сцену
  205. void SoundScene::GetSoundEnvironmentScene(Enveronment & envPeset)
  206. {
  207. for(dword i = 0; i < ARRSIZE(envPeset.val); i++)
  208. {
  209. envPeset.val[i] = envSet.val[i];
  210. }
  211. }
  212. //Переименовать владельца сцены
  213. void SoundScene::ModifyOvnerName(const char * ovnerName)
  214. {
  215. ovnerNameSaved = ovnerName;
  216. }
  217. //Нарисовать отладочную информацию
  218. void SoundScene::DebugDraw(dword debugStates, long & line)
  219. {
  220. //Рисуем слушателя
  221. Sound::DebugDrawEnvironment(debugStates, line, ovnerNameSaved.c_str(), envCurrent);
  222. //Рисуем звуки
  223. for(dword i = 0; i < sounds.Size(); i++)
  224. {
  225. sounds[i]->DebugDraw(debugStates, line, ovnerNameSaved.c_str());
  226. }
  227. //Рисуем слушателя
  228. Sound::DebugDrawListener(debugStates, listener, ovnerNameSaved.c_str());
  229. }
  230. //Написать в лог сообщение об неудалённой сцене
  231. void SoundScene::UnReleaseMessage()
  232. {
  233. api->Trace("Unrelease sound scene: cpp file: %s,%i; ovner tag: %s", cppFileSaved.c_str(), cppLineSaved, ovnerNameSaved.c_str());
  234. }
  235. //Обновить сцену
  236. void SoundScene::Update(float dltTime)
  237. {
  238. if(isPause) return;
  239. //Параметры среды окружения
  240. if(isEvtBlend)
  241. {
  242. FxScene::EnvParams params;
  243. envBlendWeight += dltTime*envBlendSpeed;
  244. if(envBlendWeight < 1.0f)
  245. {
  246. float kSet = envBlendWeight;
  247. float kCur = 1.0f - kSet;
  248. for(dword i = 0; i < ARRSIZE(params.val); i++)
  249. {
  250. params.val[i] = envCurrent.val[i]*kCur + envSet.val[i]*kSet;
  251. }
  252. }else{
  253. isEvtBlend = false;
  254. envBlendWeight = 0.0f;
  255. envBlendSpeed = 0.0f;
  256. for(dword i = 0; i < ARRSIZE(params.val); i++)
  257. {
  258. params.val[i] = envCurrent.val[i] = envSet.val[i];
  259. }
  260. }
  261. Assert(sm);
  262. sm->SetEnvironment(params);
  263. }
  264. //Инверсная матрица слушателя
  265. inverseListener.Inverse(listener);
  266. //Исполняем команды
  267. for(dword i = 0; i < soundCommands.Size(); i++)
  268. {
  269. Sound * s = soundCommands[i];
  270. if(s)
  271. {
  272. s->ExecuteCommand();
  273. }
  274. }
  275. soundCommands.Empty();
  276. //Обновляем звуки
  277. for(dword i = 0; i < soundUpdates.Size();)
  278. {
  279. Sound * s = soundUpdates[i];
  280. if(s)
  281. {
  282. //Исполняем звук
  283. s->Update(dltTime);
  284. i++;
  285. }else{
  286. //Замещаем пустой указатель последним и ужимаем массив
  287. if(i < soundUpdates.Size() - 1)
  288. {
  289. soundUpdates[i] = soundUpdates[soundUpdates.Size() - 1];
  290. }
  291. soundUpdates.DelIndex(soundUpdates.Size() - 1);
  292. }
  293. }
  294. //Запускаем звуки на доигрывание
  295. if(continueQueue.Size() > 0)
  296. {
  297. //Проверяем доступное количество свободных каналов у движка
  298. dword count = soundService.Engine().GetMaxChannels() - soundService.Engine().GetPlayChannels();
  299. if(count > 0)
  300. {
  301. if(count > continueQueue.Size())
  302. {
  303. isQueueSorted = true;
  304. count = continueQueue.Size();
  305. }
  306. //Если на всех нет места, сортируем по приоритетам
  307. if(!isQueueSorted)
  308. {
  309. continueQueue.QSort(&SoundScene::CompareCntQueue);
  310. isQueueSorted = true;
  311. }
  312. //Пытаемся продолжить звуки
  313. for(dword i = 0; i < count && i < continueQueue.Size(); i++)
  314. {
  315. CntQueue & cq = continueQueue[i];
  316. if(cq.snd->ContinueLost())
  317. {
  318. cq.snd = null;
  319. }
  320. }
  321. //Удаляем отработавшие записи
  322. for(dword i = 0; i < continueQueue.Size(); )
  323. {
  324. if(!continueQueue[i].snd)
  325. {
  326. continueQueue.DelIndex(i);
  327. }else{
  328. i++;
  329. }
  330. }
  331. }
  332. }
  333. }
  334. bool SoundScene::CompareCntQueue(const CntQueue & q1, const CntQueue & q2)
  335. {
  336. //Зацикленные звуки имеют больший приоритет к востановлению (бесконечное время проигрывания)
  337. if(q1.isLoop != q2.isLoop)
  338. {
  339. return q1.isLoop == 0;
  340. }
  341. //Приоритетные звуки востанавливаються первыми
  342. if(q1.priority != q2.priority)
  343. {
  344. return q2.priority > q1.priority;
  345. }
  346. //Первыми востанавливаються те, кому больше играть
  347. return (q1.tailTime < q2.tailTime);
  348. }
  349. //Обновить громкости
  350. void SoundScene::UpdateVolumes()
  351. {
  352. //Громкости групп
  353. volumeSounds = volume*soundService.GetCurrentSoundsVolume();
  354. volumeMusic = volume*soundService.GetCurrentMusicVolume();
  355. //Громкости активных звуков
  356. Sound ** s = soundUpdates.GetBuffer();
  357. dword count = soundUpdates.Size();
  358. for(dword i = 0; i < count; i++)
  359. {
  360. if(s[i])
  361. {
  362. s[i]->SetVolume(s[i]->GetVolume());
  363. }
  364. }
  365. }
  366. //Остановить проигрывание всех звуков
  367. void SoundScene::StopAllSounds(const char * sceneOvner)
  368. {
  369. if(sceneOvner && string::NotEqual(ovnerNameSaved.c_str(), sceneOvner))
  370. {
  371. return;
  372. }
  373. for(dword i = 0; i < sounds.Size(); i++)
  374. {
  375. sounds[i]->Stop();
  376. sounds[i]->ExecuteCommand();
  377. }
  378. }
  379. //Проверить на используемость
  380. bool SoundScene::IsUse(SoundBankFileSound & sbfs)
  381. {
  382. for(dword i = 0; i < sounds.Size(); i++)
  383. {
  384. if(sounds[i]->IsThis(sbfs)) return true;
  385. }
  386. return false;
  387. }
  388. //Путь удаляемого звукового банка
  389. void SoundScene::CheckForDelete(const char * soundBankName)
  390. {
  391. #ifndef STOP_DEBUG
  392. bool TryDeleteSoundBankWithUsingSounds = true;
  393. for(dword i = 0; i < sounds.Size(); i++)
  394. {
  395. if(sounds[i]->GetSoundBankName() == soundBankName)
  396. {
  397. api->Trace("SoundService error! Sound \"%s\" not release from removed sound bank \"%s\"", sounds[i]->GetName(), soundBankName);
  398. TryDeleteSoundBankWithUsingSounds = false;
  399. }
  400. }
  401. Assert(TryDeleteSoundBankWithUsingSounds);
  402. #endif
  403. }
  404. //Поставить звук на обновление
  405. void SoundScene::StartUpdate(Sound * snd)
  406. {
  407. Sound ** s = soundUpdates.GetBuffer();
  408. dword count = soundUpdates.Size();
  409. for(dword i = 0; i < count; i++)
  410. {
  411. if(s[i] == snd) return;
  412. }
  413. soundUpdates.Add(snd);
  414. }
  415. //Прекратить обновлять звук
  416. void SoundScene::StopUpdate(Sound * snd)
  417. {
  418. Sound ** s = soundUpdates.GetBuffer();
  419. dword count = soundUpdates.Size();
  420. for(dword i = 0; i < count; i++)
  421. {
  422. if(s[i] == snd)
  423. {
  424. s[i] = null;
  425. return;
  426. }
  427. }
  428. }
  429. //Поставить звук в очередь на доигрывание
  430. void SoundScene::SetToContinueQueue(Sound * snd, float tailTime, dword priority, bool isLoop)
  431. {
  432. isQueueSorted = false;
  433. for(dword i = 0; i < continueQueue.Size(); i++)
  434. {
  435. CntQueue & cq = continueQueue[i];
  436. if(cq.snd == snd)
  437. {
  438. //Изменились параметры
  439. cq.tailTime = tailTime;
  440. cq.priority = priority;
  441. cq.isLoop = isLoop ? 1 : 0;
  442. return;
  443. }
  444. }
  445. //Надо добавить новую запись
  446. CntQueue & cnt = continueQueue[continueQueue.Add()];
  447. cnt.snd = snd;
  448. cnt.tailTime = tailTime;
  449. cnt.priority = priority;
  450. cnt.isLoop = isLoop ? 1 : 0;
  451. }
  452. //Удалить звук из очереди на доигрывание
  453. void SoundScene::RemoveFromContinueQueue(Sound * snd)
  454. {
  455. for(dword i = 0; i < continueQueue.Size(); i++)
  456. {
  457. if(continueQueue[i].snd == snd)
  458. {
  459. continueQueue.DelIndex(i);
  460. return;
  461. }
  462. }
  463. }
  464. //Удалить звук
  465. void SoundScene::ReleaseSound(Sound * snd)
  466. {
  467. sounds.Del(snd);
  468. StopUpdate(snd);
  469. RemoveFromContinueQueue(snd);
  470. for(long i = 0; i < soundCommands; i++)
  471. {
  472. if(soundCommands[i] == snd)
  473. {
  474. soundCommands[i] = null;
  475. }
  476. }
  477. SoundDelete(snd);
  478. }
  479. //Получить звуковой движёк
  480. SoundsEngine & SoundScene::GetSoundsEngine()
  481. {
  482. return soundService.Engine();
  483. }
  484. namespace SoundScenePulls
  485. {
  486. Pulls<sizeof(Sound)> soundPulls;
  487. };
  488. //Выделить из пула звук
  489. Sound * SoundScene::SoundNew(SoundScene & scene, bool is3D, bool isAutodelete, SoundBankFileSound & sbfs, const char * bankName, const char * cppFile, long cppLine)
  490. {
  491. dword code;
  492. void * ptr = SoundScenePulls::soundPulls.Alloc(code);
  493. Sound * snd = new('a', ptr) Sound(scene, is3D, isAutodelete, sbfs, bankName, cppFile, cppLine);
  494. snd->SetPullCode(code);
  495. return snd;
  496. }
  497. //Освободить в пуле звук
  498. void SoundScene::SoundDelete(Sound * ptr)
  499. {
  500. dword code = ptr->GetPullCode();
  501. ptr->~Sound();
  502. SoundScenePulls::soundPulls.Delete(code);
  503. }
  504. //Очистить все пулы
  505. void SoundScene::ClearPulls()
  506. {
  507. SoundScenePulls::soundPulls.Clear();
  508. }