@adatechnology/game-audio 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1054) hide show
  1. package/README.md +20 -0
  2. package/assets/sfx/CREDITOS.md +1046 -0
  3. package/assets/sfx/ambiente/ambience_city_day_01.ogg +0 -0
  4. package/assets/sfx/ambiente/ambience_city_day_02.ogg +0 -0
  5. package/assets/sfx/ambiente/ambience_construction_01.ogg +0 -0
  6. package/assets/sfx/ambiente/ambience_night_01.ogg +0 -0
  7. package/assets/sfx/ambiente/ambience_room_tone_01.ogg +0 -0
  8. package/assets/sfx/ambiente/ambience_room_tone_02.ogg +0 -0
  9. package/assets/sfx/ambiente/ambience_rural_day_01.ogg +0 -0
  10. package/assets/sfx/ambiente/ambience_rural_day_02.ogg +0 -0
  11. package/assets/sfx/ambiente/rain_loop_01.ogg +0 -0
  12. package/assets/sfx/ambiente/water_river_loop_01.ogg +0 -0
  13. package/assets/sfx/ambiente/water_river_loop_02.ogg +0 -0
  14. package/assets/sfx/ambiente/water_river_loop_03.ogg +0 -0
  15. package/assets/sfx/ambiente/water_splash_01.ogg +0 -0
  16. package/assets/sfx/ambiente/water_splash_02.ogg +0 -0
  17. package/assets/sfx/ambiente/water_splash_03.ogg +0 -0
  18. package/assets/sfx/ambiente/water_splash_04.ogg +0 -0
  19. package/assets/sfx/ambiente/water_splash_05.ogg +0 -0
  20. package/assets/sfx/ambiente/water_splash_06.ogg +0 -0
  21. package/assets/sfx/ambiente/water_splash_07.ogg +0 -0
  22. package/assets/sfx/ambiente/water_splash_08.ogg +0 -0
  23. package/assets/sfx/ambiente/water_splash_09.ogg +0 -0
  24. package/assets/sfx/ambiente/water_splash_10.ogg +0 -0
  25. package/assets/sfx/ambiente/water_splash_11.ogg +0 -0
  26. package/assets/sfx/ambiente/water_splash_12.ogg +0 -0
  27. package/assets/sfx/ambiente/water_splash_13.ogg +0 -0
  28. package/assets/sfx/ambiente/water_splash_14.ogg +0 -0
  29. package/assets/sfx/ambiente/water_splash_15.ogg +0 -0
  30. package/assets/sfx/armas/bolt_lift_medium_01.ogg +0 -0
  31. package/assets/sfx/armas/bolt_lift_medium_02.ogg +0 -0
  32. package/assets/sfx/armas/bolt_lift_medium_03.ogg +0 -0
  33. package/assets/sfx/armas/bolt_lift_medium_04.ogg +0 -0
  34. package/assets/sfx/armas/bolt_lift_medium_05.ogg +0 -0
  35. package/assets/sfx/armas/bolt_lock_medium_01.ogg +0 -0
  36. package/assets/sfx/armas/bolt_lock_medium_02.ogg +0 -0
  37. package/assets/sfx/armas/bolt_lock_medium_03.ogg +0 -0
  38. package/assets/sfx/armas/bolt_lock_medium_04.ogg +0 -0
  39. package/assets/sfx/armas/bolt_lock_medium_05.ogg +0 -0
  40. package/assets/sfx/armas/bolt_pull_heavy_01.ogg +0 -0
  41. package/assets/sfx/armas/bolt_pull_medium_01.ogg +0 -0
  42. package/assets/sfx/armas/bolt_pull_medium_02.ogg +0 -0
  43. package/assets/sfx/armas/bolt_pull_medium_03.ogg +0 -0
  44. package/assets/sfx/armas/bolt_pull_medium_04.ogg +0 -0
  45. package/assets/sfx/armas/bolt_pull_medium_05.ogg +0 -0
  46. package/assets/sfx/armas/bolt_pull_medium_06.ogg +0 -0
  47. package/assets/sfx/armas/bolt_push_heavy_01.ogg +0 -0
  48. package/assets/sfx/armas/bolt_push_medium_01.ogg +0 -0
  49. package/assets/sfx/armas/bolt_push_medium_02.ogg +0 -0
  50. package/assets/sfx/armas/bolt_push_medium_03.ogg +0 -0
  51. package/assets/sfx/armas/bolt_push_medium_04.ogg +0 -0
  52. package/assets/sfx/armas/bolt_push_medium_05.ogg +0 -0
  53. package/assets/sfx/armas/bolt_push_medium_06.ogg +0 -0
  54. package/assets/sfx/armas/casing_drop_concreto_01.ogg +0 -0
  55. package/assets/sfx/armas/casing_drop_concreto_02.ogg +0 -0
  56. package/assets/sfx/armas/casing_drop_concreto_03.ogg +0 -0
  57. package/assets/sfx/armas/casing_drop_metal_01.ogg +0 -0
  58. package/assets/sfx/armas/casing_drop_metal_02.ogg +0 -0
  59. package/assets/sfx/armas/casing_drop_metal_03.ogg +0 -0
  60. package/assets/sfx/armas/casing_drop_terra_01.ogg +0 -0
  61. package/assets/sfx/armas/casing_drop_terra_02.ogg +0 -0
  62. package/assets/sfx/armas/casing_drop_terra_03.ogg +0 -0
  63. package/assets/sfx/armas/charging_handle_pull_light_01.ogg +0 -0
  64. package/assets/sfx/armas/charging_handle_pull_light_02.ogg +0 -0
  65. package/assets/sfx/armas/charging_handle_pull_light_03.ogg +0 -0
  66. package/assets/sfx/armas/charging_handle_pull_light_04.ogg +0 -0
  67. package/assets/sfx/armas/charging_handle_pull_medium_01.ogg +0 -0
  68. package/assets/sfx/armas/charging_handle_pull_medium_02.ogg +0 -0
  69. package/assets/sfx/armas/charging_handle_pull_medium_03.ogg +0 -0
  70. package/assets/sfx/armas/charging_handle_pull_medium_04.ogg +0 -0
  71. package/assets/sfx/armas/charging_handle_pull_medium_05.ogg +0 -0
  72. package/assets/sfx/armas/charging_handle_release_medium_01.ogg +0 -0
  73. package/assets/sfx/armas/charging_handle_release_medium_02.ogg +0 -0
  74. package/assets/sfx/armas/charging_handle_release_medium_03.ogg +0 -0
  75. package/assets/sfx/armas/charging_handle_release_medium_04.ogg +0 -0
  76. package/assets/sfx/armas/charging_handle_release_medium_05.ogg +0 -0
  77. package/assets/sfx/armas/cylinder_close_light_01.ogg +0 -0
  78. package/assets/sfx/armas/cylinder_close_light_02.ogg +0 -0
  79. package/assets/sfx/armas/cylinder_close_light_03.ogg +0 -0
  80. package/assets/sfx/armas/cylinder_close_light_04.ogg +0 -0
  81. package/assets/sfx/armas/cylinder_close_light_05.ogg +0 -0
  82. package/assets/sfx/armas/cylinder_eject_light_01.ogg +0 -0
  83. package/assets/sfx/armas/cylinder_eject_light_02.ogg +0 -0
  84. package/assets/sfx/armas/cylinder_eject_light_03.ogg +0 -0
  85. package/assets/sfx/armas/cylinder_open_light_01.ogg +0 -0
  86. package/assets/sfx/armas/cylinder_open_light_02.ogg +0 -0
  87. package/assets/sfx/armas/cylinder_open_light_03.ogg +0 -0
  88. package/assets/sfx/armas/cylinder_open_light_04.ogg +0 -0
  89. package/assets/sfx/armas/cylinder_open_light_05.ogg +0 -0
  90. package/assets/sfx/armas/lever_close_medium_01.ogg +0 -0
  91. package/assets/sfx/armas/lever_close_medium_02.ogg +0 -0
  92. package/assets/sfx/armas/lever_open_medium_01.ogg +0 -0
  93. package/assets/sfx/armas/lever_open_medium_02.ogg +0 -0
  94. package/assets/sfx/armas/mag_out_heavy_01.ogg +0 -0
  95. package/assets/sfx/armas/mag_out_heavy_02.ogg +0 -0
  96. package/assets/sfx/armas/mag_out_light_01.ogg +0 -0
  97. package/assets/sfx/armas/mag_out_light_02.ogg +0 -0
  98. package/assets/sfx/armas/mag_out_light_03.ogg +0 -0
  99. package/assets/sfx/armas/mag_out_light_04.ogg +0 -0
  100. package/assets/sfx/armas/mag_out_medium_01.ogg +0 -0
  101. package/assets/sfx/armas/mag_out_medium_02.ogg +0 -0
  102. package/assets/sfx/armas/mag_out_medium_03.ogg +0 -0
  103. package/assets/sfx/armas/mag_seat_heavy_01.ogg +0 -0
  104. package/assets/sfx/armas/mag_seat_heavy_02.ogg +0 -0
  105. package/assets/sfx/armas/mag_seat_light_01.ogg +0 -0
  106. package/assets/sfx/armas/mag_seat_light_02.ogg +0 -0
  107. package/assets/sfx/armas/mag_seat_light_03.ogg +0 -0
  108. package/assets/sfx/armas/mag_seat_light_04.ogg +0 -0
  109. package/assets/sfx/armas/mag_seat_light_05.ogg +0 -0
  110. package/assets/sfx/armas/mag_seat_light_06.ogg +0 -0
  111. package/assets/sfx/armas/mag_seat_medium_01.ogg +0 -0
  112. package/assets/sfx/armas/mag_seat_medium_02.ogg +0 -0
  113. package/assets/sfx/armas/mag_seat_medium_03.ogg +0 -0
  114. package/assets/sfx/armas/pistol_22lr_close_01.ogg +0 -0
  115. package/assets/sfx/armas/pistol_22lr_close_02.ogg +0 -0
  116. package/assets/sfx/armas/pistol_22lr_far_01.ogg +0 -0
  117. package/assets/sfx/armas/pistol_22lr_far_02.ogg +0 -0
  118. package/assets/sfx/armas/pistol_22lr_far_03.ogg +0 -0
  119. package/assets/sfx/armas/pistol_22lr_far_04.ogg +0 -0
  120. package/assets/sfx/armas/pistol_45_close_01.ogg +0 -0
  121. package/assets/sfx/armas/pistol_45_close_02.ogg +0 -0
  122. package/assets/sfx/armas/pistol_45_close_03.ogg +0 -0
  123. package/assets/sfx/armas/pistol_45_close_04.ogg +0 -0
  124. package/assets/sfx/armas/pistol_45_close_05.ogg +0 -0
  125. package/assets/sfx/armas/pistol_45_far_01.ogg +0 -0
  126. package/assets/sfx/armas/pistol_45_far_02.ogg +0 -0
  127. package/assets/sfx/armas/pistol_45_far_03.ogg +0 -0
  128. package/assets/sfx/armas/pistol_45_far_04.ogg +0 -0
  129. package/assets/sfx/armas/pistol_9mm_close_01.ogg +0 -0
  130. package/assets/sfx/armas/pistol_9mm_close_02.ogg +0 -0
  131. package/assets/sfx/armas/pistol_9mm_close_03.ogg +0 -0
  132. package/assets/sfx/armas/pistol_9mm_close_04.ogg +0 -0
  133. package/assets/sfx/armas/pistol_9mm_close_05.ogg +0 -0
  134. package/assets/sfx/armas/pistol_9mm_close_06.ogg +0 -0
  135. package/assets/sfx/armas/pistol_9mm_far_01.ogg +0 -0
  136. package/assets/sfx/armas/pistol_9mm_far_02.ogg +0 -0
  137. package/assets/sfx/armas/pistol_9mm_far_03.ogg +0 -0
  138. package/assets/sfx/armas/pistol_9mm_far_04.ogg +0 -0
  139. package/assets/sfx/armas/pump_back_heavy_01.ogg +0 -0
  140. package/assets/sfx/armas/pump_back_heavy_02.ogg +0 -0
  141. package/assets/sfx/armas/pump_back_heavy_03.ogg +0 -0
  142. package/assets/sfx/armas/pump_back_heavy_04.ogg +0 -0
  143. package/assets/sfx/armas/pump_back_heavy_05.ogg +0 -0
  144. package/assets/sfx/armas/pump_forward_heavy_01.ogg +0 -0
  145. package/assets/sfx/armas/pump_forward_heavy_02.ogg +0 -0
  146. package/assets/sfx/armas/pump_forward_heavy_03.ogg +0 -0
  147. package/assets/sfx/armas/revolver_38_357_close_01.ogg +0 -0
  148. package/assets/sfx/armas/revolver_38_357_close_02.ogg +0 -0
  149. package/assets/sfx/armas/revolver_38_357_close_03.ogg +0 -0
  150. package/assets/sfx/armas/revolver_38_357_close_04.ogg +0 -0
  151. package/assets/sfx/armas/revolver_38_357_far_01.ogg +0 -0
  152. package/assets/sfx/armas/revolver_38_357_far_02.ogg +0 -0
  153. package/assets/sfx/armas/revolver_38_357_far_03.ogg +0 -0
  154. package/assets/sfx/armas/revolver_38_357_far_04.ogg +0 -0
  155. package/assets/sfx/armas/rifle_308_3006_close_01.ogg +0 -0
  156. package/assets/sfx/armas/rifle_308_3006_close_02.ogg +0 -0
  157. package/assets/sfx/armas/rifle_308_3006_close_03.ogg +0 -0
  158. package/assets/sfx/armas/rifle_308_3006_close_04.ogg +0 -0
  159. package/assets/sfx/armas/rifle_308_3006_close_05.ogg +0 -0
  160. package/assets/sfx/armas/rifle_308_3006_close_06.ogg +0 -0
  161. package/assets/sfx/armas/rifle_308_3006_far_01.ogg +0 -0
  162. package/assets/sfx/armas/rifle_308_3006_far_02.ogg +0 -0
  163. package/assets/sfx/armas/rifle_308_3006_far_03.ogg +0 -0
  164. package/assets/sfx/armas/rifle_308_3006_far_04.ogg +0 -0
  165. package/assets/sfx/armas/rifle_308_3006_far_05.ogg +0 -0
  166. package/assets/sfx/armas/rifle_308_3006_far_06.ogg +0 -0
  167. package/assets/sfx/armas/rifle_5_56_close_01.ogg +0 -0
  168. package/assets/sfx/armas/rifle_5_56_close_02.ogg +0 -0
  169. package/assets/sfx/armas/rifle_5_56_close_03.ogg +0 -0
  170. package/assets/sfx/armas/rifle_5_56_close_04.ogg +0 -0
  171. package/assets/sfx/armas/rifle_5_56_close_05.ogg +0 -0
  172. package/assets/sfx/armas/rifle_5_56_far_01.ogg +0 -0
  173. package/assets/sfx/armas/rifle_5_56_far_02.ogg +0 -0
  174. package/assets/sfx/armas/rifle_5_56_far_03.ogg +0 -0
  175. package/assets/sfx/armas/rifle_5_56_far_04.ogg +0 -0
  176. package/assets/sfx/armas/rifle_7_62x39_close_01.ogg +0 -0
  177. package/assets/sfx/armas/rifle_7_62x39_close_02.ogg +0 -0
  178. package/assets/sfx/armas/rifle_7_62x39_close_03.ogg +0 -0
  179. package/assets/sfx/armas/rifle_7_62x39_close_04.ogg +0 -0
  180. package/assets/sfx/armas/rifle_7_62x39_close_05.ogg +0 -0
  181. package/assets/sfx/armas/rifle_7_62x39_close_06.ogg +0 -0
  182. package/assets/sfx/armas/rifle_7_62x39_close_07.ogg +0 -0
  183. package/assets/sfx/armas/rifle_7_62x39_close_08.ogg +0 -0
  184. package/assets/sfx/armas/rifle_7_62x39_close_09.ogg +0 -0
  185. package/assets/sfx/armas/rifle_7_62x39_close_10.ogg +0 -0
  186. package/assets/sfx/armas/rifle_7_62x39_close_11.ogg +0 -0
  187. package/assets/sfx/armas/rifle_7_62x39_close_12.ogg +0 -0
  188. package/assets/sfx/armas/rifle_7_62x39_far_01.ogg +0 -0
  189. package/assets/sfx/armas/rifle_7_62x39_far_02.ogg +0 -0
  190. package/assets/sfx/armas/rifle_7_62x39_far_03.ogg +0 -0
  191. package/assets/sfx/armas/shell_insert_heavy_01.ogg +0 -0
  192. package/assets/sfx/armas/shell_insert_heavy_02.ogg +0 -0
  193. package/assets/sfx/armas/shell_insert_heavy_03.ogg +0 -0
  194. package/assets/sfx/armas/shell_insert_heavy_04.ogg +0 -0
  195. package/assets/sfx/armas/shell_insert_heavy_05.ogg +0 -0
  196. package/assets/sfx/armas/shell_insert_heavy_06.ogg +0 -0
  197. package/assets/sfx/armas/shell_insert_heavy_07.ogg +0 -0
  198. package/assets/sfx/armas/shell_insert_heavy_08.ogg +0 -0
  199. package/assets/sfx/armas/shell_insert_heavy_09.ogg +0 -0
  200. package/assets/sfx/armas/shotgun_12_close_01.ogg +0 -0
  201. package/assets/sfx/armas/shotgun_12_close_02.ogg +0 -0
  202. package/assets/sfx/armas/shotgun_12_close_03.ogg +0 -0
  203. package/assets/sfx/armas/shotgun_12_close_04.ogg +0 -0
  204. package/assets/sfx/armas/shotgun_12_close_05.ogg +0 -0
  205. package/assets/sfx/armas/shotgun_12_close_06.ogg +0 -0
  206. package/assets/sfx/armas/shotgun_12_far_01.ogg +0 -0
  207. package/assets/sfx/armas/shotgun_12_far_02.ogg +0 -0
  208. package/assets/sfx/armas/shotgun_12_far_03.ogg +0 -0
  209. package/assets/sfx/armas/shotgun_12_far_04.ogg +0 -0
  210. package/assets/sfx/armas/shotgun_12_far_05.ogg +0 -0
  211. package/assets/sfx/armas/shotgun_12_far_06.ogg +0 -0
  212. package/assets/sfx/armas/slide_release_light_01.ogg +0 -0
  213. package/assets/sfx/armas/slide_release_light_02.ogg +0 -0
  214. package/assets/sfx/armas/slide_release_light_03.ogg +0 -0
  215. package/assets/sfx/armas/slide_release_light_04.ogg +0 -0
  216. package/assets/sfx/armas/slide_release_light_05.ogg +0 -0
  217. package/assets/sfx/armas/slide_release_light_06.ogg +0 -0
  218. package/assets/sfx/armas/slide_release_medium_01.ogg +0 -0
  219. package/assets/sfx/armas/slide_release_medium_02.ogg +0 -0
  220. package/assets/sfx/armas/slide_release_medium_03.ogg +0 -0
  221. package/assets/sfx/armas/slide_release_medium_04.ogg +0 -0
  222. package/assets/sfx/armas/sniper_338_300wm_close_01.ogg +0 -0
  223. package/assets/sfx/armas/sniper_338_300wm_close_02.ogg +0 -0
  224. package/assets/sfx/armas/sniper_338_300wm_close_03.ogg +0 -0
  225. package/assets/sfx/armas/sniper_338_300wm_close_04.ogg +0 -0
  226. package/assets/sfx/armas/sniper_338_300wm_close_05.ogg +0 -0
  227. package/assets/sfx/armas/sniper_338_300wm_close_06.ogg +0 -0
  228. package/assets/sfx/armas/sniper_338_300wm_close_07.ogg +0 -0
  229. package/assets/sfx/armas/sniper_338_300wm_far_01.ogg +0 -0
  230. package/assets/sfx/armas/sniper_338_300wm_far_02.ogg +0 -0
  231. package/assets/sfx/armas/sniper_338_300wm_far_03.ogg +0 -0
  232. package/assets/sfx/armas/sniper_338_300wm_far_04.ogg +0 -0
  233. package/assets/sfx/armas/sniper_338_300wm_far_05.ogg +0 -0
  234. package/assets/sfx/armas/sniper_338_300wm_far_06.ogg +0 -0
  235. package/assets/sfx/armas/speedloader_light_01.ogg +0 -0
  236. package/assets/sfx/armas/speedloader_light_02.ogg +0 -0
  237. package/assets/sfx/armas/speedloader_light_03.ogg +0 -0
  238. package/assets/sfx/armas/speedloader_light_04.ogg +0 -0
  239. package/assets/sfx/armas/speedloader_light_05.ogg +0 -0
  240. package/assets/sfx/armas/speedloader_light_06.ogg +0 -0
  241. package/assets/sfx/armas/speedloader_light_07.ogg +0 -0
  242. package/assets/sfx/armas/speedloader_light_08.ogg +0 -0
  243. package/assets/sfx/armas/suppressed_pistol_close_01.ogg +0 -0
  244. package/assets/sfx/armas/suppressed_pistol_close_02.ogg +0 -0
  245. package/assets/sfx/armas/suppressed_pistol_close_03.ogg +0 -0
  246. package/assets/sfx/armas/suppressed_pistol_close_04.ogg +0 -0
  247. package/assets/sfx/armas/suppressed_pistol_close_05.ogg +0 -0
  248. package/assets/sfx/armas/suppressed_pistol_far_01.ogg +0 -0
  249. package/assets/sfx/armas/suppressed_pistol_far_02.ogg +0 -0
  250. package/assets/sfx/armas/suppressed_pistol_far_03.ogg +0 -0
  251. package/assets/sfx/armas/suppressed_pistol_far_04.ogg +0 -0
  252. package/assets/sfx/armas/suppressed_pistol_far_05.ogg +0 -0
  253. package/assets/sfx/armas/suppressed_rifle_close_01.ogg +0 -0
  254. package/assets/sfx/armas/suppressed_rifle_close_02.ogg +0 -0
  255. package/assets/sfx/armas/suppressed_rifle_close_03.ogg +0 -0
  256. package/assets/sfx/armas/suppressed_rifle_close_04.ogg +0 -0
  257. package/assets/sfx/armas/suppressed_rifle_far_01.ogg +0 -0
  258. package/assets/sfx/armas/suppressed_rifle_far_02.ogg +0 -0
  259. package/assets/sfx/armas/suppressed_rifle_far_03.ogg +0 -0
  260. package/assets/sfx/armas/suppressed_rifle_far_04.ogg +0 -0
  261. package/assets/sfx/explosoes-fogo/debris_rain_mixed_01.ogg +0 -0
  262. package/assets/sfx/explosoes-fogo/debris_rain_mixed_02.ogg +0 -0
  263. package/assets/sfx/explosoes-fogo/debris_rain_mixed_03.ogg +0 -0
  264. package/assets/sfx/explosoes-fogo/debris_rain_mixed_04.ogg +0 -0
  265. package/assets/sfx/explosoes-fogo/debris_rain_mixed_05.ogg +0 -0
  266. package/assets/sfx/explosoes-fogo/debris_rain_mixed_06.ogg +0 -0
  267. package/assets/sfx/explosoes-fogo/debris_rain_mixed_07.ogg +0 -0
  268. package/assets/sfx/explosoes-fogo/debris_rain_stone_01.ogg +0 -0
  269. package/assets/sfx/explosoes-fogo/debris_rain_stone_02.ogg +0 -0
  270. package/assets/sfx/explosoes-fogo/debris_rain_stone_03.ogg +0 -0
  271. package/assets/sfx/explosoes-fogo/debris_rain_stone_04.ogg +0 -0
  272. package/assets/sfx/explosoes-fogo/debris_rain_stone_05.ogg +0 -0
  273. package/assets/sfx/explosoes-fogo/debris_rain_stone_06.ogg +0 -0
  274. package/assets/sfx/explosoes-fogo/debris_rain_stone_07.ogg +0 -0
  275. package/assets/sfx/explosoes-fogo/debris_rain_stone_08.ogg +0 -0
  276. package/assets/sfx/explosoes-fogo/debris_rain_stone_09.ogg +0 -0
  277. package/assets/sfx/explosoes-fogo/explosion_big_01.ogg +0 -0
  278. package/assets/sfx/explosoes-fogo/explosion_big_02.ogg +0 -0
  279. package/assets/sfx/explosoes-fogo/explosion_big_03.ogg +0 -0
  280. package/assets/sfx/explosoes-fogo/explosion_big_04.ogg +0 -0
  281. package/assets/sfx/explosoes-fogo/explosion_big_05.ogg +0 -0
  282. package/assets/sfx/explosoes-fogo/explosion_car_01.ogg +0 -0
  283. package/assets/sfx/explosoes-fogo/explosion_car_02.ogg +0 -0
  284. package/assets/sfx/explosoes-fogo/explosion_car_03.ogg +0 -0
  285. package/assets/sfx/explosoes-fogo/explosion_car_04.ogg +0 -0
  286. package/assets/sfx/explosoes-fogo/explosion_far_close_01.ogg +0 -0
  287. package/assets/sfx/explosoes-fogo/explosion_far_close_02.ogg +0 -0
  288. package/assets/sfx/explosoes-fogo/explosion_far_close_03.ogg +0 -0
  289. package/assets/sfx/explosoes-fogo/explosion_far_close_04.ogg +0 -0
  290. package/assets/sfx/explosoes-fogo/explosion_flashbang_01.ogg +0 -0
  291. package/assets/sfx/explosoes-fogo/explosion_flashbang_02.ogg +0 -0
  292. package/assets/sfx/explosoes-fogo/explosion_grenade_01.ogg +0 -0
  293. package/assets/sfx/explosoes-fogo/explosion_grenade_02.ogg +0 -0
  294. package/assets/sfx/explosoes-fogo/explosion_grenade_03.ogg +0 -0
  295. package/assets/sfx/explosoes-fogo/explosion_grenade_04.ogg +0 -0
  296. package/assets/sfx/explosoes-fogo/explosion_grenade_05.ogg +0 -0
  297. package/assets/sfx/explosoes-fogo/explosion_grenade_06.ogg +0 -0
  298. package/assets/sfx/explosoes-fogo/explosion_small_bang_01.ogg +0 -0
  299. package/assets/sfx/explosoes-fogo/explosion_small_bang_02.ogg +0 -0
  300. package/assets/sfx/explosoes-fogo/explosion_small_bang_03.ogg +0 -0
  301. package/assets/sfx/explosoes-fogo/explosion_small_bang_04.ogg +0 -0
  302. package/assets/sfx/explosoes-fogo/explosion_small_bang_05.ogg +0 -0
  303. package/assets/sfx/explosoes-fogo/explosion_small_bang_06.ogg +0 -0
  304. package/assets/sfx/explosoes-fogo/explosion_small_bang_07.ogg +0 -0
  305. package/assets/sfx/explosoes-fogo/explosion_small_bang_08.ogg +0 -0
  306. package/assets/sfx/explosoes-fogo/explosion_small_bang_09.ogg +0 -0
  307. package/assets/sfx/explosoes-fogo/explosion_small_bang_10.ogg +0 -0
  308. package/assets/sfx/explosoes-fogo/fire_crackle_01.ogg +0 -0
  309. package/assets/sfx/explosoes-fogo/fire_crackle_02.ogg +0 -0
  310. package/assets/sfx/explosoes-fogo/fire_crackle_03.ogg +0 -0
  311. package/assets/sfx/explosoes-fogo/fire_crackle_05.ogg +0 -0
  312. package/assets/sfx/explosoes-fogo/fire_crackle_07.ogg +0 -0
  313. package/assets/sfx/explosoes-fogo/fire_extinguish_01.ogg +0 -0
  314. package/assets/sfx/explosoes-fogo/fire_extinguish_02.ogg +0 -0
  315. package/assets/sfx/explosoes-fogo/fire_ignite_01.ogg +0 -0
  316. package/assets/sfx/explosoes-fogo/fire_ignite_02.ogg +0 -0
  317. package/assets/sfx/explosoes-fogo/fire_ignite_03.ogg +0 -0
  318. package/assets/sfx/explosoes-fogo/fire_ignite_04.ogg +0 -0
  319. package/assets/sfx/explosoes-fogo/fire_loop_01.ogg +0 -0
  320. package/assets/sfx/explosoes-fogo/fire_loop_03.ogg +0 -0
  321. package/assets/sfx/explosoes-fogo/fire_loop_04.ogg +0 -0
  322. package/assets/sfx/explosoes-fogo/fire_loop_small_01.ogg +0 -0
  323. package/assets/sfx/explosoes-fogo/fire_pop_01.ogg +0 -0
  324. package/assets/sfx/explosoes-fogo/fire_pop_02.ogg +0 -0
  325. package/assets/sfx/explosoes-fogo/fire_pop_03.ogg +0 -0
  326. package/assets/sfx/explosoes-fogo/flamethrower_loop_01.ogg +0 -0
  327. package/assets/sfx/explosoes-fogo/gas_leak_01.ogg +0 -0
  328. package/assets/sfx/explosoes-fogo/molotov_break_ignite_01.ogg +0 -0
  329. package/assets/sfx/explosoes-fogo/molotov_break_ignite_02.ogg +0 -0
  330. package/assets/sfx/impactos/ceramic_hit_close_01.ogg +0 -0
  331. package/assets/sfx/impactos/concrete_block_drag_close_01.ogg +0 -0
  332. package/assets/sfx/impactos/concrete_block_drag_close_02.ogg +0 -0
  333. package/assets/sfx/impactos/concrete_block_drag_close_03.ogg +0 -0
  334. package/assets/sfx/impactos/concrete_block_drag_close_04.ogg +0 -0
  335. package/assets/sfx/impactos/concrete_block_drag_close_05.ogg +0 -0
  336. package/assets/sfx/impactos/concrete_block_drag_close_06.ogg +0 -0
  337. package/assets/sfx/impactos/concrete_block_drag_close_07.ogg +0 -0
  338. package/assets/sfx/impactos/crack_close_01.ogg +0 -0
  339. package/assets/sfx/impactos/crack_close_02.ogg +0 -0
  340. package/assets/sfx/impactos/crack_close_03.ogg +0 -0
  341. package/assets/sfx/impactos/crack_close_04.ogg +0 -0
  342. package/assets/sfx/impactos/crack_close_05.ogg +0 -0
  343. package/assets/sfx/impactos/crack_close_06.ogg +0 -0
  344. package/assets/sfx/impactos/crack_close_07.ogg +0 -0
  345. package/assets/sfx/impactos/crack_close_08.ogg +0 -0
  346. package/assets/sfx/impactos/crack_close_09.ogg +0 -0
  347. package/assets/sfx/impactos/crack_close_10.ogg +0 -0
  348. package/assets/sfx/impactos/crumble_close_01.ogg +0 -0
  349. package/assets/sfx/impactos/crumble_close_02.ogg +0 -0
  350. package/assets/sfx/impactos/crumble_close_03.ogg +0 -0
  351. package/assets/sfx/impactos/crumble_close_04.ogg +0 -0
  352. package/assets/sfx/impactos/crumble_close_05.ogg +0 -0
  353. package/assets/sfx/impactos/flesh_fruit_splat_close_01.ogg +0 -0
  354. package/assets/sfx/impactos/flesh_fruit_splat_close_02.ogg +0 -0
  355. package/assets/sfx/impactos/flesh_fruit_splat_close_03.ogg +0 -0
  356. package/assets/sfx/impactos/furniture_push_wood_close_01.ogg +0 -0
  357. package/assets/sfx/impactos/glass_blunt_heavy_close_01.ogg +0 -0
  358. package/assets/sfx/impactos/glass_blunt_heavy_close_02.ogg +0 -0
  359. package/assets/sfx/impactos/glass_blunt_heavy_close_03.ogg +0 -0
  360. package/assets/sfx/impactos/glass_blunt_heavy_close_04.ogg +0 -0
  361. package/assets/sfx/impactos/glass_blunt_heavy_close_05.ogg +0 -0
  362. package/assets/sfx/impactos/glass_blunt_light_close_01.ogg +0 -0
  363. package/assets/sfx/impactos/glass_blunt_light_close_02.ogg +0 -0
  364. package/assets/sfx/impactos/glass_blunt_light_close_03.ogg +0 -0
  365. package/assets/sfx/impactos/glass_blunt_light_close_04.ogg +0 -0
  366. package/assets/sfx/impactos/glass_blunt_light_close_05.ogg +0 -0
  367. package/assets/sfx/impactos/glass_blunt_medium_close_01.ogg +0 -0
  368. package/assets/sfx/impactos/glass_blunt_medium_close_02.ogg +0 -0
  369. package/assets/sfx/impactos/glass_blunt_medium_close_03.ogg +0 -0
  370. package/assets/sfx/impactos/glass_blunt_medium_close_04.ogg +0 -0
  371. package/assets/sfx/impactos/glass_blunt_medium_close_05.ogg +0 -0
  372. package/assets/sfx/impactos/glass_bottle_break_close_01.ogg +0 -0
  373. package/assets/sfx/impactos/glass_debris_fall_close_01.ogg +0 -0
  374. package/assets/sfx/impactos/glass_debris_fall_close_02.ogg +0 -0
  375. package/assets/sfx/impactos/glass_debris_fall_close_03.ogg +0 -0
  376. package/assets/sfx/impactos/glass_debris_fall_close_04.ogg +0 -0
  377. package/assets/sfx/impactos/glass_shatter_close_01.ogg +0 -0
  378. package/assets/sfx/impactos/glass_shatter_close_02.ogg +0 -0
  379. package/assets/sfx/impactos/glass_shatter_close_03.ogg +0 -0
  380. package/assets/sfx/impactos/glass_shatter_close_04.ogg +0 -0
  381. package/assets/sfx/impactos/glass_shatter_close_05.ogg +0 -0
  382. package/assets/sfx/impactos/glass_shatter_close_06.ogg +0 -0
  383. package/assets/sfx/impactos/glass_shatter_close_07.ogg +0 -0
  384. package/assets/sfx/impactos/glass_shatter_close_08.ogg +0 -0
  385. package/assets/sfx/impactos/glass_shatter_close_09.ogg +0 -0
  386. package/assets/sfx/impactos/gravel_hit_close_21.ogg +0 -0
  387. package/assets/sfx/impactos/gravel_hit_close_22.ogg +0 -0
  388. package/assets/sfx/impactos/gravel_hit_close_23.ogg +0 -0
  389. package/assets/sfx/impactos/gravel_hit_close_24.ogg +0 -0
  390. package/assets/sfx/impactos/gravel_hit_close_25.ogg +0 -0
  391. package/assets/sfx/impactos/gravel_hit_close_26.ogg +0 -0
  392. package/assets/sfx/impactos/gravel_hit_close_27.ogg +0 -0
  393. package/assets/sfx/impactos/gravel_hit_close_28.ogg +0 -0
  394. package/assets/sfx/impactos/gravel_hit_close_29.ogg +0 -0
  395. package/assets/sfx/impactos/impact_generic_light_close_01.ogg +0 -0
  396. package/assets/sfx/impactos/impact_generic_light_close_02.ogg +0 -0
  397. package/assets/sfx/impactos/impact_generic_light_close_03.ogg +0 -0
  398. package/assets/sfx/impactos/impact_generic_light_close_04.ogg +0 -0
  399. package/assets/sfx/impactos/impact_generic_light_close_05.ogg +0 -0
  400. package/assets/sfx/impactos/masonry_blunt_close_01.ogg +0 -0
  401. package/assets/sfx/impactos/masonry_blunt_close_02.ogg +0 -0
  402. package/assets/sfx/impactos/masonry_blunt_close_03.ogg +0 -0
  403. package/assets/sfx/impactos/masonry_blunt_close_04.ogg +0 -0
  404. package/assets/sfx/impactos/masonry_blunt_close_05.ogg +0 -0
  405. package/assets/sfx/impactos/masonry_blunt_close_06.ogg +0 -0
  406. package/assets/sfx/impactos/masonry_blunt_close_07.ogg +0 -0
  407. package/assets/sfx/impactos/masonry_bullet_close_01.ogg +0 -0
  408. package/assets/sfx/impactos/masonry_bullet_close_02.ogg +0 -0
  409. package/assets/sfx/impactos/masonry_bullet_close_03.ogg +0 -0
  410. package/assets/sfx/impactos/masonry_bullet_close_04.ogg +0 -0
  411. package/assets/sfx/impactos/masonry_bullet_close_05.ogg +0 -0
  412. package/assets/sfx/impactos/masonry_bullet_close_21.ogg +0 -0
  413. package/assets/sfx/impactos/masonry_bullet_close_22.ogg +0 -0
  414. package/assets/sfx/impactos/masonry_bullet_close_23.ogg +0 -0
  415. package/assets/sfx/impactos/masonry_bullet_close_24.ogg +0 -0
  416. package/assets/sfx/impactos/masonry_bullet_close_25.ogg +0 -0
  417. package/assets/sfx/impactos/masonry_bullet_close_26.ogg +0 -0
  418. package/assets/sfx/impactos/masonry_bullet_close_27.ogg +0 -0
  419. package/assets/sfx/impactos/masonry_bullet_close_28.ogg +0 -0
  420. package/assets/sfx/impactos/metal_blunt_close_01.ogg +0 -0
  421. package/assets/sfx/impactos/metal_blunt_close_02.ogg +0 -0
  422. package/assets/sfx/impactos/metal_blunt_close_03.ogg +0 -0
  423. package/assets/sfx/impactos/metal_blunt_close_04.ogg +0 -0
  424. package/assets/sfx/impactos/metal_blunt_close_05.ogg +0 -0
  425. package/assets/sfx/impactos/metal_blunt_heavy_close_01.ogg +0 -0
  426. package/assets/sfx/impactos/metal_blunt_heavy_close_02.ogg +0 -0
  427. package/assets/sfx/impactos/metal_blunt_heavy_close_03.ogg +0 -0
  428. package/assets/sfx/impactos/metal_blunt_heavy_close_04.ogg +0 -0
  429. package/assets/sfx/impactos/metal_blunt_heavy_close_05.ogg +0 -0
  430. package/assets/sfx/impactos/metal_blunt_light_close_01.ogg +0 -0
  431. package/assets/sfx/impactos/metal_blunt_light_close_02.ogg +0 -0
  432. package/assets/sfx/impactos/metal_blunt_light_close_03.ogg +0 -0
  433. package/assets/sfx/impactos/metal_blunt_light_close_04.ogg +0 -0
  434. package/assets/sfx/impactos/metal_blunt_light_close_05.ogg +0 -0
  435. package/assets/sfx/impactos/metal_blunt_medium_close_01.ogg +0 -0
  436. package/assets/sfx/impactos/metal_blunt_medium_close_02.ogg +0 -0
  437. package/assets/sfx/impactos/metal_blunt_medium_close_03.ogg +0 -0
  438. package/assets/sfx/impactos/metal_blunt_medium_close_04.ogg +0 -0
  439. package/assets/sfx/impactos/metal_blunt_medium_close_05.ogg +0 -0
  440. package/assets/sfx/impactos/metal_bullet_close_01.ogg +0 -0
  441. package/assets/sfx/impactos/metal_bullet_close_02.ogg +0 -0
  442. package/assets/sfx/impactos/metal_bullet_close_03.ogg +0 -0
  443. package/assets/sfx/impactos/metal_bullet_close_04.ogg +0 -0
  444. package/assets/sfx/impactos/metal_bullet_close_05.ogg +0 -0
  445. package/assets/sfx/impactos/metal_bullet_close_06.ogg +0 -0
  446. package/assets/sfx/impactos/metal_bullet_close_21.ogg +0 -0
  447. package/assets/sfx/impactos/metal_bullet_close_22.ogg +0 -0
  448. package/assets/sfx/impactos/metal_bullet_close_23.ogg +0 -0
  449. package/assets/sfx/impactos/metal_bullet_close_24.ogg +0 -0
  450. package/assets/sfx/impactos/metal_bullet_close_25.ogg +0 -0
  451. package/assets/sfx/impactos/metal_bullet_close_26.ogg +0 -0
  452. package/assets/sfx/impactos/metal_bullet_close_27.ogg +0 -0
  453. package/assets/sfx/impactos/metal_bullet_close_28.ogg +0 -0
  454. package/assets/sfx/impactos/metal_bullet_close_29.ogg +0 -0
  455. package/assets/sfx/impactos/metal_bullet_close_30.ogg +0 -0
  456. package/assets/sfx/impactos/metal_bullet_close_31.ogg +0 -0
  457. package/assets/sfx/impactos/metal_bullet_close_32.ogg +0 -0
  458. package/assets/sfx/impactos/metal_bullet_close_33.ogg +0 -0
  459. package/assets/sfx/impactos/metal_bullet_close_34.ogg +0 -0
  460. package/assets/sfx/impactos/metal_fall_close_01.ogg +0 -0
  461. package/assets/sfx/impactos/metal_fall_close_02.ogg +0 -0
  462. package/assets/sfx/impactos/metal_fall_close_03.ogg +0 -0
  463. package/assets/sfx/impactos/metal_fall_close_04.ogg +0 -0
  464. package/assets/sfx/impactos/metal_fall_close_05.ogg +0 -0
  465. package/assets/sfx/impactos/metal_fall_close_06.ogg +0 -0
  466. package/assets/sfx/impactos/metal_fall_close_07.ogg +0 -0
  467. package/assets/sfx/impactos/metal_fall_close_08.ogg +0 -0
  468. package/assets/sfx/impactos/metal_fall_close_09.ogg +0 -0
  469. package/assets/sfx/impactos/metal_fall_close_10.ogg +0 -0
  470. package/assets/sfx/impactos/metal_thin_close_01.ogg +0 -0
  471. package/assets/sfx/impactos/metal_thin_close_02.ogg +0 -0
  472. package/assets/sfx/impactos/metal_thin_close_03.ogg +0 -0
  473. package/assets/sfx/impactos/metal_thin_close_04.ogg +0 -0
  474. package/assets/sfx/impactos/metal_thin_close_05.ogg +0 -0
  475. package/assets/sfx/impactos/metal_thin_close_06.ogg +0 -0
  476. package/assets/sfx/impactos/metal_thin_close_07.ogg +0 -0
  477. package/assets/sfx/impactos/metal_thin_close_08.ogg +0 -0
  478. package/assets/sfx/impactos/metal_thin_close_09.ogg +0 -0
  479. package/assets/sfx/impactos/metal_thin_close_10.ogg +0 -0
  480. package/assets/sfx/impactos/metal_thin_close_11.ogg +0 -0
  481. package/assets/sfx/impactos/metal_thin_close_12.ogg +0 -0
  482. package/assets/sfx/impactos/metal_thin_close_13.ogg +0 -0
  483. package/assets/sfx/impactos/metal_thin_close_14.ogg +0 -0
  484. package/assets/sfx/impactos/metal_thin_close_15.ogg +0 -0
  485. package/assets/sfx/impactos/metal_thin_close_16.ogg +0 -0
  486. package/assets/sfx/impactos/metal_thin_close_17.ogg +0 -0
  487. package/assets/sfx/impactos/metal_thin_close_18.ogg +0 -0
  488. package/assets/sfx/impactos/metal_thin_close_19.ogg +0 -0
  489. package/assets/sfx/impactos/metal_thin_close_20.ogg +0 -0
  490. package/assets/sfx/impactos/metal_thin_close_21.ogg +0 -0
  491. package/assets/sfx/impactos/metal_thin_close_22.ogg +0 -0
  492. package/assets/sfx/impactos/metal_thin_close_23.ogg +0 -0
  493. package/assets/sfx/impactos/metal_thin_close_24.ogg +0 -0
  494. package/assets/sfx/impactos/metal_thin_close_25.ogg +0 -0
  495. package/assets/sfx/impactos/metal_thin_close_26.ogg +0 -0
  496. package/assets/sfx/impactos/paper_tear_close_01.ogg +0 -0
  497. package/assets/sfx/impactos/paper_tear_close_02.ogg +0 -0
  498. package/assets/sfx/impactos/plastic_hit_close_01.ogg +0 -0
  499. package/assets/sfx/impactos/plastic_hit_close_02.ogg +0 -0
  500. package/assets/sfx/impactos/plastic_hit_close_03.ogg +0 -0
  501. package/assets/sfx/impactos/plastic_hit_close_04.ogg +0 -0
  502. package/assets/sfx/impactos/ricochet_metal_close_21.ogg +0 -0
  503. package/assets/sfx/impactos/ricochet_metal_close_22.ogg +0 -0
  504. package/assets/sfx/impactos/ricochet_metal_close_23.ogg +0 -0
  505. package/assets/sfx/impactos/ricochet_metal_close_24.ogg +0 -0
  506. package/assets/sfx/impactos/ricochet_metal_close_25.ogg +0 -0
  507. package/assets/sfx/impactos/ricochet_metal_close_26.ogg +0 -0
  508. package/assets/sfx/impactos/ricochet_metal_close_27.ogg +0 -0
  509. package/assets/sfx/impactos/ricochet_metal_close_28.ogg +0 -0
  510. package/assets/sfx/impactos/rubble_falling_close_01.ogg +0 -0
  511. package/assets/sfx/impactos/rubble_falling_close_02.ogg +0 -0
  512. package/assets/sfx/impactos/rubble_falling_close_03.ogg +0 -0
  513. package/assets/sfx/impactos/rubble_falling_close_04.ogg +0 -0
  514. package/assets/sfx/impactos/rubble_falling_close_05.ogg +0 -0
  515. package/assets/sfx/impactos/rubble_falling_close_06.ogg +0 -0
  516. package/assets/sfx/impactos/rubble_falling_close_07.ogg +0 -0
  517. package/assets/sfx/impactos/rubble_falling_close_08.ogg +0 -0
  518. package/assets/sfx/impactos/rubble_falling_close_09.ogg +0 -0
  519. package/assets/sfx/impactos/soft_bullet_close_01.ogg +0 -0
  520. package/assets/sfx/impactos/soft_bullet_close_02.ogg +0 -0
  521. package/assets/sfx/impactos/soft_bullet_close_03.ogg +0 -0
  522. package/assets/sfx/impactos/soft_bullet_close_04.ogg +0 -0
  523. package/assets/sfx/impactos/soft_bullet_close_05.ogg +0 -0
  524. package/assets/sfx/impactos/soft_bullet_close_06.ogg +0 -0
  525. package/assets/sfx/impactos/soft_bullet_close_07.ogg +0 -0
  526. package/assets/sfx/impactos/soft_bullet_close_08.ogg +0 -0
  527. package/assets/sfx/impactos/soft_bullet_close_09.ogg +0 -0
  528. package/assets/sfx/impactos/soft_bullet_close_10.ogg +0 -0
  529. package/assets/sfx/impactos/soil_bullet_close_21.ogg +0 -0
  530. package/assets/sfx/impactos/soil_bullet_close_22.ogg +0 -0
  531. package/assets/sfx/impactos/soil_bullet_close_23.ogg +0 -0
  532. package/assets/sfx/impactos/wood_blunt_heavy_close_01.ogg +0 -0
  533. package/assets/sfx/impactos/wood_blunt_heavy_close_02.ogg +0 -0
  534. package/assets/sfx/impactos/wood_blunt_heavy_close_03.ogg +0 -0
  535. package/assets/sfx/impactos/wood_blunt_heavy_close_04.ogg +0 -0
  536. package/assets/sfx/impactos/wood_blunt_heavy_close_05.ogg +0 -0
  537. package/assets/sfx/impactos/wood_blunt_light_close_01.ogg +0 -0
  538. package/assets/sfx/impactos/wood_blunt_light_close_02.ogg +0 -0
  539. package/assets/sfx/impactos/wood_blunt_light_close_03.ogg +0 -0
  540. package/assets/sfx/impactos/wood_blunt_light_close_04.ogg +0 -0
  541. package/assets/sfx/impactos/wood_blunt_light_close_05.ogg +0 -0
  542. package/assets/sfx/impactos/wood_blunt_medium_close_01.ogg +0 -0
  543. package/assets/sfx/impactos/wood_blunt_medium_close_02.ogg +0 -0
  544. package/assets/sfx/impactos/wood_blunt_medium_close_03.ogg +0 -0
  545. package/assets/sfx/impactos/wood_blunt_medium_close_04.ogg +0 -0
  546. package/assets/sfx/impactos/wood_blunt_medium_close_05.ogg +0 -0
  547. package/assets/sfx/impactos/wood_fall_close_01.ogg +0 -0
  548. package/assets/sfx/impactos/wood_fall_close_02.ogg +0 -0
  549. package/assets/sfx/impactos/wood_fall_close_03.ogg +0 -0
  550. package/assets/sfx/impactos/wood_fall_close_04.ogg +0 -0
  551. package/assets/sfx/impactos/wood_fall_close_05.ogg +0 -0
  552. package/assets/sfx/impactos/wood_fall_close_06.ogg +0 -0
  553. package/assets/sfx/impactos/wood_fall_close_07.ogg +0 -0
  554. package/assets/sfx/impactos/wood_fall_close_08.ogg +0 -0
  555. package/assets/sfx/impactos/wood_fall_close_09.ogg +0 -0
  556. package/assets/sfx/impactos/wood_hit_close_01.ogg +0 -0
  557. package/assets/sfx/impactos/wood_hit_close_02.ogg +0 -0
  558. package/assets/sfx/impactos/wood_hit_close_03.ogg +0 -0
  559. package/assets/sfx/impactos/wood_hit_close_04.ogg +0 -0
  560. package/assets/sfx/impactos/wood_hit_close_05.ogg +0 -0
  561. package/assets/sfx/impactos/wood_hit_close_06.ogg +0 -0
  562. package/assets/sfx/impactos/wood_hit_close_07.ogg +0 -0
  563. package/assets/sfx/impactos/wood_hit_close_08.ogg +0 -0
  564. package/assets/sfx/impactos/wood_hit_close_09.ogg +0 -0
  565. package/assets/sfx/impactos/wood_hit_close_10.ogg +0 -0
  566. package/assets/sfx/impactos/wood_hit_close_11.ogg +0 -0
  567. package/assets/sfx/impactos/wood_hit_close_12.ogg +0 -0
  568. package/assets/sfx/impactos/wood_hit_close_13.ogg +0 -0
  569. package/assets/sfx/impactos/wood_hit_close_14.ogg +0 -0
  570. package/assets/sfx/impactos/wood_hit_close_21.ogg +0 -0
  571. package/assets/sfx/impactos/wood_hit_close_22.ogg +0 -0
  572. package/assets/sfx/impactos/wood_hit_close_23.ogg +0 -0
  573. package/assets/sfx/impactos/wood_hit_close_24.ogg +0 -0
  574. package/assets/sfx/impactos/wood_hit_close_25.ogg +0 -0
  575. package/assets/sfx/impactos/wood_hit_close_26.ogg +0 -0
  576. package/assets/sfx/impactos/wood_hit_close_27.ogg +0 -0
  577. package/assets/sfx/itens-portas/backpack_open_shut_01.ogg +0 -0
  578. package/assets/sfx/itens-portas/backpack_open_shut_02.ogg +0 -0
  579. package/assets/sfx/itens-portas/backpack_open_shut_03.ogg +0 -0
  580. package/assets/sfx/itens-portas/backpack_open_shut_04.ogg +0 -0
  581. package/assets/sfx/itens-portas/backpack_open_shut_05.ogg +0 -0
  582. package/assets/sfx/itens-portas/backpack_open_shut_06.ogg +0 -0
  583. package/assets/sfx/itens-portas/book_open_shut_01.ogg +0 -0
  584. package/assets/sfx/itens-portas/book_open_shut_02.ogg +0 -0
  585. package/assets/sfx/itens-portas/book_open_shut_03.ogg +0 -0
  586. package/assets/sfx/itens-portas/book_open_shut_04.ogg +0 -0
  587. package/assets/sfx/itens-portas/book_open_shut_05.ogg +0 -0
  588. package/assets/sfx/itens-portas/book_open_shut_06.ogg +0 -0
  589. package/assets/sfx/itens-portas/book_open_shut_07.ogg +0 -0
  590. package/assets/sfx/itens-portas/book_open_shut_08.ogg +0 -0
  591. package/assets/sfx/itens-portas/book_open_shut_09.ogg +0 -0
  592. package/assets/sfx/itens-portas/book_open_shut_10.ogg +0 -0
  593. package/assets/sfx/itens-portas/book_open_shut_11.ogg +0 -0
  594. package/assets/sfx/itens-portas/door_creak_01.ogg +0 -0
  595. package/assets/sfx/itens-portas/door_creak_02.ogg +0 -0
  596. package/assets/sfx/itens-portas/door_creak_03.ogg +0 -0
  597. package/assets/sfx/itens-portas/door_creak_06.ogg +0 -0
  598. package/assets/sfx/itens-portas/door_creak_07.ogg +0 -0
  599. package/assets/sfx/itens-portas/door_glass_sliding_01.ogg +0 -0
  600. package/assets/sfx/itens-portas/door_glass_sliding_02.ogg +0 -0
  601. package/assets/sfx/itens-portas/door_glass_sliding_03.ogg +0 -0
  602. package/assets/sfx/itens-portas/door_glass_sliding_04.ogg +0 -0
  603. package/assets/sfx/itens-portas/door_knock_01.ogg +0 -0
  604. package/assets/sfx/itens-portas/door_lock_unlock_01.ogg +0 -0
  605. package/assets/sfx/itens-portas/door_lock_unlock_02.ogg +0 -0
  606. package/assets/sfx/itens-portas/door_lock_unlock_03.ogg +0 -0
  607. package/assets/sfx/itens-portas/door_lock_unlock_04.ogg +0 -0
  608. package/assets/sfx/itens-portas/door_lock_unlock_05.ogg +0 -0
  609. package/assets/sfx/itens-portas/door_lock_unlock_06.ogg +0 -0
  610. package/assets/sfx/itens-portas/door_lock_unlock_07.ogg +0 -0
  611. package/assets/sfx/itens-portas/door_lock_unlock_08.ogg +0 -0
  612. package/assets/sfx/itens-portas/door_lock_unlock_09.ogg +0 -0
  613. package/assets/sfx/itens-portas/door_lock_unlock_10.ogg +0 -0
  614. package/assets/sfx/itens-portas/door_lock_unlock_11.ogg +0 -0
  615. package/assets/sfx/itens-portas/door_locked_rattle_01.ogg +0 -0
  616. package/assets/sfx/itens-portas/door_locked_rattle_02.ogg +0 -0
  617. package/assets/sfx/itens-portas/door_locked_rattle_03.ogg +0 -0
  618. package/assets/sfx/itens-portas/door_metal_open_shut_01.ogg +0 -0
  619. package/assets/sfx/itens-portas/door_metal_open_shut_02.ogg +0 -0
  620. package/assets/sfx/itens-portas/door_metal_open_shut_03.ogg +0 -0
  621. package/assets/sfx/itens-portas/door_metal_open_shut_04.ogg +0 -0
  622. package/assets/sfx/itens-portas/door_metal_open_shut_05.ogg +0 -0
  623. package/assets/sfx/itens-portas/door_metal_open_shut_06.ogg +0 -0
  624. package/assets/sfx/itens-portas/door_metal_open_shut_07.ogg +0 -0
  625. package/assets/sfx/itens-portas/door_slam_wood_01.ogg +0 -0
  626. package/assets/sfx/itens-portas/door_slam_wood_02.ogg +0 -0
  627. package/assets/sfx/itens-portas/door_slam_wood_03.ogg +0 -0
  628. package/assets/sfx/itens-portas/door_slam_wood_04.ogg +0 -0
  629. package/assets/sfx/itens-portas/door_wood_open_01.ogg +0 -0
  630. package/assets/sfx/itens-portas/door_wood_open_02.ogg +0 -0
  631. package/assets/sfx/itens-portas/door_wood_open_03.ogg +0 -0
  632. package/assets/sfx/itens-portas/door_wood_open_04.ogg +0 -0
  633. package/assets/sfx/itens-portas/door_wood_shut_01.ogg +0 -0
  634. package/assets/sfx/itens-portas/door_wood_shut_02.ogg +0 -0
  635. package/assets/sfx/itens-portas/door_wood_shut_03.ogg +0 -0
  636. package/assets/sfx/itens-portas/door_wood_shut_04.ogg +0 -0
  637. package/assets/sfx/itens-portas/door_wood_shut_05.ogg +0 -0
  638. package/assets/sfx/itens-portas/door_wood_shut_06.ogg +0 -0
  639. package/assets/sfx/itens-portas/door_wood_shut_07.ogg +0 -0
  640. package/assets/sfx/itens-portas/door_wood_shut_08.ogg +0 -0
  641. package/assets/sfx/itens-portas/drawer_open_01.ogg +0 -0
  642. package/assets/sfx/itens-portas/drawer_open_02.ogg +0 -0
  643. package/assets/sfx/itens-portas/drawer_shut_01.ogg +0 -0
  644. package/assets/sfx/itens-portas/drawer_shut_02.ogg +0 -0
  645. package/assets/sfx/itens-portas/item_drop_bag_01.ogg +0 -0
  646. package/assets/sfx/itens-portas/item_drop_bag_02.ogg +0 -0
  647. package/assets/sfx/itens-portas/item_drop_glass_01.ogg +0 -0
  648. package/assets/sfx/itens-portas/item_drop_metal_01.ogg +0 -0
  649. package/assets/sfx/itens-portas/item_drop_metal_02.ogg +0 -0
  650. package/assets/sfx/itens-portas/item_drop_metal_03.ogg +0 -0
  651. package/assets/sfx/itens-portas/item_drop_metal_04.ogg +0 -0
  652. package/assets/sfx/itens-portas/item_drop_metal_05.ogg +0 -0
  653. package/assets/sfx/itens-portas/item_drop_paper_01.ogg +0 -0
  654. package/assets/sfx/itens-portas/item_pickup_coins_01.ogg +0 -0
  655. package/assets/sfx/itens-portas/item_pickup_coins_02.ogg +0 -0
  656. package/assets/sfx/itens-portas/item_pickup_generic_01.ogg +0 -0
  657. package/assets/sfx/itens-portas/item_pickup_generic_02.ogg +0 -0
  658. package/assets/sfx/itens-portas/item_pickup_generic_03.ogg +0 -0
  659. package/assets/sfx/itens-portas/item_pickup_generic_04.ogg +0 -0
  660. package/assets/sfx/itens-portas/item_pickup_leather_01.ogg +0 -0
  661. package/assets/sfx/itens-portas/item_pickup_leather_02.ogg +0 -0
  662. package/assets/sfx/itens-portas/item_pickup_leather_03.ogg +0 -0
  663. package/assets/sfx/itens-portas/item_pickup_leather_04.ogg +0 -0
  664. package/assets/sfx/itens-portas/item_pickup_leather_05.ogg +0 -0
  665. package/assets/sfx/itens-portas/item_setdown_01.ogg +0 -0
  666. package/assets/sfx/itens-portas/item_setdown_02.ogg +0 -0
  667. package/assets/sfx/itens-portas/keys_jingle_01.ogg +0 -0
  668. package/assets/sfx/itens-portas/keys_jingle_02.ogg +0 -0
  669. package/assets/sfx/itens-portas/keys_jingle_03.ogg +0 -0
  670. package/assets/sfx/itens-portas/keys_jingle_04.ogg +0 -0
  671. package/assets/sfx/itens-portas/keys_jingle_05.ogg +0 -0
  672. package/assets/sfx/itens-portas/keys_jingle_06.ogg +0 -0
  673. package/assets/sfx/itens-portas/keys_jingle_07.ogg +0 -0
  674. package/assets/sfx/itens-portas/lever_pull_01.ogg +0 -0
  675. package/assets/sfx/itens-portas/lever_pull_02.ogg +0 -0
  676. package/assets/sfx/itens-portas/lever_pull_03.ogg +0 -0
  677. package/assets/sfx/itens-portas/lever_pull_04.ogg +0 -0
  678. package/assets/sfx/itens-portas/lever_pull_05.ogg +0 -0
  679. package/assets/sfx/itens-portas/lever_pull_06.ogg +0 -0
  680. package/assets/sfx/itens-portas/metal_latch_01.ogg +0 -0
  681. package/assets/sfx/itens-portas/metal_latch_02.ogg +0 -0
  682. package/assets/sfx/itens-portas/plates_hit_01.ogg +0 -0
  683. package/assets/sfx/itens-portas/plates_hit_02.ogg +0 -0
  684. package/assets/sfx/itens-portas/plates_hit_03.ogg +0 -0
  685. package/assets/sfx/itens-portas/plates_hit_04.ogg +0 -0
  686. package/assets/sfx/itens-portas/plates_hit_05.ogg +0 -0
  687. package/assets/sfx/itens-portas/plates_hit_06.ogg +0 -0
  688. package/assets/sfx/itens-portas/plates_hit_07.ogg +0 -0
  689. package/assets/sfx/itens-portas/plates_hit_08.ogg +0 -0
  690. package/assets/sfx/itens-portas/plates_hit_09.ogg +0 -0
  691. package/assets/sfx/itens-portas/plates_hit_10.ogg +0 -0
  692. package/assets/sfx/itens-portas/plates_slide_01.ogg +0 -0
  693. package/assets/sfx/itens-portas/plates_slide_02.ogg +0 -0
  694. package/assets/sfx/itens-portas/plates_slide_03.ogg +0 -0
  695. package/assets/sfx/itens-portas/plates_slide_04.ogg +0 -0
  696. package/assets/sfx/itens-portas/saw_wood_01.ogg +0 -0
  697. package/assets/sfx/itens-portas/switch_click_01.ogg +0 -0
  698. package/assets/sfx/itens-portas/switch_click_02.ogg +0 -0
  699. package/assets/sfx/itens-portas/switch_click_03.ogg +0 -0
  700. package/assets/sfx/itens-portas/switch_click_04.ogg +0 -0
  701. package/assets/sfx/itens-portas/toilet_flush_01.ogg +0 -0
  702. package/assets/sfx/itens-portas/tools_handling_01.ogg +0 -0
  703. package/assets/sfx/itens-portas/tools_handling_02.ogg +0 -0
  704. package/assets/sfx/itens-portas/tools_handling_03.ogg +0 -0
  705. package/assets/sfx/itens-portas/tools_handling_04.ogg +0 -0
  706. package/assets/sfx/itens-portas/tools_handling_05.ogg +0 -0
  707. package/assets/sfx/itens-portas/tools_handling_06.ogg +0 -0
  708. package/assets/sfx/itens-portas/tools_handling_07.ogg +0 -0
  709. package/assets/sfx/itens-portas/tools_handling_08.ogg +0 -0
  710. package/assets/sfx/itens-portas/tools_handling_09.ogg +0 -0
  711. package/assets/sfx/itens-portas/tools_handling_10.ogg +0 -0
  712. package/assets/sfx/itens-portas/tools_handling_11.ogg +0 -0
  713. package/assets/sfx/itens-portas/tools_handling_12.ogg +0 -0
  714. package/assets/sfx/itens-portas/tools_handling_13.ogg +0 -0
  715. package/assets/sfx/itens-portas/tools_handling_14.ogg +0 -0
  716. package/assets/sfx/itens-portas/tools_handling_15.ogg +0 -0
  717. package/assets/sfx/itens-portas/tools_handling_16.ogg +0 -0
  718. package/assets/sfx/itens-portas/water_drip_01.ogg +0 -0
  719. package/assets/sfx/itens-portas/water_drip_02.ogg +0 -0
  720. package/assets/sfx/itens-portas/water_drip_03.ogg +0 -0
  721. package/assets/sfx/itens-portas/water_drip_04.ogg +0 -0
  722. package/assets/sfx/itens-portas/water_faucet_01.ogg +0 -0
  723. package/assets/sfx/itens-portas/water_faucet_02.ogg +0 -0
  724. package/assets/sfx/itens-portas/water_faucet_03.ogg +0 -0
  725. package/assets/sfx/itens-portas/water_faucet_04.ogg +0 -0
  726. package/assets/sfx/itens-portas/water_faucet_05.ogg +0 -0
  727. package/assets/sfx/itens-portas/water_faucet_06.ogg +0 -0
  728. package/assets/sfx/itens-portas/water_faucet_07.ogg +0 -0
  729. package/assets/sfx/itens-portas/water_faucet_08.ogg +0 -0
  730. package/assets/sfx/itens-portas/water_faucet_09.ogg +0 -0
  731. package/assets/sfx/itens-portas/water_faucet_10.ogg +0 -0
  732. package/assets/sfx/manifest.json +11959 -0
  733. package/assets/sfx/personagem/axe_chop_01.ogg +0 -0
  734. package/assets/sfx/personagem/axe_chop_02.ogg +0 -0
  735. package/assets/sfx/personagem/blunt_hit_metal_01.ogg +0 -0
  736. package/assets/sfx/personagem/blunt_hit_metal_02.ogg +0 -0
  737. package/assets/sfx/personagem/blunt_hit_metal_03.ogg +0 -0
  738. package/assets/sfx/personagem/blunt_hit_metal_04.ogg +0 -0
  739. package/assets/sfx/personagem/blunt_hit_metal_05.ogg +0 -0
  740. package/assets/sfx/personagem/body_fall_01.ogg +0 -0
  741. package/assets/sfx/personagem/body_fall_02.ogg +0 -0
  742. package/assets/sfx/personagem/body_fall_03.ogg +0 -0
  743. package/assets/sfx/personagem/body_fall_04.ogg +0 -0
  744. package/assets/sfx/personagem/body_fall_05.ogg +0 -0
  745. package/assets/sfx/personagem/cloth_rustle_01.ogg +0 -0
  746. package/assets/sfx/personagem/cloth_rustle_02.ogg +0 -0
  747. package/assets/sfx/personagem/cloth_rustle_03.ogg +0 -0
  748. package/assets/sfx/personagem/cloth_rustle_04.ogg +0 -0
  749. package/assets/sfx/personagem/cloth_rustle_05.ogg +0 -0
  750. package/assets/sfx/personagem/cloth_rustle_06.ogg +0 -0
  751. package/assets/sfx/personagem/cloth_rustle_07.ogg +0 -0
  752. package/assets/sfx/personagem/cloth_rustle_08.ogg +0 -0
  753. package/assets/sfx/personagem/cloth_rustle_09.ogg +0 -0
  754. package/assets/sfx/personagem/cloth_rustle_10.ogg +0 -0
  755. package/assets/sfx/personagem/cloth_rustle_11.ogg +0 -0
  756. package/assets/sfx/personagem/cloth_rustle_12.ogg +0 -0
  757. package/assets/sfx/personagem/cloth_rustle_13.ogg +0 -0
  758. package/assets/sfx/personagem/cloth_rustle_14.ogg +0 -0
  759. package/assets/sfx/personagem/drink_gulp_01.ogg +0 -0
  760. package/assets/sfx/personagem/drink_gulp_02.ogg +0 -0
  761. package/assets/sfx/personagem/drink_gulp_03.ogg +0 -0
  762. package/assets/sfx/personagem/footstep_carpet_alt_01.ogg +0 -0
  763. package/assets/sfx/personagem/footstep_carpet_alt_02.ogg +0 -0
  764. package/assets/sfx/personagem/footstep_carpet_alt_03.ogg +0 -0
  765. package/assets/sfx/personagem/footstep_carpet_alt_04.ogg +0 -0
  766. package/assets/sfx/personagem/footstep_carpet_alt_05.ogg +0 -0
  767. package/assets/sfx/personagem/footstep_concrete_alt_01.ogg +0 -0
  768. package/assets/sfx/personagem/footstep_concrete_alt_02.ogg +0 -0
  769. package/assets/sfx/personagem/footstep_concrete_alt_03.ogg +0 -0
  770. package/assets/sfx/personagem/footstep_concrete_alt_04.ogg +0 -0
  771. package/assets/sfx/personagem/footstep_concrete_alt_05.ogg +0 -0
  772. package/assets/sfx/personagem/footstep_concrete_run_01.ogg +0 -0
  773. package/assets/sfx/personagem/footstep_concrete_run_02.ogg +0 -0
  774. package/assets/sfx/personagem/footstep_concrete_run_03.ogg +0 -0
  775. package/assets/sfx/personagem/footstep_concrete_run_04.ogg +0 -0
  776. package/assets/sfx/personagem/footstep_concrete_run_05.ogg +0 -0
  777. package/assets/sfx/personagem/footstep_concrete_walk_01.ogg +0 -0
  778. package/assets/sfx/personagem/footstep_concrete_walk_02.ogg +0 -0
  779. package/assets/sfx/personagem/footstep_concrete_walk_03.ogg +0 -0
  780. package/assets/sfx/personagem/footstep_concrete_walk_04.ogg +0 -0
  781. package/assets/sfx/personagem/footstep_concrete_walk_05.ogg +0 -0
  782. package/assets/sfx/personagem/footstep_dirt_run_01.ogg +0 -0
  783. package/assets/sfx/personagem/footstep_dirt_run_02.ogg +0 -0
  784. package/assets/sfx/personagem/footstep_dirt_run_03.ogg +0 -0
  785. package/assets/sfx/personagem/footstep_dirt_run_04.ogg +0 -0
  786. package/assets/sfx/personagem/footstep_dirt_run_05.ogg +0 -0
  787. package/assets/sfx/personagem/footstep_dirt_walk_01.ogg +0 -0
  788. package/assets/sfx/personagem/footstep_dirt_walk_02.ogg +0 -0
  789. package/assets/sfx/personagem/footstep_dirt_walk_03.ogg +0 -0
  790. package/assets/sfx/personagem/footstep_dirt_walk_04.ogg +0 -0
  791. package/assets/sfx/personagem/footstep_dirt_walk_05.ogg +0 -0
  792. package/assets/sfx/personagem/footstep_generic_alt_01.ogg +0 -0
  793. package/assets/sfx/personagem/footstep_generic_alt_02.ogg +0 -0
  794. package/assets/sfx/personagem/footstep_generic_alt_03.ogg +0 -0
  795. package/assets/sfx/personagem/footstep_generic_alt_04.ogg +0 -0
  796. package/assets/sfx/personagem/footstep_generic_alt_05.ogg +0 -0
  797. package/assets/sfx/personagem/footstep_generic_alt_06.ogg +0 -0
  798. package/assets/sfx/personagem/footstep_generic_alt_07.ogg +0 -0
  799. package/assets/sfx/personagem/footstep_generic_alt_08.ogg +0 -0
  800. package/assets/sfx/personagem/footstep_generic_alt_09.ogg +0 -0
  801. package/assets/sfx/personagem/footstep_generic_alt_10.ogg +0 -0
  802. package/assets/sfx/personagem/footstep_grass_alt2_01.ogg +0 -0
  803. package/assets/sfx/personagem/footstep_grass_alt2_02.ogg +0 -0
  804. package/assets/sfx/personagem/footstep_grass_alt2_03.ogg +0 -0
  805. package/assets/sfx/personagem/footstep_grass_alt2_04.ogg +0 -0
  806. package/assets/sfx/personagem/footstep_grass_alt_01.ogg +0 -0
  807. package/assets/sfx/personagem/footstep_grass_alt_02.ogg +0 -0
  808. package/assets/sfx/personagem/footstep_grass_alt_03.ogg +0 -0
  809. package/assets/sfx/personagem/footstep_grass_alt_04.ogg +0 -0
  810. package/assets/sfx/personagem/footstep_grass_alt_05.ogg +0 -0
  811. package/assets/sfx/personagem/footstep_grass_run_01.ogg +0 -0
  812. package/assets/sfx/personagem/footstep_grass_run_02.ogg +0 -0
  813. package/assets/sfx/personagem/footstep_grass_run_03.ogg +0 -0
  814. package/assets/sfx/personagem/footstep_grass_run_04.ogg +0 -0
  815. package/assets/sfx/personagem/footstep_grass_run_05.ogg +0 -0
  816. package/assets/sfx/personagem/footstep_grass_walk_01.ogg +0 -0
  817. package/assets/sfx/personagem/footstep_grass_walk_02.ogg +0 -0
  818. package/assets/sfx/personagem/footstep_grass_walk_03.ogg +0 -0
  819. package/assets/sfx/personagem/footstep_grass_walk_04.ogg +0 -0
  820. package/assets/sfx/personagem/footstep_grass_walk_05.ogg +0 -0
  821. package/assets/sfx/personagem/footstep_hard_alt_01.ogg +0 -0
  822. package/assets/sfx/personagem/footstep_hard_alt_02.ogg +0 -0
  823. package/assets/sfx/personagem/footstep_hard_alt_03.ogg +0 -0
  824. package/assets/sfx/personagem/footstep_hard_alt_04.ogg +0 -0
  825. package/assets/sfx/personagem/footstep_hard_alt_05.ogg +0 -0
  826. package/assets/sfx/personagem/footstep_hard_alt_06.ogg +0 -0
  827. package/assets/sfx/personagem/footstep_hard_alt_07.ogg +0 -0
  828. package/assets/sfx/personagem/footstep_hard_alt_08.ogg +0 -0
  829. package/assets/sfx/personagem/footstep_hard_alt_09.ogg +0 -0
  830. package/assets/sfx/personagem/footstep_metal_run_01.ogg +0 -0
  831. package/assets/sfx/personagem/footstep_metal_run_02.ogg +0 -0
  832. package/assets/sfx/personagem/footstep_metal_run_03.ogg +0 -0
  833. package/assets/sfx/personagem/footstep_metal_run_04.ogg +0 -0
  834. package/assets/sfx/personagem/footstep_metal_run_05.ogg +0 -0
  835. package/assets/sfx/personagem/footstep_metal_walk_01.ogg +0 -0
  836. package/assets/sfx/personagem/footstep_metal_walk_02.ogg +0 -0
  837. package/assets/sfx/personagem/footstep_metal_walk_03.ogg +0 -0
  838. package/assets/sfx/personagem/footstep_metal_walk_04.ogg +0 -0
  839. package/assets/sfx/personagem/footstep_metal_walk_05.ogg +0 -0
  840. package/assets/sfx/personagem/footstep_snow_alt_01.ogg +0 -0
  841. package/assets/sfx/personagem/footstep_snow_alt_02.ogg +0 -0
  842. package/assets/sfx/personagem/footstep_snow_alt_03.ogg +0 -0
  843. package/assets/sfx/personagem/footstep_snow_alt_04.ogg +0 -0
  844. package/assets/sfx/personagem/footstep_snow_alt_05.ogg +0 -0
  845. package/assets/sfx/personagem/footstep_snow_run_01.ogg +0 -0
  846. package/assets/sfx/personagem/footstep_snow_run_02.ogg +0 -0
  847. package/assets/sfx/personagem/footstep_snow_run_03.ogg +0 -0
  848. package/assets/sfx/personagem/footstep_snow_run_04.ogg +0 -0
  849. package/assets/sfx/personagem/footstep_snow_run_05.ogg +0 -0
  850. package/assets/sfx/personagem/footstep_snow_walk_01.ogg +0 -0
  851. package/assets/sfx/personagem/footstep_snow_walk_02.ogg +0 -0
  852. package/assets/sfx/personagem/footstep_snow_walk_03.ogg +0 -0
  853. package/assets/sfx/personagem/footstep_snow_walk_04.ogg +0 -0
  854. package/assets/sfx/personagem/footstep_snow_walk_05.ogg +0 -0
  855. package/assets/sfx/personagem/footstep_wood_alt_01.ogg +0 -0
  856. package/assets/sfx/personagem/footstep_wood_alt_02.ogg +0 -0
  857. package/assets/sfx/personagem/footstep_wood_alt_03.ogg +0 -0
  858. package/assets/sfx/personagem/footstep_wood_alt_04.ogg +0 -0
  859. package/assets/sfx/personagem/footstep_wood_alt_05.ogg +0 -0
  860. package/assets/sfx/personagem/footstep_wood_run_01.ogg +0 -0
  861. package/assets/sfx/personagem/footstep_wood_run_02.ogg +0 -0
  862. package/assets/sfx/personagem/footstep_wood_run_03.ogg +0 -0
  863. package/assets/sfx/personagem/footstep_wood_run_04.ogg +0 -0
  864. package/assets/sfx/personagem/footstep_wood_run_05.ogg +0 -0
  865. package/assets/sfx/personagem/footstep_wood_walk_01.ogg +0 -0
  866. package/assets/sfx/personagem/footstep_wood_walk_02.ogg +0 -0
  867. package/assets/sfx/personagem/footstep_wood_walk_03.ogg +0 -0
  868. package/assets/sfx/personagem/footstep_wood_walk_04.ogg +0 -0
  869. package/assets/sfx/personagem/footstep_wood_walk_05.ogg +0 -0
  870. package/assets/sfx/personagem/frying_pan_hit_01.ogg +0 -0
  871. package/assets/sfx/personagem/frying_pan_hit_02.ogg +0 -0
  872. package/assets/sfx/personagem/frying_pan_hit_03.ogg +0 -0
  873. package/assets/sfx/personagem/grab_01.ogg +0 -0
  874. package/assets/sfx/personagem/kick_hit_01.ogg +0 -0
  875. package/assets/sfx/personagem/kick_hit_02.ogg +0 -0
  876. package/assets/sfx/personagem/kick_hit_03.ogg +0 -0
  877. package/assets/sfx/personagem/kick_hit_04.ogg +0 -0
  878. package/assets/sfx/personagem/kick_hit_05.ogg +0 -0
  879. package/assets/sfx/personagem/knife_draw_01.ogg +0 -0
  880. package/assets/sfx/personagem/knife_draw_02.ogg +0 -0
  881. package/assets/sfx/personagem/knife_draw_03.ogg +0 -0
  882. package/assets/sfx/personagem/knife_scrape_01.ogg +0 -0
  883. package/assets/sfx/personagem/knife_slash_01.ogg +0 -0
  884. package/assets/sfx/personagem/knife_slash_02.ogg +0 -0
  885. package/assets/sfx/personagem/land_concrete_01.ogg +0 -0
  886. package/assets/sfx/personagem/land_concrete_02.ogg +0 -0
  887. package/assets/sfx/personagem/land_dirt_01.ogg +0 -0
  888. package/assets/sfx/personagem/land_dirt_02.ogg +0 -0
  889. package/assets/sfx/personagem/land_grass_01.ogg +0 -0
  890. package/assets/sfx/personagem/land_grass_02.ogg +0 -0
  891. package/assets/sfx/personagem/land_metal_01.ogg +0 -0
  892. package/assets/sfx/personagem/land_metal_02.ogg +0 -0
  893. package/assets/sfx/personagem/land_snow_01.ogg +0 -0
  894. package/assets/sfx/personagem/land_snow_02.ogg +0 -0
  895. package/assets/sfx/personagem/land_wood_01.ogg +0 -0
  896. package/assets/sfx/personagem/land_wood_02.ogg +0 -0
  897. package/assets/sfx/personagem/player_breath_run_01.ogg +0 -0
  898. package/assets/sfx/personagem/player_breath_run_02.ogg +0 -0
  899. package/assets/sfx/personagem/player_breath_run_03.ogg +0 -0
  900. package/assets/sfx/personagem/player_breath_run_04.ogg +0 -0
  901. package/assets/sfx/personagem/player_breath_run_05.ogg +0 -0
  902. package/assets/sfx/personagem/player_death_female_01.ogg +0 -0
  903. package/assets/sfx/personagem/player_death_female_02.ogg +0 -0
  904. package/assets/sfx/personagem/player_death_female_03.ogg +0 -0
  905. package/assets/sfx/personagem/player_death_female_04.ogg +0 -0
  906. package/assets/sfx/personagem/player_death_female_05.ogg +0 -0
  907. package/assets/sfx/personagem/player_death_female_06.ogg +0 -0
  908. package/assets/sfx/personagem/player_death_female_07.ogg +0 -0
  909. package/assets/sfx/personagem/player_death_female_08.ogg +0 -0
  910. package/assets/sfx/personagem/player_death_male_01.ogg +0 -0
  911. package/assets/sfx/personagem/player_death_male_02.ogg +0 -0
  912. package/assets/sfx/personagem/player_death_male_03.ogg +0 -0
  913. package/assets/sfx/personagem/player_death_male_04.ogg +0 -0
  914. package/assets/sfx/personagem/player_death_male_05.ogg +0 -0
  915. package/assets/sfx/personagem/player_death_male_06.ogg +0 -0
  916. package/assets/sfx/personagem/player_death_male_07.ogg +0 -0
  917. package/assets/sfx/personagem/player_death_male_08.ogg +0 -0
  918. package/assets/sfx/personagem/player_effort_01.ogg +0 -0
  919. package/assets/sfx/personagem/player_effort_02.ogg +0 -0
  920. package/assets/sfx/personagem/player_effort_03.ogg +0 -0
  921. package/assets/sfx/personagem/player_effort_04.ogg +0 -0
  922. package/assets/sfx/personagem/player_hurt_female_01.ogg +0 -0
  923. package/assets/sfx/personagem/player_hurt_female_02.ogg +0 -0
  924. package/assets/sfx/personagem/player_hurt_female_03.ogg +0 -0
  925. package/assets/sfx/personagem/player_hurt_female_04.ogg +0 -0
  926. package/assets/sfx/personagem/player_hurt_female_05.ogg +0 -0
  927. package/assets/sfx/personagem/player_hurt_female_06.ogg +0 -0
  928. package/assets/sfx/personagem/player_hurt_male_01.ogg +0 -0
  929. package/assets/sfx/personagem/player_hurt_male_02.ogg +0 -0
  930. package/assets/sfx/personagem/player_hurt_male_03.ogg +0 -0
  931. package/assets/sfx/personagem/player_hurt_male_04.ogg +0 -0
  932. package/assets/sfx/personagem/player_hurt_male_05.ogg +0 -0
  933. package/assets/sfx/personagem/player_hurt_male_06.ogg +0 -0
  934. package/assets/sfx/personagem/punch_hit_alt_01.ogg +0 -0
  935. package/assets/sfx/personagem/punch_hit_alt_02.ogg +0 -0
  936. package/assets/sfx/personagem/punch_hit_alt_03.ogg +0 -0
  937. package/assets/sfx/personagem/punch_hit_alt_04.ogg +0 -0
  938. package/assets/sfx/personagem/punch_hit_alt_05.ogg +0 -0
  939. package/assets/sfx/personagem/punch_hit_alt_06.ogg +0 -0
  940. package/assets/sfx/personagem/punch_hit_alt_07.ogg +0 -0
  941. package/assets/sfx/personagem/punch_hit_alt_08.ogg +0 -0
  942. package/assets/sfx/personagem/punch_hit_alt_09.ogg +0 -0
  943. package/assets/sfx/personagem/punch_hit_alt_10.ogg +0 -0
  944. package/assets/sfx/personagem/punch_hit_body_01.ogg +0 -0
  945. package/assets/sfx/personagem/punch_hit_body_02.ogg +0 -0
  946. package/assets/sfx/personagem/punch_hit_body_03.ogg +0 -0
  947. package/assets/sfx/personagem/punch_hit_body_04.ogg +0 -0
  948. package/assets/sfx/personagem/punch_hit_body_05.ogg +0 -0
  949. package/assets/sfx/personagem/punch_hit_body_06.ogg +0 -0
  950. package/assets/sfx/personagem/punch_hit_face_01.ogg +0 -0
  951. package/assets/sfx/personagem/punch_hit_face_02.ogg +0 -0
  952. package/assets/sfx/personagem/punch_hit_face_03.ogg +0 -0
  953. package/assets/sfx/personagem/punch_hit_face_04.ogg +0 -0
  954. package/assets/sfx/personagem/punch_hit_face_05.ogg +0 -0
  955. package/assets/sfx/personagem/punch_swing_01.ogg +0 -0
  956. package/assets/sfx/personagem/punch_swing_02.ogg +0 -0
  957. package/assets/sfx/personagem/punch_swing_03.ogg +0 -0
  958. package/assets/sfx/personagem/punch_swing_04.ogg +0 -0
  959. package/assets/sfx/personagem/punch_swing_05.ogg +0 -0
  960. package/assets/sfx/personagem/punch_swing_06.ogg +0 -0
  961. package/assets/sfx/personagem/punch_swing_07.ogg +0 -0
  962. package/assets/sfx/personagem/punch_swing_08.ogg +0 -0
  963. package/assets/sfx/personagem/scream_01.ogg +0 -0
  964. package/assets/sfx/personagem/scream_02.ogg +0 -0
  965. package/assets/sfx/personagem/scream_03.ogg +0 -0
  966. package/assets/sfx/personagem/scream_04.ogg +0 -0
  967. package/assets/sfx/personagem/slap_01.ogg +0 -0
  968. package/assets/sfx/personagem/swing_whoosh_alt_01.ogg +0 -0
  969. package/assets/sfx/personagem/swing_whoosh_alt_02.ogg +0 -0
  970. package/assets/sfx/personagem/swing_whoosh_alt_03.ogg +0 -0
  971. package/assets/sfx/personagem/swing_whoosh_alt_04.ogg +0 -0
  972. package/assets/sfx/personagem/swing_whoosh_alt_05.ogg +0 -0
  973. package/assets/sfx/personagem/swing_whoosh_alt_06.ogg +0 -0
  974. package/assets/sfx/personagem/swing_whoosh_alt_07.ogg +0 -0
  975. package/assets/sfx/personagem/swing_whoosh_alt_08.ogg +0 -0
  976. package/assets/sfx/personagem/swing_whoosh_alt_09.ogg +0 -0
  977. package/assets/sfx/personagem/swing_whoosh_alt_10.ogg +0 -0
  978. package/assets/sfx/personagem/swing_whoosh_alt_11.ogg +0 -0
  979. package/assets/sfx/personagem/swing_whoosh_alt_12.ogg +0 -0
  980. package/assets/sfx/personagem/swing_whoosh_alt_13.ogg +0 -0
  981. package/assets/sfx/personagem/swing_whoosh_alt_14.ogg +0 -0
  982. package/assets/sfx/personagem/swing_whoosh_alt_15.ogg +0 -0
  983. package/assets/sfx/personagem/swing_whoosh_alt_16.ogg +0 -0
  984. package/assets/sfx/personagem/swing_whoosh_alt_17.ogg +0 -0
  985. package/assets/sfx/personagem/swing_whoosh_alt_18.ogg +0 -0
  986. package/assets/sfx/personagem/swing_whoosh_alt_19.ogg +0 -0
  987. package/assets/sfx/personagem/swing_whoosh_alt_20.ogg +0 -0
  988. package/assets/sfx/personagem/swing_whoosh_alt_21.ogg +0 -0
  989. package/assets/sfx/personagem/swing_whoosh_alt_22.ogg +0 -0
  990. package/assets/sfx/personagem/swing_whoosh_alt_23.ogg +0 -0
  991. package/assets/sfx/personagem/swing_whoosh_alt_24.ogg +0 -0
  992. package/assets/sfx/personagem/swing_whoosh_alt_25.ogg +0 -0
  993. package/assets/sfx/personagem/swing_whoosh_alt_26.ogg +0 -0
  994. package/assets/sfx/personagem/swing_whoosh_alt_27.ogg +0 -0
  995. package/assets/sfx/personagem/swing_whoosh_alt_28.ogg +0 -0
  996. package/assets/sfx/personagem/swing_whoosh_alt_29.ogg +0 -0
  997. package/assets/sfx/personagem/swing_whoosh_alt_30.ogg +0 -0
  998. package/assets/sfx/personagem/swing_whoosh_alt_31.ogg +0 -0
  999. package/assets/sfx/personagem/swing_whoosh_alt_32.ogg +0 -0
  1000. package/assets/sfx/personagem/swing_whoosh_alt_33.ogg +0 -0
  1001. package/assets/sfx/personagem/swing_whoosh_alt_34.ogg +0 -0
  1002. package/assets/sfx/personagem/swing_whoosh_alt_35.ogg +0 -0
  1003. package/assets/sfx/personagem/swing_whoosh_alt_36.ogg +0 -0
  1004. package/assets/sfx/personagem/swing_whoosh_alt_37.ogg +0 -0
  1005. package/assets/sfx/personagem/swing_whoosh_alt_38.ogg +0 -0
  1006. package/assets/sfx/personagem/swing_whoosh_alt_39.ogg +0 -0
  1007. package/assets/sfx/personagem/swing_whoosh_alt_40.ogg +0 -0
  1008. package/assets/sfx/personagem/swing_whoosh_alt_41.ogg +0 -0
  1009. package/assets/sfx/personagem/swing_whoosh_alt_42.ogg +0 -0
  1010. package/assets/sfx/personagem/swing_whoosh_alt_43.ogg +0 -0
  1011. package/assets/sfx/personagem/zombie_creature_01.ogg +0 -0
  1012. package/assets/sfx/personagem/zombie_creature_02.ogg +0 -0
  1013. package/assets/sfx/personagem/zombie_creature_03.ogg +0 -0
  1014. package/assets/sfx/personagem/zombie_death_01.ogg +0 -0
  1015. package/assets/sfx/personagem/zombie_death_02.ogg +0 -0
  1016. package/assets/sfx/personagem/zombie_death_03.ogg +0 -0
  1017. package/assets/sfx/personagem/zombie_death_04.ogg +0 -0
  1018. package/assets/sfx/personagem/zombie_death_05.ogg +0 -0
  1019. package/assets/sfx/personagem/zombie_death_06.ogg +0 -0
  1020. package/assets/sfx/personagem/zombie_death_07.ogg +0 -0
  1021. package/assets/sfx/personagem/zombie_death_08.ogg +0 -0
  1022. package/assets/sfx/personagem/zombie_groan_01.ogg +0 -0
  1023. package/assets/sfx/personagem/zombie_groan_02.ogg +0 -0
  1024. package/assets/sfx/personagem/zombie_groan_03.ogg +0 -0
  1025. package/assets/sfx/personagem/zombie_groan_04.ogg +0 -0
  1026. package/assets/sfx/personagem/zombie_groan_05.ogg +0 -0
  1027. package/assets/sfx/personagem/zombie_groan_06.ogg +0 -0
  1028. package/assets/sfx/personagem/zombie_groan_07.ogg +0 -0
  1029. package/assets/sfx/personagem/zombie_groan_08.ogg +0 -0
  1030. package/assets/sfx/personagem/zombie_groan_09.ogg +0 -0
  1031. package/assets/sfx/personagem/zombie_groan_10.ogg +0 -0
  1032. package/assets/sfx/personagem/zombie_groan_11.ogg +0 -0
  1033. package/assets/sfx/veiculos/car_door_open_01.ogg +0 -0
  1034. package/assets/sfx/veiculos/car_door_shut_01.ogg +0 -0
  1035. package/assets/sfx/veiculos/car_gear_shift_01.ogg +0 -0
  1036. package/assets/sfx/veiculos/car_trunk_shut_01.ogg +0 -0
  1037. package/assets/sfx/veiculos/car_window_01.ogg +0 -0
  1038. package/assets/sfx/veiculos/car_window_02.ogg +0 -0
  1039. package/assets/sfx/veiculos/engine_loop_car_high_01.ogg +0 -0
  1040. package/assets/sfx/veiculos/engine_loop_car_idle_01.ogg +0 -0
  1041. package/assets/sfx/veiculos/engine_start_run_stop_01.ogg +0 -0
  1042. package/assets/sfx/veiculos/engine_start_run_stop_02.ogg +0 -0
  1043. package/dist/{chunk-DZITVFMJ.js → chunk-7TLFY7VO.js} +1985 -50
  1044. package/dist/chunk-7TLFY7VO.js.map +1 -0
  1045. package/dist/index.d.ts +223 -3
  1046. package/dist/index.global.js +3098 -949
  1047. package/dist/index.global.js.map +1 -1
  1048. package/dist/index.js +875 -5
  1049. package/dist/index.js.map +1 -1
  1050. package/dist/{testing-BZQid7h0.d.ts → locale-BugSe8dA.d.ts} +479 -61
  1051. package/dist/testing.d.ts +82 -2
  1052. package/dist/testing.js +11 -3
  1053. package/package.json +9 -6
  1054. package/dist/chunk-DZITVFMJ.js.map +0 -1
