SoundService.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. #include "SoundService.h"
  2. #include "SoundsEngine.h"
  3. #include "SoundBanks.h"
  4. #include "Sound.h"
  5. #include "..\..\common_h\FileService.h"
  6. #include "..\..\common_h\LocStrings.h"
  7. #include "UnitTests\SoundServiceUnitTests.h"
  8. //============================================================================================
  9. CREATE_SERVICE_NAMED("SoundService", SoundService, 2)
  10. //============================================================================================
  11. SoundService::SoundService() : scenes(_FL_)
  12. #ifndef NO_TOOLS
  13. , previewSounds(_FL_)
  14. #endif
  15. {
  16. states = 0;
  17. engine = NEW SoundsEngine();
  18. soundBanks = NEW SoundBanks();
  19. //Громкости
  20. globalVolume = 1.0f;
  21. soundsVolume = 1.0f;
  22. musicVolume = 0.4f;
  23. //Текущие громкости
  24. curSoundsVolume = globalVolume*soundsVolume;
  25. curMusicVolume = globalVolume*musicVolume;
  26. //Доступ к громкостям в базе
  27. stGlobalVolume = api->Storage().GetItemFloat("Options.GlobalVolume", _FL_);
  28. Assert(stGlobalVolume);
  29. stSoundsVolume = api->Storage().GetItemFloat("Options.FxVolume", _FL_);
  30. Assert(stSoundsVolume);
  31. stMusicVolume = api->Storage().GetItemFloat("Options.MusicVolume", _FL_);
  32. Assert(stMusicVolume);
  33. #ifndef NO_TOOLS
  34. isEnablePreview = false;
  35. //********************
  36. // UnitTestWaveSelectorsProcess(false);
  37. //********************
  38. #endif
  39. }
  40. SoundService::~SoundService()
  41. {
  42. while(scenes)
  43. {
  44. scenes[scenes - 1]->UnReleaseMessage();
  45. scenes[scenes - 1]->Release();
  46. }
  47. SoundScene::ClearPulls();
  48. delete engine;
  49. delete soundBanks;
  50. stGlobalVolume->Release();
  51. stSoundsVolume->Release();
  52. stMusicVolume->Release();
  53. }
  54. //Инициализвация
  55. bool SoundService::Init()
  56. {
  57. //Параметры сервиса
  58. IFileService * fs = (IFileService *)api->GetService("FileService");
  59. Assert(fs);
  60. IIniFile * ini = fs->SystemIni();
  61. if(ini)
  62. {
  63. if(ini->GetLong("Sound", "off", 0) != 0)
  64. {
  65. states |= SoundsEngine::dbg_snd_off;
  66. }
  67. long traceMode = ini->GetLong("Sound", "trace", 0);
  68. if(traceMode != 0)
  69. {
  70. states |= SoundsEngine::dbg_logout;
  71. }
  72. if(traceMode > 1)
  73. {
  74. states |= SoundsEngine::dbg_tracecreates;
  75. }
  76. long dl = ini->GetLong("Sound", "debug", 0);
  77. switch(dl)
  78. {
  79. case 0:
  80. SetDebugView(dv_none);
  81. break;
  82. case 1:
  83. SetDebugLevel(dl_minimal);
  84. SetDebugView(dv_all);
  85. break;
  86. default:
  87. SetDebugLevel(dl_maximum);
  88. SetDebugView(dv_all);
  89. }
  90. globalVolume = (float)ini->GetDouble("Sound", "global volume", 1.0f);
  91. soundsVolume = (float)ini->GetDouble("Sound", "sounds volume", 1.0f);
  92. musicVolume = (float)ini->GetDouble("Sound", "music volume", 0.4f);
  93. ini = null;
  94. }
  95. //Если выключен то прекращаем инициализацию
  96. if(states & SoundsEngine::dbg_snd_off)
  97. {
  98. api->Trace("SoundService started in silence mode (off)...");
  99. return true;
  100. }
  101. //Инициализируем звук
  102. if(!engine->Init())
  103. {
  104. api->Trace("SoundService error: Sound engine init error. Switch to silence mode (off)...");
  105. engine->Release();
  106. states |= SoundsEngine::dbg_snd_off;
  107. return true;
  108. }
  109. //Подписываем сервис
  110. api->SetEndFrameLevel(this, Core_DefaultExecuteLevel);
  111. api->Trace("SoundService started is successful");
  112. states |= s_needUpdateVolumes;
  113. EndFrame(0.0f);
  114. return true;
  115. }
  116. //Исполнение
  117. void SoundService::EndFrame(float dltTime)
  118. {
  119. //Проверяем изменение громкостей
  120. float vol = Clampf(stGlobalVolume->Get(globalVolume), 0.0f, 1.0f);
  121. if(fabsf(vol - globalVolume) > 1e-8f)
  122. {
  123. globalVolume = vol;
  124. states |= s_needUpdateVolumes;
  125. }
  126. vol = Clampf(stSoundsVolume->Get(soundsVolume), 0.0f, 1.0f);
  127. if(fabsf(vol - soundsVolume) > 1e-8f)
  128. {
  129. soundsVolume = vol;
  130. states |= s_needUpdateVolumes;
  131. }
  132. vol = Clampf(stMusicVolume->Get(musicVolume), 0.0f, 1.0f)*0.6f;
  133. if(fabsf(vol - musicVolume) > 1e-8f)
  134. {
  135. musicVolume = vol;
  136. states |= s_needUpdateVolumes;
  137. }
  138. //Звук не умеет скалироваться
  139. dltTime = api->GetNoScaleDeltaTime();
  140. if(!(states & s_needUpdateVolumes))
  141. {
  142. //Обновляем сцены
  143. for(long i = 0; i < scenes; i++)
  144. {
  145. scenes[i]->Update(dltTime);
  146. }
  147. }else{
  148. curSoundsVolume = soundsVolume*globalVolume;
  149. curMusicVolume = musicVolume*globalVolume;
  150. #ifndef NO_TOOLS
  151. engine->EditPrewiewSetMasterVolume(curSoundsVolume);
  152. #endif
  153. //Обновляем сцены
  154. for(long i = 0; i < scenes; i++)
  155. {
  156. scenes[i]->UpdateVolumes();
  157. scenes[i]->Update(dltTime);
  158. }
  159. states &= ~s_needUpdateVolumes;
  160. }
  161. if(engine)
  162. {
  163. engine->Update();
  164. bool isPause = !api->IsActive();
  165. engine->SetPause(isPause);
  166. }
  167. }
  168. //Создать звуковую сцену
  169. ISoundScene * SoundService::CreateScene(const char * ovnerName, const char * cppFile, long cppLine)
  170. {
  171. if(states & SoundsEngine::dbg_snd_off)
  172. {
  173. return &sceneOff;
  174. }
  175. SoundScene * scene = NEW SoundScene(*this, ovnerName, cppFile, cppLine);
  176. scenes.Add(scene);
  177. return scene;
  178. }
  179. //Загрузить звуковой банк
  180. bool SoundService::LoadSoundBank(const char * path)
  181. {
  182. if(states & SoundsEngine::dbg_snd_off)
  183. {
  184. return true;
  185. }
  186. return soundBanks->LoadSoundBank(path);
  187. }
  188. //Удалить звуковой банк
  189. void SoundService::ReleaseSoundBank(const char * path)
  190. {
  191. //Поток XAudio после удаления продолжал работать, поэтому банки не удаляю
  192. return;
  193. if(states & SoundsEngine::dbg_snd_off)
  194. {
  195. return;
  196. }
  197. path = soundBanks->GetSoundBankNativeName(path);
  198. if(!path)
  199. {
  200. return;
  201. }
  202. for(dword i = 0; i < scenes.Size(); i++)
  203. {
  204. scenes[i]->CheckForDelete(path);
  205. }
  206. return soundBanks->ReleaseSoundBank(path);
  207. }
  208. //Установить общую громкость
  209. void SoundService::SetGlobalVolume(float volume)
  210. {
  211. globalVolume = volume;
  212. states |= s_needUpdateVolumes;
  213. }
  214. //Получить общую громкость
  215. float SoundService::GetGlobalVolume()
  216. {
  217. return globalVolume;
  218. }
  219. //Установить громкость звуков
  220. void SoundService::SetSoundsVolume(float volume)
  221. {
  222. soundsVolume = volume;
  223. states |= s_needUpdateVolumes;
  224. }
  225. //Получить громкость звуков
  226. float SoundService::GetSoundsVolume()
  227. {
  228. return soundsVolume;
  229. }
  230. //Установить громкость музыки
  231. void SoundService::SetMusicVolume(float volume)
  232. {
  233. musicVolume = volume;
  234. }
  235. //Получить громкость музыки
  236. float SoundService::GetMusicVolume()
  237. {
  238. return musicVolume;
  239. }
  240. //Установка отладочных параметров
  241. void SoundService::SetDebugLevel(DebugLevel dl)
  242. {
  243. switch(dl)
  244. {
  245. case dl_minimal:
  246. states = (states & ~SoundsEngine::dbg_drawlevel_mask) | SoundsEngine::dbg_drawlevel_min;
  247. break;
  248. case dl_maximum:
  249. states = (states & ~SoundsEngine::dbg_drawlevel_mask) | SoundsEngine::dbg_drawlevel_max;
  250. break;
  251. }
  252. }
  253. SoundService::DebugLevel SoundService::GetDebugLevel()
  254. {
  255. if((states & SoundsEngine::dbg_drawlevel_mask) == SoundsEngine::dbg_drawlevel_max)
  256. {
  257. return dl_maximum;
  258. }
  259. return dl_minimal;
  260. }
  261. void SoundService::SetDebugView(dword dv)
  262. {
  263. states &= ~(SoundsEngine::dbg_draw2d | SoundsEngine::dbg_draw3d | SoundsEngine::dbg_drawlistener);
  264. if(dv & dv_2d)
  265. {
  266. states |= SoundsEngine::dbg_draw2d;
  267. }
  268. if(dv & dv_3d)
  269. {
  270. states |= SoundsEngine::dbg_draw3d;
  271. }
  272. if(dv & dv_listener)
  273. {
  274. states |= SoundsEngine::dbg_drawlistener;
  275. }
  276. }
  277. dword SoundService::GetDebugView()
  278. {
  279. dword debugView = 0;
  280. if(states & SoundsEngine::dbg_draw2d)
  281. {
  282. debugView |= dv_2d;
  283. }
  284. if(states & SoundsEngine::dbg_draw3d)
  285. {
  286. debugView |= dv_3d;
  287. }
  288. if(states & SoundsEngine::dbg_drawlistener)
  289. {
  290. debugView |= dv_listener;
  291. }
  292. return debugView;
  293. }
  294. //Нарисовать отладочную информацию
  295. void SoundService::DebugDraw()
  296. {
  297. if(!IsDebugDraw() || !engine) return;
  298. long line = 0;
  299. //Рисуем сцены
  300. for(dword i = 0; i < scenes.Size(); i++)
  301. {
  302. scenes[i]->DebugDraw(states, line);
  303. }
  304. //Вывод глобальной информации
  305. Sound::DebugDrawGlobals(states, *this);
  306. }
  307. #ifdef _XBOX
  308. void * SoundService::GetXAudio2()
  309. {
  310. if(engine)
  311. {
  312. return engine->GetXAudio();
  313. }
  314. return null;
  315. }
  316. #endif
  317. //Найти звук по имени
  318. SoundBankFileSound * SoundService::FindSound(const ConstString & name, const char ** bankName)
  319. {
  320. #ifndef NO_TOOLS
  321. if(isEnablePreview)
  322. {
  323. static const char * previewBankName = "Fake preview bank name";
  324. if(bankName)
  325. {
  326. *bankName = previewBankName;
  327. }
  328. if(previewSounds.Size() > 0)
  329. {
  330. for(dword i = 0; i < previewSounds.Size(); i++)
  331. {
  332. if(string::IsEqual(previewSounds[i]->name, name.c_str()))
  333. {
  334. return previewSounds[i];
  335. }
  336. }
  337. }
  338. return null;
  339. }
  340. #endif
  341. return soundBanks->FindSound(name, bankName);
  342. }
  343. //Получить количество звуков ожидающих продолжение
  344. dword SoundService::GetContinueWaiting()
  345. {
  346. #ifndef STOP_DEBUG
  347. dword count = 0;
  348. for(dword i = 0; i < scenes.Size(); i++)
  349. {
  350. SoundScene * scene = scenes[i];
  351. if(scene)
  352. {
  353. count += scene->GetCouninueQueueSize();
  354. }
  355. }
  356. return count;
  357. #else
  358. return 0;
  359. #endif
  360. }
  361. #ifndef NO_TOOLS
  362. //Разрешить-запретить создавать звуки с временных данных
  363. void SoundService::EditEnablePreview(bool isEnable)
  364. {
  365. isEnablePreview = isEnable;
  366. }
  367. //Зарегистрировать звук для предпрослушивания
  368. void SoundService::EditRegistrySound(SoundBankFileSound * sbfs)
  369. {
  370. for(dword i = 0; i < previewSounds.Size(); i++)
  371. {
  372. if(previewSounds[i] == sbfs)
  373. {
  374. return;
  375. }
  376. }
  377. previewSounds.Add(sbfs);
  378. }
  379. //Отменить регистрацию звука для предпрослушивания
  380. bool SoundService::EditUnregistrySound(SoundBankFileSound * sbfs)
  381. {
  382. Assert(sbfs);
  383. for(dword i = 0; i < scenes.Size(); i++)
  384. {
  385. if(scenes[i]->IsUse(*sbfs))
  386. {
  387. return false;
  388. }
  389. }
  390. for(dword i = 0; i < previewSounds.Size(); i++)
  391. {
  392. if(previewSounds[i] == sbfs)
  393. {
  394. previewSounds.DelIndex(i);
  395. }
  396. }
  397. return true;
  398. }
  399. //Обновить параметры звука
  400. bool SoundService::EditPatchSound(EditPatchSoundData & data, bool isCheckIds)
  401. {
  402. if(string::IsEmpty(data.soundName))
  403. {
  404. return false;
  405. }
  406. //Получаем по имени звук
  407. Assert(data.nameLen < sizeof(data.soundName));
  408. SoundBankFileHeader * header = null;
  409. SoundBankFileSound * sbfSound = soundBanks->FindSound(data.soundName, data.nameHash, data.nameLen, &header);
  410. if(!sbfSound || sbfSound->wavesCount != data.wavesCount)
  411. {
  412. return false;
  413. }
  414. //Таблица отладки
  415. Assert(header);
  416. if(!header->ids)
  417. {
  418. return false;
  419. }
  420. SoundBankFileObjectId * ids = header->ids;
  421. dword idsCount = header->idsCount;
  422. if(isCheckIds)
  423. {
  424. //Сверяем идентификаторы звука
  425. for(dword i = 0; i < idsCount; i++)
  426. {
  427. if(ids[i].objectPtr == (byte *)sbfSound)
  428. {
  429. if(!ids[i].IsEqual(data.soundId))
  430. {
  431. return false;
  432. }
  433. }
  434. }
  435. //Сверяем волны
  436. for(dword i = 0; i < sbfSound->wavesCount; i++)
  437. {
  438. if(sbfSound->waves[i].wave)
  439. {
  440. byte * wavePtr = (byte *)sbfSound->waves[i].wave;
  441. for(dword j = 0; j < idsCount; j++)
  442. {
  443. if(ids[i].objectPtr == wavePtr)
  444. {
  445. if(!ids[i].IsEqual(data.waves[i].waveId))
  446. {
  447. return false;
  448. }
  449. }
  450. }
  451. }else{
  452. dword * wid = data.waves[i].waveId;
  453. if(wid[0] | wid[1] | wid[2] | wid[3])
  454. {
  455. //Идентификатор не пустой
  456. return false;
  457. }
  458. }
  459. }
  460. }
  461. //Обнавляем параметры
  462. dword priority = data.priority & SoundBankFileSetup::mode_priority_mask;
  463. Assert(priority == data.priority);
  464. sbfSound->setup.mode &= ~SoundBankFileSetup::mode_priority_mask;
  465. sbfSound->setup.mode |= priority;
  466. sbfSound->setup.maxCount = data.maxCount;
  467. sbfSound->att.c[0] = data.c[0];
  468. sbfSound->att.c[1] = data.c[1];
  469. sbfSound->att.c[2] = data.c[2];
  470. sbfSound->att.c[3] = data.c[3];
  471. Assert(data.minDist2 < data.maxDist2);
  472. sbfSound->att.minDist2 = data.minDist2;
  473. sbfSound->att.maxDist2 = data.maxDist2;
  474. sbfSound->att.kNorm2 = data.kNorm2;
  475. Assert(data.wavesCount == sbfSound->wavesCount);
  476. for(dword i = 0; i < data.wavesCount; i++)
  477. {
  478. sbfSound->waves[i].volume = data.waves[i].volume;
  479. sbfSound->waves[i].probability = data.waves[i].probability;
  480. sbfSound->waves[i].playTime = data.waves[i].playTime;
  481. }
  482. states |= s_needUpdateVolumes;
  483. return true;
  484. }
  485. //Остановить проигрывание всех звуков
  486. void SoundService::EditStopAllSounds(const char * sceneOvner)
  487. {
  488. for(dword i = 0; i < scenes.Size(); i++)
  489. {
  490. scenes[i]->StopAllSounds(sceneOvner);
  491. }
  492. }
  493. #endif