SoundBankFile.h 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. #ifndef _SoundBankFile_h_
  2. #define _SoundBankFile_h_
  3. #include "..\..\common_h\core.h"
  4. #include "..\..\Common_h\data_swizzle.h"
  5. #ifdef _XBOX
  6. #include <Audiodefs.h>
  7. #endif
  8. //===========================================================================================================================
  9. //
  10. // SoundBankId
  11. // xbox part---------------------------
  12. // SoundBankFileHeader
  13. // SoundBankFileSound[SoundBankFileHeader.soundsCount]
  14. // SoundBankFileWaveInfo[SoundBankFileHeader.winfosCount]
  15. // SoundBankFileWave[SoundBankFileHeader.wavesCount]
  16. // SoundBankFileSound * entry[SoundBankFileHeader.mask + 1]
  17. // SoundBankFileExtra[SoundBankFileHeader.extrasCount]
  18. // SoundBankFileWaveQueue data
  19. // Names binary data
  20. // Extra binary data
  21. // WAVEFORMATEX data
  22. // [UINT32]
  23. // Waves binary data
  24. // ---------------------------
  25. // pc part-----------------------------
  26. // тоже что и в xbox только в порядке от меньшего к большему и волны в формате для РС
  27. //
  28. // SoundBankFileId[SoundBankFileHeader.idsCount] (только PC)
  29. //===========================================================================================================================
  30. __forceinline void SoundBankFile_Prepare4byteAlignedSwizzler(void * ptr, dword bytes, bool isNeedSwizzle)
  31. {
  32. //Порядок байт в файле задан от старшего к младшему
  33. if(!isNeedSwizzle) return;
  34. Assert((bytes & 3) == 0);
  35. dword * p = (dword *)ptr;
  36. for(dword * pe = p + (bytes >> 2); p < pe; p++)
  37. {
  38. __RefDataSwizzler(*p);
  39. }
  40. }
  41. template<class T> __forceinline bool SoundBankFile_RestorePointer(T * & aptr, byte * dataStart, dword size)
  42. {
  43. if(aptr)
  44. {
  45. if((((byte *)aptr) - ((byte *)null)) >= (long)size)
  46. {
  47. return false;
  48. }
  49. aptr = (T *)((((byte *)aptr) - ((byte *)null)) + dataStart);
  50. }
  51. return true;
  52. }
  53. template<class T> __forceinline void SoundBankFile_PreparePointer(T * & aptr, byte * dataStart)
  54. {
  55. if(aptr)
  56. {
  57. aptr = (T *)(((byte *)aptr) - dataStart);
  58. }
  59. }
  60. //Идентификаторы типа расширенных данных
  61. enum SoundBankFileExtraId
  62. {
  63. sbf_extra_phonemes = 1, //Фонемы
  64. };
  65. //Заголовок указывающий на расширенные данные
  66. struct SoundBankFileExtra
  67. {
  68. dword id; //Идентификатор расширенных данных (SoundBankFileExtraId)
  69. byte * data; //Указатель где данные распологаються
  70. //Подготовить данные для использования
  71. __forceinline bool Restore(byte * dataStart, dword size)
  72. {
  73. if(!SoundBankFile_RestorePointer(data, dataStart, size)) return false;
  74. return true;
  75. }
  76. //Упаковать данные для сохранения
  77. __forceinline void Prepare(byte * dataStart, bool isNeedSwizzle)
  78. {
  79. SoundBankFile_PreparePointer(data, dataStart);
  80. SoundBankFile_Prepare4byteAlignedSwizzler(this, sizeof(SoundBankFileExtra), isNeedSwizzle);
  81. }
  82. };
  83. //Уникальный идентификатор для настройки (есть только в PC версии)
  84. struct SoundBankFileObjectId
  85. {
  86. byte * objectPtr; //Объект, которому принадлежит идентификатор
  87. dword data[4]; //Идентификатор объекта
  88. //Подготовить данные для использования
  89. __forceinline bool Restore(byte * dataStart, dword size)
  90. {
  91. if(!SoundBankFile_RestorePointer(objectPtr, dataStart, size)) return false;
  92. return true;
  93. }
  94. //Упаковать данные для сохранения
  95. __forceinline void Prepare(byte * dataStart, bool isNeedSwizzle)
  96. {
  97. SoundBankFile_PreparePointer(objectPtr, dataStart);
  98. Assert(!isNeedSwizzle);
  99. }
  100. bool IsEqual(dword id[4])
  101. {
  102. dword res = (id[0] ^ data[0]) | (id[1] ^ data[1]) | (id[2] ^ data[2]) | (id[3] ^ data[3]);
  103. return res == 0;
  104. }
  105. };
  106. //Базовые параметры звука
  107. struct SoundBankFileSetup
  108. {
  109. enum Modes
  110. {
  111. //Приоритет
  112. mode_priority_base = 0x1000, //Базовый приоритет для редактора
  113. mode_priority_range = 0x2000, //Диапазон приоритетов для редактора
  114. mode_priority_mask = 0xffff, //Приоритет по отношению к остальным звукам, больше число - выше приоритет
  115. //Методы выбора волны
  116. mode_select_rnd = 0x0000, //Выбирать волны случайным образом
  117. mode_select_queue = 0x10000, //Выбирать волны случайно, избегая повторений с учётом весов
  118. mode_select_sequence = 0x20000, //Выбирать волны последовательно как они заданны
  119. mode_select_mask = 0x30000,
  120. //Зацикленные звуки
  121. mode_loop_diasble = 0x0000, //Звук не зациклен
  122. mode_loop_one_wave = 0x40000, //Отыгрывать зацикленно звук с 1й волной
  123. // mode_loop_sel_wave_rnd = 0x80000, //Отыгрывать зацикленно звук каждый раз выбирая новую волну как в mode_select_rnd
  124. // mode_loop_sel_wave_que = 0xc0000, //Отыгрывать зацикленно звук каждый раз выбирая новую волну как в mode_select_queue
  125. mode_loop_mask = 0xc0000,
  126. //Какие эффекты применять к звуку
  127. mode_fx_full = 0x000000, //Применять все эффекты
  128. mode_fx_premaster = 0x100000, //Пропусить эфект окружающей среды
  129. mode_fx_master = 0x200000, //Пропусить эфект окружающей среды и премастера
  130. mode_fx_music = 0x300000, //Музыка
  131. mode_fx_mask = 0x300000,
  132. };
  133. #ifndef GAME_RUSSIAN
  134. dword maxCount; //Максимальное количество одновременно проигрываемых данных звуков, 0 неограничено
  135. dword mode; //Режим использования звука
  136. #else
  137. dword mode; //Режим использования звука
  138. dword maxCount; //Максимальное количество одновременно проигрываемых данных звуков, 0 неограничено
  139. #endif
  140. //Получить приоритет звука
  141. __forceinline dword GetPriority()
  142. {
  143. return mode & mode_priority_mask;
  144. }
  145. //Получить режим выбора волны
  146. __forceinline dword GetModeSelect()
  147. {
  148. return mode & mode_select_mask;
  149. }
  150. //Получить режим выбора волны
  151. __forceinline dword GetModeLoop()
  152. {
  153. return mode & mode_loop_mask;
  154. }
  155. //Определить какаие эффекты применять для звука
  156. __forceinline dword GetFxMode()
  157. {
  158. return mode & mode_fx_mask;
  159. }
  160. };
  161. //Параметры затухания звука от дистанции
  162. struct SoundBankFileAttenuation
  163. {
  164. float c[4]; //Коэфициенты графика затухания
  165. #ifndef GAME_RUSSIAN
  166. float minDist2; //Минимальныя дистанция в квадрате
  167. float maxDist2; //Максимальныя дистанция в квадрате
  168. float kNorm2; //Коэфициент нормализации в квадрате 1.0/(maxDist2 - minDist2)
  169. #else
  170. #ifndef GAME_DEMO
  171. float kNorm2; //Коэфициент нормализации в квадрате 1.0/(maxDist2 - minDist2)
  172. float minDist2; //Минимальныя дистанция в квадрате
  173. float maxDist2; //Максимальныя дистанция в квадрате
  174. #else
  175. float minDist2; //Минимальныя дистанция в квадрате
  176. float kNorm2; //Коэфициент нормализации в квадрате 1.0/(maxDist2 - minDist2)
  177. float maxDist2; //Максимальныя дистанция в квадрате
  178. #endif
  179. #endif
  180. //Расчитать затухание для звука в локальной системе слушателя
  181. __forceinline float Attenuation(float dist2)
  182. {
  183. if(dist2 >= minDist2)
  184. {
  185. if(dist2 < maxDist2)
  186. {
  187. float k = (dist2 - minDist2)*kNorm2;
  188. float att = AttenuationBySpline(k, c[0], c[1], c[2], c[3]);
  189. if(att < 0.0f) att = 0.0f;
  190. if(att > 1.0f) att = 1.0f;
  191. return att;
  192. }
  193. return 0.0f;
  194. }
  195. return 1.0f;
  196. }
  197. };
  198. //Физическое представление волны
  199. struct SoundBankFileWave
  200. {
  201. enum Format
  202. {
  203. f_format_error = 0x00000000,//Такого быть не должно
  204. f_freq_mask = 0x0001ffff,//Маска для описания частоты дискретизации
  205. f_format_pcm = 0x00100000,//Не кодированый формат, 16 бит
  206. f_format_xma = 0x00200000,//Архивированый формат xma
  207. f_format_xvma = 0x00300000,//Архивированый формат xvma
  208. f_format_mask = 0x00700000,//Маска для получения формата кодирования
  209. f_quality_mask = 0x3f000000,//Маска для получения качества сжатия 0-минимальное качество, 63-максимальное качество
  210. f_quality_shift = 24, //Сдвиг для получения качества сжатия
  211. f_stereo = 0x00020000,//Стерео или моно
  212. f_tmp_music = 0x80000000,//Это музыка, не сохраняемый в файле флаг (дублирует mode_fx_music)
  213. };
  214. struct XWMAWAVEFORMAT
  215. {
  216. WAVEFORMATEX format;
  217. dword tableCount;
  218. dword table[1];
  219. };
  220. #ifndef GAME_RUSSIAN
  221. const byte * data; //Звуковые данные волны
  222. dword dataSize; //Размер звуковых данных в байтах
  223. dword samplesCount; //Количество сэмплов в волне
  224. dword format; //Внутреннее описание формата волн
  225. float unimportantTime; //Время малозначительного остатка, когда звук можно проигнорировать
  226. float maxNormalizedAmp; //Максимальная нормализованная амплитуда от 0 до 1
  227. const byte * waveFormatInfo; //Структура описывающая формат волны WAVEFORMATEX или XMA2WAVEFORMAT или XWMAWAVEFORMAT
  228. SoundBankFileExtra * extraData; //Расширенные данные в таблице расширений
  229. dword extraCount; //Количество расширенных данных
  230. #else
  231. #ifndef GAME_DEMO
  232. const byte * data; //Звуковые данные волны
  233. dword dataSize; //Размер звуковых данных в файтах
  234. dword samplesCount; //Количество сэмплов в волне
  235. dword format; //Внутреннее описание формата волн
  236. const byte * waveFormatInfo; //Структура описывающая формат волны WAVEFORMATEX или XMA2WAVEFORMAT или XWMAWAVEFORMAT
  237. float maxNormalizedAmp; //Максимальная нормализованная амплитуда от 0 до 1
  238. float unimportantTime; //Время малозначительного остатка, когда звук можно проигнорировать
  239. SoundBankFileExtra * extraData; //Расширенные данные в таблице расширений
  240. dword extraCount; //Количество расширенных данных
  241. #else
  242. dword format; //Внутреннее описание формата волн
  243. dword dataSize; //Размер звуковых данных в файтах
  244. dword samplesCount; //Количество сэмплов в волне
  245. const byte * waveFormatInfo; //Структура описывающая формат волны WAVEFORMATEX или XMA2WAVEFORMAT или XWMAWAVEFORMAT
  246. SoundBankFileExtra * extraData; //Расширенные данные в таблице расширений
  247. float maxNormalizedAmp; //Максимальная нормализованная амплитуда от 0 до 1
  248. const byte * data; //Звуковые данные волны
  249. float unimportantTime; //Время малозначительного остатка, когда звук можно проигнорировать
  250. dword extraCount; //Количество расширенных данных
  251. #endif
  252. #endif
  253. //Подготовить данные для использования
  254. __forceinline bool Restore(byte * dataStart, dword size)
  255. {
  256. if(!SoundBankFile_RestorePointer(data, dataStart, size)) return false;
  257. if(!SoundBankFile_RestorePointer(waveFormatInfo, dataStart, size)) return false;
  258. if(!SoundBankFile_RestorePointer(extraData, dataStart, size)) return false;
  259. return true;
  260. }
  261. //Упаковать данные для сохранения
  262. __forceinline void Prepare(byte * dataStart, bool isNeedSwizzle)
  263. {
  264. SoundBankFile_PreparePointer(data, dataStart);
  265. SoundBankFile_PreparePointer(waveFormatInfo, dataStart);
  266. SoundBankFile_PreparePointer(extraData, dataStart);
  267. SoundBankFile_Prepare4byteAlignedSwizzler(this, sizeof(SoundBankFileWave), isNeedSwizzle);
  268. }
  269. #ifdef GAME_RUSSIAN
  270. //Кодирование волн. Если будут проблемы, то закаментировать содержимое
  271. __forceinline void EncodeWaveData()
  272. {
  273. if(data)
  274. {
  275. dword magic = 0;
  276. dword count = 0;
  277. byte xcode = 0;
  278. EncodeInit(magic, count, xcode);
  279. byte * d = (byte *)data;
  280. for(dword i = 0; i < dataSize; i++)
  281. {
  282. d[i] ^= xcode;
  283. if(count == 0)
  284. {
  285. if(d[i] == 0)
  286. {
  287. EncodeStep(magic, count, xcode);
  288. }
  289. }else{
  290. count--;
  291. }
  292. }
  293. }
  294. }
  295. #pragma optimize("", off)
  296. void DecodeWaveData()
  297. {
  298. if(data)
  299. {
  300. dword magic = *(dword *)api->Storage().GetString("system.core.id", " ");
  301. dword count = dataSize;
  302. byte xcode = 13;
  303. byte * d = (byte *)data;
  304. EncodeInit(magic, count, xcode);
  305. for(dword i = 0; i < dataSize; i++)
  306. {
  307. d[i] ^= xcode;
  308. if(count == 0)
  309. {
  310. if(d[i] == xcode)
  311. {
  312. EncodeStep(magic, count, xcode);
  313. }
  314. }else{
  315. count--;
  316. }
  317. }
  318. }
  319. }
  320. void EncodeInit(dword & magic, dword & count, byte & xcode)
  321. {
  322. magic = 18532;
  323. count = 341;
  324. xcode = byte(magic);
  325. }
  326. void EncodeStep(dword & magic, dword & count, byte & xcode)
  327. {
  328. dword cur = magic;
  329. magic = ((cur + 1253947)*112492*cur + 84723) >> 5;
  330. xcode = byte(magic);
  331. count = ((magic + 43)*(magic + 11)) & 1023;
  332. if(count > 923) count = 1374;
  333. if(count < 157) count = 232;
  334. }
  335. #pragma optimize("", on)
  336. #endif
  337. };
  338. //Описание волны принадлежащей звуку
  339. struct SoundBankFileWaveInfo
  340. {
  341. #ifndef GAME_RUSSIAN
  342. float volume; //Громкость с какой проигрывать волну
  343. float probability; //Вероятность выбора волны
  344. float playTime; //Время активности волны (время проигрывание волны или тишины)
  345. SoundBankFileWave * wave; //Данные волны
  346. #else
  347. #ifndef GAME_DEMO
  348. SoundBankFileWave * wave; //Данные волны
  349. float volume; //Громкость с какой проигрывать волну
  350. float probability; //Вероятность выбора волны
  351. float playTime; //Время активности волны (время проигрывание волны или тишины)
  352. #else
  353. float volume; //Громкость с какой проигрывать волну
  354. float probability; //Вероятность выбора волны
  355. SoundBankFileWave * wave; //Данные волны
  356. float playTime; //Время активности волны (время проигрывание волны или тишины)
  357. #endif
  358. #endif
  359. //Подготовить данные для использования
  360. __forceinline bool Restore(byte * dataStart, dword size)
  361. {
  362. if(!SoundBankFile_RestorePointer(wave, dataStart, size)) return false;
  363. return true;
  364. }
  365. //Упаковать данные для сохранения
  366. __forceinline void Prepare(byte * dataStart, bool isNeedSwizzle)
  367. {
  368. SoundBankFile_PreparePointer(wave, dataStart);
  369. SoundBankFile_Prepare4byteAlignedSwizzler(this, sizeof(SoundBankFileWaveInfo), isNeedSwizzle);
  370. }
  371. };
  372. //Очередь для выбора волн
  373. struct SoundBankFileWaveQueue
  374. {
  375. struct Wave
  376. {
  377. float weight; //Текущий вес волны
  378. };
  379. static __forceinline dword GetSize(dword wavesCount)
  380. {
  381. return sizeof(SoundBankFileWaveQueue) + sizeof(Wave)*(wavesCount - 1);
  382. }
  383. //Сделать выборку волны из очереди
  384. __forceinline dword Select(SoundBankFileWaveInfo * waves, dword wavesCount)
  385. {
  386. //Считаем сумарный вес
  387. float totalWeight = 0.0f;
  388. for(dword i = 0; i < wavesCount; i++)
  389. {
  390. if(wave[i].weight <= 0.0f) continue;
  391. totalWeight += wave[i].weight;
  392. }
  393. //Если необходимо, обнавляем волны
  394. while(totalWeight <= 0.0001f)
  395. {
  396. //Инициализируем пустую таблицу
  397. totalWeight = 0.0f;
  398. for(dword i = 0; i < wavesCount; i++)
  399. {
  400. wave[i].weight += waves[i].probability;
  401. totalWeight += wave[i].weight;
  402. }
  403. }
  404. Assert(totalWeight > 0.0f);
  405. long last = -1;
  406. float rnd = Rnd(totalWeight);
  407. float cur = 0.0f;
  408. for(dword i = 0; i < wavesCount; i++)
  409. {
  410. Wave & w = wave[i];
  411. if(w.weight <= 0.0f)
  412. {
  413. //Пропускаем выпавшие из очереди волны
  414. continue;
  415. }
  416. last = i;
  417. cur += w.weight;
  418. if(cur >= rnd)
  419. {
  420. //Правим веса
  421. w.weight -= minWeight;
  422. return i;
  423. }
  424. }
  425. return 0;
  426. }
  427. dword count; //Текущее количество элементов в массиве (максимум SoundBankFileSound::wavesCount)
  428. float minWeight; //Минимальный вес в таблице волн
  429. float totalWeight; //Сумарный вес
  430. Wave wave[1]; //Масив элементов для выбора волны
  431. };
  432. //Описание звука
  433. struct SoundBankFileSound
  434. {
  435. #ifndef GAME_RUSSIAN
  436. SoundBankFileWaveInfo * waves; //Индекс начала таблицы волн этого звука
  437. dword wavesCount; //Количество волн приписаных звуку
  438. dword playSoundsCount; //Количество звуков проигрываемых в текущий момент
  439. void * playSoundsList; //Вхождение в список проигрываемых звуков
  440. union
  441. {
  442. SoundBankFileWaveQueue * squeue;//Очередь для случайного выбора волн при проигрывании звука
  443. dword selectSequenceCount; //Счётчик для последовательного выбора волн
  444. };
  445. // SoundBankFileWaveQueue * lqueue;//Очередь для случайного выбора волн зацикленного звука
  446. const char * name; //Имя звука
  447. dword nameHash; //Хэшь значение имени
  448. dword nameLen; //Длинна имени
  449. SoundBankFileSound * next; //Следующий в цепочке поиска
  450. SoundBankFileExtra * extraData; //Расширенные данные в таблице расширений
  451. dword extraCount; //Количество расширенных данных
  452. SoundBankFileSetup setup; //Базовые настройки звука
  453. SoundBankFileAttenuation att; //Параметры для 3D звука
  454. #else
  455. #ifndef GAME_DEMO
  456. void * playSoundsList; //Вхождение в список проигрываемых звуков
  457. dword playSoundsCount; //Количество звуков проигрываемых в текущий момент
  458. SoundBankFileWaveInfo * waves; //Индекс начала таблицы волн этого звука
  459. dword wavesCount; //Количество волн приписаных звуку
  460. union
  461. {
  462. SoundBankFileWaveQueue * squeue;//Очередь для случайного выбора волн при проигрывании звука
  463. dword selectSequenceCount; //Счётчик для последовательного выбора волн
  464. };
  465. // SoundBankFileWaveQueue * lqueue;//Очередь для случайного выбора волн зацикленного звука
  466. dword nameHash; //Хэшь значение имени
  467. dword nameLen; //Длинна имени
  468. SoundBankFileSound * next; //Следующий в цепочке поиска
  469. const char * name; //Имя звука
  470. SoundBankFileExtra * extraData; //Расширенные данные в таблице расширений
  471. dword extraCount; //Количество расширенных данных
  472. SoundBankFileAttenuation att; //Параметры для 3D звука
  473. SoundBankFileSetup setup; //Базовые настройки звука
  474. #else
  475. const char * name; //Имя звука
  476. dword nameHash; //Хэшь значение имени
  477. dword nameLen; //Длинна имени
  478. SoundBankFileSetup setup; //Базовые настройки звука
  479. SoundBankFileAttenuation att; //Параметры для 3D звука
  480. SoundBankFileWaveInfo * waves; //Индекс начала таблицы волн этого звука
  481. dword wavesCount; //Количество волн приписаных звуку
  482. dword playSoundsCount; //Количество звуков проигрываемых в текущий момент
  483. void * playSoundsList; //Вхождение в список проигрываемых звуков
  484. union
  485. {
  486. SoundBankFileWaveQueue * squeue;//Очередь для случайного выбора волн при проигрывании звука
  487. dword selectSequenceCount; //Счётчик для последовательного выбора волн
  488. };
  489. // SoundBankFileWaveQueue * lqueue;//Очередь для случайного выбора волн зацикленного звука
  490. SoundBankFileSound * next; //Следующий в цепочке поиска
  491. SoundBankFileExtra * extraData; //Расширенные данные в таблице расширений
  492. dword extraCount; //Количество расширенных данных
  493. #endif
  494. #endif
  495. //Подготовить данные для использования
  496. __forceinline bool Restore(byte * dataStart, dword size)
  497. {
  498. if(!SoundBankFile_RestorePointer(waves, dataStart, size)) return false;
  499. if(!SoundBankFile_RestorePointer(name, dataStart, size)) return false;
  500. if(!SoundBankFile_RestorePointer(next, dataStart, size)) return false;
  501. if(!SoundBankFile_RestorePointer(extraData, dataStart, size)) return false;
  502. if(!SoundBankFile_RestorePointer(squeue, dataStart, size)) return false;
  503. playSoundsCount = 0;
  504. playSoundsList = null;
  505. InitSelectors();
  506. return true;
  507. }
  508. //Упаковать данные для сохранения
  509. __forceinline void Prepare(byte * dataStart, bool isNeedSwizzle)
  510. {
  511. if(wavesCount > 1)
  512. {
  513. dword selMode = setup.GetModeSelect();
  514. switch(selMode)
  515. {
  516. case SoundBankFileSetup::mode_select_rnd:
  517. squeue = null;
  518. break;
  519. case SoundBankFileSetup::mode_select_queue:
  520. memset(squeue, 0, SoundBankFileWaveQueue::GetSize(wavesCount));
  521. SoundBankFile_PreparePointer(squeue, dataStart);
  522. break;
  523. case SoundBankFileSetup::mode_select_sequence:
  524. squeue = null;
  525. break;
  526. };
  527. /* dword loopMode = setup->GetModeLoop();
  528. if(loopMode == SoundBankFileSetup::mode_loop_sel_wave_que)
  529. {
  530. memset(lqueue, 0, SoundBankFileWaveQueue::GetSize(wavesCount));
  531. SoundBankFile_PreparePointer(lqueue, dataStart);
  532. }else{
  533. lqueue = null;
  534. }
  535. */
  536. }else{
  537. squeue = null;
  538. // lqueue = null;
  539. }
  540. playSoundsCount = 0;
  541. playSoundsList = null;
  542. SoundBankFile_PreparePointer(waves, dataStart);
  543. SoundBankFile_PreparePointer(name, dataStart);
  544. SoundBankFile_PreparePointer(next, dataStart);
  545. SoundBankFile_PreparePointer(extraData, dataStart);
  546. SoundBankFile_Prepare4byteAlignedSwizzler(this, sizeof(SoundBankFileSound), isNeedSwizzle);
  547. }
  548. //Инициализация параметров выбора волн
  549. __forceinline void InitSelectors()
  550. {
  551. if(wavesCount > 1)
  552. {
  553. dword selMode = setup.GetModeSelect();
  554. switch(selMode)
  555. {
  556. case SoundBankFileSetup::mode_select_rnd:
  557. squeue = null;
  558. break;
  559. case SoundBankFileSetup::mode_select_queue:
  560. {
  561. //Ищем минимальное значение, чтобы определить количество экземпляров в очереди
  562. float minValue = waves[0].probability;
  563. for(dword i = 1; i < wavesCount; i++)
  564. {
  565. if(minValue < waves[i].probability)
  566. {
  567. minValue = waves[i].probability;
  568. }
  569. }
  570. //Не более 100 проигрывания на звук из таблицы
  571. squeue->minWeight = coremax(minValue, 0.01f);
  572. //Таблица в начале пустая
  573. squeue->count = 0;
  574. }
  575. break;
  576. case SoundBankFileSetup::mode_select_sequence:
  577. selectSequenceCount = 0;
  578. break;
  579. };
  580. /* dword loopMode = setup->GetModeLoop();
  581. if(loopMode == SoundBankFileSetup::mode_loop_sel_wave_que)
  582. {
  583. if(!SoundBankFile_RestorePointer(lqueue, dataStart, size)) return false;
  584. lqueue->minWeight = 100.0f;
  585. lqueue->count = 0;
  586. }else{
  587. lqueue = null;
  588. }
  589. */
  590. }else{
  591. squeue = null;
  592. // lqueue = null;
  593. }
  594. }
  595. //Выбрать волну для воспроизведения
  596. __forceinline dword SelectWaveIndex()
  597. {
  598. if(wavesCount == 1)
  599. {
  600. return 0;
  601. }
  602. dword selMode = setup.GetModeSelect();
  603. switch(selMode)
  604. {
  605. case SoundBankFileSetup::mode_select_rnd:
  606. return GetRandomWaveIndex();
  607. case SoundBankFileSetup::mode_select_queue:
  608. return squeue->Select(waves, wavesCount);
  609. case SoundBankFileSetup::mode_select_sequence:
  610. {
  611. if(selectSequenceCount >= wavesCount)
  612. {
  613. selectSequenceCount = 0;
  614. }
  615. dword index = selectSequenceCount;
  616. selectSequenceCount++;
  617. return index;
  618. }
  619. };
  620. Assert(false);
  621. return 0;
  622. }
  623. /*
  624. //Выбрать волну для повторения
  625. __forceinline long GetLoopWaveIndex(long currentIndex)
  626. {
  627. if(wavesCount == 1)
  628. {
  629. return currentIndex;
  630. }
  631. dword loopMode = setup->GetModeLoop();
  632. switch(loopMode)
  633. {
  634. case SoundBankFileSetup::mode_loop_diasble:
  635. Assert(false);
  636. return currentIndex;
  637. case SoundBankFileSetup::mode_loop_one_wave:
  638. return currentIndex;
  639. case SoundBankFileSetup::mode_loop_sel_wave_rnd:
  640. return GetRandomWaveIndex();
  641. case SoundBankFileSetup::mode_loop_sel_wave_que:
  642. return lqueue->Select(waves, wavesCount);
  643. }
  644. Assert(false);
  645. return currentIndex;
  646. }
  647. */
  648. private:
  649. dword GetRandomWaveIndex()
  650. {
  651. float rnd = Rnd();
  652. float cur = 0.0f;
  653. for(dword i = 0; i < wavesCount; i++)
  654. {
  655. cur += waves[i].probability;
  656. if(cur >= rnd)
  657. {
  658. return i;
  659. }
  660. }
  661. return wavesCount - 1;
  662. }
  663. };
  664. //Описание фонем прикреплёных к волне
  665. struct SoundBankFilePhonemes
  666. {
  667. enum Consts
  668. {
  669. currentVersion = 1,
  670. phoneme_id_silence = 0, //Фонема тишины
  671. phoneme_id_max = 254, //Последний занят для корректного сравнения времени
  672. };
  673. dword version; //Текущая версия данных
  674. dword framesCount; //Количество кадров
  675. dword phoneme[1]; //В старших 3х байтах находиться время в милисекундах, в младшем байте идентификатор фонемы
  676. static __forceinline dword GetSize(dword framesCount)
  677. {
  678. return sizeof(SoundBankFilePhonemes) + sizeof(dword)*(framesCount - 1);
  679. }
  680. //Подготовить данные для использования
  681. __forceinline bool Restore(byte * dataStart, dword size)
  682. {
  683. return true;
  684. }
  685. //Упаковать данные для сохранения
  686. __forceinline void Prepare(byte * dataStart, bool isNeedSwizzle)
  687. {
  688. SoundBankFile_Prepare4byteAlignedSwizzler(this, sizeof(SoundBankFilePhonemes) + sizeof(dword)*(framesCount - 1), isNeedSwizzle);
  689. }
  690. //Найти кадр текущей фонемы зная время в милисекундах и последний кадр
  691. __forceinline dword FindFrame(dword currentTimeInMs, dword lookFromFrame = 0)
  692. {
  693. dword time = (currentTimeInMs <= 0xffffff) ? ((currentTimeInMs << 8) | 0xff) : 0xffffffff;
  694. for(dword i = lookFromFrame + 1; i < framesCount; i++)
  695. {
  696. if(time < phoneme[i])
  697. {
  698. return i - 1;
  699. }
  700. }
  701. return framesCount - 1;
  702. }
  703. //Получить идентификатор фонемы из запакованного значения
  704. __forceinline dword GetPhonemeId(dword frame)
  705. {
  706. return phoneme[frame] & 0xff;
  707. }
  708. //Запаковать фонему имея время в милисекундах и идентификатор
  709. static __forceinline dword PackPhoneme(dword timeInMs, byte id)
  710. {
  711. Assert(timeInMs <= 0xffffff);
  712. Assert(id < phoneme_id_max);
  713. return (timeInMs << 8) | dword(id);
  714. }
  715. };
  716. //Заголовок файла
  717. struct SoundBankFileHeader
  718. {
  719. dword uniqueId[4]; //Уникальный идентификатор звукового банка
  720. SoundBankFileSound * sounds; //Звуки
  721. dword soundsCount; //Количество звуков
  722. SoundBankFileWaveInfo * winfos; //Описание волн подвязаных к звукам
  723. dword winfosCount; //Размер таблицы волн
  724. SoundBankFileWave * waves; //Волны, используещиеся в банке
  725. dword wavesCount; //Количество волн используемых в банке
  726. SoundBankFileSound ** entry; //Входная таблица поиска звуков по имени
  727. dword mask; //Маска входа через таблицу поиска
  728. SoundBankFileObjectId * ids; //Таблица идентификаторов, используемых для отладки
  729. dword idsCount; //Количество идентификаторов
  730. SoundBankFileExtra * extras; //Таблица расширений
  731. dword extrasCount; //Количество расширений
  732. //Подготовить данные для использования
  733. __forceinline bool Restore(dword size)
  734. {
  735. //Указатель к которому приводим данные
  736. byte * dataStart = (byte *)this;
  737. //Себя
  738. if(!SoundBankFile_RestorePointer(sounds, dataStart, size)) return false;
  739. if(!SoundBankFile_RestorePointer(winfos, dataStart, size)) return false;
  740. if(!SoundBankFile_RestorePointer(waves, dataStart, size)) return false;
  741. if(!SoundBankFile_RestorePointer(entry, dataStart, size)) return false;
  742. if(!SoundBankFile_RestorePointer(ids, dataStart, size)) return false;
  743. if(!SoundBankFile_RestorePointer(extras, dataStart, size)) return false;
  744. //Таблица расширений
  745. if(!RestoreArray(extras, extrasCount, dataStart, size)) return false;
  746. //Входная таблица поиска звуков по имени
  747. for(dword i = 0; i <= mask; i++)
  748. {
  749. if(!SoundBankFile_RestorePointer(entry[i], dataStart, size)) return false;
  750. }
  751. //Волны, используещиеся в банке
  752. if(!RestoreArray(waves, wavesCount, dataStart, size)) return false;
  753. //Описание волн подвязаных к звукам
  754. if(!RestoreArray(winfos, winfosCount, dataStart, size)) return false;
  755. //Звуки
  756. if(!RestoreArray(sounds, soundsCount, dataStart, size)) return false;
  757. //Идентификаторы
  758. if(!RestoreArray(ids, idsCount, dataStart, size)) return false;
  759. return true;
  760. }
  761. //Упаковать данные для сохранения
  762. __forceinline void Prepare(bool isNeedSwizzle)
  763. {
  764. //Указатель к которому приводим данные
  765. byte * dataStart = (byte *)this;
  766. //Идентификаторы
  767. if(!isNeedSwizzle && ids)
  768. {
  769. PrepareArray(ids, idsCount, dataStart, false);
  770. }else{
  771. ids = null;
  772. idsCount = 0;
  773. }
  774. //Звуки
  775. PrepareArray(sounds, soundsCount, dataStart, isNeedSwizzle);
  776. //Описание волн подвязаных к звукам
  777. PrepareArray(winfos, winfosCount, dataStart, isNeedSwizzle);
  778. //Волны, используещиеся в банке
  779. PrepareArray(waves, wavesCount, dataStart, isNeedSwizzle);
  780. //Входная таблица поиска звуков по имени
  781. for(dword i = 0; i <= mask; i++)
  782. {
  783. SoundBankFile_PreparePointer(entry[i], dataStart);
  784. }
  785. SoundBankFile_Prepare4byteAlignedSwizzler(entry, (mask + 1)*sizeof(SoundBankFileSound *), isNeedSwizzle);
  786. //Таблица расширений
  787. for(dword i = 0; i <= extrasCount; i++)
  788. {
  789. switch(extras[i].id)
  790. {
  791. case sbf_extra_phonemes:
  792. ((SoundBankFilePhonemes *)extras[i].data)->Prepare(dataStart, isNeedSwizzle);
  793. break;
  794. // default:
  795. //Непрописанный тип. Надо внести в таблицу.
  796. // Assert(false);
  797. }
  798. }
  799. PrepareArray(extras, extrasCount, dataStart, isNeedSwizzle);
  800. //Себя
  801. SoundBankFile_PreparePointer(ids, dataStart);
  802. SoundBankFile_PreparePointer(sounds, dataStart);
  803. SoundBankFile_PreparePointer(winfos, dataStart);
  804. SoundBankFile_PreparePointer(waves, dataStart);
  805. SoundBankFile_PreparePointer(entry, dataStart);
  806. SoundBankFile_PreparePointer(extras, dataStart);
  807. SoundBankFile_Prepare4byteAlignedSwizzler(this, sizeof(SoundBankFileHeader), isNeedSwizzle);
  808. }
  809. private:
  810. template<class T> __forceinline bool RestoreArray(T * aptr, dword count, byte * dataStart, dword size)
  811. {
  812. for(dword i = 0; i < count; i++)
  813. {
  814. if(!aptr[i].Restore(dataStart, size)) return false;
  815. }
  816. return true;
  817. }
  818. template<class T> __forceinline void PrepareArray(T * aptr, dword count, byte * dataStart, bool isNeedSwizzle)
  819. {
  820. for(dword i = 0; i < count; i++)
  821. {
  822. aptr[i].Prepare(dataStart, isNeedSwizzle);
  823. }
  824. }
  825. };
  826. //Идентификатор файла
  827. struct SoundBankFileId
  828. {
  829. enum Consts
  830. {
  831. current_version = 4,
  832. };
  833. //Получить идентификатор файла
  834. inline static const byte * GetId()
  835. {
  836. static const char * id = "SBF ";
  837. return (const byte *)id;
  838. };
  839. //Получить версию текущего описания файла
  840. inline static const byte * GetVer(long verIndex = current_version)
  841. {
  842. static const char * ver = "1.2 ";
  843. if(verIndex == 4)
  844. {
  845. return (const byte *)ver;
  846. }
  847. return null;
  848. };
  849. //Получить значение хэшь функции заданной для теста
  850. inline static void GetTestStringHash(byte v[4])
  851. {
  852. static const dword hashValue = string::Hash("This Is String For Check Hash");
  853. v[0] = (hashValue >> 0) & 0xff;
  854. v[1] = (hashValue >> 8) & 0xff;
  855. v[2] = (hashValue >> 16) & 0xff;
  856. v[3] = (hashValue >> 24) & 0xff;
  857. };
  858. inline static void CheckMachine()
  859. {
  860. Assert(sizeof(word) == 2);
  861. Assert(sizeof(dword) == 4);
  862. Assert(sizeof(const char *) == 4);
  863. Assert(sizeof(SoundBankFileId) == 16);
  864. };
  865. inline void Init(dword pcOffset)
  866. {
  867. for(long i = 0; i < 4; i++)
  868. {
  869. id[i] = GetId()[i];
  870. ver[i] = GetVer()[i];
  871. dword shift = i << 3;
  872. pcoffset[i] = byte(pcOffset >> shift);
  873. }
  874. GetTestStringHash(checkHash);
  875. }
  876. inline bool CheckId()
  877. {
  878. const byte * sid = GetId();
  879. for(long i = 0; i < 4; i++)
  880. {
  881. if(id[i] != sid[i])
  882. {
  883. return false;
  884. }
  885. }
  886. byte tHash[4];
  887. GetTestStringHash(tHash);
  888. for(long i = 0; i < 4; i++)
  889. {
  890. if(tHash[i] != checkHash[i])
  891. {
  892. return false;
  893. }
  894. }
  895. return true;
  896. }
  897. inline bool CheckVer(long verIndex = current_version)
  898. {
  899. const byte * sver = GetVer(verIndex);
  900. if(!sver)
  901. {
  902. return false;
  903. }
  904. for(long i = 0; i < 4; i++)
  905. {
  906. if(ver[i] != sver[i])
  907. {
  908. return false;
  909. }
  910. }
  911. return true;
  912. }
  913. inline dword GetXboxChankOffset()
  914. {
  915. return sizeof(SoundBankFileId);
  916. }
  917. inline dword GetXboxChankSize()
  918. {
  919. return GetPCChankOffset() - GetXboxChankOffset();
  920. }
  921. inline dword GetPCChankOffset()
  922. {
  923. dword size = pcoffset[0];
  924. size |= dword(pcoffset[1]) << 8;
  925. size |= dword(pcoffset[2]) << 16;
  926. size |= dword(pcoffset[3]) << 24;
  927. return size;
  928. }
  929. inline dword GetPCChankSize(dword totalFileSize)
  930. {
  931. dword size = totalFileSize - GetPCChankOffset();
  932. return size;
  933. }
  934. byte id[4]; //Идентификатор файла
  935. byte ver[4]; //Версия файла
  936. byte checkHash[4]; //Хэшь для проверки
  937. byte pcoffset[4]; //Положение чанка данных для pc
  938. };
  939. #endif