@@ -186,15 +186,31 @@ var mix_profiles_default = [
186
186
  {
187
187
  id: "game",
188
188
  master: 0.5,
189
- noise: { seconds: 1.5, create: "lazy" },
190
- sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
189
+ noise: {
190
+ seconds: 1.5,
191
+ create: "lazy"
192
+ },
193
+ sources: [
194
+ "jogo:L62077-62081 master 0.5 to the output",
195
+ "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"
196
+ ]
191
197
  },
192
198
  {
193
199
  id: "art_scene",
194
200
  master: 0.85,
195
- compressor: { threshold: -12, ratio: 5 },
196
- reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
197
- noise: { seconds: 2, create: "eager" },
201
+ compressor: {
202
+ threshold: -12,
203
+ ratio: 5
204
+ },
205
+ reverb: {
206
+ seconds: 2.2,
207
+ decay: 3.4,
208
+ wet: 0.4
209
+ },
210
+ noise: {
211
+ seconds: 2,
212
+ create: "eager"
213
+ },
198
214
  sources: [
199
215
  "cena:L1308 compressor -12 dB, ratio 5",
200
216
  "cena:L1309 master 0.85",
@@ -202,6 +218,30 @@ var mix_profiles_default = [
202
218
  "cena:L1311 wet 0.4",
203
219
  "cena:L1312 noise 2 s made with the chain"
204
220
  ]
221
+ },
222
+ {
223
+ id: "kit",
224
+ master: 0.85,
225
+ compressor: {
226
+ threshold: -12,
227
+ ratio: 5
228
+ },
229
+ reverb: {
230
+ seconds: 2.2,
231
+ decay: 3.4,
232
+ wet: 0.4
233
+ },
234
+ noise: {
235
+ seconds: 2,
236
+ create: "eager"
237
+ },
238
+ sources: [
239
+ "sdk: the art scene chain (cena L1308-L1312) with a limiter after the compressor: the page has none, and a blast with its debris and a fire catching reached +7 dBFS"
240
+ ],
241
+ limiter: {
242
+ ceiling: -1,
243
+ knee: -6
244
+ }
205
245
  }
206
246
  ];
207
247
 
@@ -209,7 +249,7 @@ var mix_profiles_default = [
209
249
  var MIX_PROFILES = Object.fromEntries(
210
250
  mix_profiles_default.map((profile) => [profile.id, profile])
211
251
  );
212
- var DEFAULT_MIX = "art_scene";
252
+ var DEFAULT_MIX = "kit";
213
253
  function resolveMix(mix, profiles = MIX_PROFILES) {
214
254
  if (typeof mix !== "string") return mix;
215
255
  const profile = profiles[mix];
@@ -236,6 +276,19 @@ var voice_groups_default = {
236
276
  "jogo:L66986 one groan every 0.25 s (`groanBudget`), only nearer than 40 m",
237
277
  "jogo:L70472 the budget counts down by the frame time"
238
278
  ]
279
+ },
280
+ fire_ignite: {
281
+ maxConcurrent: 2,
282
+ cooldown: 0.15,
283
+ sources: [
284
+ "sdk: many parts catching at once (a blast sets a shelf alight) are one or two ignitions, not forty"
285
+ ]
286
+ },
287
+ fire_crackle: {
288
+ maxConcurrent: 4,
289
+ sources: [
290
+ "sdk: the crackles of every fire share four voices"
291
+ ]
239
292
  }
240
293
  };
241
294
 
@@ -331,6 +384,7 @@ function createSoundRegistry(banks = []) {
331
384
  const sounds = /* @__PURE__ */ new Map();
332
385
  const loops = /* @__PURE__ */ new Map();
333
386
  const sets = /* @__PURE__ */ new Map();
387
+ const samples = /* @__PURE__ */ new Map();
334
388
  const owners = /* @__PURE__ */ new Map();
335
389
  const registry = {
336
390
  register(bank) {
@@ -347,25 +401,34 @@ function createSoundRegistry(banks = []) {
347
401
  sets.set(set.id, set);
348
402
  owners.set(set.id, bank.id);
349
403
  }
404
+ for (const sample of bank.samples ?? []) {
405
+ samples.set(sample.id, sample);
406
+ owners.set(sample.id, bank.id);
407
+ }
350
408
  },
351
409
  patch(id, patch) {
352
410
  const sound = sounds.get(id);
353
411
  if (sound) sounds.set(id, mergeRecords(sound, patch));
354
412
  const loop = loops.get(id);
355
413
  if (loop) loops.set(id, mergeRecords(loop, patch));
414
+ const sample = samples.get(id);
415
+ if (sample) samples.set(id, mergeRecords(sample, patch));
356
416
  },
357
417
  remove(id) {
358
418
  sounds.delete(id);
359
419
  loops.delete(id);
360
420
  sets.delete(id);
421
+ samples.delete(id);
361
422
  owners.delete(id);
362
423
  },
363
424
  sound: (id) => sounds.get(id),
364
425
  loop: (id) => loops.get(id),
365
426
  set: (id) => sets.get(id),
427
+ sample: (id) => samples.get(id),
366
428
  soundIds: () => [...sounds.keys()],
367
429
  setIds: () => [...sets.keys()],
368
430
  loopIds: () => [...loops.keys()],
431
+ sampleIds: () => [...samples.keys()],
369
432
  bankOf: (id) => owners.get(id)
370
433
  };
371
434
  for (const bank of banks) registry.register(bank);
@@ -633,7 +696,32 @@ function bufferOf(context, channels, requestedLength) {
633
696
  }
634
697
 
635
698
  // src/webaudio/chain.ts
699
+ var LIMITER_POINTS = 4097;
700
+ function limiterCurve(ceilingDb, kneeDb, range, points = LIMITER_POINTS) {
701
+ const ceiling = 10 ** (ceilingDb / 20);
702
+ const knee = Math.min(10 ** (kneeDb / 20), ceiling);
703
+ const curve = new Float32Array(new ArrayBuffer(points * 4));
704
+ for (let i = 0; i < points; i++) {
705
+ const x = (i / (points - 1) * 2 - 1) * range;
706
+ const a = Math.abs(x);
707
+ const y = a <= knee || ceiling === knee ? Math.min(a, ceiling) : knee + (ceiling - knee) * Math.tanh((a - knee) / (ceiling - knee));
708
+ curve[i] = Math.sign(x) * y;
709
+ }
710
+ return curve;
711
+ }
636
712
  function buildChain(context, profile, random) {
713
+ let limiter;
714
+ if (profile.limiter) {
715
+ const range = profile.limiter.range ?? 4;
716
+ const input = context.createGain();
717
+ input.gain.value = 1 / range;
718
+ const shaper = context.createWaveShaper();
719
+ shaper.curve = limiterCurve(profile.limiter.ceiling, profile.limiter.knee, range);
720
+ input.connect(shaper);
721
+ shaper.connect(context.destination);
722
+ limiter = { input, shaper };
723
+ }
724
+ const output = limiter?.input ?? context.destination;
637
725
  let compressor;
638
726
  if (profile.compressor) {
639
727
  compressor = context.createDynamicsCompressor();
@@ -642,17 +730,19 @@ function buildChain(context, profile, random) {
642
730
  if (profile.compressor.knee !== void 0) compressor.knee.value = profile.compressor.knee;
643
731
  if (profile.compressor.attack !== void 0) compressor.attack.value = profile.compressor.attack;
644
732
  if (profile.compressor.release !== void 0) compressor.release.value = profile.compressor.release;
645
- compressor.connect(context.destination);
733
+ compressor.connect(output);
646
734
  }
647
735
  const master = context.createGain();
648
736
  master.gain.value = profile.master;
649
- master.connect(compressor ?? context.destination);
737
+ master.connect(compressor ?? output);
650
738
  if (!profile.reverb) {
651
739
  return {
652
740
  master,
653
741
  disconnect: () => {
654
742
  master.disconnect();
655
743
  compressor?.disconnect();
744
+ limiter?.input.disconnect();
745
+ limiter?.shaper.disconnect();
656
746
  }
657
747
  };
658
748
  }
@@ -671,6 +761,8 @@ function buildChain(context, profile, random) {
671
761
  convolver.disconnect();
672
762
  master.disconnect();
673
763
  compressor?.disconnect();
764
+ limiter?.input.disconnect();
765
+ limiter?.shaper.disconnect();
674
766
  }
675
767
  };
676
768
  }
@@ -682,7 +774,7 @@ function globalContext() {
682
774
  return Constructor ? new Constructor() : null;
683
775
  }
684
776
  function unlockContext(context) {
685
- if (context.state === "suspended") void context.resume();
777
+ if (context.state === "suspended" && typeof context.close === "function") void context.resume();
686
778
  }
687
779
 
688
780
  // src/loops.ts
@@ -760,6 +852,16 @@ function voiceOf(sources) {
760
852
  }
761
853
 
762
854
  // src/webaudio/realize-loop.ts
855
+ function outputStage(recipe, target, gain) {
856
+ if (!recipe.pan) {
857
+ gain.connect(target.output);
858
+ return { out: gain };
859
+ }
860
+ const panner = target.context.createStereoPanner();
861
+ gain.connect(panner);
862
+ panner.connect(target.output);
863
+ return { out: panner, panner };
864
+ }
763
865
  var fixed = (range) => typeof range === "number" ? range : 0;
764
866
  var fixedFrequency = (automation) => fixed("set" in automation ? automation.set : automation.from);
765
867
  function sourceOf(recipe, target) {
@@ -786,7 +888,7 @@ function realizeGameLoop(recipe, target) {
786
888
  gain.gain.value = 0;
787
889
  const last = filters.reduce((previous, filter) => previous ? previous.connect(filter) : filter, void 0);
788
890
  last?.connect(gain);
789
- gain.connect(target.output);
891
+ const output = outputStage(recipe, target, gain);
790
892
  const { source, frequency } = sourceOf(recipe, target);
791
893
  recipe.filters?.bank.forEach((spec, index) => {
792
894
  const filter = filters[index];
@@ -813,7 +915,7 @@ function realizeGameLoop(recipe, target) {
813
915
  }
814
916
  source.connect(filters[0] ?? gain);
815
917
  source.start();
816
- return { gain, source, ...frequency ? { frequency } : {}, stop: stopAll(sources) };
918
+ return { gain, ...output, source, ...frequency ? { frequency } : {}, ...filters[0] ? { cutoff: filters[0].frequency } : {}, stop: stopAll(sources) };
817
919
  }
818
920
  function realizeChainLoop(recipe, target, volume) {
819
921
  const { context } = target;
@@ -834,10 +936,10 @@ function realizeChainLoop(recipe, target, volume) {
834
936
  let tail = source;
835
937
  for (const filter of filters) tail = tail.connect(filter);
836
938
  tail.connect(gain);
837
- gain.connect(target.output);
939
+ const output = outputStage(recipe, target, gain);
838
940
  source.start();
839
941
  for (const lfo of lfos) lfo.start();
840
- return { gain, source, ...frequency ? { frequency } : {}, stop: stopAll([source, ...lfos]) };
942
+ return { gain, ...output, source, ...frequency ? { frequency } : {}, ...filters[0] ? { cutoff: filters[0].frequency } : {}, stop: stopAll([source, ...lfos]) };
841
943
  }
842
944
 
843
945
  // src/webaudio/engine-loop.ts
@@ -857,12 +959,12 @@ function createLoopHandle(recipe, host, volume) {
857
959
  return nodes !== void 0;
858
960
  },
859
961
  rewire() {
860
- nodes?.gain.disconnect();
861
- nodes?.gain.connect(host.output(loopRecipe.bus));
962
+ nodes?.out.disconnect();
963
+ nodes?.out.connect(host.output(loopRecipe.bus));
862
964
  },
863
965
  stop() {
864
966
  nodes?.stop();
865
- nodes?.gain.disconnect();
967
+ nodes?.out.disconnect();
866
968
  nodes = void 0;
867
969
  state = createLoopState(loopRecipe);
868
970
  host.unregister(entry);
@@ -882,16 +984,255 @@ function createLoopHandle(recipe, host, volume) {
882
984
  state = createLoopState({ ...loopRecipe, volume: opening }, true);
883
985
  };
884
986
  if (isChain) open();
987
+ let position;
988
+ let cutoff;
989
+ const placed = loopRecipe.falloff !== void 0 || loopRecipe.pan === true;
885
990
  return {
886
991
  set(next) {
887
992
  if (isChain && !nodes) open();
888
993
  const context = host.ready();
889
994
  if (!context) return;
995
+ position = next.position ?? position;
996
+ cutoff = next.cutoff ?? cutoff;
890
997
  const action = state.set(next);
891
998
  if (!action) return;
892
999
  nodes ?? (nodes = create(context, 0));
893
- nodes.gain.gain.setTargetAtTime(action.volume, context.currentTime, smoothing.volume);
1000
+ const listener = placed && position ? host.listener?.() : void 0;
1001
+ const distance = listener && position ? listenerDistance(listener, position, host.distance) : 0;
1002
+ const level = listener ? falloffGain(loopRecipe.falloff, action.volume, distance) : action.volume;
1003
+ nodes.gain.gain.setTargetAtTime(level, context.currentTime, smoothing.volume);
894
1004
  if (action.frequency !== void 0 && nodes.frequency) nodes.frequency.setTargetAtTime(action.frequency, context.currentTime, smoothing.frequency);
1005
+ if (cutoff !== void 0 && nodes.cutoff) nodes.cutoff.setTargetAtTime(cutoff / cutoffDivisor(loopRecipe.falloff, distance), context.currentTime, smoothing.frequency);
1006
+ if (listener && position && nodes.panner) nodes.panner.pan.setTargetAtTime(panFor(listener, position), context.currentTime, smoothing.frequency);
1007
+ },
1008
+ stop: entry.stop
1009
+ };
1010
+ }
1011
+
1012
+ // src/sample.ts
1013
+ var SAMPLE_ENVIRONMENTS = ["indoor", "outdoor"];
1014
+ var DEFAULT_SAMPLE_FALLOFF = { model: "inverse_square", k: 2e-3, minGain: 2e-3 };
1015
+ var DEFAULT_CROSSOVER = { from: 30, to: 80 };
1016
+ var DEFAULT_SAMPLE_PITCH = 0.04;
1017
+ var DEFAULT_TAIL_GAIN = 0.6;
1018
+ var DEFAULT_SAMPLE_CUTOFF_K = 0.01;
1019
+ var OPEN_CUTOFF = 2e4;
1020
+ var LAYER_FLOOR = 1e-3;
1021
+ function pickTake(count, last, random) {
1022
+ if (count <= 1) return 0;
1023
+ if (last === void 0 || last < 0 || last >= count) return Math.min(count - 1, Math.floor(random() * count));
1024
+ const drawn = Math.min(count - 2, Math.floor(random() * (count - 1)));
1025
+ return drawn >= last ? drawn + 1 : drawn;
1026
+ }
1027
+ function farMixAt(crossover, distance) {
1028
+ if (crossover.to <= crossover.from) return distance >= crossover.to ? 1 : 0;
1029
+ const t = (distance - crossover.from) / (crossover.to - crossover.from);
1030
+ return t <= 0 ? 0 : t >= 1 ? 1 : t;
1031
+ }
1032
+ function crossGains(farMix) {
1033
+ return { close: Math.cos(farMix * Math.PI / 2), far: Math.sin(farMix * Math.PI / 2) };
1034
+ }
1035
+ function sampleCutoff(cutoffK, distance, occlusion = 0) {
1036
+ const byDistance = cutoffK > 0 ? OPEN_CUTOFF / (1 + distance * cutoffK) : OPEN_CUTOFF;
1037
+ const occluded = occlusion > 0 ? byDistance / (1 + occlusion * 9) : byDistance;
1038
+ return Math.max(80, Math.min(OPEN_CUTOFF, occluded));
1039
+ }
1040
+ function sampleUrls(sound) {
1041
+ const tiers = (sound.tiers ?? []).flatMap((tier) => [...tier.close, ...tier.far ?? []]);
1042
+ const all = [...sound.close, ...sound.far ?? [], ...tiers, ...sound.tail?.indoor ?? [], ...sound.tail?.outdoor ?? []].map((ref) => ref.url);
1043
+ return [...new Set(all)];
1044
+ }
1045
+ function tierFor(sound, intensity) {
1046
+ if (intensity === void 0 || !sound.tiers) return void 0;
1047
+ let chosen;
1048
+ for (const tier of sound.tiers) if (tier.from <= intensity) chosen = tier;
1049
+ return chosen ?? sound.tiers[0];
1050
+ }
1051
+ function planSample(sound, input) {
1052
+ if (sound.close.length === 0) throw new Error(`sample sound ${sound.id} has no close take`);
1053
+ const listener = input.listener ?? DEFAULT_LISTENER;
1054
+ const distance = input.distance ?? (input.position ? listenerDistance(listener, input.position, input.distanceMode) : 0);
1055
+ const falloff = sound.falloff ?? DEFAULT_SAMPLE_FALLOFF;
1056
+ const occlusion = Math.max(0, Math.min(1, input.occlusion ?? 0));
1057
+ const level = falloffGain(falloff, (input.volume ?? 1) * (sound.gain ?? 1), distance) * (1 - 0.45 * occlusion);
1058
+ if (isSilent(falloff, level) || level <= 0) return null;
1059
+ const pitch = sound.pitch ?? DEFAULT_SAMPLE_PITCH;
1060
+ const rate = pitch > 0 ? 1 + (input.random() * 2 - 1) * pitch : 1;
1061
+ const environment = input.environment ?? "outdoor";
1062
+ const tier = tierFor(sound, input.intensity);
1063
+ const close = tier?.close.length ? tier.close : sound.close;
1064
+ const far = tier?.far?.length ? tier.far : sound.far ?? [];
1065
+ const farMix = far.length > 0 ? farMixAt(sound.crossover ?? DEFAULT_CROSSOVER, distance) : 0;
1066
+ const gains = crossGains(farMix);
1067
+ const layers = [];
1068
+ const take = (role, refs, gain, at) => {
1069
+ if (refs.length === 0 || gain < LAYER_FLOOR) return;
1070
+ const key = `${sound.id}/${tier && role !== "tail" ? `${tier.name}/` : ""}${role}`;
1071
+ const index = pickTake(refs.length, input.memory?.get(key), input.random);
1072
+ input.memory?.set(key, index);
1073
+ const ref = refs[index];
1074
+ layers.push({ role, url: ref.url, take: index, gain: gain * (ref.gain ?? 1) * level, rate, at });
1075
+ };
1076
+ take("close", close, gains.close, 0);
1077
+ take("far", far, gains.far, 0);
1078
+ const tails = sound.tail?.[environment] ?? [];
1079
+ take("tail", tails, sound.tail?.gain ?? DEFAULT_TAIL_GAIN, sound.tail?.at ?? 0);
1080
+ const pan = (sound.pan ?? true) && input.position ? panFor(listener, input.position) : void 0;
1081
+ return {
1082
+ kind: "sample",
1083
+ id: sound.id,
1084
+ bus: sound.bus,
1085
+ level,
1086
+ distance,
1087
+ ...pan === void 0 ? {} : { pan },
1088
+ cutoff: sampleCutoff(sound.cutoffK ?? DEFAULT_SAMPLE_CUTOFF_K, distance, occlusion),
1089
+ rate,
1090
+ environment,
1091
+ ...tier ? { tier: tier.name } : {},
1092
+ farMix,
1093
+ layers,
1094
+ priority: sound.priority ?? input.priority ?? busPriority(sound.bus),
1095
+ ...sound.group ? { group: sound.group } : {}
1096
+ };
1097
+ }
1098
+
1099
+ // src/webaudio/sample-loop.ts
1100
+ var DEFAULT_LOOP_CROSSFADE = 0.25;
1101
+ var LOOKAHEAD = 1.5;
1102
+ var VOLUME_SMOOTHING = 0.05;
1103
+ function loopCrossfade(sound) {
1104
+ if (!sound.loop) return void 0;
1105
+ return sound.loop === true ? DEFAULT_LOOP_CROSSFADE : Math.max(0, sound.loop.crossfade ?? DEFAULT_LOOP_CROSSFADE);
1106
+ }
1107
+ var CROSSFADE_STEPS = 8;
1108
+ var equalPowerIn = (t) => Math.sin(Math.max(0, Math.min(1, t)) * Math.PI / 2);
1109
+ var ramp2 = (param, direction, at, seconds) => {
1110
+ const value = (t) => direction === "in" ? equalPowerIn(t) : equalPowerIn(1 - t);
1111
+ param.setValueAtTime(value(0), at);
1112
+ for (let step = 1; step <= CROSSFADE_STEPS; step++) param.linearRampToValueAtTime(value(step / CROSSFADE_STEPS), at + seconds * step / CROSSFADE_STEPS);
1113
+ };
1114
+ function createSampleLoopHandle(sound, host, volume = 0) {
1115
+ const crossfade = loopCrossfade(sound) ?? DEFAULT_LOOP_CROSSFADE;
1116
+ let level = volume;
1117
+ let stopped = false;
1118
+ let fallback;
1119
+ let master;
1120
+ let segments = [];
1121
+ let last;
1122
+ let timer;
1123
+ const entry = {
1124
+ get created() {
1125
+ return master !== void 0;
1126
+ },
1127
+ rewire() {
1128
+ master?.disconnect();
1129
+ master?.connect(host.output(sound.bus));
1130
+ },
1131
+ stop() {
1132
+ stopped = true;
1133
+ if (timer !== void 0) clearTimeout(timer);
1134
+ timer = void 0;
1135
+ for (const segment of segments) {
1136
+ try {
1137
+ segment.source.stop();
1138
+ } catch {
1139
+ }
1140
+ segment.source.disconnect();
1141
+ segment.gain.disconnect();
1142
+ }
1143
+ segments = [];
1144
+ master?.disconnect();
1145
+ master = void 0;
1146
+ fallback?.stop();
1147
+ fallback = void 0;
1148
+ host.unregister(entry);
1149
+ }
1150
+ };
1151
+ const nextBuffer = () => {
1152
+ const takes = sound.close;
1153
+ const take = pickTake(takes.length, last, host.random);
1154
+ last = take;
1155
+ const ref = takes[take];
1156
+ return ref ? host.buffer(ref.url) : void 0;
1157
+ };
1158
+ const schedule = (context, output, at, first) => {
1159
+ const buffer = nextBuffer();
1160
+ if (!buffer) return void 0;
1161
+ const source = context.createBufferSource();
1162
+ source.buffer = buffer;
1163
+ const gain = context.createGain();
1164
+ source.connect(gain);
1165
+ gain.connect(output);
1166
+ const fade = Math.min(crossfade, buffer.duration / 2);
1167
+ if (buffer.duration < 2 * crossfade || sound.close.length === 1) {
1168
+ source.loop = true;
1169
+ if (!first) ramp2(gain.gain, "in", at, Math.max(1e-3, fade));
1170
+ source.start(at);
1171
+ segments.push({ source, gain, end: Number.POSITIVE_INFINITY });
1172
+ return void 0;
1173
+ }
1174
+ if (first) gain.gain.setValueAtTime(1, at);
1175
+ else ramp2(gain.gain, "in", at, fade);
1176
+ const end3 = at + buffer.duration;
1177
+ ramp2(gain.gain, "out", end3 - fade, fade);
1178
+ source.start(at);
1179
+ source.stop(end3);
1180
+ segments.push({ source, gain, end: end3 });
1181
+ source.onended = () => {
1182
+ segments = segments.filter((segment) => segment.source !== source);
1183
+ source.disconnect();
1184
+ gain.disconnect();
1185
+ };
1186
+ return end3 - fade;
1187
+ };
1188
+ const pump = (context, output, at, first) => {
1189
+ if (stopped) return;
1190
+ let next = schedule(context, output, at, first);
1191
+ while (next !== void 0 && next < context.currentTime + LOOKAHEAD) next = schedule(context, output, Math.max(next, context.currentTime), false);
1192
+ if (next === void 0) return;
1193
+ const wait = Math.max(0, (next - context.currentTime - LOOKAHEAD / 2) * 1e3);
1194
+ timer = setTimeout(() => {
1195
+ timer = void 0;
1196
+ pump(context, output, next, false);
1197
+ }, wait);
1198
+ };
1199
+ const fileLevel = () => level * (sound.gain ?? 1);
1200
+ const startFiles = () => {
1201
+ if (stopped || master || !host.isReady(sound)) return master !== void 0;
1202
+ const context = host.ready();
1203
+ if (!context) return false;
1204
+ master = context.createGain();
1205
+ master.gain.setValueAtTime(fileLevel(), context.currentTime);
1206
+ master.connect(host.output(sound.bus));
1207
+ host.register(entry);
1208
+ pump(context, master, context.currentTime, true);
1209
+ if (fallback) {
1210
+ fallback.set({ volume: 0 });
1211
+ const old = fallback;
1212
+ fallback = void 0;
1213
+ setTimeout(() => old.stop(), VOLUME_SMOOTHING * 6e3);
1214
+ }
1215
+ return true;
1216
+ };
1217
+ const ensure = () => {
1218
+ if (stopped || master) return;
1219
+ if (startFiles()) return;
1220
+ if (!fallback) {
1221
+ fallback = host.fallback(level);
1222
+ void host.load(sound).then(() => {
1223
+ if (level > 0 || master) startFiles();
1224
+ }).catch(() => void 0);
1225
+ }
1226
+ };
1227
+ if (volume > 0) ensure();
1228
+ return {
1229
+ set(next) {
1230
+ if (stopped) return;
1231
+ if (next.volume !== void 0) level = host.muted(sound.bus) ? 0 : Math.max(0, next.volume);
1232
+ if (level > 0) ensure();
1233
+ const context = host.ready();
1234
+ if (master && context) master.gain.setTargetAtTime(fileLevel(), context.currentTime, VOLUME_SMOOTHING);
1235
+ fallback?.set(next.volume === void 0 ? next : { ...next, volume: level });
895
1236
  },
896
1237
  stop: entry.stop
897
1238
  };
@@ -1179,7 +1520,7 @@ function realizeCalls(plan, target) {
1179
1520
 
1180
1521
  // src/webaudio/realize-layered.ts
1181
1522
  var end2 = (layer, start) => start + layer.duration + layer.tail;
1182
- function outputStage(plan, layer, target) {
1523
+ function outputStage2(plan, layer, target) {
1183
1524
  const { context } = target;
1184
1525
  const level = gainNode(context, layer.level);
1185
1526
  let node = level;
@@ -1211,7 +1552,7 @@ function realizeNoiseLayer(plan, layer, target) {
1211
1552
  let tail = source;
1212
1553
  for (const filter of filters) tail = tail.connect(filter);
1213
1554
  tail.connect(envelope);
1214
- envelope.connect(outputStage(plan, layer, target));
1555
+ envelope.connect(outputStage2(plan, layer, target));
1215
1556
  source.start(time, layer.source.kind === "noise" ? layer.source.offset : 0);
1216
1557
  source.stop(end2(layer, time));
1217
1558
  return [source];
@@ -1228,7 +1569,7 @@ function realizeToneLayer(plan, layer, target) {
1228
1569
  const envelope = context.createGain();
1229
1570
  applyEnvelope(envelope.gain, layer.envelope, time);
1230
1571
  oscillator.connect(envelope);
1231
- envelope.connect(outputStage(plan, layer, target));
1572
+ envelope.connect(outputStage2(plan, layer, target));
1232
1573
  oscillator.start(time);
1233
1574
  oscillator.stop(end2(layer, time));
1234
1575
  return [oscillator];
@@ -1260,7 +1601,7 @@ function realizeVoiceLayer(plan, layer, target) {
1260
1601
  const envelope = context.createGain();
1261
1602
  applyEnvelope(envelope.gain, layer.envelope, time);
1262
1603
  mix.connect(envelope);
1263
- envelope.connect(outputStage(plan, layer, target));
1604
+ envelope.connect(outputStage2(plan, layer, target));
1264
1605
  const stop = end2(layer, time);
1265
1606
  oscillator.start(time);
1266
1607
  vibrato.start(time);
@@ -1439,7 +1780,151 @@ function createSetPicker() {
1439
1780
  };
1440
1781
  }
1441
1782
 
1783
+ // src/webaudio/sample-store.ts
1784
+ function fetchLoader(baseUrl) {
1785
+ return async (url2) => {
1786
+ const target = baseUrl ? new URL(url2, baseUrl).toString() : url2;
1787
+ const response = await fetch(target);
1788
+ if (!response.ok) throw new Error(`${response.status} ${response.statusText} for ${target}`);
1789
+ return response.arrayBuffer();
1790
+ };
1791
+ }
1792
+ function inlineLoader(files) {
1793
+ return async (url2) => {
1794
+ const text = files[url2];
1795
+ if (text === void 0) throw new Error(`no inline file for ${url2}`);
1796
+ const base64 = text.startsWith("data:") ? text.slice(text.indexOf(",") + 1) : text;
1797
+ const binary = atob(base64);
1798
+ const bytes = new Uint8Array(binary.length);
1799
+ for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
1800
+ return bytes.buffer;
1801
+ };
1802
+ }
1803
+ var decode = (context, bytes) => new Promise((resolve, reject) => {
1804
+ const result = context.decodeAudioData(bytes, resolve, reject);
1805
+ result?.catch?.(reject);
1806
+ });
1807
+ function createSampleStore(loader = fetchLoader()) {
1808
+ const buffers = /* @__PURE__ */ new Map();
1809
+ const pending = /* @__PURE__ */ new Map();
1810
+ const failed = /* @__PURE__ */ new Map();
1811
+ let generation = 0;
1812
+ const loadOne = (url2, context) => {
1813
+ const existing = buffers.get(url2);
1814
+ if (existing) return Promise.resolve(existing);
1815
+ const inFlight = pending.get(url2);
1816
+ if (inFlight) return inFlight;
1817
+ const started = generation;
1818
+ failed.delete(url2);
1819
+ const promise = loader(url2).then((bytes) => decode(context, bytes)).then((buffer) => {
1820
+ if (started === generation) buffers.set(url2, buffer);
1821
+ return buffer;
1822
+ }).catch((error) => {
1823
+ if (started === generation) failed.set(url2, error instanceof Error ? error.message : String(error));
1824
+ throw error;
1825
+ }).finally(() => {
1826
+ if (pending.get(url2) === promise) pending.delete(url2);
1827
+ });
1828
+ pending.set(url2, promise);
1829
+ return promise;
1830
+ };
1831
+ return {
1832
+ status(url2) {
1833
+ if (buffers.has(url2)) return "ready";
1834
+ if (pending.has(url2)) return "loading";
1835
+ if (failed.has(url2)) return "failed";
1836
+ return "none";
1837
+ },
1838
+ buffer: (url2) => buffers.get(url2),
1839
+ ready: (urls) => urls.every((url2) => buffers.has(url2)),
1840
+ seconds: (url2) => buffers.get(url2)?.duration,
1841
+ async load(urls, context) {
1842
+ const results = await Promise.allSettled(urls.map((url2) => loadOne(url2, context)));
1843
+ const loaded = [];
1844
+ const errors = [];
1845
+ results.forEach((result, index) => {
1846
+ const url2 = urls[index];
1847
+ if (result.status === "fulfilled") loaded.push(url2);
1848
+ else errors.push({ url: url2, error: result.reason instanceof Error ? result.reason.message : String(result.reason) });
1849
+ });
1850
+ return { loaded, failed: errors };
1851
+ },
1852
+ clear() {
1853
+ generation++;
1854
+ buffers.clear();
1855
+ pending.clear();
1856
+ failed.clear();
1857
+ }
1858
+ };
1859
+ }
1860
+
1861
+ // src/webaudio/realize-sample.ts
1862
+ function realizeSample(plan, target) {
1863
+ const context = target.context;
1864
+ let head = target.output;
1865
+ if (plan.pan !== void 0 && typeof context.createStereoPanner === "function") {
1866
+ const panner = context.createStereoPanner();
1867
+ panner.pan.value = plan.pan;
1868
+ panner.connect(head);
1869
+ head = panner;
1870
+ }
1871
+ if (plan.cutoff < OPEN_CUTOFF) {
1872
+ const lowpass = context.createBiquadFilter();
1873
+ lowpass.type = "lowpass";
1874
+ lowpass.frequency.value = plan.cutoff;
1875
+ lowpass.Q.value = 0.7;
1876
+ lowpass.connect(head);
1877
+ head = lowpass;
1878
+ }
1879
+ const voice = context.createGain();
1880
+ voice.connect(head);
1881
+ head = voice;
1882
+ const sources = [];
1883
+ for (const layer of plan.layers) {
1884
+ const buffer = target.buffer(layer.url);
1885
+ if (!buffer) continue;
1886
+ const source = context.createBufferSource();
1887
+ source.buffer = buffer;
1888
+ source.playbackRate.value = layer.rate;
1889
+ const gain = gainNode(context, layer.gain);
1890
+ source.connect(gain);
1891
+ gain.connect(head);
1892
+ source.start(target.time + layer.at);
1893
+ sources.push(source);
1894
+ }
1895
+ const realized = voiceOf(sources);
1896
+ return {
1897
+ ...realized,
1898
+ fade(at, seconds) {
1899
+ voice.gain.setValueAtTime(1, at);
1900
+ voice.gain.linearRampToValueAtTime(0, at + seconds);
1901
+ for (const source of sources) {
1902
+ try {
1903
+ source.stop(at + seconds);
1904
+ } catch {
1905
+ }
1906
+ }
1907
+ }
1908
+ };
1909
+ }
1910
+ function sampleLength(plan, seconds) {
1911
+ let length = 0;
1912
+ for (const layer of plan.layers) length = Math.max(length, layer.at + (seconds(layer.url) ?? 0) / layer.rate);
1913
+ return length;
1914
+ }
1915
+
1442
1916
  // src/webaudio/engine.ts
1917
+ function limiterCurve2(knee, ceiling, range, points = 2049) {
1918
+ const curve = new Float32Array(points);
1919
+ const room = Math.max(1e-6, ceiling - knee);
1920
+ for (let index = 0; index < points; index++) {
1921
+ const value = (index / (points - 1) * 2 - 1) * range;
1922
+ const size = Math.abs(value);
1923
+ const bent = size <= knee ? size : knee + room * Math.tanh((size - knee) / room);
1924
+ curve[index] = Math.sign(value) * bent;
1925
+ }
1926
+ return curve;
1927
+ }
1443
1928
  var usesNoise = (recipe) => recipe.layers.some((layer) => layer.source.kind !== "osc");
1444
1929
  var planUsesNoise = (plan) => plan.layers.some((layer) => layer.source.kind !== "osc");
1445
1930
  function createAudioEngine(options = {}) {
@@ -1459,6 +1944,43 @@ function createAudioEngine(options = {}) {
1459
1944
  let chain = null;
1460
1945
  let listener = DEFAULT_LISTENER;
1461
1946
  let lastTime = 0;
1947
+ let environment = options.environment ?? "outdoor";
1948
+ const sampleLimiters = /* @__PURE__ */ new Map();
1949
+ const sampleOutput = (bus) => {
1950
+ const setting = options.samples?.limiter;
1951
+ if (setting === false || !context) return outputFor(bus);
1952
+ const existing = sampleLimiters.get(bus);
1953
+ if (existing) return existing;
1954
+ const range = 4;
1955
+ const input = context.createGain();
1956
+ input.gain.value = 1 / range;
1957
+ const shaper = context.createWaveShaper();
1958
+ shaper.curve = limiterCurve2(setting?.knee ?? 0.5, setting?.ceiling ?? 0.891, range);
1959
+ ensureBus(bus);
1960
+ input.connect(shaper);
1961
+ shaper.connect(outputFor(bus));
1962
+ sampleLimiters.set(bus, input);
1963
+ return input;
1964
+ };
1965
+ const chokes = /* @__PURE__ */ new Map();
1966
+ const choked = (id) => {
1967
+ const list = (chokes.get(id) ?? []).filter((entry) => active.has(entry.id));
1968
+ chokes.set(id, list);
1969
+ return list;
1970
+ };
1971
+ const watchers = /* @__PURE__ */ new Set();
1972
+ const announce = (event) => {
1973
+ options.onVoiceStart?.(event);
1974
+ for (const watcher of watchers) watcher(event);
1975
+ };
1976
+ const sources = [];
1977
+ const baseLoader = options.samples?.loader ?? fetchLoader(options.samples?.baseUrl);
1978
+ const sampleStore = createSampleStore((url2) => (sources.find((source) => source.accepts(url2))?.loader ?? baseLoader)(url2));
1979
+ const memory = /* @__PURE__ */ new Map();
1980
+ const latencyOf = (audio) => {
1981
+ const live = audio;
1982
+ return (live.baseLatency ?? 0) + (live.outputLatency ?? 0);
1983
+ };
1462
1984
  const outputFor = (bus) => busNodes.get(bus) ?? chain?.master;
1463
1985
  const watched = /* @__PURE__ */ new Set();
1464
1986
  const meterOf = (bus) => {
@@ -1515,17 +2037,31 @@ function createAudioEngine(options = {}) {
1515
2037
  ...options.occlusion && playOptions.position && recipe.falloff?.model !== "none" ? { occlusion: options.occlusion(playOptions.position) } : {}
1516
2038
  });
1517
2039
  const startQueue = options.deferredStart ? createStartQueue(options.deferredStart) : null;
1518
- const build = (plan, store, delay) => {
2040
+ const build = (plan, store, delay, requestedAt, fallbackOf) => {
1519
2041
  const audio = context;
1520
- return realize(plan, {
2042
+ const time = audio.currentTime + delay;
2043
+ const realized = realize(plan, {
1521
2044
  context: audio,
1522
2045
  output: outputFor(plan.bus),
1523
2046
  ...chain?.wet ? { wet: chain.wet } : {},
1524
2047
  noise: () => noiseBuffer(store, audio, mix.noise.seconds),
1525
- time: audio.currentTime + delay
2048
+ time
2049
+ });
2050
+ announce({
2051
+ id: plan.id,
2052
+ kind: "recipe",
2053
+ ...fallbackOf ? { fallbackOf } : {},
2054
+ requestedAt,
2055
+ startAt: time,
2056
+ outputLatency: latencyOf(audio),
2057
+ level: plan.level,
2058
+ distance: plan.distance,
2059
+ ...plan.pan === void 0 ? {} : { pan: plan.pan }
1526
2060
  });
2061
+ return realized;
1527
2062
  };
1528
- const deferVoice = (plan, store, voiceId, delay) => {
2063
+ const deferVoice = (plan, store, voiceId, delay, fallbackOf) => {
2064
+ const requestedAt = context?.currentTime ?? 0;
1529
2065
  let built = null;
1530
2066
  let cancelled = false;
1531
2067
  const pending = {
@@ -1539,7 +2075,7 @@ function createAudioEngine(options = {}) {
1539
2075
  };
1540
2076
  startQueue.push({
1541
2077
  run() {
1542
- if (!cancelled && context) built = build(plan, store, delay);
2078
+ if (!cancelled && context) built = build(plan, store, delay, requestedAt, fallbackOf);
1543
2079
  },
1544
2080
  drop() {
1545
2081
  if (voiceId === void 0) return;
@@ -1549,13 +2085,14 @@ function createAudioEngine(options = {}) {
1549
2085
  });
1550
2086
  return pending;
1551
2087
  };
1552
- const start = (plan, store, voiceId, delay = 0) => {
1553
- const realized = startQueue ? deferVoice(plan, store, voiceId, delay) : build(plan, store, delay);
2088
+ const start = (plan, store, voiceId, delay = 0, fallbackOf, urgent = false) => {
2089
+ const realized = startQueue && !urgent ? deferVoice(plan, store, voiceId, delay, fallbackOf) : build(plan, store, delay, context?.currentTime ?? 0, fallbackOf);
1554
2090
  if (voiceId === void 0) return null;
1555
2091
  voices.setLength(voiceId, plan.length + delay);
1556
2092
  active.set(voiceId, realized);
1557
2093
  return {
1558
2094
  id: voiceId,
2095
+ kind: "recipe",
1559
2096
  plan,
1560
2097
  stop() {
1561
2098
  realized.stop();
@@ -1579,7 +2116,83 @@ function createAudioEngine(options = {}) {
1579
2116
  const set = registry.set(id);
1580
2117
  return set ? chooser.pick(set, random) : { id, rate: 1 };
1581
2118
  };
1582
- const playWith = (asked, playOptions, streamRandom, store) => {
2119
+ const loadSounds = (sounds) => {
2120
+ const audio = ready();
2121
+ if (!audio) return Promise.resolve({ loaded: [], failed: sounds.flatMap(sampleUrls).map((url2) => ({ url: url2, error: "no audio context" })) });
2122
+ return sampleStore.load([...new Set(sounds.flatMap(sampleUrls))], audio);
2123
+ };
2124
+ const sampleInput = (playOptions, random, withMemory) => ({
2125
+ random,
2126
+ listener,
2127
+ environment: playOptions.environment ?? environment,
2128
+ ...withMemory ? { memory } : {},
2129
+ ...options.distance ? { distanceMode: options.distance } : {},
2130
+ ...playOptions.volume === void 0 ? {} : { volume: playOptions.volume },
2131
+ ...playOptions.intensity === void 0 ? {} : { intensity: playOptions.intensity },
2132
+ ...playOptions.distance === void 0 ? {} : { distance: playOptions.distance },
2133
+ ...playOptions.position ? { position: playOptions.position } : {},
2134
+ ...playOptions.occlusion !== void 0 ? { occlusion: playOptions.occlusion } : options.occlusion && playOptions.position ? { occlusion: options.occlusion(playOptions.position) } : {}
2135
+ });
2136
+ const playSample = (sample, playOptions, random, store) => {
2137
+ if (busSettings.get(sample.bus)?.muted) return null;
2138
+ if (!sampleStore.ready(sampleUrls(sample))) {
2139
+ if (options.samples?.autoLoad !== false && ready()) void loadSounds([sample]).catch(() => void 0);
2140
+ if (sample.fallback && sample.fallback !== sample.id) return playWith(sample.fallback, playOptions, random, store, sample.id);
2141
+ return registry.sound(sample.id) ? void 0 : null;
2142
+ }
2143
+ const plan = planSample(sample, sampleInput(playOptions, playOptions.seed === void 0 ? random : createRng(playOptions.seed), true));
2144
+ if (!plan) return null;
2145
+ const audio = ready();
2146
+ if (!audio) return null;
2147
+ unlockContext(audio);
2148
+ advance();
2149
+ const voiceId = admit(plan, plan.level, plan.distance);
2150
+ if (voiceId === null) return null;
2151
+ const requestedAt = audio.currentTime;
2152
+ const time = requestedAt + (playOptions.delay ?? 0);
2153
+ const chokeList = sample.choke ? choked(sample.id) : void 0;
2154
+ const realized = realizeSample(plan, { context: audio, output: sampleOutput(plan.bus), buffer: (url2) => sampleStore.buffer(url2), time });
2155
+ announce({
2156
+ id: plan.id,
2157
+ kind: "sample",
2158
+ requestedAt,
2159
+ startAt: time,
2160
+ outputLatency: latencyOf(audio),
2161
+ level: plan.level,
2162
+ distance: plan.distance,
2163
+ ...plan.pan === void 0 ? {} : { pan: plan.pan },
2164
+ layers: plan.layers.map((layer) => ({ role: layer.role, url: layer.url, take: layer.take, rate: layer.rate })),
2165
+ ...plan.tier ? { tier: plan.tier } : {}
2166
+ });
2167
+ voices.setLength(voiceId, sampleLength(plan, (url2) => sampleStore.seconds(url2)) + (playOptions.delay ?? 0));
2168
+ active.set(voiceId, realized);
2169
+ if (chokeList && sample.choke) {
2170
+ chokeList.push({ id: voiceId, voice: realized });
2171
+ while (chokeList.length > Math.max(1, sample.choke.voices)) {
2172
+ const oldest = chokeList.shift();
2173
+ if (!oldest) break;
2174
+ oldest.voice.fade(time, sample.choke.fade ?? 0.03);
2175
+ voices.release(oldest.id);
2176
+ active.delete(oldest.id);
2177
+ }
2178
+ }
2179
+ return {
2180
+ id: voiceId,
2181
+ kind: "sample",
2182
+ plan,
2183
+ stop() {
2184
+ realized.stop();
2185
+ voices.release(voiceId);
2186
+ active.delete(voiceId);
2187
+ }
2188
+ };
2189
+ };
2190
+ const playWith = (asked, playOptions, streamRandom, store, fallbackOf) => {
2191
+ const sample = fallbackOf === void 0 ? registry.sample(asked) : void 0;
2192
+ if (sample) {
2193
+ const played = playSample(sample, playOptions, streamRandom, store);
2194
+ if (played !== void 0) return played;
2195
+ }
1583
2196
  const seeded = playOptions.seed === void 0 ? null : createRng(playOptions.seed);
1584
2197
  const { id, rate } = resolve(asked, seeded ?? streamRandom);
1585
2198
  const random = seeded ?? streamRandom;
@@ -1597,7 +2210,7 @@ function createAudioEngine(options = {}) {
1597
2210
  if (voiceId === null) return null;
1598
2211
  if (!silent && usesNoise(recipe)) prepareNoise(store, audio, mix.noise.seconds);
1599
2212
  const plan = planSound(recipe, inputFor(recipe, playOptions, random));
1600
- return plan ? start(retunePlan(plan, rate), store, voiceId, playOptions.delay) : null;
2213
+ return plan ? start(retunePlan(plan, rate), store, voiceId, playOptions.delay, fallbackOf, playOptions.urgent) : null;
1601
2214
  };
1602
2215
  const randomFor = (playOptions) => {
1603
2216
  if (playOptions.channel === void 0) return engineRandom;
@@ -1619,12 +2232,42 @@ function createAudioEngine(options = {}) {
1619
2232
  prepareNoise: () => context && prepareNoise(shared, context, mix.noise.seconds),
1620
2233
  noise: () => noiseBuffer(shared, context, mix.noise.seconds),
1621
2234
  register: (loop) => void loops.add(loop),
1622
- unregister: (loop) => void loops.delete(loop)
2235
+ unregister: (loop) => void loops.delete(loop),
2236
+ listener: () => listener,
2237
+ ...options.distance ? { distance: options.distance } : {}
1623
2238
  };
1624
2239
  return {
1625
2240
  registry,
1626
2241
  register: (bank) => registry.register(bank),
1627
2242
  plan: (id, playOptions = {}) => planWith(id, playOptions, createRng(playOptions.seed ?? seed)),
2243
+ planSample(id, playOptions = {}) {
2244
+ const sample = registry.sample(id);
2245
+ return sample ? planSample(sample, sampleInput(playOptions, createRng(playOptions.seed ?? seed), false)) : null;
2246
+ },
2247
+ loadSamples(ids) {
2248
+ const chosen = (ids ?? registry.sampleIds()).map((id) => registry.sample(id)).filter((sample) => sample !== void 0);
2249
+ return loadSounds(chosen);
2250
+ },
2251
+ sampleStatus(id) {
2252
+ const sample = registry.sample(id);
2253
+ if (!sample) return "none";
2254
+ const statuses = sampleUrls(sample).map((url2) => sampleStore.status(url2));
2255
+ if (statuses.every((status) => status === "ready")) return "ready";
2256
+ if (statuses.includes("failed")) return "failed";
2257
+ if (statuses.includes("loading")) return "loading";
2258
+ return statuses.includes("ready") ? "loading" : "none";
2259
+ },
2260
+ setEnvironment(next) {
2261
+ environment = next;
2262
+ },
2263
+ output: () => chain?.master ?? null,
2264
+ addSampleSource(accepts, loader) {
2265
+ sources.push({ accepts, loader });
2266
+ },
2267
+ watchVoices(listener2) {
2268
+ watchers.add(listener2);
2269
+ return () => void watchers.delete(listener2);
2270
+ },
1628
2271
  play: (id, playOptions = {}) => playWith(id, playOptions, randomFor(playOptions), shared),
1629
2272
  playPlan(plan, playOptions = {}) {
1630
2273
  const audio = ready();
@@ -1636,7 +2279,26 @@ function createAudioEngine(options = {}) {
1636
2279
  if (planUsesNoise(plan)) prepareNoise(shared, audio, mix.noise.seconds);
1637
2280
  return start(plan, shared, voiceId, playOptions.delay);
1638
2281
  },
1639
- loop: (id, loopOptions = {}) => createLoopHandle(registry.loop(id), loopHost, loopOptions.volume),
2282
+ loop(id, loopOptions = {}) {
2283
+ const sample = registry.sample(id);
2284
+ if (!sample?.loop) return createLoopHandle(registry.loop(id), loopHost, loopOptions.volume);
2285
+ return createSampleLoopHandle(
2286
+ sample,
2287
+ {
2288
+ ready,
2289
+ output: sampleOutput,
2290
+ buffer: (url2) => sampleStore.buffer(url2),
2291
+ isReady: (sound) => sampleStore.ready(sampleUrls(sound)),
2292
+ load: (sound) => options.samples?.autoLoad === false ? Promise.resolve() : loadSounds([sound]),
2293
+ fallback: (volume) => createLoopHandle(registry.loop(sample.fallback ?? sample.id) ?? registry.loop(sample.id), loopHost, volume),
2294
+ random: engineRandom,
2295
+ register: loopHost.register,
2296
+ unregister: loopHost.unregister,
2297
+ muted: (bus) => busSettings.get(bus)?.muted === true
2298
+ },
2299
+ loopOptions.volume
2300
+ );
2301
+ },
1640
2302
  channel(channelOptions) {
1641
2303
  const random = channelOptions.random ?? (channelOptions.seed === void 0 ? engineRandom : createRng(channelOptions.seed));
1642
2304
  const store = channelOptions.ownNoise ? createNoiseStore(random) : shared;
@@ -1717,6 +2379,10 @@ function createAudioEngine(options = {}) {
1717
2379
  busNodes.clear();
1718
2380
  meters.clear();
1719
2381
  shared.reset();
2382
+ sampleStore.clear();
2383
+ memory.clear();
2384
+ sampleLimiters.clear();
2385
+ chokes.clear();
1720
2386
  }
1721
2387
  };
1722
2388
  }
@@ -1773,7 +2439,7 @@ var EN = {
1773
2439
  determinism: "The same seed gives the same sound plan, another seed another one",
1774
2440
  limiter: "The voice limiter holds a storm of voices to its group rule and its global cap"
1775
2441
  },
1776
- mixes: { game: "Game", art_scene: "Art scene" },
2442
+ mixes: { game: "Game", art_scene: "Art scene", kit: "Kit (art scene + limiter)" },
1777
2443
  sheet: { title: "Sound plan", level: "level", distance: "distance", pan: "pan", length: "seconds", silent: "too far to be heard", layer: "layer", none: "no sound chosen" }
1778
2444
  };
1779
2445
  var PT_BR = {
@@ -1827,7 +2493,7 @@ var PT_BR = {
1827
2493
  determinism: "A mesma semente d\xE1 o mesmo plano de som, outra semente d\xE1 outro",
1828
2494
  limiter: "O limite de vozes segura uma tempestade de vozes na regra do grupo e no teto global"
1829
2495
  },
1830
- mixes: { game: "Jogo", art_scene: "Cena de Arte" },
2496
+ mixes: { game: "Jogo", art_scene: "Cena de Arte", kit: "Kit (Cena de Arte + limitador)" },
1831
2497
  sheet: { title: "Plano do som", level: "n\xEDvel", distance: "dist\xE2ncia", pan: "pan", length: "segundos", silent: "longe demais para ouvir", layer: "camada", none: "nenhum som escolhido" }
1832
2498
  };
1833
2499
  var audioBenchTextOf = (locale) => locale === "en" ? EN : PT_BR;
@@ -1901,7 +2567,7 @@ function createAudioTestModule(options = {}) {
1901
2567
  distance: 10,
1902
2568
  bearing: 0,
1903
2569
  volume: 1,
1904
- mix: "art_scene",
2570
+ mix: DEFAULT_MIX,
1905
2571
  seed: options.seed ?? 1,
1906
2572
  source: "bench",
1907
2573
  loop: NONE,
@@ -2181,6 +2847,1218 @@ function createAudioTestModule(options = {}) {
2181
2847
  return module;
2182
2848
  }
2183
2849
 
2850
+ // src/catalog.ts
2851
+ var SFX_CATEGORIES = ["armas", "impactos", "explosoes-fogo", "personagem", "veiculos", "itens-portas", "ambiente"];
2852
+ var entries = (category, list) => list.map(([id, priority, current]) => ({ id, category, priority, ...current ? { current } : {} }));
2853
+ var SFX_CATALOG = [
2854
+ ...entries("armas", [
2855
+ ["pistol_22lr", 2, "sfx_pistol"],
2856
+ ["pistol_9mm", 1, "sfx_pistol"],
2857
+ ["pistol_45", 1, "sfx_pistol"],
2858
+ ["revolver_38_357", 2, "sfx_pistol"],
2859
+ ["revolver_44_50ae", 3, "sfx_pistol"],
2860
+ ["smg_9mm_auto", 1, "sfx_pistol"],
2861
+ ["shotgun_12", 1, "sfx_shotgun"],
2862
+ ["rifle_5_56", 1, "sfx_rifle"],
2863
+ ["rifle_7_62x39", 1, "sfx_rifle"],
2864
+ ["rifle_auto_burst", 1, "sfx_rifle"],
2865
+ ["rifle_308_3006", 2, "sfx_rifle"],
2866
+ ["sniper_338_300wm", 2, "sfx_rifle"],
2867
+ ["antimateriel_50bmg", 3, "sfx_rifle"],
2868
+ ["suppressed_pistol", 2],
2869
+ ["suppressed_rifle", 2],
2870
+ ["gunshot_far_pistol", 1],
2871
+ ["gunshot_far_rifle", 1],
2872
+ ["gunshot_far_shotgun", 1],
2873
+ ["gunshot_far_heavy", 2],
2874
+ ["gunshot_tail_indoor", 1],
2875
+ ["gunshot_tail_outdoor", 1],
2876
+ ["bullet_crack_by", 2],
2877
+ ["bullet_whiz", 2],
2878
+ ["ricochet_metal", 2, "ping"],
2879
+ ["dry_fire", 1],
2880
+ ["mag_out", 1],
2881
+ ["mag_in", 1],
2882
+ ["slide_pull_release", 1],
2883
+ ["pump_cycle", 1],
2884
+ ["casing_drop_concreto_pistol", 1],
2885
+ ["casing_drop_concreto_rifle", 1],
2886
+ ["casing_drop_concreto_shell", 1],
2887
+ ["casing_drop_madeira_pistol", 1],
2888
+ ["casing_drop_madeira_rifle", 1],
2889
+ ["casing_drop_madeira_shell", 1],
2890
+ ["casing_drop_metal_pistol", 1],
2891
+ ["casing_drop_metal_rifle", 1],
2892
+ ["casing_drop_metal_shell", 1],
2893
+ ["casing_drop_terra_pistol", 1],
2894
+ ["casing_drop_terra_rifle", 1],
2895
+ ["casing_drop_terra_shell", 1],
2896
+ ["rocket_fire", 2]
2897
+ ]),
2898
+ ...entries("explosoes-fogo", [
2899
+ ["explosion_grenade", 1, "boom"],
2900
+ ["explosion_big", 1, "boom_big"],
2901
+ ["explosion_car", 2, "boom_big"],
2902
+ ["explosion_far", 1],
2903
+ ["debris_rain_stone", 1],
2904
+ ["molotov_break_ignite", 1, "glass_shatter"],
2905
+ ["fire_ignite", 1, "hiss"],
2906
+ ["fire_loop_small", 1],
2907
+ ["fire_loop_large", 1],
2908
+ ["fire_extinguish", 2, "hiss"],
2909
+ ["gas_leak_hiss", 2],
2910
+ ["structure_collapse", 2, "crumble"]
2911
+ ]),
2912
+ ...entries("personagem", [
2913
+ ["footstep_concrete_walk", 1, "sfx_step"],
2914
+ ["footstep_wood_walk", 1, "sfx_step"],
2915
+ ["footstep_dirt_walk", 1, "sfx_step"],
2916
+ ["footstep_grass_walk", 1, "sfx_step"],
2917
+ ["footstep_gravel_walk", 1, "sfx_step"],
2918
+ ["land_concrete", 1, "sfx_step"],
2919
+ ["punch_swing", 1],
2920
+ ["punch_hit_body", 1, "sfx_flesh"],
2921
+ ["kick_hit", 1, "sfx_flesh"],
2922
+ ["knife_stab", 1],
2923
+ ["blunt_hit", 1],
2924
+ ["bite", 1, "sfx_flesh"],
2925
+ ["body_fall", 1],
2926
+ ["player_hurt", 2]
2927
+ ]),
2928
+ ...entries("veiculos", [
2929
+ ["engine_loop_car", 1],
2930
+ ["engine_start", 1],
2931
+ ["crash_light", 1, "crash"],
2932
+ ["crash_heavy", 1, "crash"],
2933
+ ["car_door_open", 1, "latch"],
2934
+ ["car_door_close", 1, "shut_metal"],
2935
+ ["horn_car", 2, "horn"],
2936
+ ["tire_skid_asphalt", 2]
2937
+ ]),
2938
+ ...entries("itens-portas", [
2939
+ ["item_pickup_metal", 1],
2940
+ ["can_open", 1],
2941
+ ["can_crush", 1],
2942
+ ["door_wood_open", 1, "latch"],
2943
+ ["door_wood_close", 1, "shut_wood"],
2944
+ ["door_creak", 1, "creak_wood"],
2945
+ ["door_locked_rattle", 1, "rattle"],
2946
+ ["drawer_open", 2, "slide"],
2947
+ ["fridge_close", 2, "shut_metal"]
2948
+ ]),
2949
+ ...entries("ambiente", [
2950
+ ["rain_loop", 2],
2951
+ ["wind_loop", 2],
2952
+ ["thunder_near", 2],
2953
+ ["thunder_far", 2],
2954
+ ["water_splash", 2]
2955
+ ])
2956
+ ];
2957
+ var SFX_MATERIALS = [
2958
+ ["steel", "metal"],
2959
+ ["aluminium", "metal"],
2960
+ ["wood", "wood"],
2961
+ ["plywood", "wood"],
2962
+ ["mdf", "wood"],
2963
+ ["glass", "glass"],
2964
+ ["tempered_glass", "glass"],
2965
+ ["ceramic", "glass"],
2966
+ ["concrete", "masonry"],
2967
+ ["brick", "masonry"],
2968
+ ["plaster", "masonry"],
2969
+ ["plastic", "soft"],
2970
+ ["fabric", "soft"],
2971
+ ["paper", "soft"],
2972
+ ["foliage", "soft"],
2973
+ ["soil", "soft"],
2974
+ ["flesh", "soft"]
2975
+ ];
2976
+ var SFX_BLOWS = ["bullet", "blunt", "blade", "break", "drag"];
2977
+ var CURRENT_BY_GROUP = {
2978
+ metal: { bullet: "clang", blunt: "clang", blade: "clang", break: "clang", drag: "drag_metal" },
2979
+ wood: { bullet: "wood_hit", blunt: "wood_hit", blade: "wood_hit", break: "crack", drag: "drag_wood" },
2980
+ glass: { bullet: "ping", blunt: "ping", break: "glass_shatter", drag: "drag_glass" },
2981
+ masonry: { bullet: "chip", blunt: "chip", blade: "chip", break: "crumble", drag: "drag_masonry" },
2982
+ soft: { bullet: "thud", blunt: "thud", blade: "thud", break: "thud", drag: "drag_soft" }
2983
+ };
2984
+ var impactSoundId = (material, blow) => `impact_${material}_${blow}`;
2985
+ var SFX_IMPACTS = SFX_MATERIALS.flatMap(
2986
+ ([material, group]) => SFX_BLOWS.map((blow) => {
2987
+ const current = CURRENT_BY_GROUP[group]?.[blow];
2988
+ return { id: impactSoundId(material, blow), category: "impactos", priority: ["steel", "wood", "glass", "concrete", "brick", "soil", "flesh"].includes(material) && blow === "bullet" ? 1 : 2, ...current ? { current } : {} };
2989
+ })
2990
+ );
2991
+ function sfxState(entry, has) {
2992
+ if (has.sample(entry.id)) return "file";
2993
+ if (entry.current && has.sound(entry.current) || has.sound(entry.id)) return "synth";
2994
+ return "missing";
2995
+ }
2996
+
2997
+ // src/measure/calibration.ts
2998
+ var CALIBRATION_ID = "calibration_shot";
2999
+ var CALIBRATION_RATE = 48e3;
3000
+ function encodeWav(samples, sampleRate = CALIBRATION_RATE) {
3001
+ const bytes = new ArrayBuffer(44 + samples.length * 2);
3002
+ const view = new DataView(bytes);
3003
+ const text = (at, value) => {
3004
+ for (let index = 0; index < value.length; index++) view.setUint8(at + index, value.charCodeAt(index));
3005
+ };
3006
+ text(0, "RIFF");
3007
+ view.setUint32(4, 36 + samples.length * 2, true);
3008
+ text(8, "WAVE");
3009
+ text(12, "fmt ");
3010
+ view.setUint32(16, 16, true);
3011
+ view.setUint16(20, 1, true);
3012
+ view.setUint16(22, 1, true);
3013
+ view.setUint32(24, sampleRate, true);
3014
+ view.setUint32(28, sampleRate * 2, true);
3015
+ view.setUint16(32, 2, true);
3016
+ view.setUint16(34, 16, true);
3017
+ text(36, "data");
3018
+ view.setUint32(40, samples.length * 2, true);
3019
+ for (let index = 0; index < samples.length; index++) {
3020
+ const value = Math.max(-1, Math.min(1, samples[index]));
3021
+ view.setInt16(44 + index * 2, value < 0 ? value * 32768 : value * 32767, true);
3022
+ }
3023
+ return bytes;
3024
+ }
3025
+ function shotSamples(shot, sampleRate = CALIBRATION_RATE) {
3026
+ const random = createRng(shot.seed);
3027
+ const length = Math.round(shot.seconds * sampleRate);
3028
+ const samples = new Float32Array(length);
3029
+ let low = 0;
3030
+ let phase = 0;
3031
+ const attack = Math.max(1, Math.round((shot.attack ?? 0) * sampleRate));
3032
+ for (let index = 0; index < length; index++) {
3033
+ const time = index / sampleRate;
3034
+ const envelope = Math.exp(-time / shot.decay) * Math.min(1, (index + 1) / attack);
3035
+ phase += 2 * Math.PI * shot.thump * (1 + 0.6 * Math.exp(-time * 30)) / sampleRate;
3036
+ const noise = random() * 2 - 1;
3037
+ low += shot.brightness * (noise - low);
3038
+ const fade = Math.min(1, (length - index) / (0.01 * sampleRate));
3039
+ samples[index] = shot.gain * envelope * fade * (0.55 * Math.sin(phase) + shot.noise * low);
3040
+ }
3041
+ return samples;
3042
+ }
3043
+ var TAKES = {
3044
+ "close_1.wav": { seconds: 0.4, thump: 150, noise: 1, decay: 0.06, brightness: 0.9, gain: 0.85, seed: 1 },
3045
+ "close_2.wav": { seconds: 0.4, thump: 160, noise: 1, decay: 0.065, brightness: 0.85, gain: 0.85, seed: 2 },
3046
+ "close_3.wav": { seconds: 0.4, thump: 142, noise: 1, decay: 0.055, brightness: 0.95, gain: 0.85, seed: 3 },
3047
+ "close_4.wav": { seconds: 0.4, thump: 170, noise: 1, decay: 0.07, brightness: 0.8, gain: 0.85, seed: 4 },
3048
+ "far_1.wav": { seconds: 0.9, thump: 90, noise: 0.8, decay: 0.2, brightness: 0.08, gain: 0.7, seed: 5, attack: 4e-3 },
3049
+ "far_2.wav": { seconds: 0.9, thump: 95, noise: 0.8, decay: 0.22, brightness: 0.07, gain: 0.7, seed: 6, attack: 4e-3 },
3050
+ "light_1.wav": { seconds: 0.25, thump: 220, noise: 0.6, decay: 0.03, brightness: 0.6, gain: 0.35, seed: 7 },
3051
+ "light_2.wav": { seconds: 0.25, thump: 230, noise: 0.6, decay: 0.03, brightness: 0.55, gain: 0.35, seed: 8 },
3052
+ "heavy_1.wav": { seconds: 0.6, thump: 110, noise: 1.2, decay: 0.11, brightness: 0.95, gain: 0.95, seed: 9 },
3053
+ "heavy_2.wav": { seconds: 0.6, thump: 105, noise: 1.2, decay: 0.12, brightness: 0.9, gain: 0.95, seed: 10 },
3054
+ "tail_in.wav": { seconds: 0.5, thump: 0, noise: 1, decay: 0.08, brightness: 0.4, gain: 0.25, seed: 11, attack: 0.01 },
3055
+ "tail_out.wav": { seconds: 2, thump: 0, noise: 1, decay: 0.45, brightness: 0.25, gain: 0.2, seed: 12, attack: 0.02 },
3056
+ "loop_1.wav": { seconds: 0.6, thump: 0, noise: 1, decay: 100, brightness: 0.5, gain: 0.5, seed: 13, attack: 0.01 },
3057
+ "loop_2.wav": { seconds: 0.6, thump: 0, noise: 1, decay: 100, brightness: 0.45, gain: 0.5, seed: 14, attack: 0.01 },
3058
+ "loop_3.wav": { seconds: 0.6, thump: 0, noise: 1, decay: 100, brightness: 0.55, gain: 0.5, seed: 15, attack: 0.01 }
3059
+ };
3060
+ var PREFIX = "calibration/";
3061
+ var url = (name) => `${PREFIX}${name}`;
3062
+ var CALIBRATION_SOUND = {
3063
+ id: CALIBRATION_ID,
3064
+ bus: "weapons",
3065
+ close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })),
3066
+ far: ["far_1.wav", "far_2.wav"].map((name) => ({ url: url(name) })),
3067
+ tiers: [
3068
+ { name: "light", from: 0, close: ["light_1.wav", "light_2.wav"].map((name) => ({ url: url(name) })) },
3069
+ { name: "medium", from: 0.34, close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })) },
3070
+ { name: "heavy", from: 0.67, close: ["heavy_1.wav", "heavy_2.wav"].map((name) => ({ url: url(name) })) }
3071
+ ],
3072
+ tail: { indoor: [{ url: url("tail_in.wav") }], outdoor: [{ url: url("tail_out.wav") }] },
3073
+ pitch: 0.04,
3074
+ choke: { voices: 2 },
3075
+ fallback: "sfx_pistol",
3076
+ sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
3077
+ };
3078
+ var CALIBRATION_LOOP_ID = "calibration_loop";
3079
+ var CALIBRATION_LOOP_SOUND = {
3080
+ id: CALIBRATION_LOOP_ID,
3081
+ bus: "ambience",
3082
+ close: ["loop_1.wav", "loop_2.wav", "loop_3.wav"].map((name) => ({ url: url(name) })),
3083
+ loop: { crossfade: 0.15 },
3084
+ sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
3085
+ };
3086
+ var isCalibrationUrl = (url2) => url2.startsWith(PREFIX);
3087
+ function calibrationLoader(next) {
3088
+ const made = /* @__PURE__ */ new Map();
3089
+ return async (requested) => {
3090
+ if (!requested.startsWith(PREFIX)) {
3091
+ if (next) return next(requested);
3092
+ throw new Error(`not a calibration file: ${requested}`);
3093
+ }
3094
+ const name = requested.slice(PREFIX.length);
3095
+ const shot = TAKES[name];
3096
+ if (!shot) throw new Error(`no calibration take ${name}`);
3097
+ let bytes = made.get(name);
3098
+ if (!bytes) {
3099
+ bytes = encodeWav(shotSamples(shot));
3100
+ made.set(name, bytes);
3101
+ }
3102
+ return bytes.slice(0);
3103
+ };
3104
+ }
3105
+
3106
+ // src/measure/analyze.ts
3107
+ var dbOf = (amplitude) => amplitude > 0 ? 20 * Math.log10(amplitude) : -Infinity;
3108
+ var clampIndex = (channels, index) => Math.max(0, Math.min(channels[0]?.length ?? 0, Math.round(index)));
3109
+ function peakOf(channels, start = 0, end3 = Number.POSITIVE_INFINITY) {
3110
+ let peak = 0;
3111
+ const from = clampIndex(channels, start);
3112
+ for (const channel of channels) {
3113
+ const to = Math.min(channel.length, end3);
3114
+ for (let index = from; index < to; index++) {
3115
+ const value = Math.abs(channel[index]);
3116
+ if (value > peak) peak = value;
3117
+ }
3118
+ }
3119
+ return peak;
3120
+ }
3121
+ function peakIndex(channels, start = 0, end3 = Number.POSITIVE_INFINITY) {
3122
+ let peak = -1;
3123
+ let at = -1;
3124
+ const from = clampIndex(channels, start);
3125
+ for (const channel of channels) {
3126
+ const to = Math.min(channel.length, end3);
3127
+ for (let index = from; index < to; index++) {
3128
+ const value = Math.abs(channel[index]);
3129
+ if (value > peak) {
3130
+ peak = value;
3131
+ at = index;
3132
+ }
3133
+ }
3134
+ }
3135
+ return at;
3136
+ }
3137
+ function onsetIndex(channels, start = 0, threshold = 1e-3) {
3138
+ const length = channels[0]?.length ?? 0;
3139
+ for (let index = clampIndex(channels, start); index < length; index++) {
3140
+ for (const channel of channels) if (Math.abs(channel[index]) >= threshold) return index;
3141
+ }
3142
+ return -1;
3143
+ }
3144
+ function rmsDb(channels, start, end3) {
3145
+ let sum = 0;
3146
+ let count = 0;
3147
+ const from = clampIndex(channels, start);
3148
+ for (const channel of channels) {
3149
+ const to = Math.min(channel.length, Math.round(end3));
3150
+ for (let index = from; index < to; index++) {
3151
+ const value = channel[index];
3152
+ sum += value * value;
3153
+ count++;
3154
+ }
3155
+ }
3156
+ return count === 0 ? -Infinity : dbOf(Math.sqrt(sum / count));
3157
+ }
3158
+ function centroidHz(channels, sampleRate, start, size = 2048) {
3159
+ const from = clampIndex(channels, start);
3160
+ const frame = new Float64Array(size);
3161
+ for (const channel of channels) {
3162
+ for (let index = 0; index < size; index++) frame[index] = frame[index] + (channel[from + index] ?? 0);
3163
+ }
3164
+ for (let index = 0; index < size; index++) frame[index] = frame[index] * (0.5 - 0.5 * Math.cos(2 * Math.PI * index / (size - 1)));
3165
+ let weighted = 0;
3166
+ let total = 0;
3167
+ const bins = size / 2;
3168
+ for (let bin = 1; bin < bins; bin++) {
3169
+ let re = 0;
3170
+ let im = 0;
3171
+ const step = 2 * Math.PI * bin / size;
3172
+ for (let index = 0; index < size; index++) {
3173
+ const value = frame[index];
3174
+ re += value * Math.cos(step * index);
3175
+ im -= value * Math.sin(step * index);
3176
+ }
3177
+ const magnitude = Math.hypot(re, im);
3178
+ weighted += magnitude * (bin * sampleRate / size);
3179
+ total += magnitude;
3180
+ }
3181
+ return total > 0 ? weighted / total : 0;
3182
+ }
3183
+ function balanceOf(left, right, start, end3) {
3184
+ let l = 0;
3185
+ let r = 0;
3186
+ const to = Math.min(left.length, right.length, Math.round(end3));
3187
+ for (let index = Math.max(0, Math.round(start)); index < to; index++) {
3188
+ l += left[index] ** 2;
3189
+ r += right[index] ** 2;
3190
+ }
3191
+ return l + r > 0 ? (r - l) / (r + l) : 0;
3192
+ }
3193
+ function ringSeconds(channels, sampleRate, start, floorDb = -60) {
3194
+ const window = Math.max(1, Math.round(sampleRate * 0.01));
3195
+ const length = channels[0]?.length ?? 0;
3196
+ let last = clampIndex(channels, start);
3197
+ for (let index = last; index < length; index += window) {
3198
+ if (dbOf(peakOf(channels, index, index + window)) > floorDb) last = index + window;
3199
+ }
3200
+ return (last - start) / sampleRate;
3201
+ }
3202
+ function countHits(channels, sampleRate, threshold) {
3203
+ const window = Math.max(1, Math.round(sampleRate * 2e-3));
3204
+ const length = channels[0]?.length ?? 0;
3205
+ const envelope = [];
3206
+ for (let index = 0; index < length; index += window) envelope.push(peakOf(channels, index, index + window));
3207
+ const history = 10;
3208
+ const refractory = Math.round(0.03 / 2e-3);
3209
+ let hits = 0;
3210
+ let quietUntil = -1;
3211
+ for (let index = 0; index < envelope.length; index++) {
3212
+ const level = envelope[index];
3213
+ if (index < quietUntil || level < threshold) continue;
3214
+ let sum = 0;
3215
+ for (let back = Math.max(0, index - history); back < index; back++) sum += envelope[back];
3216
+ const before = index === 0 ? 0 : sum / Math.min(history, index);
3217
+ if (level >= 2 * before) {
3218
+ hits++;
3219
+ quietUntil = index + refractory;
3220
+ }
3221
+ }
3222
+ return hits;
3223
+ }
3224
+ function endDropDb(channels, sampleRate, seconds = 5e-3) {
3225
+ const length = channels[0]?.length ?? 0;
3226
+ const whole = peakOf(channels);
3227
+ if (whole === 0) return -Infinity;
3228
+ return dbOf(peakOf(channels, length - Math.round(sampleRate * seconds), length) / whole);
3229
+ }
3230
+
3231
+ // src/measure/criteria.ts
3232
+ var CRITERIA = ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10"];
3233
+ var CRITERIA_TARGETS = {
3234
+ /** C1: event to the first sample, and onset to the peak (one 60 fps frame). */
3235
+ syncMs: 20,
3236
+ peakAfterOnsetMs: 1e3 / 60,
3237
+ /** C3: distances measured, metres. */
3238
+ distances: [1, 10, 50, 200],
3239
+ /** C5: plays, distinct takes and the pitch range (fraction). */
3240
+ plays: 10,
3241
+ minTakes: 4,
3242
+ pitch: [0.03, 0.05],
3243
+ /** C6: the highest peak, dBFS. */
3244
+ peakDb: -1,
3245
+ /** C8: the end of each file against its peak, dB. */
3246
+ endDropDb: -40,
3247
+ /** C9: a burst of rapid fire. */
3248
+ burst: 20,
3249
+ burstSpacing: 0.06
3250
+ };
3251
+ var EVENT_AT = 0.2;
3252
+ var offlineFactory = (options) => options.createOfflineContext ?? ((channels, length, sampleRate) => {
3253
+ const Constructor = globalThis.OfflineAudioContext;
3254
+ if (!Constructor) throw new Error("no OfflineAudioContext here: the harness runs in a browser");
3255
+ return new Constructor(channels, length, sampleRate);
3256
+ });
3257
+ async function render(options, seconds, act, engineExtras = {}) {
3258
+ const sampleRate = options.sampleRate ?? 48e3;
3259
+ const context = offlineFactory(options)(2, Math.ceil(seconds * sampleRate), sampleRate);
3260
+ const events = [];
3261
+ const engine = createAudioEngine({
3262
+ banks: options.banks,
3263
+ createContext: () => context,
3264
+ samples: { loader: options.loader, autoLoad: false },
3265
+ onVoiceStart: (event) => events.push(event),
3266
+ ...options.mix ? { mix: options.mix } : {},
3267
+ ...engineExtras.occlusion ? { occlusion: engineExtras.occlusion } : {},
3268
+ ...engineExtras.environment ? { environment: engineExtras.environment } : {}
3269
+ });
3270
+ const ids = [.../* @__PURE__ */ new Set([options.sound, ...(options.actions ?? []).map((action) => action.play), ...options.loudnessOrder ?? []])].filter((id) => engine.registry.sample(id));
3271
+ const report = await engine.loadSamples(ids);
3272
+ if (report.failed.length > 0) throw new Error(`files did not load: ${report.failed.map((entry) => `${entry.url} (${entry.error})`).join(", ")}`);
3273
+ const handles = act(engine);
3274
+ const buffer = await context.startRendering();
3275
+ const channels = Array.from({ length: buffer.numberOfChannels }, (_, index) => buffer.getChannelData(index));
3276
+ return { channels, sampleRate, events, handles };
3277
+ }
3278
+ var ms = (seconds) => `${(seconds * 1e3).toFixed(1)} ms`;
3279
+ var db = (value) => Number.isFinite(value) ? `${value.toFixed(1)} dB` : "\u2212\u221E";
3280
+ var decreasing = (values) => values.every((value, index) => index === 0 || value < values[index - 1]);
3281
+ async function c1(options) {
3282
+ const result = await render(options, 1.2, (engine) => engine.play(options.sound, { distance: 1, delay: EVENT_AT }) ? 1 : 0);
3283
+ const onset = onsetIndex(result.channels, 0, 1e-3);
3284
+ const event = result.events.find((entry) => entry.id === options.sound);
3285
+ if (onset < 0 || !event) return { id: "C1", pass: false, value: "sem som", target: `\u2264 ${CRITERIA_TARGETS.syncMs} ms` };
3286
+ const delay = onset / result.sampleRate - EVENT_AT + (event.startAt - event.requestedAt - EVENT_AT) + (options.baseLatency ?? 0);
3287
+ const peak = peakIndex(result.channels, onset, onset + Math.round(result.sampleRate * 0.25));
3288
+ const toPeak = (peak - onset) / result.sampleRate;
3289
+ const pass = delay <= CRITERIA_TARGETS.syncMs / 1e3 && toPeak <= CRITERIA_TARGETS.peakAfterOnsetMs / 1e3;
3290
+ return {
3291
+ id: "C1",
3292
+ pass,
3293
+ value: `${ms(delay)}, pico +${ms(toPeak)}`,
3294
+ target: `\u2264 ${CRITERIA_TARGETS.syncMs} ms; pico no quadro do contato`,
3295
+ data: { delay, toPeak, baseLatency: options.baseLatency ?? 0, outputLatency: options.outputLatency ?? 0 }
3296
+ };
3297
+ }
3298
+ async function c2(options) {
3299
+ const actions = options.actions ?? [{ action: options.sound, play: options.sound, expect: options.sound }];
3300
+ const result = await render(options, 0.5, (engine) => {
3301
+ let played = 0;
3302
+ for (const action of actions) if (engine.play(action.play, { distance: 1, ...action.options })) played++;
3303
+ return played;
3304
+ });
3305
+ const wrong = actions.filter((action, index) => {
3306
+ const event = result.events[index];
3307
+ return !event || (event.fallbackOf ?? event.id) !== action.expect || event.kind !== "sample";
3308
+ });
3309
+ return {
3310
+ id: "C2",
3311
+ pass: wrong.length === 0,
3312
+ value: `${actions.length - wrong.length}/${actions.length} certas`,
3313
+ target: "100% das a\xE7\xF5es batem com a tabela (arquivo, n\xE3o o substituto)",
3314
+ data: { wrong: wrong.map((action) => action.action), events: result.events.map((event) => `${event.kind}:${event.id}`) }
3315
+ };
3316
+ }
3317
+ async function c3(options, sound) {
3318
+ const levels = [];
3319
+ const brightness = [];
3320
+ for (const distance of CRITERIA_TARGETS.distances) {
3321
+ const result = await render(options, 1.2, (engine) => engine.play(options.sound, { position: [0, 0, -distance], seed: 1, delay: EVENT_AT }) ? 1 : 0);
3322
+ const onset = onsetIndex(result.channels, 0, 1e-5);
3323
+ levels.push(onset < 0 ? -Infinity : rmsDb(result.channels, onset, onset + result.sampleRate * 0.3));
3324
+ brightness.push(onset < 0 ? 0 : centroidHz(result.channels, result.sampleRate, onset));
3325
+ }
3326
+ const far = planSample(sound, { random: createRng(1), distance: CRITERIA_TARGETS.distances.at(-1) });
3327
+ const switched = (far?.farMix ?? 0) === 1 && (far?.layers.some((layer) => layer.role === "far") ?? false);
3328
+ const pass = decreasing(levels) && decreasing(brightness) && switched;
3329
+ return {
3330
+ id: "C3",
3331
+ pass,
3332
+ value: `${levels.map((level) => db(level)).join(" \u203A ")}; ${brightness.map((hz) => `${Math.round(hz)} Hz`).join(" \u203A ")}${switched ? "; longe = far" : "; sem camada far"}`,
3333
+ target: "cai e escurece com a dist\xE2ncia; troca para a vers\xE3o de longe depois de ~50 m",
3334
+ data: { distances: CRITERIA_TARGETS.distances, levels, brightness, switched }
3335
+ };
3336
+ }
3337
+ async function c4(options) {
3338
+ const side = async (x) => {
3339
+ const result = await render(options, 0.8, (engine) => engine.play(options.sound, { position: [x, 0, -2], seed: 1, delay: EVENT_AT }) ? 1 : 0);
3340
+ const [left2, right2] = result.channels;
3341
+ return balanceOf(left2, right2, 0, left2.length);
3342
+ };
3343
+ const right = await side(10);
3344
+ const left = await side(-10);
3345
+ const bright = async (occluded) => {
3346
+ const result = await render(options, 0.8, (engine) => engine.play(options.sound, { position: [0, 0, -10], seed: 1, delay: EVENT_AT }) ? 1 : 0, occluded ? { occlusion: () => 1 } : {});
3347
+ const onset = onsetIndex(result.channels, 0, 1e-5);
3348
+ return onset < 0 ? 0 : centroidHz(result.channels, result.sampleRate, onset);
3349
+ };
3350
+ const clear = await bright(false);
3351
+ const wall = await bright(true);
3352
+ const pass = right > 0.2 && left < -0.2 && wall < clear * 0.7;
3353
+ return {
3354
+ id: "C4",
3355
+ pass,
3356
+ value: `dir ${right.toFixed(2)} esq ${left.toFixed(2)}; parede ${Math.round(wall)} Hz de ${Math.round(clear)} Hz`,
3357
+ target: "lado certo; atr\xE1s da parede fica abafado",
3358
+ data: { right, left, clear, wall }
3359
+ };
3360
+ }
3361
+ async function c5(options, sound) {
3362
+ const result = await render(options, 0.3 * CRITERIA_TARGETS.plays + 1, (engine) => {
3363
+ let played = 0;
3364
+ for (let index = 0; index < CRITERIA_TARGETS.plays; index++) if (engine.play(options.sound, { distance: 1, delay: 0.1 + index * 0.3 })) played++;
3365
+ return played;
3366
+ });
3367
+ const close = result.events.map((event) => event.layers?.find((layer) => layer.role === "close"));
3368
+ const takes = close.map((layer) => layer?.url ?? "");
3369
+ const repeats = takes.filter((take, index) => index > 0 && take === takes[index - 1]).length;
3370
+ const distinct = new Set(takes).size;
3371
+ const rates = close.map((layer) => layer?.rate ?? 1);
3372
+ const spread = (Math.max(...rates) - Math.min(...rates)) / 2;
3373
+ const pitch = sound.pitch ?? 0.04;
3374
+ const pass = distinct >= CRITERIA_TARGETS.minTakes && repeats === 0 && pitch >= CRITERIA_TARGETS.pitch[0] && pitch <= CRITERIA_TARGETS.pitch[1] && spread > 0.01;
3375
+ return {
3376
+ id: "C5",
3377
+ pass,
3378
+ value: `${distinct} tomadas, ${repeats} repeti\xE7\xF5es seguidas, tom \xB1${(pitch * 100).toFixed(0)}%`,
3379
+ target: `\u2265 ${CRITERIA_TARGETS.minTakes} varia\xE7\xF5es, nunca a mesma duas vezes, tom \xB13\u20135%`,
3380
+ data: { takes, rates }
3381
+ };
3382
+ }
3383
+ async function c6(options) {
3384
+ const peakAt = async (id) => {
3385
+ const result = await render(options, 1.2, (engine) => engine.play(id, { distance: 1, seed: 1, delay: EVENT_AT }) ? 1 : 0);
3386
+ const onset = onsetIndex(result.channels, 0, 1e-5);
3387
+ return { peak: dbOf(peakOf(result.channels)), rms: onset < 0 ? -Infinity : rmsDb(result.channels, onset, onset + result.sampleRate * 0.3) };
3388
+ };
3389
+ const own = await peakAt(options.sound);
3390
+ const order = options.loudnessOrder ?? [];
3391
+ const loudness = [];
3392
+ for (const id of order) loudness.push((await peakAt(id)).rms);
3393
+ const ordered = order.length < 2 || decreasing(loudness);
3394
+ const pass = own.peak <= CRITERIA_TARGETS.peakDb && ordered;
3395
+ return {
3396
+ id: "C6",
3397
+ pass,
3398
+ value: `pico ${db(own.peak)}, RMS ${db(own.rms)}${order.length > 1 ? `; ordem ${ordered ? "ok" : "errada"}` : ""}`,
3399
+ target: "tiro > explos\xE3o > impacto > passo; pico \u2264 \u22121 dBFS",
3400
+ data: { peak: own.peak, rms: own.rms, order, loudness }
3401
+ };
3402
+ }
3403
+ async function c7(options, sound) {
3404
+ if (!sound.tiers || sound.tiers.length < 2) return { id: "C7", pass: false, value: "sem camadas leve/m\xE9dio/forte", target: "muda de camada, n\xE3o s\xF3 de volume" };
3405
+ const at = async (intensity) => {
3406
+ const result = await render(options, 1.2, (engine) => engine.play(options.sound, { distance: 1, seed: 1, intensity, delay: EVENT_AT }) ? 1 : 0);
3407
+ const onset = onsetIndex(result.channels, 0, 1e-5);
3408
+ const event = result.events[0];
3409
+ return { tier: event?.tier ?? "", rms: onset < 0 ? -Infinity : rmsDb(result.channels, onset, onset + result.sampleRate * 0.3), files: event?.layers?.find((layer) => layer.role === "close")?.url ?? "" };
3410
+ };
3411
+ const light = await at(0.1);
3412
+ const heavy = await at(0.9);
3413
+ const pass = light.tier !== heavy.tier && light.files !== heavy.files && heavy.rms > light.rms;
3414
+ return {
3415
+ id: "C7",
3416
+ pass,
3417
+ value: `${light.tier} ${db(light.rms)} \u2192 ${heavy.tier} ${db(heavy.rms)}`,
3418
+ target: "golpe fraco x forte troca a camada (leve/m\xE9dio/forte), n\xE3o s\xF3 o volume",
3419
+ data: { light, heavy }
3420
+ };
3421
+ }
3422
+ async function c8(options, sound) {
3423
+ const sampleRate = options.sampleRate ?? 48e3;
3424
+ const decoder = offlineFactory(options)(1, sampleRate, sampleRate);
3425
+ const drops = [];
3426
+ for (const url2 of sampleUrls(sound)) {
3427
+ const buffer = await decoder.decodeAudioData(await options.loader(url2));
3428
+ drops.push({ url: url2, drop: endDropDb([buffer.getChannelData(0)], buffer.sampleRate) });
3429
+ }
3430
+ const worst = drops.reduce((max, entry) => Math.max(max, entry.drop), -Infinity);
3431
+ const ring = async (environment) => {
3432
+ const result = await render(options, 3, (engine) => engine.play(options.sound, { distance: 1, seed: 1, environment, delay: EVENT_AT }) ? 1 : 0);
3433
+ return ringSeconds(result.channels, result.sampleRate, Math.round(EVENT_AT * result.sampleRate));
3434
+ };
3435
+ const indoor = await ring("indoor");
3436
+ const outdoor = await ring("outdoor");
3437
+ const hasTails = Boolean(sound.tail?.indoor?.length && sound.tail?.outdoor?.length);
3438
+ const pass = worst <= CRITERIA_TARGETS.endDropDb && hasTails && outdoor > indoor;
3439
+ return {
3440
+ id: "C8",
3441
+ pass,
3442
+ value: `fim ${db(worst)}; cauda dentro ${indoor.toFixed(2)} s, fora ${outdoor.toFixed(2)} s${hasTails ? "" : " (sem as duas caudas)"}`,
3443
+ target: "n\xE3o corta seco; cauda de interior x exterior coerente",
3444
+ data: { drops, indoor, outdoor }
3445
+ };
3446
+ }
3447
+ async function c9(options) {
3448
+ const { burst, burstSpacing } = CRITERIA_TARGETS;
3449
+ const first = 0.1;
3450
+ const result = await render(options, burst * burstSpacing + 1.5, (engine) => {
3451
+ let played = 0;
3452
+ for (let index = 0; index < burst; index++) if (engine.play(options.sound, { distance: 1, delay: first + index * burstSpacing })) played++;
3453
+ return played;
3454
+ });
3455
+ const peak = dbOf(peakOf(result.channels));
3456
+ const slots = [];
3457
+ for (let index = 0; index < burst; index++) {
3458
+ const at = Math.round((first + index * burstSpacing) * result.sampleRate);
3459
+ slots.push(rmsDb(result.channels, at, at + Math.round(burstSpacing * result.sampleRate)));
3460
+ }
3461
+ const sorted = [...slots].sort((a, b) => a - b);
3462
+ const median = sorted[Math.floor(sorted.length / 2)];
3463
+ const vanished = slots.filter((level) => level < median - 6).length;
3464
+ const buildUp = slots.slice(-5).reduce((sum, level) => sum + level, 0) / 5 - slots[0];
3465
+ const pass = result.handles === burst && vanished === 0 && buildUp <= 6 && peak <= CRITERIA_TARGETS.peakDb;
3466
+ return {
3467
+ id: "C9",
3468
+ pass,
3469
+ value: `${result.handles}/${burst} tocaram, ${vanished} sumiram, ac\xFAmulo ${buildUp >= 0 ? "+" : ""}${buildUp.toFixed(1)} dB, pico ${db(peak)}`,
3470
+ target: "rajada sem amontoar (ac\xFAmulo \u2264 6 dB) nem sumir; pico \u2264 \u22121 dBFS",
3471
+ data: { handles: result.handles, slots, vanished, buildUp, peak }
3472
+ };
3473
+ }
3474
+ async function measureCriteria(options, only = CRITERIA) {
3475
+ const probe = createAudioEngine({ banks: options.banks, createContext: () => null });
3476
+ const sound = probe.registry.sample(options.sound);
3477
+ if (!sound) throw new Error(`${options.sound} is not a sample sound of these banks`);
3478
+ const results = [];
3479
+ for (const id of only) {
3480
+ if (id === "C1") results.push(await c1(options));
3481
+ else if (id === "C2") results.push(await c2(options));
3482
+ else if (id === "C3") results.push(await c3(options, sound));
3483
+ else if (id === "C4") results.push(await c4(options));
3484
+ else if (id === "C5") results.push(await c5(options, sound));
3485
+ else if (id === "C6") results.push(await c6(options));
3486
+ else if (id === "C7") results.push(await c7(options, sound));
3487
+ else if (id === "C8") results.push(await c8(options, sound));
3488
+ else if (id === "C9") results.push(await c9(options));
3489
+ else results.push({ id: "C10", pass: null, value: "gravar e ouvir", target: "aprovado pelo ouvido do dono (print + grava\xE7\xE3o na 4280)" });
3490
+ }
3491
+ return results;
3492
+ }
3493
+ async function recordOutput(engine, seconds, act) {
3494
+ engine.unlock();
3495
+ const output = engine.output();
3496
+ const Recorder = globalThis.MediaRecorder;
3497
+ const context = output?.context;
3498
+ if (!output || !Recorder || !context || typeof context.createMediaStreamDestination !== "function") return null;
3499
+ const tap = context.createMediaStreamDestination();
3500
+ output.connect(tap);
3501
+ const recorder = new Recorder(tap.stream);
3502
+ const chunks = [];
3503
+ recorder.ondataavailable = (event) => chunks.push(event.data);
3504
+ const done = new Promise((resolve) => {
3505
+ recorder.onstop = () => resolve();
3506
+ });
3507
+ recorder.start();
3508
+ act();
3509
+ await new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
3510
+ recorder.stop();
3511
+ await done;
3512
+ output.disconnect(tap);
3513
+ return new Blob(chunks, { type: recorder.mimeType || "audio/webm" });
3514
+ }
3515
+
3516
+ // src/bench/sound-check-locale.ts
3517
+ var PT = {
3518
+ group: "Som",
3519
+ name: "Painel de som (arquivos e C1\u2013C10)",
3520
+ controls: {
3521
+ category: "1 \xB7 Categoria",
3522
+ sound: "1 \xB7 Som",
3523
+ play: "1 \xB7 \u25B6 Tocar",
3524
+ material: "2 \xB7 Material",
3525
+ blow: "2 \xB7 Golpe",
3526
+ strike: "2 \xB7 \u25B6 Tocar golpe",
3527
+ distance: "3 \xB7 Dist\xE2ncia",
3528
+ bearing: "3 \xB7 Dire\xE7\xE3o",
3529
+ environment: "3 \xB7 Lugar",
3530
+ strength: "3 \xB7 For\xE7a",
3531
+ wall: "3 \xB7 Atr\xE1s da parede",
3532
+ burst: "3 \xB7 Rajada 20\xD7",
3533
+ play_a: "4 \xB7 \u25B6 A (atual)",
3534
+ play_b: "4 \xB7 \u25B6 B (novo)",
3535
+ ab_cycle: "4 \xB7 Alternar A/B",
3536
+ blind: "4 \xB7 \xC0s cegas (X)",
3537
+ reveal: "4 \xB7 Revelar X",
3538
+ prefer_a: "4 \xB7 Prefiro A",
3539
+ prefer_b: "4 \xB7 Prefiro B",
3540
+ measure: "5 \xB7 Medir C1\u2013C10",
3541
+ record: "5 \xB7 Gravar 3 s",
3542
+ approve: "5 \xB7 Aprovo (C10)"
3543
+ },
3544
+ hints: {
3545
+ sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
3546
+ strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
3547
+ wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
3548
+ burst: "Vinte vezes a cada 60 ms, como uma rajada (C9).",
3549
+ ab_cycle: "A, B, A, B, um por segundo.",
3550
+ blind: "Toca A ou B sem dizer qual; depois revele.",
3551
+ measure: "Mede o som escolhido no motor real (contexto offline): sincronia, som certo, dist\xE2ncia, lado, varia\xE7\xE3o, volume, for\xE7a, cauda e rajada.",
3552
+ record: "Grava 3 s da sa\xEDda com o som tocando e baixa o arquivo (C10).",
3553
+ approve: "Marca o C10 do som escolhido como aprovado pelo seu ouvido."
3554
+ },
3555
+ categories: {
3556
+ armas: "Armas",
3557
+ impactos: "Impactos",
3558
+ "explosoes-fogo": "Explos\xF5es e fogo",
3559
+ personagem: "Personagem",
3560
+ veiculos: "Ve\xEDculos",
3561
+ "itens-portas": "Itens e portas",
3562
+ ambiente: "Ambiente",
3563
+ calibracao: "Calibra\xE7\xE3o (SDK)"
3564
+ },
3565
+ blows: { bullet: "tiro", blunt: "soco/chute", blade: "faca", break: "quebra", drag: "arrasto/queda" },
3566
+ materials: {
3567
+ steel: "a\xE7o",
3568
+ aluminium: "alum\xEDnio",
3569
+ wood: "madeira",
3570
+ plywood: "compensado",
3571
+ mdf: "MDF",
3572
+ glass: "vidro",
3573
+ tempered_glass: "vidro temperado",
3574
+ ceramic: "cer\xE2mica",
3575
+ concrete: "concreto",
3576
+ brick: "tijolo",
3577
+ plaster: "gesso",
3578
+ plastic: "pl\xE1stico",
3579
+ fabric: "tecido",
3580
+ paper: "papel\xE3o",
3581
+ foliage: "folhagem",
3582
+ soil: "terra",
3583
+ flesh: "carne"
3584
+ },
3585
+ environments: { indoor: "interior", outdoor: "exterior" },
3586
+ strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
3587
+ states: { file: "A", synth: "S", missing: "F" },
3588
+ criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
3589
+ metrics: { chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
3590
+ run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
3591
+ words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
3592
+ probe: "Fonte do som",
3593
+ wall: "Parede (oclus\xE3o)",
3594
+ scenarios: { pipeline: "Arquivo \u2192 decodifica \u2192 toca (round-robin, cauda)", criteria: "Crit\xE9rios C1\u2013C9 no som de calibra\xE7\xE3o", loop: "Loop de arquivo: emenda sem buraco (crossfade)", panel: "Painel: categorias, matriz, A/B e parede" }
3595
+ };
3596
+ var EN2 = {
3597
+ ...PT,
3598
+ group: "Sound",
3599
+ name: "Sound panel (files and C1\u2013C10)",
3600
+ controls: {
3601
+ category: "1 \xB7 Category",
3602
+ sound: "1 \xB7 Sound",
3603
+ play: "1 \xB7 \u25B6 Play",
3604
+ material: "2 \xB7 Material",
3605
+ blow: "2 \xB7 Blow",
3606
+ strike: "2 \xB7 \u25B6 Play blow",
3607
+ distance: "3 \xB7 Distance",
3608
+ bearing: "3 \xB7 Bearing",
3609
+ environment: "3 \xB7 Place",
3610
+ strength: "3 \xB7 Strength",
3611
+ wall: "3 \xB7 Behind the wall",
3612
+ burst: "3 \xB7 Burst 20\xD7",
3613
+ play_a: "4 \xB7 \u25B6 A (current)",
3614
+ play_b: "4 \xB7 \u25B6 B (new)",
3615
+ ab_cycle: "4 \xB7 Alternate A/B",
3616
+ blind: "4 \xB7 Blind (X)",
3617
+ reveal: "4 \xB7 Reveal X",
3618
+ prefer_a: "4 \xB7 Prefer A",
3619
+ prefer_b: "4 \xB7 Prefer B",
3620
+ measure: "5 \xB7 Measure C1\u2013C10",
3621
+ record: "5 \xB7 Record 3 s",
3622
+ approve: "5 \xB7 Approve (C10)"
3623
+ },
3624
+ hints: {
3625
+ sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
3626
+ strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
3627
+ wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
3628
+ burst: "Twenty times every 60 ms, like a burst (C9).",
3629
+ ab_cycle: "A, B, A, B, one a second.",
3630
+ blind: "Plays A or B without saying which; reveal it after.",
3631
+ measure: "Measures the chosen sound through the real engine (offline context): sync, right sound, distance, side, variation, level, strength, tail and burst.",
3632
+ record: "Records 3 s of the output with the sound playing and downloads it (C10).",
3633
+ approve: "Marks C10 of the chosen sound as approved by your ear."
3634
+ },
3635
+ categories: { armas: "Weapons", impactos: "Impacts", "explosoes-fogo": "Explosions and fire", personagem: "Character", veiculos: "Vehicles", "itens-portas": "Items and doors", ambiente: "Ambience", calibracao: "Calibration (SDK)" },
3636
+ blows: { bullet: "bullet", blunt: "punch/kick", blade: "knife", break: "break", drag: "drag/fall" },
3637
+ materials: {
3638
+ steel: "steel",
3639
+ aluminium: "aluminium",
3640
+ wood: "wood",
3641
+ plywood: "plywood",
3642
+ mdf: "MDF",
3643
+ glass: "glass",
3644
+ tempered_glass: "tempered glass",
3645
+ ceramic: "ceramic",
3646
+ concrete: "concrete",
3647
+ brick: "brick",
3648
+ plaster: "plaster",
3649
+ plastic: "plastic",
3650
+ fabric: "fabric",
3651
+ paper: "cardboard",
3652
+ foliage: "foliage",
3653
+ soil: "soil",
3654
+ flesh: "flesh"
3655
+ },
3656
+ environments: { indoor: "indoor", outdoor: "outdoor" },
3657
+ strengths: { light: "light", medium: "medium", heavy: "heavy" },
3658
+ criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
3659
+ metrics: { chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
3660
+ run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
3661
+ words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
3662
+ probe: "Sound source",
3663
+ wall: "Wall (occlusion)",
3664
+ scenarios: { pipeline: "File \u2192 decode \u2192 play (round-robin, tail)", criteria: "Criteria C1\u2013C9 on the calibration sound", loop: "File loop: seamless joins (crossfade)", panel: "Panel: categories, matrix, A/B and wall" }
3665
+ };
3666
+ var soundCheckTextOf = (locale) => locale.startsWith("en") ? EN2 : PT;
3667
+
3668
+ // src/bench/sound-check.ts
3669
+ var SOUND_STRENGTHS = { light: 0.1, medium: 0.5, heavy: 0.9 };
3670
+ var CALIBRATION_CATEGORY = "calibracao";
3671
+ var CALIBRATION_BANK = { id: "calibration", samples: [CALIBRATION_SOUND, CALIBRATION_LOOP_SOUND] };
3672
+ var DISTANCES2 = [1, 10, 50, 200];
3673
+ var PROBE_ID2 = "sound_check_source";
3674
+ var WALL_ID = "sound_check_wall";
3675
+ var EYE = [0, 1.7, 3];
3676
+ var DRAWN_MAX = 11;
3677
+ var WALL_AT = -2.5;
3678
+ var LOG_LIMIT = 200;
3679
+ function createSoundCheckModule(options = {}) {
3680
+ const locale = options.locale ?? "pt-BR";
3681
+ const text = soundCheckTextOf(locale);
3682
+ const ownBanks = [CALIBRATION_BANK, ...options.banks ?? []];
3683
+ const loader = calibrationLoader(options.loader ?? fetchLoader());
3684
+ const log = [];
3685
+ const catalog = options.catalog ?? [...SFX_CATALOG, ...SFX_IMPACTS];
3686
+ let engine = options.engine ?? createAudioEngine({ banks: [GAME_SFX_BANK, ...ownBanks], samples: { loader } });
3687
+ if (options.engine) for (const bank of ownBanks) engine.register(bank);
3688
+ let host = null;
3689
+ let results = [];
3690
+ let run = "idle";
3691
+ const verdicts = {};
3692
+ const approvals = /* @__PURE__ */ new Set();
3693
+ let blind = null;
3694
+ const chosen = {
3695
+ category: options.sound && options.sound !== CALIBRATION_ID ? catalog.find((entry) => entry.id === options.sound)?.category ?? CALIBRATION_CATEGORY : CALIBRATION_CATEGORY,
3696
+ sound: options.sound ?? CALIBRATION_ID,
3697
+ material: "concrete",
3698
+ blow: "bullet",
3699
+ distance: 10,
3700
+ bearing: 0,
3701
+ environment: "outdoor",
3702
+ strength: "medium",
3703
+ wall: false
3704
+ };
3705
+ const registry = () => engine.registry;
3706
+ const entryOf = (id) => catalog.find((entry) => entry.id === id);
3707
+ const stateOf = (id) => {
3708
+ const entry = entryOf(id);
3709
+ if (entry) return sfxState(entry, registry());
3710
+ return registry().sample(id) ? "file" : registry().sound(id) ? "synth" : "missing";
3711
+ };
3712
+ const pairOf = (id) => {
3713
+ const entry = entryOf(id);
3714
+ const sample = registry().sample(id);
3715
+ const current = entry?.current ?? sample?.fallback ?? (registry().sound(id) ? id : void 0);
3716
+ return { a: current && registry().sound(current) ? current : null, b: sample ? id : null };
3717
+ };
3718
+ const soundsOf = (category) => {
3719
+ if (category === CALIBRATION_CATEGORY) return registry().sampleIds().filter((id) => !entryOf(id));
3720
+ return catalog.filter((entry) => entry.category === category).map((entry) => entry.id);
3721
+ };
3722
+ const label = (id) => {
3723
+ const entry = entryOf(id);
3724
+ return `${id}${entry ? ` \xB7 P${entry.priority}` : ""} \xB7 ${text.states[stateOf(id)]}`;
3725
+ };
3726
+ const soundOptions = () => soundsOf(chosen.category).map((id) => ({ id, name: label(id) }));
3727
+ const listener = () => {
3728
+ const camera = host?.camera;
3729
+ const three = host?.THREE;
3730
+ if (typeof camera?.getWorldDirection !== "function" || typeof three?.Vector3 !== "function" || !camera.position) return { position: EYE, yaw: 0 };
3731
+ const direction = camera.getWorldDirection(new three.Vector3());
3732
+ return { position: [camera.position.x, camera.position.y, camera.position.z], yaw: Math.atan2(-direction.x, -direction.z) };
3733
+ };
3734
+ const offset = (ears, distance) => {
3735
+ const bearing = chosen.bearing * Math.PI / 180;
3736
+ const forward = [-Math.sin(ears.yaw), -Math.cos(ears.yaw)];
3737
+ const right = [Math.cos(ears.yaw), -Math.sin(ears.yaw)];
3738
+ return [ears.position[0] + distance * (forward[0] * Math.cos(bearing) + right[0] * Math.sin(bearing)), ears.position[1], ears.position[2] + distance * (forward[1] * Math.cos(bearing) + right[1] * Math.sin(bearing))];
3739
+ };
3740
+ const playOptions = (extra = {}) => {
3741
+ const ears = listener();
3742
+ engine.setListener(ears);
3743
+ return { position: offset(ears, chosen.distance), environment: chosen.environment, intensity: SOUND_STRENGTHS[chosen.strength], occlusion: chosen.wall ? 1 : 0, ...extra };
3744
+ };
3745
+ const playId = (id, extra = {}) => {
3746
+ if (!id) return null;
3747
+ engine.unlock();
3748
+ return engine.play(id, playOptions(extra));
3749
+ };
3750
+ const preferred = (id) => pairOf(id).b ?? pairOf(id).a ?? (registry().sound(id) ? id : null);
3751
+ const play = () => playId(preferred(chosen.sound));
3752
+ const playB = async (delay = 0) => {
3753
+ const { b } = pairOf(chosen.sound);
3754
+ if (!b) return;
3755
+ if (engine.sampleStatus(b) !== "ready") await engine.loadSamples([b]);
3756
+ playId(b, { delay });
3757
+ };
3758
+ const playA = (delay = 0) => void playId(pairOf(chosen.sound).a, { delay });
3759
+ const placeScenery = () => {
3760
+ const scene = host?.scene;
3761
+ if (typeof scene?.traverse !== "function") return;
3762
+ const at = offset({ position: EYE, yaw: 0 }, Math.min(chosen.distance, DRAWN_MAX));
3763
+ scene.traverse((object) => {
3764
+ if (object.userData?.[PROBE_ID2] === true) object.position?.set(at[0], 0, at[2]);
3765
+ if (object.userData?.[WALL_ID] === true) object.visible = chosen.wall;
3766
+ });
3767
+ };
3768
+ const measure = async () => {
3769
+ run = "measuring";
3770
+ try {
3771
+ engine.unlock();
3772
+ const context = engine.output()?.context ?? null;
3773
+ const bank = {
3774
+ id: "measured",
3775
+ sounds: registry().soundIds().map((id) => registry().sound(id)).filter((recipe) => recipe !== void 0),
3776
+ loops: registry().loopIds().map((id) => registry().loop(id)).filter((recipe) => recipe !== void 0),
3777
+ samples: registry().sampleIds().map((id) => registry().sample(id)).filter((sample) => sample !== void 0)
3778
+ };
3779
+ results = await measureCriteria({
3780
+ sound: chosen.sound,
3781
+ banks: [bank],
3782
+ loader,
3783
+ ...context ? { baseLatency: context.baseLatency ?? 0, outputLatency: context.outputLatency ?? 0 } : {},
3784
+ ...options.actions?.[chosen.sound] ? { actions: options.actions[chosen.sound] } : {},
3785
+ ...options.loudnessOrder ? { loudnessOrder: options.loudnessOrder } : {}
3786
+ });
3787
+ if (approvals.has(chosen.sound)) results = results.map((result) => result.id === "C10" ? { ...result, pass: true, value: text.words.approved } : result);
3788
+ run = "done";
3789
+ } catch (error) {
3790
+ run = "failed";
3791
+ results = [{ id: "C1", pass: false, value: error instanceof Error ? error.message : String(error), target: "" }];
3792
+ }
3793
+ ;
3794
+ globalThis.__soundCheck = { sound: chosen.sound, results };
3795
+ return results;
3796
+ };
3797
+ const record = async () => {
3798
+ run = "recording";
3799
+ const blob = await recordOutput(engine, 3, () => {
3800
+ for (let index = 0; index < 4; index++) playId(preferred(chosen.sound), { delay: index * 0.6 });
3801
+ });
3802
+ const documentLike = globalThis.document;
3803
+ if (blob && documentLike && typeof URL.createObjectURL === "function") {
3804
+ const link = documentLike.createElement("a");
3805
+ link.href = URL.createObjectURL(blob);
3806
+ link.download = `${chosen.sound}-${chosen.environment}-${chosen.distance}m.webm`;
3807
+ link.click();
3808
+ run = "recorded";
3809
+ } else run = blob ? "recorded" : "failed";
3810
+ };
3811
+ const approve = () => {
3812
+ approvals.add(chosen.sound);
3813
+ results = results.map((result) => result.id === "C10" ? { ...result, pass: true, value: text.words.approved } : result);
3814
+ host?.log(`${chosen.sound}: C10 ${text.words.approved}`, { sound: chosen.sound }, "sound");
3815
+ };
3816
+ const prefer = (side) => {
3817
+ verdicts[chosen.sound] = side;
3818
+ const pair = pairOf(chosen.sound);
3819
+ host?.log(`${chosen.sound}: ${text.words.prefers} ${side}`, { sound: chosen.sound, prefers: side, a: pair.a, b: pair.b }, "sound");
3820
+ };
3821
+ const controls = () => [
3822
+ { kind: "choice", id: "category", name: text.controls.category, options: [...SFX_CATEGORIES, CALIBRATION_CATEGORY].map((id) => ({ id, name: text.categories[id] ?? id })), default: chosen.category },
3823
+ { kind: "choice", id: "sound", name: text.controls.sound, hint: text.hints.sound, options: soundOptions(), default: chosen.sound },
3824
+ { kind: "action", id: "play", name: text.controls.play },
3825
+ { kind: "choice", id: "material", name: text.controls.material, options: SFX_MATERIALS.map(([id]) => ({ id, name: text.materials[id] })), default: chosen.material },
3826
+ { kind: "choice", id: "blow", name: text.controls.blow, options: SFX_BLOWS.map((id) => ({ id, name: text.blows[id] })), default: chosen.blow },
3827
+ { kind: "action", id: "strike", name: text.controls.strike, hint: text.hints.strike },
3828
+ { kind: "choice", id: "distance", name: text.controls.distance, options: DISTANCES2.map((meters) => ({ id: String(meters), name: `${meters} m` })), default: String(chosen.distance) },
3829
+ { kind: "number", id: "bearing", name: text.controls.bearing, unit: "\xB0", min: -180, max: 180, step: 15, default: chosen.bearing },
3830
+ { kind: "choice", id: "environment", name: text.controls.environment, options: SAMPLE_ENVIRONMENTS.map((id) => ({ id, name: text.environments[id] })), default: chosen.environment },
3831
+ { kind: "choice", id: "strength", name: text.controls.strength, options: Object.keys(SOUND_STRENGTHS).map((id) => ({ id, name: text.strengths[id] })), default: chosen.strength },
3832
+ { kind: "boolean", id: "wall", name: text.controls.wall, hint: text.hints.wall, default: chosen.wall },
3833
+ { kind: "action", id: "burst", name: text.controls.burst, hint: text.hints.burst },
3834
+ { kind: "action", id: "play_a", name: text.controls.play_a },
3835
+ { kind: "action", id: "play_b", name: text.controls.play_b },
3836
+ { kind: "action", id: "ab_cycle", name: text.controls.ab_cycle, hint: text.hints.ab_cycle },
3837
+ { kind: "action", id: "blind", name: text.controls.blind, hint: text.hints.blind },
3838
+ { kind: "action", id: "reveal", name: text.controls.reveal },
3839
+ { kind: "action", id: "prefer_a", name: text.controls.prefer_a },
3840
+ { kind: "action", id: "prefer_b", name: text.controls.prefer_b },
3841
+ { kind: "action", id: "measure", name: text.controls.measure, hint: text.hints.measure },
3842
+ { kind: "action", id: "record", name: text.controls.record, hint: text.hints.record },
3843
+ { kind: "action", id: "approve", name: text.controls.approve, hint: text.hints.approve }
3844
+ ];
3845
+ const line = (id) => {
3846
+ const result = results.find((entry) => entry.id === id);
3847
+ if (!result) return text.words.none;
3848
+ return `${result.pass === null ? "\u25CC" : result.pass ? "\u2713" : "\u2717"} ${result.value}`;
3849
+ };
3850
+ const counts = () => {
3851
+ const states = catalog.map((entry) => sfxState(entry, registry()));
3852
+ const count = (state) => states.filter((each) => each === state).length;
3853
+ return `${text.states.file} ${count("file")} \xB7 ${text.states.synth} ${count("synth")} \xB7 ${text.states.missing} ${count("missing")}`;
3854
+ };
3855
+ const strikeId = () => impactSoundId(chosen.material, chosen.blow);
3856
+ const lastLine = () => {
3857
+ const last = log.at(-1);
3858
+ if (!last) return text.words.none;
3859
+ const files = last.layers?.map((layer) => layer.url.split("/").pop()).join("+") ?? "";
3860
+ return `${last.kind}:${last.fallbackOf ? `${last.fallbackOf}\u2192` : ""}${last.id}${last.tier ? `/${last.tier}` : ""} ${files}`.trim();
3861
+ };
3862
+ const metrics = () => [
3863
+ { id: "count", name: text.metrics.count, read: counts },
3864
+ { id: "chosen", name: text.metrics.chosen, read: () => `${label(chosen.sound)}${registry().sample(chosen.sound) ? ` (${engine.sampleStatus(chosen.sound)})` : ""}` },
3865
+ { id: "matrix", name: text.metrics.matrix, read: () => `${strikeId()} \xB7 ${text.states[stateOf(strikeId())]}${pairOf(strikeId()).a ? ` \xB7 A=${pairOf(strikeId()).a}` : ""}` },
3866
+ { id: "ab", name: text.metrics.ab, read: () => `A ${pairOf(chosen.sound).a ?? text.words.none} \xB7 B ${pairOf(chosen.sound).b ?? text.words.none}` },
3867
+ { id: "blind_state", name: text.metrics.blind, read: () => !blind ? text.words.none : blind.revealed ? `X = ${blind.side}` : text.words.hidden },
3868
+ { id: "verdicts", name: text.metrics.verdicts, read: () => Object.entries(verdicts).map(([id, side]) => `${id} ${text.words.prefers} ${side}`).join("; ") || text.words.none },
3869
+ { id: "last", name: text.metrics.last, read: lastLine },
3870
+ { id: "state", name: text.metrics.state, read: () => text.run[run] },
3871
+ ...CRITERIA.map((id) => ({ id: `criterion_${id.toLowerCase()}`, name: text.criteria[id], read: () => line(id) }))
3872
+ ];
3873
+ const act = (id) => {
3874
+ if (id === "play") play();
3875
+ else if (id === "strike") playId(preferred(strikeId()));
3876
+ else if (id === "burst") for (let index = 0; index < 20; index++) playId(preferred(chosen.sound), { delay: index * 0.06 });
3877
+ else if (id === "play_a") playA();
3878
+ else if (id === "play_b") void playB();
3879
+ else if (id === "ab_cycle") {
3880
+ playA(0);
3881
+ void playB(1).then(() => {
3882
+ playA(2);
3883
+ return playB(3);
3884
+ });
3885
+ } else if (id === "blind") {
3886
+ const side = Math.random() < 0.5 ? "A" : "B";
3887
+ blind = { side, revealed: false };
3888
+ if (side === "A") playA();
3889
+ else void playB();
3890
+ } else if (id === "reveal" && blind) blind.revealed = true;
3891
+ else if (id === "prefer_a") prefer("A");
3892
+ else if (id === "prefer_b") prefer("B");
3893
+ else if (id === "measure") void measure();
3894
+ else if (id === "record") void record();
3895
+ else if (id === "approve") approve();
3896
+ };
3897
+ const onChange = (change) => {
3898
+ if (change.kind === "action") return act(change.id);
3899
+ if (change.kind !== "control") return;
3900
+ const { id, value } = change;
3901
+ if (id === "category" && typeof value === "string") {
3902
+ chosen.category = value;
3903
+ const first = soundsOf(value)[0];
3904
+ if (first) chosen.sound = first;
3905
+ host?.bench?.patch("sound", { options: soundOptions(), value: chosen.sound });
3906
+ results = [];
3907
+ } else if (id === "sound" && typeof value === "string") {
3908
+ chosen.sound = value;
3909
+ results = [];
3910
+ if (registry().sample(value)) void engine.loadSamples([value]);
3911
+ } else if (id === "material" && typeof value === "string") chosen.material = value;
3912
+ else if (id === "blow" && typeof value === "string") chosen.blow = value;
3913
+ else if (id === "distance" && typeof value === "string") chosen.distance = Number(value);
3914
+ else if (id === "bearing" && typeof value === "number") chosen.bearing = value;
3915
+ else if (id === "environment" && (value === "indoor" || value === "outdoor")) chosen.environment = value;
3916
+ else if (id === "strength" && typeof value === "string" && value in SOUND_STRENGTHS) chosen.strength = value;
3917
+ else if (id === "wall" && typeof value === "boolean") chosen.wall = value;
3918
+ placeScenery();
3919
+ };
3920
+ const items = () => {
3921
+ const marked = (id, name, build) => ({
3922
+ id,
3923
+ name,
3924
+ movable: false,
3925
+ build: (THREE) => {
3926
+ const root = build(THREE);
3927
+ root.userData = root.userData ?? {};
3928
+ root.userData[id] = true;
3929
+ return root;
3930
+ }
3931
+ });
3932
+ return [...options.probe ? [marked(PROBE_ID2, text.probe, options.probe)] : [], ...options.wall ? [marked(WALL_ID, text.wall, options.wall)] : []];
3933
+ };
3934
+ const area = () => ({
3935
+ placements: [
3936
+ ...options.probe ? [{ item: PROBE_ID2, position: offset({ position: EYE, yaw: 0 }, Math.min(chosen.distance, DRAWN_MAX)), asleep: true }] : [],
3937
+ ...options.wall ? [{ item: WALL_ID, position: [0, 0, WALL_AT], asleep: true }] : []
3938
+ ],
3939
+ view: { eye: EYE, target: [0, 1.2, -8] }
3940
+ });
3941
+ const scenarios = () => [
3942
+ {
3943
+ id: "sample_pipeline",
3944
+ name: text.scenarios.pipeline,
3945
+ run: async ({ expect }) => {
3946
+ const report = await engine.loadSamples([CALIBRATION_ID]);
3947
+ expect(report.failed.length === 0 && engine.sampleStatus(CALIBRATION_ID) === "ready", "the calibration files load and decode", { failed: report.failed });
3948
+ const started = [];
3949
+ const offStarted = engine.watchVoices((event) => void started.push(event));
3950
+ const handles = Array.from({ length: 6 }, (_, index) => engine.play(CALIBRATION_ID, { distance: 2, environment: index % 2 === 0 ? "indoor" : "outdoor" }));
3951
+ offStarted();
3952
+ expect(handles.every((handle) => handle?.kind === "sample"), "it plays the files, not the fallback", { kinds: handles.map((handle) => handle?.kind) });
3953
+ const events = started.filter((event) => event.id === CALIBRATION_ID);
3954
+ const takes = events.map((event) => event.layers?.find((layer) => layer.role === "close")?.url);
3955
+ expect(takes.length === 6 && takes.every((take, index) => index === 0 || take !== takes[index - 1]), "never the same take twice in a row", { takes });
3956
+ const tails = events.map((event) => event.layers?.find((layer) => layer.role === "tail")?.url ?? "");
3957
+ expect(tails[0]?.endsWith("tail_in.wav") === true && tails[1]?.endsWith("tail_out.wav") === true, "the tail follows the place", { tails });
3958
+ for (const handle of handles) handle?.stop();
3959
+ }
3960
+ },
3961
+ {
3962
+ id: "sample_criteria",
3963
+ name: text.scenarios.criteria,
3964
+ run: async ({ expect }) => {
3965
+ const previous = chosen.sound;
3966
+ chosen.sound = CALIBRATION_ID;
3967
+ const measured = await measure();
3968
+ chosen.sound = previous;
3969
+ for (const result of measured) if (result.id !== "C10") expect(result.pass === true, `${result.id}: ${result.target}`, { value: result.value, data: result.data });
3970
+ }
3971
+ },
3972
+ {
3973
+ id: "sample_loop",
3974
+ name: text.scenarios.loop,
3975
+ run: async ({ expect }) => {
3976
+ const report = await engine.loadSamples([CALIBRATION_LOOP_ID]);
3977
+ expect(report.failed.length === 0, "the loop takes load and decode", { failed: report.failed });
3978
+ engine.unlock();
3979
+ engine.level("ambience");
3980
+ const loop = engine.loop(CALIBRATION_LOOP_ID, { volume: 0.8 });
3981
+ const wait = (ms2) => new Promise((resolve) => setTimeout(resolve, ms2));
3982
+ const started = performance.now();
3983
+ while (engine.level("ambience") < 0.01 && performance.now() - started < 2e3) await wait(20);
3984
+ expect(performance.now() - started < 2e3, "the loop starts within 2 s", { ms: Math.round(performance.now() - started) });
3985
+ await wait(200);
3986
+ const levels = [];
3987
+ for (let index = 0; index < 60; index++) {
3988
+ levels.push(engine.level("ambience"));
3989
+ await wait(40);
3990
+ }
3991
+ loop.stop();
3992
+ const sorted = [...levels].sort((a, b) => a - b);
3993
+ const median = sorted[Math.floor(sorted.length / 2)] ?? 0;
3994
+ const lowest = sorted[0] ?? 0;
3995
+ const dip = lowest > 0 && median > 0 ? 20 * Math.log10(lowest / median) : -Infinity;
3996
+ expect(median > 0.01, "the loop sounds", { median });
3997
+ expect(dip >= -6, "no seam: the level never dips more than 6 dB where two takes cross", { dip: Number(dip.toFixed(1)), lowest, median, levels: levels.map((level) => Number(level.toFixed(3))) });
3998
+ await wait(200);
3999
+ expect(engine.level("ambience") < median / 4, "stop silences it", { after: engine.level("ambience") });
4000
+ }
4001
+ },
4002
+ {
4003
+ id: "sound_panel",
4004
+ name: text.scenarios.panel,
4005
+ run: ({ expect }) => {
4006
+ const categories = SFX_CATEGORIES.map((category) => soundsOf(category).length);
4007
+ expect(categories.every((count) => count > 0), "every category lists its sounds", { categories });
4008
+ expect(soundsOf("impactos").length >= SFX_MATERIALS.length * SFX_BLOWS.length, "the matrix has every material \xD7 blow");
4009
+ const pair = pairOf(CALIBRATION_ID);
4010
+ expect(pair.a === "sfx_pistol" && pair.b === CALIBRATION_ID, "A is the synthesized sound and B the file", pair);
4011
+ const clear = engine.planSample(CALIBRATION_ID, { position: [0, 1.6, -10], occlusion: 0, seed: 1 });
4012
+ const walled = engine.planSample(CALIBRATION_ID, { position: [0, 1.6, -10], occlusion: 1, seed: 1 });
4013
+ expect((walled?.cutoff ?? Infinity) < (clear?.cutoff ?? 0) / 5, "behind the wall the sound is muffled", { clear: clear?.cutoff, walled: walled?.cutoff });
4014
+ }
4015
+ }
4016
+ ];
4017
+ return {
4018
+ id: "sound_check_area",
4019
+ name: text.name,
4020
+ group: text.group,
4021
+ ground: { surface: "concrete_slab" },
4022
+ get engine() {
4023
+ return engine;
4024
+ },
4025
+ items: () => items(),
4026
+ area: () => area(),
4027
+ controls: () => controls(),
4028
+ metrics: () => metrics(),
4029
+ scenarios: () => scenarios(),
4030
+ measure,
4031
+ results: () => results,
4032
+ events: () => log,
4033
+ play,
4034
+ pair: () => pairOf(chosen.sound),
4035
+ verdicts: () => ({ ...verdicts }),
4036
+ approvals: () => [...approvals],
4037
+ // the engine (and its context) is made on the first play or measure, not when the room loads the module
4038
+ attach(lent) {
4039
+ host = lent;
4040
+ const shared = options.engine ? void 0 : lent.audio?.engine;
4041
+ if (shared && shared !== engine) {
4042
+ for (const bank of ownBanks) shared.register(bank);
4043
+ shared.addSampleSource(isCalibrationUrl, loader);
4044
+ engine = shared;
4045
+ }
4046
+ const offVoices = engine.watchVoices((event) => {
4047
+ log.push(event);
4048
+ if (log.length > LOG_LIMIT) log.splice(0, log.length - LOG_LIMIT);
4049
+ });
4050
+ lent.bench?.patch("sound", { options: soundOptions() });
4051
+ const off = lent.bench?.onChange(onChange);
4052
+ placeScenery();
4053
+ return () => {
4054
+ off?.();
4055
+ offVoices();
4056
+ host = null;
4057
+ };
4058
+ }
4059
+ };
4060
+ }
4061
+
2184
4062
  export {
2185
4063
  createRng,
2186
4064
  streamSeed,
@@ -2203,33 +4081,90 @@ export {
2203
4081
  busPriority,
2204
4082
  createVoiceManager,
2205
4083
  planSound,
2206
- LOOP_START_ABOVE,
2207
- LOOP_SMOOTHING,
2208
- createLoopState,
4084
+ SAMPLE_ENVIRONMENTS,
4085
+ DEFAULT_SAMPLE_FALLOFF,
4086
+ DEFAULT_CROSSOVER,
4087
+ DEFAULT_SAMPLE_PITCH,
4088
+ DEFAULT_TAIL_GAIN,
4089
+ DEFAULT_SAMPLE_CUTOFF_K,
4090
+ OPEN_CUTOFF,
4091
+ LAYER_FLOOR,
4092
+ pickTake,
4093
+ farMixAt,
4094
+ crossGains,
4095
+ sampleCutoff,
4096
+ sampleUrls,
4097
+ tierFor,
4098
+ planSample,
4099
+ CALIBRATION_ID,
4100
+ encodeWav,
4101
+ CALIBRATION_SOUND,
4102
+ CALIBRATION_LOOP_ID,
4103
+ CALIBRATION_LOOP_SOUND,
4104
+ isCalibrationUrl,
4105
+ calibrationLoader,
4106
+ createSoundRegistry,
2209
4107
  MIX_PROFILES,
2210
4108
  DEFAULT_MIX,
2211
4109
  resolveMix,
2212
4110
  busGain,
2213
- createSoundRegistry,
2214
- GAME_SFX_CLASSES,
2215
- GAME_SFX_FALLBACK,
2216
- noiseClassRecipe,
2217
- GAME_SFX_BANK,
2218
- LIBRARY_SOUNDS,
2219
- LIBRARY_LOOPS,
2220
- LIBRARY_BANK,
2221
- retunePlan,
2222
- createSetPicker,
2223
4111
  fillNoise,
2224
4112
  fillImpulse,
2225
4113
  bufferOf,
2226
4114
  buildChain,
2227
4115
  globalContext,
2228
4116
  unlockContext,
4117
+ LOOP_START_ABOVE,
4118
+ LOOP_SMOOTHING,
4119
+ createLoopState,
4120
+ DEFAULT_LOOP_CROSSFADE,
4121
+ loopCrossfade,
4122
+ CROSSFADE_STEPS,
4123
+ equalPowerIn,
2229
4124
  realize,
4125
+ retunePlan,
4126
+ createSetPicker,
4127
+ fetchLoader,
4128
+ inlineLoader,
4129
+ createSampleStore,
4130
+ realizeSample,
4131
+ sampleLength,
4132
+ limiterCurve2 as limiterCurve,
2230
4133
  createAudioEngine,
4134
+ dbOf,
4135
+ peakOf,
4136
+ peakIndex,
4137
+ onsetIndex,
4138
+ rmsDb,
4139
+ centroidHz,
4140
+ balanceOf,
4141
+ ringSeconds,
4142
+ countHits,
4143
+ endDropDb,
4144
+ CRITERIA,
4145
+ CRITERIA_TARGETS,
4146
+ measureCriteria,
4147
+ recordOutput,
4148
+ SFX_CATEGORIES,
4149
+ SFX_CATALOG,
4150
+ SFX_MATERIALS,
4151
+ SFX_BLOWS,
4152
+ impactSoundId,
4153
+ SFX_IMPACTS,
4154
+ sfxState,
4155
+ GAME_SFX_CLASSES,
4156
+ GAME_SFX_FALLBACK,
4157
+ noiseClassRecipe,
4158
+ GAME_SFX_BANK,
4159
+ LIBRARY_SOUNDS,
4160
+ LIBRARY_LOOPS,
4161
+ LIBRARY_BANK,
2231
4162
  audioBenchTextOf,
2232
4163
  BENCH_BANK,
2233
- createAudioTestModule
4164
+ createAudioTestModule,
4165
+ soundCheckTextOf,
4166
+ SOUND_STRENGTHS,
4167
+ CALIBRATION_CATEGORY,
4168
+ createSoundCheckModule
2234
4169
  };
2235
- //# sourceMappingURL=chunk-DZITVFMJ.js.map
4170
+ //# sourceMappingURL=chunk-7TLFY7VO.js.map