@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.
- package/README.md +20 -0
- package/assets/sfx/CREDITOS.md +1046 -0
- package/assets/sfx/ambiente/ambience_city_day_01.ogg +0 -0
- package/assets/sfx/ambiente/ambience_city_day_02.ogg +0 -0
- package/assets/sfx/ambiente/ambience_construction_01.ogg +0 -0
- package/assets/sfx/ambiente/ambience_night_01.ogg +0 -0
- package/assets/sfx/ambiente/ambience_room_tone_01.ogg +0 -0
- package/assets/sfx/ambiente/ambience_room_tone_02.ogg +0 -0
- package/assets/sfx/ambiente/ambience_rural_day_01.ogg +0 -0
- package/assets/sfx/ambiente/ambience_rural_day_02.ogg +0 -0
- package/assets/sfx/ambiente/rain_loop_01.ogg +0 -0
- package/assets/sfx/ambiente/water_river_loop_01.ogg +0 -0
- package/assets/sfx/ambiente/water_river_loop_02.ogg +0 -0
- package/assets/sfx/ambiente/water_river_loop_03.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_01.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_02.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_03.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_04.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_05.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_06.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_07.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_08.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_09.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_10.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_11.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_12.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_13.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_14.ogg +0 -0
- package/assets/sfx/ambiente/water_splash_15.ogg +0 -0
- package/assets/sfx/armas/bolt_lift_medium_01.ogg +0 -0
- package/assets/sfx/armas/bolt_lift_medium_02.ogg +0 -0
- package/assets/sfx/armas/bolt_lift_medium_03.ogg +0 -0
- package/assets/sfx/armas/bolt_lift_medium_04.ogg +0 -0
- package/assets/sfx/armas/bolt_lift_medium_05.ogg +0 -0
- package/assets/sfx/armas/bolt_lock_medium_01.ogg +0 -0
- package/assets/sfx/armas/bolt_lock_medium_02.ogg +0 -0
- package/assets/sfx/armas/bolt_lock_medium_03.ogg +0 -0
- package/assets/sfx/armas/bolt_lock_medium_04.ogg +0 -0
- package/assets/sfx/armas/bolt_lock_medium_05.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_heavy_01.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_medium_01.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_medium_02.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_medium_03.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_medium_04.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_medium_05.ogg +0 -0
- package/assets/sfx/armas/bolt_pull_medium_06.ogg +0 -0
- package/assets/sfx/armas/bolt_push_heavy_01.ogg +0 -0
- package/assets/sfx/armas/bolt_push_medium_01.ogg +0 -0
- package/assets/sfx/armas/bolt_push_medium_02.ogg +0 -0
- package/assets/sfx/armas/bolt_push_medium_03.ogg +0 -0
- package/assets/sfx/armas/bolt_push_medium_04.ogg +0 -0
- package/assets/sfx/armas/bolt_push_medium_05.ogg +0 -0
- package/assets/sfx/armas/bolt_push_medium_06.ogg +0 -0
- package/assets/sfx/armas/casing_drop_concreto_01.ogg +0 -0
- package/assets/sfx/armas/casing_drop_concreto_02.ogg +0 -0
- package/assets/sfx/armas/casing_drop_concreto_03.ogg +0 -0
- package/assets/sfx/armas/casing_drop_metal_01.ogg +0 -0
- package/assets/sfx/armas/casing_drop_metal_02.ogg +0 -0
- package/assets/sfx/armas/casing_drop_metal_03.ogg +0 -0
- package/assets/sfx/armas/casing_drop_terra_01.ogg +0 -0
- package/assets/sfx/armas/casing_drop_terra_02.ogg +0 -0
- package/assets/sfx/armas/casing_drop_terra_03.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_light_01.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_light_02.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_light_03.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_light_04.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_medium_01.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_medium_02.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_medium_03.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_medium_04.ogg +0 -0
- package/assets/sfx/armas/charging_handle_pull_medium_05.ogg +0 -0
- package/assets/sfx/armas/charging_handle_release_medium_01.ogg +0 -0
- package/assets/sfx/armas/charging_handle_release_medium_02.ogg +0 -0
- package/assets/sfx/armas/charging_handle_release_medium_03.ogg +0 -0
- package/assets/sfx/armas/charging_handle_release_medium_04.ogg +0 -0
- package/assets/sfx/armas/charging_handle_release_medium_05.ogg +0 -0
- package/assets/sfx/armas/cylinder_close_light_01.ogg +0 -0
- package/assets/sfx/armas/cylinder_close_light_02.ogg +0 -0
- package/assets/sfx/armas/cylinder_close_light_03.ogg +0 -0
- package/assets/sfx/armas/cylinder_close_light_04.ogg +0 -0
- package/assets/sfx/armas/cylinder_close_light_05.ogg +0 -0
- package/assets/sfx/armas/cylinder_eject_light_01.ogg +0 -0
- package/assets/sfx/armas/cylinder_eject_light_02.ogg +0 -0
- package/assets/sfx/armas/cylinder_eject_light_03.ogg +0 -0
- package/assets/sfx/armas/cylinder_open_light_01.ogg +0 -0
- package/assets/sfx/armas/cylinder_open_light_02.ogg +0 -0
- package/assets/sfx/armas/cylinder_open_light_03.ogg +0 -0
- package/assets/sfx/armas/cylinder_open_light_04.ogg +0 -0
- package/assets/sfx/armas/cylinder_open_light_05.ogg +0 -0
- package/assets/sfx/armas/lever_close_medium_01.ogg +0 -0
- package/assets/sfx/armas/lever_close_medium_02.ogg +0 -0
- package/assets/sfx/armas/lever_open_medium_01.ogg +0 -0
- package/assets/sfx/armas/lever_open_medium_02.ogg +0 -0
- package/assets/sfx/armas/mag_out_heavy_01.ogg +0 -0
- package/assets/sfx/armas/mag_out_heavy_02.ogg +0 -0
- package/assets/sfx/armas/mag_out_light_01.ogg +0 -0
- package/assets/sfx/armas/mag_out_light_02.ogg +0 -0
- package/assets/sfx/armas/mag_out_light_03.ogg +0 -0
- package/assets/sfx/armas/mag_out_light_04.ogg +0 -0
- package/assets/sfx/armas/mag_out_medium_01.ogg +0 -0
- package/assets/sfx/armas/mag_out_medium_02.ogg +0 -0
- package/assets/sfx/armas/mag_out_medium_03.ogg +0 -0
- package/assets/sfx/armas/mag_seat_heavy_01.ogg +0 -0
- package/assets/sfx/armas/mag_seat_heavy_02.ogg +0 -0
- package/assets/sfx/armas/mag_seat_light_01.ogg +0 -0
- package/assets/sfx/armas/mag_seat_light_02.ogg +0 -0
- package/assets/sfx/armas/mag_seat_light_03.ogg +0 -0
- package/assets/sfx/armas/mag_seat_light_04.ogg +0 -0
- package/assets/sfx/armas/mag_seat_light_05.ogg +0 -0
- package/assets/sfx/armas/mag_seat_light_06.ogg +0 -0
- package/assets/sfx/armas/mag_seat_medium_01.ogg +0 -0
- package/assets/sfx/armas/mag_seat_medium_02.ogg +0 -0
- package/assets/sfx/armas/mag_seat_medium_03.ogg +0 -0
- package/assets/sfx/armas/pistol_22lr_close_01.ogg +0 -0
- package/assets/sfx/armas/pistol_22lr_close_02.ogg +0 -0
- package/assets/sfx/armas/pistol_22lr_far_01.ogg +0 -0
- package/assets/sfx/armas/pistol_22lr_far_02.ogg +0 -0
- package/assets/sfx/armas/pistol_22lr_far_03.ogg +0 -0
- package/assets/sfx/armas/pistol_22lr_far_04.ogg +0 -0
- package/assets/sfx/armas/pistol_45_close_01.ogg +0 -0
- package/assets/sfx/armas/pistol_45_close_02.ogg +0 -0
- package/assets/sfx/armas/pistol_45_close_03.ogg +0 -0
- package/assets/sfx/armas/pistol_45_close_04.ogg +0 -0
- package/assets/sfx/armas/pistol_45_close_05.ogg +0 -0
- package/assets/sfx/armas/pistol_45_far_01.ogg +0 -0
- package/assets/sfx/armas/pistol_45_far_02.ogg +0 -0
- package/assets/sfx/armas/pistol_45_far_03.ogg +0 -0
- package/assets/sfx/armas/pistol_45_far_04.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_close_01.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_close_02.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_close_03.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_close_04.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_close_05.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_close_06.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_far_01.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_far_02.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_far_03.ogg +0 -0
- package/assets/sfx/armas/pistol_9mm_far_04.ogg +0 -0
- package/assets/sfx/armas/pump_back_heavy_01.ogg +0 -0
- package/assets/sfx/armas/pump_back_heavy_02.ogg +0 -0
- package/assets/sfx/armas/pump_back_heavy_03.ogg +0 -0
- package/assets/sfx/armas/pump_back_heavy_04.ogg +0 -0
- package/assets/sfx/armas/pump_back_heavy_05.ogg +0 -0
- package/assets/sfx/armas/pump_forward_heavy_01.ogg +0 -0
- package/assets/sfx/armas/pump_forward_heavy_02.ogg +0 -0
- package/assets/sfx/armas/pump_forward_heavy_03.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_close_01.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_close_02.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_close_03.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_close_04.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_far_01.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_far_02.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_far_03.ogg +0 -0
- package/assets/sfx/armas/revolver_38_357_far_04.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_close_01.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_close_02.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_close_03.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_close_04.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_close_05.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_close_06.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_far_01.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_far_02.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_far_03.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_far_04.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_far_05.ogg +0 -0
- package/assets/sfx/armas/rifle_308_3006_far_06.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_close_01.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_close_02.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_close_03.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_close_04.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_close_05.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_far_01.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_far_02.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_far_03.ogg +0 -0
- package/assets/sfx/armas/rifle_5_56_far_04.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_01.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_02.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_03.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_04.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_05.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_06.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_07.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_08.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_09.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_10.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_11.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_close_12.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_far_01.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_far_02.ogg +0 -0
- package/assets/sfx/armas/rifle_7_62x39_far_03.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_01.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_02.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_03.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_04.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_05.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_06.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_07.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_08.ogg +0 -0
- package/assets/sfx/armas/shell_insert_heavy_09.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_close_01.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_close_02.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_close_03.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_close_04.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_close_05.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_close_06.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_far_01.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_far_02.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_far_03.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_far_04.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_far_05.ogg +0 -0
- package/assets/sfx/armas/shotgun_12_far_06.ogg +0 -0
- package/assets/sfx/armas/slide_release_light_01.ogg +0 -0
- package/assets/sfx/armas/slide_release_light_02.ogg +0 -0
- package/assets/sfx/armas/slide_release_light_03.ogg +0 -0
- package/assets/sfx/armas/slide_release_light_04.ogg +0 -0
- package/assets/sfx/armas/slide_release_light_05.ogg +0 -0
- package/assets/sfx/armas/slide_release_light_06.ogg +0 -0
- package/assets/sfx/armas/slide_release_medium_01.ogg +0 -0
- package/assets/sfx/armas/slide_release_medium_02.ogg +0 -0
- package/assets/sfx/armas/slide_release_medium_03.ogg +0 -0
- package/assets/sfx/armas/slide_release_medium_04.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_01.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_02.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_03.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_04.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_05.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_06.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_close_07.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_far_01.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_far_02.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_far_03.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_far_04.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_far_05.ogg +0 -0
- package/assets/sfx/armas/sniper_338_300wm_far_06.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_01.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_02.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_03.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_04.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_05.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_06.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_07.ogg +0 -0
- package/assets/sfx/armas/speedloader_light_08.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_close_01.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_close_02.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_close_03.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_close_04.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_close_05.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_far_01.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_far_02.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_far_03.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_far_04.ogg +0 -0
- package/assets/sfx/armas/suppressed_pistol_far_05.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_close_01.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_close_02.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_close_03.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_close_04.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_far_01.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_far_02.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_far_03.ogg +0 -0
- package/assets/sfx/armas/suppressed_rifle_far_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_05.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_06.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_mixed_07.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_05.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_06.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_07.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_08.ogg +0 -0
- package/assets/sfx/explosoes-fogo/debris_rain_stone_09.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_big_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_big_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_big_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_big_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_big_05.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_car_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_car_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_car_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_car_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_far_close_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_far_close_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_far_close_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_far_close_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_flashbang_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_flashbang_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_grenade_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_grenade_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_grenade_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_grenade_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_grenade_05.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_grenade_06.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_05.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_06.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_07.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_08.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_09.ogg +0 -0
- package/assets/sfx/explosoes-fogo/explosion_small_bang_10.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_crackle_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_crackle_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_crackle_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_crackle_05.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_crackle_07.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_extinguish_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_extinguish_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_ignite_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_ignite_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_ignite_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_ignite_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_loop_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_loop_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_loop_04.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_loop_small_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_pop_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_pop_02.ogg +0 -0
- package/assets/sfx/explosoes-fogo/fire_pop_03.ogg +0 -0
- package/assets/sfx/explosoes-fogo/flamethrower_loop_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/gas_leak_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/molotov_break_ignite_01.ogg +0 -0
- package/assets/sfx/explosoes-fogo/molotov_break_ignite_02.ogg +0 -0
- package/assets/sfx/impactos/ceramic_hit_close_01.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_01.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_02.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_03.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_04.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_05.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_06.ogg +0 -0
- package/assets/sfx/impactos/concrete_block_drag_close_07.ogg +0 -0
- package/assets/sfx/impactos/crack_close_01.ogg +0 -0
- package/assets/sfx/impactos/crack_close_02.ogg +0 -0
- package/assets/sfx/impactos/crack_close_03.ogg +0 -0
- package/assets/sfx/impactos/crack_close_04.ogg +0 -0
- package/assets/sfx/impactos/crack_close_05.ogg +0 -0
- package/assets/sfx/impactos/crack_close_06.ogg +0 -0
- package/assets/sfx/impactos/crack_close_07.ogg +0 -0
- package/assets/sfx/impactos/crack_close_08.ogg +0 -0
- package/assets/sfx/impactos/crack_close_09.ogg +0 -0
- package/assets/sfx/impactos/crack_close_10.ogg +0 -0
- package/assets/sfx/impactos/crumble_close_01.ogg +0 -0
- package/assets/sfx/impactos/crumble_close_02.ogg +0 -0
- package/assets/sfx/impactos/crumble_close_03.ogg +0 -0
- package/assets/sfx/impactos/crumble_close_04.ogg +0 -0
- package/assets/sfx/impactos/crumble_close_05.ogg +0 -0
- package/assets/sfx/impactos/flesh_fruit_splat_close_01.ogg +0 -0
- package/assets/sfx/impactos/flesh_fruit_splat_close_02.ogg +0 -0
- package/assets/sfx/impactos/flesh_fruit_splat_close_03.ogg +0 -0
- package/assets/sfx/impactos/furniture_push_wood_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_heavy_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_heavy_close_02.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_heavy_close_03.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_heavy_close_04.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_heavy_close_05.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_light_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_light_close_02.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_light_close_03.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_light_close_04.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_light_close_05.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_medium_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_medium_close_02.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_medium_close_03.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_medium_close_04.ogg +0 -0
- package/assets/sfx/impactos/glass_blunt_medium_close_05.ogg +0 -0
- package/assets/sfx/impactos/glass_bottle_break_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_debris_fall_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_debris_fall_close_02.ogg +0 -0
- package/assets/sfx/impactos/glass_debris_fall_close_03.ogg +0 -0
- package/assets/sfx/impactos/glass_debris_fall_close_04.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_01.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_02.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_03.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_04.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_05.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_06.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_07.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_08.ogg +0 -0
- package/assets/sfx/impactos/glass_shatter_close_09.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_21.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_22.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_23.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_24.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_25.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_26.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_27.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_28.ogg +0 -0
- package/assets/sfx/impactos/gravel_hit_close_29.ogg +0 -0
- package/assets/sfx/impactos/impact_generic_light_close_01.ogg +0 -0
- package/assets/sfx/impactos/impact_generic_light_close_02.ogg +0 -0
- package/assets/sfx/impactos/impact_generic_light_close_03.ogg +0 -0
- package/assets/sfx/impactos/impact_generic_light_close_04.ogg +0 -0
- package/assets/sfx/impactos/impact_generic_light_close_05.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_01.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_02.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_03.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_04.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_05.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_06.ogg +0 -0
- package/assets/sfx/impactos/masonry_blunt_close_07.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_01.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_02.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_03.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_04.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_05.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_21.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_22.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_23.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_24.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_25.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_26.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_27.ogg +0 -0
- package/assets/sfx/impactos/masonry_bullet_close_28.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_heavy_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_heavy_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_heavy_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_heavy_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_heavy_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_light_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_light_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_light_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_light_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_light_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_medium_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_medium_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_medium_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_medium_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_blunt_medium_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_06.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_21.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_22.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_23.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_24.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_25.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_26.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_27.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_28.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_29.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_30.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_31.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_32.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_33.ogg +0 -0
- package/assets/sfx/impactos/metal_bullet_close_34.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_06.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_07.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_08.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_09.ogg +0 -0
- package/assets/sfx/impactos/metal_fall_close_10.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_01.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_02.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_03.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_04.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_05.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_06.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_07.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_08.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_09.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_10.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_11.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_12.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_13.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_14.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_15.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_16.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_17.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_18.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_19.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_20.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_21.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_22.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_23.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_24.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_25.ogg +0 -0
- package/assets/sfx/impactos/metal_thin_close_26.ogg +0 -0
- package/assets/sfx/impactos/paper_tear_close_01.ogg +0 -0
- package/assets/sfx/impactos/paper_tear_close_02.ogg +0 -0
- package/assets/sfx/impactos/plastic_hit_close_01.ogg +0 -0
- package/assets/sfx/impactos/plastic_hit_close_02.ogg +0 -0
- package/assets/sfx/impactos/plastic_hit_close_03.ogg +0 -0
- package/assets/sfx/impactos/plastic_hit_close_04.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_21.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_22.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_23.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_24.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_25.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_26.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_27.ogg +0 -0
- package/assets/sfx/impactos/ricochet_metal_close_28.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_01.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_02.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_03.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_04.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_05.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_06.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_07.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_08.ogg +0 -0
- package/assets/sfx/impactos/rubble_falling_close_09.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_01.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_02.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_03.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_04.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_05.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_06.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_07.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_08.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_09.ogg +0 -0
- package/assets/sfx/impactos/soft_bullet_close_10.ogg +0 -0
- package/assets/sfx/impactos/soil_bullet_close_21.ogg +0 -0
- package/assets/sfx/impactos/soil_bullet_close_22.ogg +0 -0
- package/assets/sfx/impactos/soil_bullet_close_23.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_heavy_close_01.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_heavy_close_02.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_heavy_close_03.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_heavy_close_04.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_heavy_close_05.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_light_close_01.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_light_close_02.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_light_close_03.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_light_close_04.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_light_close_05.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_medium_close_01.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_medium_close_02.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_medium_close_03.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_medium_close_04.ogg +0 -0
- package/assets/sfx/impactos/wood_blunt_medium_close_05.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_01.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_02.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_03.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_04.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_05.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_06.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_07.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_08.ogg +0 -0
- package/assets/sfx/impactos/wood_fall_close_09.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_01.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_02.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_03.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_04.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_05.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_06.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_07.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_08.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_09.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_10.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_11.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_12.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_13.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_14.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_21.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_22.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_23.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_24.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_25.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_26.ogg +0 -0
- package/assets/sfx/impactos/wood_hit_close_27.ogg +0 -0
- package/assets/sfx/itens-portas/backpack_open_shut_01.ogg +0 -0
- package/assets/sfx/itens-portas/backpack_open_shut_02.ogg +0 -0
- package/assets/sfx/itens-portas/backpack_open_shut_03.ogg +0 -0
- package/assets/sfx/itens-portas/backpack_open_shut_04.ogg +0 -0
- package/assets/sfx/itens-portas/backpack_open_shut_05.ogg +0 -0
- package/assets/sfx/itens-portas/backpack_open_shut_06.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_01.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_02.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_03.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_04.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_05.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_06.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_07.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_08.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_09.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_10.ogg +0 -0
- package/assets/sfx/itens-portas/book_open_shut_11.ogg +0 -0
- package/assets/sfx/itens-portas/door_creak_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_creak_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_creak_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_creak_06.ogg +0 -0
- package/assets/sfx/itens-portas/door_creak_07.ogg +0 -0
- package/assets/sfx/itens-portas/door_glass_sliding_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_glass_sliding_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_glass_sliding_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_glass_sliding_04.ogg +0 -0
- package/assets/sfx/itens-portas/door_knock_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_04.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_05.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_06.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_07.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_08.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_09.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_10.ogg +0 -0
- package/assets/sfx/itens-portas/door_lock_unlock_11.ogg +0 -0
- package/assets/sfx/itens-portas/door_locked_rattle_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_locked_rattle_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_locked_rattle_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_04.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_05.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_06.ogg +0 -0
- package/assets/sfx/itens-portas/door_metal_open_shut_07.ogg +0 -0
- package/assets/sfx/itens-portas/door_slam_wood_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_slam_wood_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_slam_wood_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_slam_wood_04.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_open_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_open_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_open_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_open_04.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_01.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_02.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_03.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_04.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_05.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_06.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_07.ogg +0 -0
- package/assets/sfx/itens-portas/door_wood_shut_08.ogg +0 -0
- package/assets/sfx/itens-portas/drawer_open_01.ogg +0 -0
- package/assets/sfx/itens-portas/drawer_open_02.ogg +0 -0
- package/assets/sfx/itens-portas/drawer_shut_01.ogg +0 -0
- package/assets/sfx/itens-portas/drawer_shut_02.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_bag_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_bag_02.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_glass_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_metal_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_metal_02.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_metal_03.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_metal_04.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_metal_05.ogg +0 -0
- package/assets/sfx/itens-portas/item_drop_paper_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_coins_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_coins_02.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_generic_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_generic_02.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_generic_03.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_generic_04.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_leather_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_leather_02.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_leather_03.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_leather_04.ogg +0 -0
- package/assets/sfx/itens-portas/item_pickup_leather_05.ogg +0 -0
- package/assets/sfx/itens-portas/item_setdown_01.ogg +0 -0
- package/assets/sfx/itens-portas/item_setdown_02.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_01.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_02.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_03.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_04.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_05.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_06.ogg +0 -0
- package/assets/sfx/itens-portas/keys_jingle_07.ogg +0 -0
- package/assets/sfx/itens-portas/lever_pull_01.ogg +0 -0
- package/assets/sfx/itens-portas/lever_pull_02.ogg +0 -0
- package/assets/sfx/itens-portas/lever_pull_03.ogg +0 -0
- package/assets/sfx/itens-portas/lever_pull_04.ogg +0 -0
- package/assets/sfx/itens-portas/lever_pull_05.ogg +0 -0
- package/assets/sfx/itens-portas/lever_pull_06.ogg +0 -0
- package/assets/sfx/itens-portas/metal_latch_01.ogg +0 -0
- package/assets/sfx/itens-portas/metal_latch_02.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_01.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_02.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_03.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_04.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_05.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_06.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_07.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_08.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_09.ogg +0 -0
- package/assets/sfx/itens-portas/plates_hit_10.ogg +0 -0
- package/assets/sfx/itens-portas/plates_slide_01.ogg +0 -0
- package/assets/sfx/itens-portas/plates_slide_02.ogg +0 -0
- package/assets/sfx/itens-portas/plates_slide_03.ogg +0 -0
- package/assets/sfx/itens-portas/plates_slide_04.ogg +0 -0
- package/assets/sfx/itens-portas/saw_wood_01.ogg +0 -0
- package/assets/sfx/itens-portas/switch_click_01.ogg +0 -0
- package/assets/sfx/itens-portas/switch_click_02.ogg +0 -0
- package/assets/sfx/itens-portas/switch_click_03.ogg +0 -0
- package/assets/sfx/itens-portas/switch_click_04.ogg +0 -0
- package/assets/sfx/itens-portas/toilet_flush_01.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_01.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_02.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_03.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_04.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_05.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_06.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_07.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_08.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_09.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_10.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_11.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_12.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_13.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_14.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_15.ogg +0 -0
- package/assets/sfx/itens-portas/tools_handling_16.ogg +0 -0
- package/assets/sfx/itens-portas/water_drip_01.ogg +0 -0
- package/assets/sfx/itens-portas/water_drip_02.ogg +0 -0
- package/assets/sfx/itens-portas/water_drip_03.ogg +0 -0
- package/assets/sfx/itens-portas/water_drip_04.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_01.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_02.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_03.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_04.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_05.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_06.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_07.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_08.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_09.ogg +0 -0
- package/assets/sfx/itens-portas/water_faucet_10.ogg +0 -0
- package/assets/sfx/manifest.json +11959 -0
- package/assets/sfx/personagem/axe_chop_01.ogg +0 -0
- package/assets/sfx/personagem/axe_chop_02.ogg +0 -0
- package/assets/sfx/personagem/blunt_hit_metal_01.ogg +0 -0
- package/assets/sfx/personagem/blunt_hit_metal_02.ogg +0 -0
- package/assets/sfx/personagem/blunt_hit_metal_03.ogg +0 -0
- package/assets/sfx/personagem/blunt_hit_metal_04.ogg +0 -0
- package/assets/sfx/personagem/blunt_hit_metal_05.ogg +0 -0
- package/assets/sfx/personagem/body_fall_01.ogg +0 -0
- package/assets/sfx/personagem/body_fall_02.ogg +0 -0
- package/assets/sfx/personagem/body_fall_03.ogg +0 -0
- package/assets/sfx/personagem/body_fall_04.ogg +0 -0
- package/assets/sfx/personagem/body_fall_05.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_01.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_02.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_03.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_04.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_05.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_06.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_07.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_08.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_09.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_10.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_11.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_12.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_13.ogg +0 -0
- package/assets/sfx/personagem/cloth_rustle_14.ogg +0 -0
- package/assets/sfx/personagem/drink_gulp_01.ogg +0 -0
- package/assets/sfx/personagem/drink_gulp_02.ogg +0 -0
- package/assets/sfx/personagem/drink_gulp_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_carpet_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_carpet_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_carpet_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_carpet_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_carpet_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_run_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_run_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_run_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_run_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_run_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_walk_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_walk_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_walk_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_walk_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_concrete_walk_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_run_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_run_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_run_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_run_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_run_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_walk_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_walk_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_walk_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_walk_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_dirt_walk_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_06.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_07.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_08.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_09.ogg +0 -0
- package/assets/sfx/personagem/footstep_generic_alt_10.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt2_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt2_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt2_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt2_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_run_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_run_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_run_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_run_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_run_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_walk_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_walk_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_walk_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_walk_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_grass_walk_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_06.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_07.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_08.ogg +0 -0
- package/assets/sfx/personagem/footstep_hard_alt_09.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_run_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_run_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_run_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_run_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_run_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_walk_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_walk_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_walk_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_walk_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_metal_walk_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_run_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_run_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_run_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_run_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_run_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_walk_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_walk_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_walk_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_walk_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_snow_walk_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_alt_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_alt_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_alt_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_alt_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_alt_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_run_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_run_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_run_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_run_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_run_05.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_walk_01.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_walk_02.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_walk_03.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_walk_04.ogg +0 -0
- package/assets/sfx/personagem/footstep_wood_walk_05.ogg +0 -0
- package/assets/sfx/personagem/frying_pan_hit_01.ogg +0 -0
- package/assets/sfx/personagem/frying_pan_hit_02.ogg +0 -0
- package/assets/sfx/personagem/frying_pan_hit_03.ogg +0 -0
- package/assets/sfx/personagem/grab_01.ogg +0 -0
- package/assets/sfx/personagem/kick_hit_01.ogg +0 -0
- package/assets/sfx/personagem/kick_hit_02.ogg +0 -0
- package/assets/sfx/personagem/kick_hit_03.ogg +0 -0
- package/assets/sfx/personagem/kick_hit_04.ogg +0 -0
- package/assets/sfx/personagem/kick_hit_05.ogg +0 -0
- package/assets/sfx/personagem/knife_draw_01.ogg +0 -0
- package/assets/sfx/personagem/knife_draw_02.ogg +0 -0
- package/assets/sfx/personagem/knife_draw_03.ogg +0 -0
- package/assets/sfx/personagem/knife_scrape_01.ogg +0 -0
- package/assets/sfx/personagem/knife_slash_01.ogg +0 -0
- package/assets/sfx/personagem/knife_slash_02.ogg +0 -0
- package/assets/sfx/personagem/land_concrete_01.ogg +0 -0
- package/assets/sfx/personagem/land_concrete_02.ogg +0 -0
- package/assets/sfx/personagem/land_dirt_01.ogg +0 -0
- package/assets/sfx/personagem/land_dirt_02.ogg +0 -0
- package/assets/sfx/personagem/land_grass_01.ogg +0 -0
- package/assets/sfx/personagem/land_grass_02.ogg +0 -0
- package/assets/sfx/personagem/land_metal_01.ogg +0 -0
- package/assets/sfx/personagem/land_metal_02.ogg +0 -0
- package/assets/sfx/personagem/land_snow_01.ogg +0 -0
- package/assets/sfx/personagem/land_snow_02.ogg +0 -0
- package/assets/sfx/personagem/land_wood_01.ogg +0 -0
- package/assets/sfx/personagem/land_wood_02.ogg +0 -0
- package/assets/sfx/personagem/player_breath_run_01.ogg +0 -0
- package/assets/sfx/personagem/player_breath_run_02.ogg +0 -0
- package/assets/sfx/personagem/player_breath_run_03.ogg +0 -0
- package/assets/sfx/personagem/player_breath_run_04.ogg +0 -0
- package/assets/sfx/personagem/player_breath_run_05.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_01.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_02.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_03.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_04.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_05.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_06.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_07.ogg +0 -0
- package/assets/sfx/personagem/player_death_female_08.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_01.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_02.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_03.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_04.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_05.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_06.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_07.ogg +0 -0
- package/assets/sfx/personagem/player_death_male_08.ogg +0 -0
- package/assets/sfx/personagem/player_effort_01.ogg +0 -0
- package/assets/sfx/personagem/player_effort_02.ogg +0 -0
- package/assets/sfx/personagem/player_effort_03.ogg +0 -0
- package/assets/sfx/personagem/player_effort_04.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_female_01.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_female_02.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_female_03.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_female_04.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_female_05.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_female_06.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_male_01.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_male_02.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_male_03.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_male_04.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_male_05.ogg +0 -0
- package/assets/sfx/personagem/player_hurt_male_06.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_01.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_02.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_03.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_04.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_05.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_06.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_07.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_08.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_09.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_alt_10.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_body_01.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_body_02.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_body_03.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_body_04.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_body_05.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_body_06.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_face_01.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_face_02.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_face_03.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_face_04.ogg +0 -0
- package/assets/sfx/personagem/punch_hit_face_05.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_01.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_02.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_03.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_04.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_05.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_06.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_07.ogg +0 -0
- package/assets/sfx/personagem/punch_swing_08.ogg +0 -0
- package/assets/sfx/personagem/scream_01.ogg +0 -0
- package/assets/sfx/personagem/scream_02.ogg +0 -0
- package/assets/sfx/personagem/scream_03.ogg +0 -0
- package/assets/sfx/personagem/scream_04.ogg +0 -0
- package/assets/sfx/personagem/slap_01.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_01.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_02.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_03.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_04.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_05.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_06.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_07.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_08.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_09.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_10.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_11.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_12.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_13.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_14.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_15.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_16.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_17.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_18.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_19.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_20.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_21.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_22.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_23.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_24.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_25.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_26.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_27.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_28.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_29.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_30.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_31.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_32.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_33.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_34.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_35.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_36.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_37.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_38.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_39.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_40.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_41.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_42.ogg +0 -0
- package/assets/sfx/personagem/swing_whoosh_alt_43.ogg +0 -0
- package/assets/sfx/personagem/zombie_creature_01.ogg +0 -0
- package/assets/sfx/personagem/zombie_creature_02.ogg +0 -0
- package/assets/sfx/personagem/zombie_creature_03.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_01.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_02.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_03.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_04.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_05.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_06.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_07.ogg +0 -0
- package/assets/sfx/personagem/zombie_death_08.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_01.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_02.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_03.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_04.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_05.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_06.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_07.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_08.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_09.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_10.ogg +0 -0
- package/assets/sfx/personagem/zombie_groan_11.ogg +0 -0
- package/assets/sfx/veiculos/car_door_open_01.ogg +0 -0
- package/assets/sfx/veiculos/car_door_shut_01.ogg +0 -0
- package/assets/sfx/veiculos/car_gear_shift_01.ogg +0 -0
- package/assets/sfx/veiculos/car_trunk_shut_01.ogg +0 -0
- package/assets/sfx/veiculos/car_window_01.ogg +0 -0
- package/assets/sfx/veiculos/car_window_02.ogg +0 -0
- package/assets/sfx/veiculos/engine_loop_car_high_01.ogg +0 -0
- package/assets/sfx/veiculos/engine_loop_car_idle_01.ogg +0 -0
- package/assets/sfx/veiculos/engine_start_run_stop_01.ogg +0 -0
- package/assets/sfx/veiculos/engine_start_run_stop_02.ogg +0 -0
- package/dist/{chunk-DZITVFMJ.js → chunk-7TLFY7VO.js} +1985 -50
- package/dist/chunk-7TLFY7VO.js.map +1 -0
- package/dist/index.d.ts +223 -3
- package/dist/index.global.js +3098 -949
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +875 -5
- package/dist/index.js.map +1 -1
- package/dist/{testing-BZQid7h0.d.ts → locale-BugSe8dA.d.ts} +479 -61
- package/dist/testing.d.ts +82 -2
- package/dist/testing.js +11 -3
- package/package.json +9 -6
- 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: {
|
|
190
|
-
|
|
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: {
|
|
196
|
-
|
|
197
|
-
|
|
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 = "
|
|
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(
|
|
733
|
+
compressor.connect(output);
|
|
646
734
|
}
|
|
647
735
|
const master = context.createGain();
|
|
648
736
|
master.gain.value = profile.master;
|
|
649
|
-
master.connect(compressor ??
|
|
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
|
-
|
|
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
|
-
|
|
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?.
|
|
861
|
-
nodes?.
|
|
962
|
+
nodes?.out.disconnect();
|
|
963
|
+
nodes?.out.connect(host.output(loopRecipe.bus));
|
|
862
964
|
},
|
|
863
965
|
stop() {
|
|
864
966
|
nodes?.stop();
|
|
865
|
-
nodes?.
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
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-
|
|
4170
|
+
//# sourceMappingURL=chunk-7TLFY7VO.js.map
|