@adatechnology/game-audio 0.3.6 → 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-7TLFY7VO.js +4170 -0
- package/dist/chunk-7TLFY7VO.js.map +1 -0
- package/dist/index.d.ts +228 -603
- package/dist/index.global.js +2958 -463
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1088 -2044
- package/dist/index.js.map +1 -1
- package/dist/locale-BugSe8dA.d.ts +1071 -0
- package/dist/testing.d.ts +82 -0
- package/dist/testing.js +19 -0
- package/dist/testing.js.map +1 -0
- package/package.json +13 -6
package/dist/index.global.js
CHANGED
|
@@ -22,58 +22,136 @@ var GameAudio = (() => {
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
BENCH_BANK: () => BENCH_BANK,
|
|
25
|
+
BODY_FALLOFF: () => BODY_FALLOFF,
|
|
26
|
+
BODY_FOLEY_BANK: () => BODY_FOLEY_BANK,
|
|
27
|
+
BODY_FOLEY_SET_IDS: () => BODY_FOLEY_SET_IDS,
|
|
28
|
+
BODY_FOLEY_TAKES: () => BODY_FOLEY_TAKES,
|
|
25
29
|
BUILD_ORDERS: () => BUILD_ORDERS,
|
|
26
30
|
BUS_IDS: () => BUS_IDS,
|
|
27
31
|
BUS_PRIORITY: () => BUS_PRIORITY,
|
|
32
|
+
CALIBRATION_ID: () => CALIBRATION_ID,
|
|
33
|
+
CALIBRATION_LOOP_ID: () => CALIBRATION_LOOP_ID,
|
|
34
|
+
CALIBRATION_LOOP_SOUND: () => CALIBRATION_LOOP_SOUND,
|
|
35
|
+
CALIBRATION_SOUND: () => CALIBRATION_SOUND,
|
|
36
|
+
CRITERIA: () => CRITERIA,
|
|
37
|
+
CRITERIA_TARGETS: () => CRITERIA_TARGETS,
|
|
38
|
+
CROSSFADE_STEPS: () => CROSSFADE_STEPS,
|
|
39
|
+
DEFAULT_CROSSOVER: () => DEFAULT_CROSSOVER,
|
|
28
40
|
DEFAULT_LISTENER: () => DEFAULT_LISTENER,
|
|
41
|
+
DEFAULT_LOOP_CROSSFADE: () => DEFAULT_LOOP_CROSSFADE,
|
|
29
42
|
DEFAULT_MAX_VOICES: () => DEFAULT_MAX_VOICES,
|
|
30
43
|
DEFAULT_MIX: () => DEFAULT_MIX,
|
|
44
|
+
DEFAULT_SAMPLE_CUTOFF_K: () => DEFAULT_SAMPLE_CUTOFF_K,
|
|
45
|
+
DEFAULT_SAMPLE_FALLOFF: () => DEFAULT_SAMPLE_FALLOFF,
|
|
46
|
+
DEFAULT_SAMPLE_PITCH: () => DEFAULT_SAMPLE_PITCH,
|
|
47
|
+
DEFAULT_TAIL_GAIN: () => DEFAULT_TAIL_GAIN,
|
|
31
48
|
DISTANCE_CURVES: () => DISTANCE_CURVES,
|
|
49
|
+
FOLEY_BANK: () => FOLEY_BANK,
|
|
50
|
+
FOLEY_FALLOFF: () => FOLEY_FALLOFF,
|
|
51
|
+
FOOTSTEP_FALLOFF: () => FOOTSTEP_FALLOFF,
|
|
32
52
|
GAME_SFX_BANK: () => GAME_SFX_BANK,
|
|
33
53
|
GAME_SFX_CLASSES: () => GAME_SFX_CLASSES,
|
|
34
54
|
GAME_SFX_FALLBACK: () => GAME_SFX_FALLBACK,
|
|
55
|
+
ITEM_FOLEY: () => ITEM_FOLEY,
|
|
56
|
+
KIT_CATEGORY_BUS: () => KIT_CATEGORY_BUS,
|
|
57
|
+
KIT_SAMPLE_ALIASES: () => KIT_SAMPLE_ALIASES,
|
|
58
|
+
LAYER_FLOOR: () => LAYER_FLOOR,
|
|
59
|
+
LEAF_FOLEY: () => LEAF_FOLEY,
|
|
60
|
+
LEAF_FOLEY_SETS: () => LEAF_FOLEY_SETS,
|
|
35
61
|
LIBRARY_BANK: () => LIBRARY_BANK,
|
|
36
62
|
LIBRARY_LOOPS: () => LIBRARY_LOOPS,
|
|
37
63
|
LIBRARY_SOUNDS: () => LIBRARY_SOUNDS,
|
|
38
64
|
LOOP_SMOOTHING: () => LOOP_SMOOTHING,
|
|
39
65
|
LOOP_START_ABOVE: () => LOOP_START_ABOVE,
|
|
40
66
|
MIX_PROFILES: () => MIX_PROFILES,
|
|
67
|
+
OPEN_CUTOFF: () => OPEN_CUTOFF,
|
|
41
68
|
PAN_LIMIT: () => PAN_LIMIT,
|
|
42
69
|
PAN_MIN_DISTANCE: () => PAN_MIN_DISTANCE,
|
|
70
|
+
PICKUP_CLASSES: () => PICKUP_CLASSES,
|
|
71
|
+
SAMPLE_ENVIRONMENTS: () => SAMPLE_ENVIRONMENTS,
|
|
72
|
+
SDK_LICENSES: () => SDK_LICENSES,
|
|
73
|
+
SFX_BLOWS: () => SFX_BLOWS,
|
|
74
|
+
SFX_CATALOG: () => SFX_CATALOG,
|
|
75
|
+
SFX_CATEGORIES: () => SFX_CATEGORIES,
|
|
76
|
+
SFX_IMPACTS: () => SFX_IMPACTS,
|
|
77
|
+
SFX_LAYERS: () => SFX_LAYERS,
|
|
78
|
+
SFX_MATERIALS: () => SFX_MATERIALS,
|
|
79
|
+
SFX_TIERS: () => SFX_TIERS,
|
|
43
80
|
VOICE_GROUPS: () => VOICE_GROUPS,
|
|
44
81
|
audioBenchTextOf: () => audioBenchTextOf,
|
|
82
|
+
balanceOf: () => balanceOf,
|
|
45
83
|
bufferOf: () => bufferOf,
|
|
46
84
|
buildChain: () => buildChain,
|
|
47
85
|
busGain: () => busGain,
|
|
48
86
|
busPriority: () => busPriority,
|
|
87
|
+
calibrationLoader: () => calibrationLoader,
|
|
88
|
+
centroidHz: () => centroidHz,
|
|
89
|
+
countHits: () => countHits,
|
|
49
90
|
createAudioEngine: () => createAudioEngine,
|
|
50
91
|
createAudioSink: () => createAudioSink,
|
|
51
92
|
createAudioTestModule: () => createAudioTestModule,
|
|
52
93
|
createLoopState: () => createLoopState,
|
|
53
94
|
createRng: () => createRng,
|
|
95
|
+
createSampleStore: () => createSampleStore,
|
|
96
|
+
createSetPicker: () => createSetPicker,
|
|
54
97
|
createSoundRegistry: () => createSoundRegistry,
|
|
55
98
|
createVoiceManager: () => createVoiceManager,
|
|
99
|
+
crossGains: () => crossGains,
|
|
56
100
|
cutoffDivisor: () => cutoffDivisor,
|
|
101
|
+
dbOf: () => dbOf,
|
|
57
102
|
drawBetween: () => drawBetween,
|
|
103
|
+
encodeWav: () => encodeWav,
|
|
104
|
+
endDropDb: () => endDropDb,
|
|
105
|
+
equalPowerIn: () => equalPowerIn,
|
|
58
106
|
falloffGain: () => falloffGain,
|
|
107
|
+
farMixAt: () => farMixAt,
|
|
108
|
+
fetchLoader: () => fetchLoader,
|
|
59
109
|
fillImpulse: () => fillImpulse,
|
|
60
110
|
fillNoise: () => fillNoise,
|
|
61
111
|
globalContext: () => globalContext,
|
|
112
|
+
impactSoundId: () => impactSoundId,
|
|
113
|
+
inlineLoader: () => inlineLoader,
|
|
114
|
+
isCalibrationUrl: () => isCalibrationUrl,
|
|
62
115
|
isSilent: () => isSilent,
|
|
116
|
+
kitSampleBank: () => kitSampleBank,
|
|
117
|
+
kitSampleDefaults: () => kitSampleDefaults,
|
|
118
|
+
limiterCurve: () => limiterCurve2,
|
|
63
119
|
listenerDistance: () => listenerDistance,
|
|
120
|
+
loadKitSamples: () => loadKitSamples,
|
|
121
|
+
loopCrossfade: () => loopCrossfade,
|
|
122
|
+
measureCriteria: () => measureCriteria,
|
|
64
123
|
noiseClassRecipe: () => noiseClassRecipe,
|
|
124
|
+
onsetIndex: () => onsetIndex,
|
|
65
125
|
panFor: () => panFor,
|
|
126
|
+
parseSfxName: () => parseSfxName,
|
|
127
|
+
peakIndex: () => peakIndex,
|
|
128
|
+
peakOf: () => peakOf,
|
|
129
|
+
pickTake: () => pickTake,
|
|
130
|
+
planSample: () => planSample,
|
|
66
131
|
planSound: () => planSound,
|
|
67
132
|
realize: () => realize,
|
|
133
|
+
realizeSample: () => realizeSample,
|
|
134
|
+
recordOutput: () => recordOutput,
|
|
68
135
|
resolveMix: () => resolveMix,
|
|
136
|
+
retunePlan: () => retunePlan,
|
|
137
|
+
ringSeconds: () => ringSeconds,
|
|
138
|
+
rmsDb: () => rmsDb,
|
|
139
|
+
sampleBankFromManifest: () => sampleBankFromManifest,
|
|
140
|
+
sampleCutoff: () => sampleCutoff,
|
|
141
|
+
sampleLength: () => sampleLength,
|
|
142
|
+
sampleUrls: () => sampleUrls,
|
|
69
143
|
sceneMany: () => sceneMany,
|
|
70
144
|
sceneNoise: () => sceneNoise,
|
|
71
145
|
sceneRecipe: () => sceneRecipe,
|
|
72
146
|
sceneTone: () => sceneTone,
|
|
73
147
|
sceneVoice: () => sceneVoice,
|
|
148
|
+
sfxState: () => sfxState,
|
|
149
|
+
splitTier: () => splitTier,
|
|
74
150
|
streamFor: () => streamFor,
|
|
75
151
|
streamSeed: () => streamSeed,
|
|
76
|
-
|
|
152
|
+
tierFor: () => tierFor,
|
|
153
|
+
unlockContext: () => unlockContext,
|
|
154
|
+
withAliases: () => withAliases
|
|
77
155
|
});
|
|
78
156
|
|
|
79
157
|
// src/rng.ts
|
|
@@ -170,6 +248,19 @@ var GameAudio = (() => {
|
|
|
170
248
|
"jogo:L66986 one groan every 0.25 s (`groanBudget`), only nearer than 40 m",
|
|
171
249
|
"jogo:L70472 the budget counts down by the frame time"
|
|
172
250
|
]
|
|
251
|
+
},
|
|
252
|
+
fire_ignite: {
|
|
253
|
+
maxConcurrent: 2,
|
|
254
|
+
cooldown: 0.15,
|
|
255
|
+
sources: [
|
|
256
|
+
"sdk: many parts catching at once (a blast sets a shelf alight) are one or two ignitions, not forty"
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
fire_crackle: {
|
|
260
|
+
maxConcurrent: 4,
|
|
261
|
+
sources: [
|
|
262
|
+
"sdk: the crackles of every fire share four voices"
|
|
263
|
+
]
|
|
173
264
|
}
|
|
174
265
|
};
|
|
175
266
|
|
|
@@ -197,7 +288,7 @@ var GameAudio = (() => {
|
|
|
197
288
|
if (!group) return void 0;
|
|
198
289
|
if (group.maxDistance !== void 0 && !((request.distance ?? 0) < group.maxDistance)) return "distance";
|
|
199
290
|
if (group.cooldown !== void 0 && (budgets.get(request.group) ?? 0) > 0) return "cooldown";
|
|
200
|
-
const members = voices.filter((
|
|
291
|
+
const members = voices.filter((voice2) => voice2.group === request.group);
|
|
201
292
|
if (group.maxConcurrent === void 0 || members.length < group.maxConcurrent) return void 0;
|
|
202
293
|
if (!group.steal) return "group_full";
|
|
203
294
|
evicted.push(members[0].id);
|
|
@@ -209,9 +300,9 @@ var GameAudio = (() => {
|
|
|
209
300
|
const refusal = groupCheck(request, evicted);
|
|
210
301
|
if (refusal) return refuse(refusal);
|
|
211
302
|
const score = request.priority * request.gain;
|
|
212
|
-
const remaining = voices.filter((
|
|
303
|
+
const remaining = voices.filter((voice2) => !evicted.includes(voice2.id));
|
|
213
304
|
if (remaining.length >= maxVoices) {
|
|
214
|
-
const lowest = remaining.reduce((low,
|
|
305
|
+
const lowest = remaining.reduce((low, voice2) => voice2.score < low.score ? voice2 : low);
|
|
215
306
|
if (score <= lowest.score) return refuse("global_full");
|
|
216
307
|
evicted.push(lowest.id);
|
|
217
308
|
dropped += 1;
|
|
@@ -219,25 +310,25 @@ var GameAudio = (() => {
|
|
|
219
310
|
const group = request.group === void 0 ? void 0 : groups.get(request.group);
|
|
220
311
|
if (group?.cooldown !== void 0) budgets.set(request.group, group.cooldown);
|
|
221
312
|
const id = nextId++;
|
|
222
|
-
voices = [...voices.filter((
|
|
313
|
+
voices = [...voices.filter((voice2) => !evicted.includes(voice2.id)), { id, ...request.group === void 0 ? {} : { group: request.group }, score, remaining: request.length }];
|
|
223
314
|
peak = Math.max(peak, voices.length);
|
|
224
315
|
return { accepted: true, id, evicted };
|
|
225
316
|
},
|
|
226
317
|
release(id) {
|
|
227
|
-
voices = voices.filter((
|
|
318
|
+
voices = voices.filter((voice2) => voice2.id !== id);
|
|
228
319
|
},
|
|
229
320
|
setLength(id, seconds) {
|
|
230
|
-
const
|
|
231
|
-
if (
|
|
321
|
+
const voice2 = voices.find((entry) => entry.id === id);
|
|
322
|
+
if (voice2) voice2.remaining = seconds;
|
|
232
323
|
},
|
|
233
324
|
advance(dt) {
|
|
234
325
|
for (const [group, budget] of budgets) budgets.set(group, budget - dt);
|
|
235
326
|
const ended = [];
|
|
236
|
-
for (const
|
|
237
|
-
|
|
238
|
-
if (
|
|
327
|
+
for (const voice2 of voices) {
|
|
328
|
+
voice2.remaining -= dt;
|
|
329
|
+
if (voice2.remaining <= 0) ended.push(voice2.id);
|
|
239
330
|
}
|
|
240
|
-
if (ended.length > 0) voices = voices.filter((
|
|
331
|
+
if (ended.length > 0) voices = voices.filter((voice2) => voice2.remaining > 0);
|
|
241
332
|
return ended;
|
|
242
333
|
},
|
|
243
334
|
setGroup(id, group) {
|
|
@@ -345,14 +436,14 @@ var GameAudio = (() => {
|
|
|
345
436
|
const source = layer.source;
|
|
346
437
|
if (source.kind === "noise") return { kind: "noise", offset, loop: source.loop === true };
|
|
347
438
|
if (source.kind === "osc") return { kind: "osc", wave: source.wave, frequency: finishAutomation(pending.automation ?? {}, duration) };
|
|
348
|
-
const
|
|
439
|
+
const voice2 = pending.voice;
|
|
349
440
|
return {
|
|
350
441
|
kind: "formant_voice",
|
|
351
442
|
wave: source.wave,
|
|
352
|
-
frequency: finishAutomation(
|
|
353
|
-
vibrato: { rate:
|
|
354
|
-
formants:
|
|
355
|
-
breath: { ...
|
|
443
|
+
frequency: finishAutomation(voice2.frequency, duration),
|
|
444
|
+
vibrato: { rate: voice2.vibratoRate, depth: startFrequency(voice2.frequency) * source.vibrato.depth },
|
|
445
|
+
formants: voice2.formants,
|
|
446
|
+
breath: { ...voice2.breath, offset },
|
|
356
447
|
mix: source.mix
|
|
357
448
|
};
|
|
358
449
|
}
|
|
@@ -408,100 +499,231 @@ var GameAudio = (() => {
|
|
|
408
499
|
return { ...layer, filters: { ...layer.filters, bank } };
|
|
409
500
|
}
|
|
410
501
|
var layerEnd = (layer) => layer.at + layer.duration + layer.tail;
|
|
411
|
-
function planSound(
|
|
502
|
+
function planSound(recipe2, input = {}) {
|
|
412
503
|
const listener = input.listener ?? DEFAULT_LISTENER;
|
|
413
504
|
const distance = input.distance ?? (input.position ? listenerDistance(listener, input.position, input.distanceMode) : 0);
|
|
414
505
|
const occlusion = Math.min(1, Math.max(0, input.occlusion ?? 0));
|
|
415
|
-
const order =
|
|
416
|
-
const falloffLevel = falloffGain(
|
|
506
|
+
const order = recipe2.order ?? "layered";
|
|
507
|
+
const falloffLevel = falloffGain(recipe2.falloff, input.volume ?? 1, distance);
|
|
417
508
|
const level = occlusion > 0 ? falloffLevel * (1 - OCCLUSION_GAIN * occlusion) : falloffLevel;
|
|
418
|
-
const silent = isSilent(
|
|
509
|
+
const silent = isSilent(recipe2.falloff, falloffLevel);
|
|
419
510
|
const base = {
|
|
420
|
-
id:
|
|
421
|
-
bus:
|
|
511
|
+
id: recipe2.id,
|
|
512
|
+
bus: recipe2.bus,
|
|
422
513
|
order,
|
|
423
|
-
...
|
|
424
|
-
priority:
|
|
514
|
+
...recipe2.group === void 0 ? {} : { group: recipe2.group },
|
|
515
|
+
priority: recipe2.priority ?? busPriority(recipe2.bus),
|
|
425
516
|
level,
|
|
426
517
|
distance,
|
|
427
|
-
...
|
|
518
|
+
...recipe2.pan ? { pan: input.position ? panFor(listener, input.position) : 0 } : {}
|
|
428
519
|
};
|
|
429
|
-
if (silent) return
|
|
520
|
+
if (silent) return recipe2.keepSilent ? { ...base, silent: true, length: 0, layers: [] } : null;
|
|
430
521
|
const scope = { random: input.random ?? createRng(1), params: { ...input.params } };
|
|
431
|
-
for (const [name, range] of Object.entries(
|
|
522
|
+
for (const [name, range] of Object.entries(recipe2.vars ?? {})) if (scope.params[name] === void 0) scope.params[name] = draw(range, scope);
|
|
432
523
|
const defaults = {
|
|
433
|
-
...
|
|
434
|
-
...
|
|
524
|
+
...recipe2.duration === void 0 ? {} : { duration: draw(recipe2.duration, scope) },
|
|
525
|
+
...recipe2.tail === void 0 ? {} : { tail: recipe2.tail },
|
|
435
526
|
noiseSeconds: input.noiseSeconds ?? DEFAULT_NOISE_SECONDS
|
|
436
527
|
};
|
|
437
|
-
const divisor = cutoffDivisor(
|
|
438
|
-
const layers =
|
|
528
|
+
const divisor = cutoffDivisor(recipe2.falloff, distance) / (1 - OCCLUSION_CUTOFF * occlusion);
|
|
529
|
+
const layers = recipe2.layers.flatMap((layer) => planLayer(layer, scope, defaults, order !== "layered", level)).map((layer) => muffle(layer, divisor));
|
|
439
530
|
return { ...base, silent: false, length: Math.max(0, ...layers.map(layerEnd)), layers };
|
|
440
531
|
}
|
|
441
532
|
|
|
442
|
-
// src/
|
|
443
|
-
var
|
|
444
|
-
var
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
533
|
+
// src/sample.ts
|
|
534
|
+
var SAMPLE_ENVIRONMENTS = ["indoor", "outdoor"];
|
|
535
|
+
var DEFAULT_SAMPLE_FALLOFF = { model: "inverse_square", k: 2e-3, minGain: 2e-3 };
|
|
536
|
+
var DEFAULT_CROSSOVER = { from: 30, to: 80 };
|
|
537
|
+
var DEFAULT_SAMPLE_PITCH = 0.04;
|
|
538
|
+
var DEFAULT_TAIL_GAIN = 0.6;
|
|
539
|
+
var DEFAULT_SAMPLE_CUTOFF_K = 0.01;
|
|
540
|
+
var OPEN_CUTOFF = 2e4;
|
|
541
|
+
var LAYER_FLOOR = 1e-3;
|
|
542
|
+
function pickTake(count, last, random) {
|
|
543
|
+
if (count <= 1) return 0;
|
|
544
|
+
if (last === void 0 || last < 0 || last >= count) return Math.min(count - 1, Math.floor(random() * count));
|
|
545
|
+
const drawn = Math.min(count - 2, Math.floor(random() * (count - 1)));
|
|
546
|
+
return drawn >= last ? drawn + 1 : drawn;
|
|
547
|
+
}
|
|
548
|
+
function farMixAt(crossover, distance) {
|
|
549
|
+
if (crossover.to <= crossover.from) return distance >= crossover.to ? 1 : 0;
|
|
550
|
+
const t = (distance - crossover.from) / (crossover.to - crossover.from);
|
|
551
|
+
return t <= 0 ? 0 : t >= 1 ? 1 : t;
|
|
552
|
+
}
|
|
553
|
+
function crossGains(farMix) {
|
|
554
|
+
return { close: Math.cos(farMix * Math.PI / 2), far: Math.sin(farMix * Math.PI / 2) };
|
|
555
|
+
}
|
|
556
|
+
function sampleCutoff(cutoffK, distance, occlusion = 0) {
|
|
557
|
+
const byDistance = cutoffK > 0 ? OPEN_CUTOFF / (1 + distance * cutoffK) : OPEN_CUTOFF;
|
|
558
|
+
const occluded = occlusion > 0 ? byDistance / (1 + occlusion * 9) : byDistance;
|
|
559
|
+
return Math.max(80, Math.min(OPEN_CUTOFF, occluded));
|
|
560
|
+
}
|
|
561
|
+
function sampleUrls(sound) {
|
|
562
|
+
const tiers = (sound.tiers ?? []).flatMap((tier) => [...tier.close, ...tier.far ?? []]);
|
|
563
|
+
const all = [...sound.close, ...sound.far ?? [], ...tiers, ...sound.tail?.indoor ?? [], ...sound.tail?.outdoor ?? []].map((ref) => ref.url);
|
|
564
|
+
return [...new Set(all)];
|
|
565
|
+
}
|
|
566
|
+
function tierFor(sound, intensity) {
|
|
567
|
+
if (intensity === void 0 || !sound.tiers) return void 0;
|
|
568
|
+
let chosen;
|
|
569
|
+
for (const tier of sound.tiers) if (tier.from <= intensity) chosen = tier;
|
|
570
|
+
return chosen ?? sound.tiers[0];
|
|
571
|
+
}
|
|
572
|
+
function planSample(sound, input) {
|
|
573
|
+
if (sound.close.length === 0) throw new Error(`sample sound ${sound.id} has no close take`);
|
|
574
|
+
const listener = input.listener ?? DEFAULT_LISTENER;
|
|
575
|
+
const distance = input.distance ?? (input.position ? listenerDistance(listener, input.position, input.distanceMode) : 0);
|
|
576
|
+
const falloff = sound.falloff ?? DEFAULT_SAMPLE_FALLOFF;
|
|
577
|
+
const occlusion = Math.max(0, Math.min(1, input.occlusion ?? 0));
|
|
578
|
+
const level = falloffGain(falloff, (input.volume ?? 1) * (sound.gain ?? 1), distance) * (1 - 0.45 * occlusion);
|
|
579
|
+
if (isSilent(falloff, level) || level <= 0) return null;
|
|
580
|
+
const pitch = sound.pitch ?? DEFAULT_SAMPLE_PITCH;
|
|
581
|
+
const rate = pitch > 0 ? 1 + (input.random() * 2 - 1) * pitch : 1;
|
|
582
|
+
const environment = input.environment ?? "outdoor";
|
|
583
|
+
const tier = tierFor(sound, input.intensity);
|
|
584
|
+
const close = tier?.close.length ? tier.close : sound.close;
|
|
585
|
+
const far = tier?.far?.length ? tier.far : sound.far ?? [];
|
|
586
|
+
const farMix = far.length > 0 ? farMixAt(sound.crossover ?? DEFAULT_CROSSOVER, distance) : 0;
|
|
587
|
+
const gains = crossGains(farMix);
|
|
588
|
+
const layers = [];
|
|
589
|
+
const take = (role, refs, gain, at) => {
|
|
590
|
+
if (refs.length === 0 || gain < LAYER_FLOOR) return;
|
|
591
|
+
const key = `${sound.id}/${tier && role !== "tail" ? `${tier.name}/` : ""}${role}`;
|
|
592
|
+
const index = pickTake(refs.length, input.memory?.get(key), input.random);
|
|
593
|
+
input.memory?.set(key, index);
|
|
594
|
+
const ref = refs[index];
|
|
595
|
+
layers.push({ role, url: ref.url, take: index, gain: gain * (ref.gain ?? 1) * level, rate, at });
|
|
596
|
+
};
|
|
597
|
+
take("close", close, gains.close, 0);
|
|
598
|
+
take("far", far, gains.far, 0);
|
|
599
|
+
const tails = sound.tail?.[environment] ?? [];
|
|
600
|
+
take("tail", tails, sound.tail?.gain ?? DEFAULT_TAIL_GAIN, sound.tail?.at ?? 0);
|
|
601
|
+
const pan = (sound.pan ?? true) && input.position ? panFor(listener, input.position) : void 0;
|
|
449
602
|
return {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
603
|
+
kind: "sample",
|
|
604
|
+
id: sound.id,
|
|
605
|
+
bus: sound.bus,
|
|
606
|
+
level,
|
|
607
|
+
distance,
|
|
608
|
+
...pan === void 0 ? {} : { pan },
|
|
609
|
+
cutoff: sampleCutoff(sound.cutoffK ?? DEFAULT_SAMPLE_CUTOFF_K, distance, occlusion),
|
|
610
|
+
rate,
|
|
611
|
+
environment,
|
|
612
|
+
...tier ? { tier: tier.name } : {},
|
|
613
|
+
farMix,
|
|
614
|
+
layers,
|
|
615
|
+
priority: sound.priority ?? input.priority ?? busPriority(sound.bus),
|
|
616
|
+
...sound.group ? { group: sound.group } : {}
|
|
464
617
|
};
|
|
465
618
|
}
|
|
466
619
|
|
|
467
|
-
// src/
|
|
468
|
-
var
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
620
|
+
// src/measure/calibration.ts
|
|
621
|
+
var CALIBRATION_ID = "calibration_shot";
|
|
622
|
+
var CALIBRATION_RATE = 48e3;
|
|
623
|
+
function encodeWav(samples, sampleRate = CALIBRATION_RATE) {
|
|
624
|
+
const bytes = new ArrayBuffer(44 + samples.length * 2);
|
|
625
|
+
const view = new DataView(bytes);
|
|
626
|
+
const text = (at, value) => {
|
|
627
|
+
for (let index = 0; index < value.length; index++) view.setUint8(at + index, value.charCodeAt(index));
|
|
628
|
+
};
|
|
629
|
+
text(0, "RIFF");
|
|
630
|
+
view.setUint32(4, 36 + samples.length * 2, true);
|
|
631
|
+
text(8, "WAVE");
|
|
632
|
+
text(12, "fmt ");
|
|
633
|
+
view.setUint32(16, 16, true);
|
|
634
|
+
view.setUint16(20, 1, true);
|
|
635
|
+
view.setUint16(22, 1, true);
|
|
636
|
+
view.setUint32(24, sampleRate, true);
|
|
637
|
+
view.setUint32(28, sampleRate * 2, true);
|
|
638
|
+
view.setUint16(32, 2, true);
|
|
639
|
+
view.setUint16(34, 16, true);
|
|
640
|
+
text(36, "data");
|
|
641
|
+
view.setUint32(40, samples.length * 2, true);
|
|
642
|
+
for (let index = 0; index < samples.length; index++) {
|
|
643
|
+
const value = Math.max(-1, Math.min(1, samples[index]));
|
|
644
|
+
view.setInt16(44 + index * 2, value < 0 ? value * 32768 : value * 32767, true);
|
|
488
645
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
// src/mix.ts
|
|
492
|
-
var MIX_PROFILES = Object.fromEntries(
|
|
493
|
-
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
494
|
-
);
|
|
495
|
-
var DEFAULT_MIX = "art_scene";
|
|
496
|
-
function resolveMix(mix, profiles = MIX_PROFILES) {
|
|
497
|
-
if (typeof mix !== "string") return mix;
|
|
498
|
-
const profile = profiles[mix];
|
|
499
|
-
if (!profile) throw new Error(`game-audio: unknown mix profile "${mix}" (known: ${Object.keys(profiles).join(", ")})`);
|
|
500
|
-
return profile;
|
|
646
|
+
return bytes;
|
|
501
647
|
}
|
|
502
|
-
function
|
|
503
|
-
|
|
504
|
-
|
|
648
|
+
function shotSamples(shot, sampleRate = CALIBRATION_RATE) {
|
|
649
|
+
const random = createRng(shot.seed);
|
|
650
|
+
const length = Math.round(shot.seconds * sampleRate);
|
|
651
|
+
const samples = new Float32Array(length);
|
|
652
|
+
let low = 0;
|
|
653
|
+
let phase = 0;
|
|
654
|
+
const attack = Math.max(1, Math.round((shot.attack ?? 0) * sampleRate));
|
|
655
|
+
for (let index = 0; index < length; index++) {
|
|
656
|
+
const time = index / sampleRate;
|
|
657
|
+
const envelope2 = Math.exp(-time / shot.decay) * Math.min(1, (index + 1) / attack);
|
|
658
|
+
phase += 2 * Math.PI * shot.thump * (1 + 0.6 * Math.exp(-time * 30)) / sampleRate;
|
|
659
|
+
const noise = random() * 2 - 1;
|
|
660
|
+
low += shot.brightness * (noise - low);
|
|
661
|
+
const fade = Math.min(1, (length - index) / (0.01 * sampleRate));
|
|
662
|
+
samples[index] = shot.gain * envelope2 * fade * (0.55 * Math.sin(phase) + shot.noise * low);
|
|
663
|
+
}
|
|
664
|
+
return samples;
|
|
665
|
+
}
|
|
666
|
+
var TAKES = {
|
|
667
|
+
"close_1.wav": { seconds: 0.4, thump: 150, noise: 1, decay: 0.06, brightness: 0.9, gain: 0.85, seed: 1 },
|
|
668
|
+
"close_2.wav": { seconds: 0.4, thump: 160, noise: 1, decay: 0.065, brightness: 0.85, gain: 0.85, seed: 2 },
|
|
669
|
+
"close_3.wav": { seconds: 0.4, thump: 142, noise: 1, decay: 0.055, brightness: 0.95, gain: 0.85, seed: 3 },
|
|
670
|
+
"close_4.wav": { seconds: 0.4, thump: 170, noise: 1, decay: 0.07, brightness: 0.8, gain: 0.85, seed: 4 },
|
|
671
|
+
"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 },
|
|
672
|
+
"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 },
|
|
673
|
+
"light_1.wav": { seconds: 0.25, thump: 220, noise: 0.6, decay: 0.03, brightness: 0.6, gain: 0.35, seed: 7 },
|
|
674
|
+
"light_2.wav": { seconds: 0.25, thump: 230, noise: 0.6, decay: 0.03, brightness: 0.55, gain: 0.35, seed: 8 },
|
|
675
|
+
"heavy_1.wav": { seconds: 0.6, thump: 110, noise: 1.2, decay: 0.11, brightness: 0.95, gain: 0.95, seed: 9 },
|
|
676
|
+
"heavy_2.wav": { seconds: 0.6, thump: 105, noise: 1.2, decay: 0.12, brightness: 0.9, gain: 0.95, seed: 10 },
|
|
677
|
+
"tail_in.wav": { seconds: 0.5, thump: 0, noise: 1, decay: 0.08, brightness: 0.4, gain: 0.25, seed: 11, attack: 0.01 },
|
|
678
|
+
"tail_out.wav": { seconds: 2, thump: 0, noise: 1, decay: 0.45, brightness: 0.25, gain: 0.2, seed: 12, attack: 0.02 },
|
|
679
|
+
"loop_1.wav": { seconds: 0.6, thump: 0, noise: 1, decay: 100, brightness: 0.5, gain: 0.5, seed: 13, attack: 0.01 },
|
|
680
|
+
"loop_2.wav": { seconds: 0.6, thump: 0, noise: 1, decay: 100, brightness: 0.45, gain: 0.5, seed: 14, attack: 0.01 },
|
|
681
|
+
"loop_3.wav": { seconds: 0.6, thump: 0, noise: 1, decay: 100, brightness: 0.55, gain: 0.5, seed: 15, attack: 0.01 }
|
|
682
|
+
};
|
|
683
|
+
var PREFIX = "calibration/";
|
|
684
|
+
var url = (name) => `${PREFIX}${name}`;
|
|
685
|
+
var CALIBRATION_SOUND = {
|
|
686
|
+
id: CALIBRATION_ID,
|
|
687
|
+
bus: "weapons",
|
|
688
|
+
close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })),
|
|
689
|
+
far: ["far_1.wav", "far_2.wav"].map((name) => ({ url: url(name) })),
|
|
690
|
+
tiers: [
|
|
691
|
+
{ name: "light", from: 0, close: ["light_1.wav", "light_2.wav"].map((name) => ({ url: url(name) })) },
|
|
692
|
+
{ name: "medium", from: 0.34, close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })) },
|
|
693
|
+
{ name: "heavy", from: 0.67, close: ["heavy_1.wav", "heavy_2.wav"].map((name) => ({ url: url(name) })) }
|
|
694
|
+
],
|
|
695
|
+
tail: { indoor: [{ url: url("tail_in.wav") }], outdoor: [{ url: url("tail_out.wav") }] },
|
|
696
|
+
pitch: 0.04,
|
|
697
|
+
choke: { voices: 2 },
|
|
698
|
+
fallback: "sfx_pistol",
|
|
699
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
700
|
+
};
|
|
701
|
+
var CALIBRATION_LOOP_ID = "calibration_loop";
|
|
702
|
+
var CALIBRATION_LOOP_SOUND = {
|
|
703
|
+
id: CALIBRATION_LOOP_ID,
|
|
704
|
+
bus: "ambience",
|
|
705
|
+
close: ["loop_1.wav", "loop_2.wav", "loop_3.wav"].map((name) => ({ url: url(name) })),
|
|
706
|
+
loop: { crossfade: 0.15 },
|
|
707
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
708
|
+
};
|
|
709
|
+
var isCalibrationUrl = (url2) => url2.startsWith(PREFIX);
|
|
710
|
+
function calibrationLoader(next) {
|
|
711
|
+
const made = /* @__PURE__ */ new Map();
|
|
712
|
+
return async (requested) => {
|
|
713
|
+
if (!requested.startsWith(PREFIX)) {
|
|
714
|
+
if (next) return next(requested);
|
|
715
|
+
throw new Error(`not a calibration file: ${requested}`);
|
|
716
|
+
}
|
|
717
|
+
const name = requested.slice(PREFIX.length);
|
|
718
|
+
const shot = TAKES[name];
|
|
719
|
+
if (!shot) throw new Error(`no calibration take ${name}`);
|
|
720
|
+
let bytes = made.get(name);
|
|
721
|
+
if (!bytes) {
|
|
722
|
+
bytes = encodeWav(shotSamples(shot));
|
|
723
|
+
made.set(name, bytes);
|
|
724
|
+
}
|
|
725
|
+
return bytes.slice(0);
|
|
726
|
+
};
|
|
505
727
|
}
|
|
506
728
|
|
|
507
729
|
// src/bank.ts
|
|
@@ -520,6 +742,8 @@ var GameAudio = (() => {
|
|
|
520
742
|
function createSoundRegistry(banks = []) {
|
|
521
743
|
const sounds = /* @__PURE__ */ new Map();
|
|
522
744
|
const loops = /* @__PURE__ */ new Map();
|
|
745
|
+
const sets = /* @__PURE__ */ new Map();
|
|
746
|
+
const samples = /* @__PURE__ */ new Map();
|
|
523
747
|
const owners = /* @__PURE__ */ new Map();
|
|
524
748
|
const registry = {
|
|
525
749
|
register(bank) {
|
|
@@ -531,280 +755,175 @@ var GameAudio = (() => {
|
|
|
531
755
|
loops.set(loop.id, loop);
|
|
532
756
|
owners.set(loop.id, bank.id);
|
|
533
757
|
}
|
|
758
|
+
for (const set of bank.sets ?? []) {
|
|
759
|
+
if (set.variants.length === 0) throw new Error(`sound set ${set.id} has no variant`);
|
|
760
|
+
sets.set(set.id, set);
|
|
761
|
+
owners.set(set.id, bank.id);
|
|
762
|
+
}
|
|
763
|
+
for (const sample of bank.samples ?? []) {
|
|
764
|
+
samples.set(sample.id, sample);
|
|
765
|
+
owners.set(sample.id, bank.id);
|
|
766
|
+
}
|
|
534
767
|
},
|
|
535
768
|
patch(id, patch) {
|
|
536
769
|
const sound = sounds.get(id);
|
|
537
770
|
if (sound) sounds.set(id, mergeRecords(sound, patch));
|
|
538
771
|
const loop = loops.get(id);
|
|
539
772
|
if (loop) loops.set(id, mergeRecords(loop, patch));
|
|
773
|
+
const sample = samples.get(id);
|
|
774
|
+
if (sample) samples.set(id, mergeRecords(sample, patch));
|
|
540
775
|
},
|
|
541
776
|
remove(id) {
|
|
542
777
|
sounds.delete(id);
|
|
543
778
|
loops.delete(id);
|
|
779
|
+
sets.delete(id);
|
|
780
|
+
samples.delete(id);
|
|
544
781
|
owners.delete(id);
|
|
545
782
|
},
|
|
546
783
|
sound: (id) => sounds.get(id),
|
|
547
784
|
loop: (id) => loops.get(id),
|
|
785
|
+
set: (id) => sets.get(id),
|
|
786
|
+
sample: (id) => samples.get(id),
|
|
548
787
|
soundIds: () => [...sounds.keys()],
|
|
788
|
+
setIds: () => [...sets.keys()],
|
|
549
789
|
loopIds: () => [...loops.keys()],
|
|
790
|
+
sampleIds: () => [...samples.keys()],
|
|
550
791
|
bankOf: (id) => owners.get(id)
|
|
551
792
|
};
|
|
552
793
|
for (const bank of banks) registry.register(bank);
|
|
553
794
|
return registry;
|
|
554
795
|
}
|
|
555
796
|
|
|
556
|
-
// src/data/
|
|
557
|
-
var
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
797
|
+
// src/data/mix-profiles.json
|
|
798
|
+
var mix_profiles_default = [
|
|
799
|
+
{
|
|
800
|
+
id: "game",
|
|
801
|
+
master: 0.5,
|
|
802
|
+
noise: {
|
|
803
|
+
seconds: 1.5,
|
|
804
|
+
create: "lazy"
|
|
805
|
+
},
|
|
806
|
+
sources: [
|
|
807
|
+
"jogo:L62077-62081 master 0.5 to the output",
|
|
808
|
+
"jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"
|
|
809
|
+
]
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
id: "art_scene",
|
|
813
|
+
master: 0.85,
|
|
814
|
+
compressor: {
|
|
815
|
+
threshold: -12,
|
|
816
|
+
ratio: 5
|
|
817
|
+
},
|
|
818
|
+
reverb: {
|
|
819
|
+
seconds: 2.2,
|
|
820
|
+
decay: 3.4,
|
|
821
|
+
wet: 0.4
|
|
822
|
+
},
|
|
823
|
+
noise: {
|
|
824
|
+
seconds: 2,
|
|
825
|
+
create: "eager"
|
|
826
|
+
},
|
|
827
|
+
sources: [
|
|
828
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
829
|
+
"cena:L1309 master 0.85",
|
|
830
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
831
|
+
"cena:L1311 wet 0.4",
|
|
832
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
833
|
+
]
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
id: "kit",
|
|
837
|
+
master: 0.85,
|
|
838
|
+
compressor: {
|
|
839
|
+
threshold: -12,
|
|
840
|
+
ratio: 5
|
|
841
|
+
},
|
|
842
|
+
reverb: {
|
|
843
|
+
seconds: 2.2,
|
|
844
|
+
decay: 3.4,
|
|
845
|
+
wet: 0.4
|
|
846
|
+
},
|
|
847
|
+
noise: {
|
|
848
|
+
seconds: 2,
|
|
849
|
+
create: "eager"
|
|
850
|
+
},
|
|
851
|
+
sources: [
|
|
852
|
+
"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"
|
|
597
853
|
],
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
854
|
+
limiter: {
|
|
855
|
+
ceiling: -1,
|
|
856
|
+
knee: -6
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
];
|
|
860
|
+
|
|
861
|
+
// src/mix.ts
|
|
862
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
863
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
864
|
+
);
|
|
865
|
+
var DEFAULT_MIX = "kit";
|
|
866
|
+
function resolveMix(mix, profiles = MIX_PROFILES) {
|
|
867
|
+
if (typeof mix !== "string") return mix;
|
|
868
|
+
const profile = profiles[mix];
|
|
869
|
+
if (!profile) throw new Error(`game-audio: unknown mix profile "${mix}" (known: ${Object.keys(profiles).join(", ")})`);
|
|
870
|
+
return profile;
|
|
871
|
+
}
|
|
872
|
+
function busGain(setting) {
|
|
873
|
+
if (!setting) return 1;
|
|
874
|
+
return setting.muted ? 0 : setting.gain ?? 1;
|
|
601
875
|
}
|
|
602
|
-
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
603
876
|
|
|
604
|
-
// src/
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return { ...d, add: (d.add ?? 0) + attack };
|
|
877
|
+
// src/webaudio/noise.ts
|
|
878
|
+
function fillNoise(random, length) {
|
|
879
|
+
const samples = new Float32Array(length);
|
|
880
|
+
for (let index = 0; index < length; index++) samples[index] = random() * 2 - 1;
|
|
881
|
+
return samples;
|
|
610
882
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
mode: "serial",
|
|
622
|
-
bank: [{ type: o.type ?? "lowpass", frequency: o.f2 === void 0 ? { set: o.f } : { set: o.f, to: o.f2, curve: "exp", over }, q: o.q ?? 0.7 }]
|
|
623
|
-
},
|
|
624
|
-
duration: lengthOf(o.d, a),
|
|
625
|
-
gain: o.vol,
|
|
626
|
-
...o.delay === void 0 ? {} : { at: o.delay },
|
|
627
|
-
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
628
|
-
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
629
|
-
envelope: envelope(a)
|
|
630
|
-
};
|
|
883
|
+
function fillImpulse(random, options) {
|
|
884
|
+
const size = Math.floor(options.length);
|
|
885
|
+
return Array.from({ length: options.channels }, () => {
|
|
886
|
+
const samples = new Float32Array(size);
|
|
887
|
+
for (let index = 0; index < options.length; index++) {
|
|
888
|
+
const value = (random() * 2 - 1) * Math.exp(options.decay * Math.log(1 - index / options.length));
|
|
889
|
+
if (index < size) samples[index] = value;
|
|
890
|
+
}
|
|
891
|
+
return samples;
|
|
892
|
+
});
|
|
631
893
|
}
|
|
632
|
-
function
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
gain: o.vol,
|
|
637
|
-
...o.delay === void 0 ? {} : { at: o.delay },
|
|
638
|
-
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
639
|
-
envelope: envelope(ATTACK)
|
|
640
|
-
};
|
|
894
|
+
function bufferOf(context, channels, requestedLength) {
|
|
895
|
+
const buffer = context.createBuffer(channels.length, requestedLength, context.sampleRate);
|
|
896
|
+
channels.forEach((samples, channel) => buffer.getChannelData(channel).set(samples));
|
|
897
|
+
return buffer;
|
|
641
898
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
657
|
-
mix: 3.2
|
|
658
|
-
},
|
|
659
|
-
envelope: [
|
|
660
|
-
[0, 1e-4, "set", "fixed"],
|
|
661
|
-
[0.1, 1, "exp"],
|
|
662
|
-
["0.6d", 1, "set"],
|
|
663
|
-
["1d", 1e-4, "exp", "fixed"]
|
|
664
|
-
]
|
|
665
|
-
};
|
|
899
|
+
|
|
900
|
+
// src/webaudio/chain.ts
|
|
901
|
+
var LIMITER_POINTS = 4097;
|
|
902
|
+
function limiterCurve(ceilingDb, kneeDb, range, points = LIMITER_POINTS) {
|
|
903
|
+
const ceiling = 10 ** (ceilingDb / 20);
|
|
904
|
+
const knee = Math.min(10 ** (kneeDb / 20), ceiling);
|
|
905
|
+
const curve = new Float32Array(new ArrayBuffer(points * 4));
|
|
906
|
+
for (let i = 0; i < points; i++) {
|
|
907
|
+
const x = (i / (points - 1) * 2 - 1) * range;
|
|
908
|
+
const a = Math.abs(x);
|
|
909
|
+
const y = a <= knee || ceiling === knee ? Math.min(a, ceiling) : knee + (ceiling - knee) * Math.tanh((a - knee) / (ceiling - knee));
|
|
910
|
+
curve[i] = Math.sign(x) * y;
|
|
911
|
+
}
|
|
912
|
+
return curve;
|
|
666
913
|
}
|
|
667
|
-
var sceneMany = (count, make) => Array.from({ length: count }, make);
|
|
668
|
-
function sceneRecipe(id, layers, line, options = {}) {
|
|
669
|
-
return {
|
|
670
|
-
id,
|
|
671
|
-
bus: options.bus ?? "world",
|
|
672
|
-
pan: true,
|
|
673
|
-
layers,
|
|
674
|
-
falloff: DISTANCE_CURVES.art_scene,
|
|
675
|
-
...options.vars ? { vars: options.vars } : {},
|
|
676
|
-
...options.group ? { group: options.group } : {},
|
|
677
|
-
sources: [`cena:${line}`]
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// src/library/crowd_rumble.json
|
|
682
|
-
var crowd_rumble_default = {
|
|
683
|
-
id: "crowd_rumble",
|
|
684
|
-
bus: "ambience",
|
|
685
|
-
order: "game_loop",
|
|
686
|
-
source: { kind: "noise", loop: true },
|
|
687
|
-
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 160 } }] },
|
|
688
|
-
smoothing: { volume: 0.15, frequency: 0.08 },
|
|
689
|
-
startAbove: 2e-3,
|
|
690
|
-
sources: ["jogo:L62116 horda: noise through a 160 Hz lowpass", "jogo:L70424 level min(0.16, near \xD7 0.0016)", "temporary home until the crowd package (Q12)"]
|
|
691
|
-
};
|
|
692
|
-
|
|
693
|
-
// src/library/engine_saw.json
|
|
694
|
-
var engine_saw_default = {
|
|
695
|
-
id: "engine_saw",
|
|
696
|
-
bus: "world",
|
|
697
|
-
order: "game_loop",
|
|
698
|
-
source: { kind: "osc", wave: "sawtooth", loop: true },
|
|
699
|
-
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 400 } }] },
|
|
700
|
-
smoothing: { volume: 0.15, frequency: 0.08 },
|
|
701
|
-
startAbove: 2e-3,
|
|
702
|
-
sources: [
|
|
703
|
-
"jogo:L62115 motor: sawtooth through a 400 Hz lowpass",
|
|
704
|
-
"jogo:L70421 level 0.035 + speed \xD7 0.003, frequency 38 + speed \xD7 7 (the host drives `set`)",
|
|
705
|
-
"temporary home until the vehicles package (Q12)"
|
|
706
|
-
]
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
// src/library/horn.json
|
|
710
|
-
var horn_default = {
|
|
711
|
-
id: "horn",
|
|
712
|
-
bus: "world",
|
|
713
|
-
order: "chord",
|
|
714
|
-
duration: 0.6,
|
|
715
|
-
tail: 0.02,
|
|
716
|
-
layers: [
|
|
717
|
-
{ source: { kind: "osc", wave: "square", frequency: { set: 415 } }, envelope: [[0, 0.08, "set"], [0.6, 1e-4, "set", "fixed"]] },
|
|
718
|
-
{ source: { kind: "osc", wave: "square", frequency: { set: 523 } }, envelope: [[0, 0.08, "set"], [0.6, 1e-4, "set", "fixed"]] }
|
|
719
|
-
],
|
|
720
|
-
falloff: { model: "none" },
|
|
721
|
-
sources: ["jogo:L70272-70276 buzina: squares at 415 and 523 Hz, 0.08 for 0.6 s", "temporary home until the vehicles package (Q12)"]
|
|
722
|
-
};
|
|
723
|
-
|
|
724
|
-
// src/library/radio_static.json
|
|
725
|
-
var radio_static_default = {
|
|
726
|
-
id: "radio_static",
|
|
727
|
-
bus: "world",
|
|
728
|
-
order: "static",
|
|
729
|
-
duration: 0.6,
|
|
730
|
-
layers: [
|
|
731
|
-
{
|
|
732
|
-
source: { kind: "noise", offset: "random" },
|
|
733
|
-
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: 1800 }, q: 0.8 }] },
|
|
734
|
-
envelope: [[0, 0.06, "set"], ["1d", 1e-3, "exp", "fixed"]]
|
|
735
|
-
}
|
|
736
|
-
],
|
|
737
|
-
falloff: { model: "none" },
|
|
738
|
-
sources: ["jogo:L69998-70004 chiado: noise through a 1800 Hz bandpass (Q 0.8), 0.06 falling over 0.6 s", "temporary home until the props or radio package (Q12)"]
|
|
739
|
-
};
|
|
740
|
-
|
|
741
|
-
// src/library/rotor_blades.json
|
|
742
|
-
var rotor_blades_default = {
|
|
743
|
-
id: "rotor_blades",
|
|
744
|
-
bus: "world",
|
|
745
|
-
order: "game_loop",
|
|
746
|
-
source: { kind: "noise", loop: true },
|
|
747
|
-
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 300 } }] },
|
|
748
|
-
modulators: [{ target: "gain", rate: 11, depth: 0.5, base: 0.5 }],
|
|
749
|
-
smoothing: { volume: 0.15, frequency: 0.08 },
|
|
750
|
-
startAbove: 2e-3,
|
|
751
|
-
sources: [
|
|
752
|
-
"jogo:L62116-62120 rotor: noise through a 300 Hz lowpass, blade beat as an 11 Hz LFO of 0.5 on a 0.5 gain stage",
|
|
753
|
-
"jogo:L70426 level min(0.5, 30 / (distance + 10))",
|
|
754
|
-
"temporary home until the vehicles package (Q12)"
|
|
755
|
-
]
|
|
756
|
-
};
|
|
757
|
-
|
|
758
|
-
// src/library/siren.json
|
|
759
|
-
var siren_default = {
|
|
760
|
-
id: "siren",
|
|
761
|
-
bus: "world",
|
|
762
|
-
order: "siren",
|
|
763
|
-
duration: 9,
|
|
764
|
-
tail: 0.2,
|
|
765
|
-
layers: [
|
|
766
|
-
{
|
|
767
|
-
wet: 1.5,
|
|
768
|
-
source: { kind: "osc", wave: "sine", frequency: { set: 850 } },
|
|
769
|
-
modulators: [{ target: "frequency", rate: 0.18, depth: 280 }],
|
|
770
|
-
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 1400 } }] },
|
|
771
|
-
envelope: [[0, 1e-4, "set", "fixed"], [2, 0.035, "exp"], [6, 0.035, "set"], [9, 1e-4, "exp", "fixed"]]
|
|
772
|
-
}
|
|
773
|
-
],
|
|
774
|
-
falloff: { model: "none" },
|
|
775
|
-
sources: ["cena:L1369 siren: 850 Hz sine swept \xB1280 Hz at 0.18 Hz, 1400 Hz lowpass, 0.035 for 9 s, reverb send 1.5", "temporary home until the vehicles package (Q12)"]
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
// src/library/index.ts
|
|
779
|
-
var LIBRARY_SOUNDS = [horn_default, radio_static_default, siren_default];
|
|
780
|
-
var LIBRARY_LOOPS = [engine_saw_default, rotor_blades_default, crowd_rumble_default];
|
|
781
|
-
var LIBRARY_BANK = { id: "library", sounds: LIBRARY_SOUNDS, loops: LIBRARY_LOOPS };
|
|
782
|
-
|
|
783
|
-
// src/webaudio/noise.ts
|
|
784
|
-
function fillNoise(random, length) {
|
|
785
|
-
const samples = new Float32Array(length);
|
|
786
|
-
for (let index = 0; index < length; index++) samples[index] = random() * 2 - 1;
|
|
787
|
-
return samples;
|
|
788
|
-
}
|
|
789
|
-
function fillImpulse(random, options) {
|
|
790
|
-
const size = Math.floor(options.length);
|
|
791
|
-
return Array.from({ length: options.channels }, () => {
|
|
792
|
-
const samples = new Float32Array(size);
|
|
793
|
-
for (let index = 0; index < options.length; index++) {
|
|
794
|
-
const value = (random() * 2 - 1) * Math.exp(options.decay * Math.log(1 - index / options.length));
|
|
795
|
-
if (index < size) samples[index] = value;
|
|
796
|
-
}
|
|
797
|
-
return samples;
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
function bufferOf(context, channels, requestedLength) {
|
|
801
|
-
const buffer = context.createBuffer(channels.length, requestedLength, context.sampleRate);
|
|
802
|
-
channels.forEach((samples, channel) => buffer.getChannelData(channel).set(samples));
|
|
803
|
-
return buffer;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
// src/webaudio/chain.ts
|
|
807
914
|
function buildChain(context, profile, random) {
|
|
915
|
+
let limiter;
|
|
916
|
+
if (profile.limiter) {
|
|
917
|
+
const range = profile.limiter.range ?? 4;
|
|
918
|
+
const input = context.createGain();
|
|
919
|
+
input.gain.value = 1 / range;
|
|
920
|
+
const shaper = context.createWaveShaper();
|
|
921
|
+
shaper.curve = limiterCurve(profile.limiter.ceiling, profile.limiter.knee, range);
|
|
922
|
+
input.connect(shaper);
|
|
923
|
+
shaper.connect(context.destination);
|
|
924
|
+
limiter = { input, shaper };
|
|
925
|
+
}
|
|
926
|
+
const output = limiter?.input ?? context.destination;
|
|
808
927
|
let compressor;
|
|
809
928
|
if (profile.compressor) {
|
|
810
929
|
compressor = context.createDynamicsCompressor();
|
|
@@ -813,17 +932,19 @@ var GameAudio = (() => {
|
|
|
813
932
|
if (profile.compressor.knee !== void 0) compressor.knee.value = profile.compressor.knee;
|
|
814
933
|
if (profile.compressor.attack !== void 0) compressor.attack.value = profile.compressor.attack;
|
|
815
934
|
if (profile.compressor.release !== void 0) compressor.release.value = profile.compressor.release;
|
|
816
|
-
compressor.connect(
|
|
935
|
+
compressor.connect(output);
|
|
817
936
|
}
|
|
818
937
|
const master = context.createGain();
|
|
819
938
|
master.gain.value = profile.master;
|
|
820
|
-
master.connect(compressor ??
|
|
939
|
+
master.connect(compressor ?? output);
|
|
821
940
|
if (!profile.reverb) {
|
|
822
941
|
return {
|
|
823
942
|
master,
|
|
824
943
|
disconnect: () => {
|
|
825
944
|
master.disconnect();
|
|
826
945
|
compressor?.disconnect();
|
|
946
|
+
limiter?.input.disconnect();
|
|
947
|
+
limiter?.shaper.disconnect();
|
|
827
948
|
}
|
|
828
949
|
};
|
|
829
950
|
}
|
|
@@ -842,6 +963,8 @@ var GameAudio = (() => {
|
|
|
842
963
|
convolver.disconnect();
|
|
843
964
|
master.disconnect();
|
|
844
965
|
compressor?.disconnect();
|
|
966
|
+
limiter?.input.disconnect();
|
|
967
|
+
limiter?.shaper.disconnect();
|
|
845
968
|
}
|
|
846
969
|
};
|
|
847
970
|
}
|
|
@@ -853,7 +976,32 @@ var GameAudio = (() => {
|
|
|
853
976
|
return Constructor ? new Constructor() : null;
|
|
854
977
|
}
|
|
855
978
|
function unlockContext(context) {
|
|
856
|
-
if (context.state === "suspended") void context.resume();
|
|
979
|
+
if (context.state === "suspended" && typeof context.close === "function") void context.resume();
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// src/loops.ts
|
|
983
|
+
var LOOP_START_ABOVE = 2e-3;
|
|
984
|
+
var LOOP_SMOOTHING = { volume: 0.15, frequency: 0.08 };
|
|
985
|
+
function createLoopState(recipe2, open = false) {
|
|
986
|
+
const startAbove = recipe2.startAbove ?? LOOP_START_ABOVE;
|
|
987
|
+
let created = open;
|
|
988
|
+
let volume = recipe2.volume ?? 0;
|
|
989
|
+
return {
|
|
990
|
+
set(state) {
|
|
991
|
+
volume = state.volume ?? volume;
|
|
992
|
+
const create = !created;
|
|
993
|
+
if (create && !(volume >= startAbove)) return null;
|
|
994
|
+
created = true;
|
|
995
|
+
const frequency = recipe2.source.kind === "osc" && state.frequency ? state.frequency : void 0;
|
|
996
|
+
return { create, volume, ...frequency === void 0 ? {} : { frequency } };
|
|
997
|
+
},
|
|
998
|
+
get created() {
|
|
999
|
+
return created;
|
|
1000
|
+
},
|
|
1001
|
+
reset() {
|
|
1002
|
+
created = false;
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
857
1005
|
}
|
|
858
1006
|
|
|
859
1007
|
// src/webaudio/nodes.ts
|
|
@@ -906,13 +1054,23 @@ var GameAudio = (() => {
|
|
|
906
1054
|
}
|
|
907
1055
|
|
|
908
1056
|
// src/webaudio/realize-loop.ts
|
|
1057
|
+
function outputStage(recipe2, target, gain) {
|
|
1058
|
+
if (!recipe2.pan) {
|
|
1059
|
+
gain.connect(target.output);
|
|
1060
|
+
return { out: gain };
|
|
1061
|
+
}
|
|
1062
|
+
const panner = target.context.createStereoPanner();
|
|
1063
|
+
gain.connect(panner);
|
|
1064
|
+
panner.connect(target.output);
|
|
1065
|
+
return { out: panner, panner };
|
|
1066
|
+
}
|
|
909
1067
|
var fixed = (range) => typeof range === "number" ? range : 0;
|
|
910
1068
|
var fixedFrequency = (automation) => fixed("set" in automation ? automation.set : automation.from);
|
|
911
|
-
function sourceOf(
|
|
912
|
-
if (
|
|
1069
|
+
function sourceOf(recipe2, target) {
|
|
1070
|
+
if (recipe2.source.kind === "noise") return { source: noiseSource(target, true) };
|
|
913
1071
|
const oscillator = target.context.createOscillator();
|
|
914
|
-
oscillator.type =
|
|
915
|
-
if (
|
|
1072
|
+
oscillator.type = recipe2.source.wave;
|
|
1073
|
+
if (recipe2.source.frequency) oscillator.frequency.value = fixedFrequency(recipe2.source.frequency);
|
|
916
1074
|
return { source: oscillator, frequency: oscillator.frequency };
|
|
917
1075
|
}
|
|
918
1076
|
function stopAll(sources) {
|
|
@@ -925,23 +1083,23 @@ var GameAudio = (() => {
|
|
|
925
1083
|
}
|
|
926
1084
|
};
|
|
927
1085
|
}
|
|
928
|
-
function realizeGameLoop(
|
|
1086
|
+
function realizeGameLoop(recipe2, target) {
|
|
929
1087
|
const { context } = target;
|
|
930
1088
|
const gain = context.createGain();
|
|
931
|
-
const filters = (
|
|
1089
|
+
const filters = (recipe2.filters?.bank ?? []).map(() => context.createBiquadFilter());
|
|
932
1090
|
gain.gain.value = 0;
|
|
933
1091
|
const last = filters.reduce((previous, filter) => previous ? previous.connect(filter) : filter, void 0);
|
|
934
1092
|
last?.connect(gain);
|
|
935
|
-
|
|
936
|
-
const { source, frequency } = sourceOf(
|
|
937
|
-
|
|
1093
|
+
const output = outputStage(recipe2, target, gain);
|
|
1094
|
+
const { source, frequency } = sourceOf(recipe2, target);
|
|
1095
|
+
recipe2.filters?.bank.forEach((spec, index) => {
|
|
938
1096
|
const filter = filters[index];
|
|
939
1097
|
filter.type = spec.type;
|
|
940
1098
|
filter.frequency.value = fixedFrequency(spec.frequency);
|
|
941
1099
|
if (spec.q !== void 0) filter.Q.value = fixed(spec.q);
|
|
942
1100
|
});
|
|
943
1101
|
const sources = [source];
|
|
944
|
-
for (const modulator of
|
|
1102
|
+
for (const modulator of recipe2.modulators ?? []) {
|
|
945
1103
|
const lfo = context.createOscillator();
|
|
946
1104
|
const depth = context.createGain();
|
|
947
1105
|
const stage = context.createGain();
|
|
@@ -959,16 +1117,16 @@ var GameAudio = (() => {
|
|
|
959
1117
|
}
|
|
960
1118
|
source.connect(filters[0] ?? gain);
|
|
961
1119
|
source.start();
|
|
962
|
-
return { gain, source, ...frequency ? { frequency } : {}, stop: stopAll(sources) };
|
|
1120
|
+
return { gain, ...output, source, ...frequency ? { frequency } : {}, ...filters[0] ? { cutoff: filters[0].frequency } : {}, stop: stopAll(sources) };
|
|
963
1121
|
}
|
|
964
|
-
function realizeChainLoop(
|
|
1122
|
+
function realizeChainLoop(recipe2, target, volume) {
|
|
965
1123
|
const { context } = target;
|
|
966
|
-
const { source, frequency } = sourceOf(
|
|
967
|
-
const filters = (
|
|
1124
|
+
const { source, frequency } = sourceOf(recipe2, target);
|
|
1125
|
+
const filters = (recipe2.filters?.bank ?? []).map(
|
|
968
1126
|
(spec) => filterNode(context, { type: spec.type, frequency: { value: fixedFrequency(spec.frequency) }, ...spec.q === void 0 ? {} : { q: fixed(spec.q) } }, target.time)
|
|
969
1127
|
);
|
|
970
1128
|
const gain = gainNode(context, volume);
|
|
971
|
-
const lfos = (
|
|
1129
|
+
const lfos = (recipe2.modulators ?? []).map((modulator) => {
|
|
972
1130
|
const lfo = context.createOscillator();
|
|
973
1131
|
if (modulator.wave) lfo.type = modulator.wave;
|
|
974
1132
|
lfo.frequency.value = fixed(modulator.rate);
|
|
@@ -980,19 +1138,19 @@ var GameAudio = (() => {
|
|
|
980
1138
|
let tail = source;
|
|
981
1139
|
for (const filter of filters) tail = tail.connect(filter);
|
|
982
1140
|
tail.connect(gain);
|
|
983
|
-
|
|
1141
|
+
const output = outputStage(recipe2, target, gain);
|
|
984
1142
|
source.start();
|
|
985
1143
|
for (const lfo of lfos) lfo.start();
|
|
986
|
-
return { gain, source, ...frequency ? { frequency } : {}, stop: stopAll([source, ...lfos]) };
|
|
1144
|
+
return { gain, ...output, source, ...frequency ? { frequency } : {}, ...filters[0] ? { cutoff: filters[0].frequency } : {}, stop: stopAll([source, ...lfos]) };
|
|
987
1145
|
}
|
|
988
1146
|
|
|
989
1147
|
// src/webaudio/engine-loop.ts
|
|
990
1148
|
var INERT = { set() {
|
|
991
1149
|
}, stop() {
|
|
992
1150
|
} };
|
|
993
|
-
function createLoopHandle(
|
|
994
|
-
if (!
|
|
995
|
-
const loopRecipe =
|
|
1151
|
+
function createLoopHandle(recipe2, host, volume) {
|
|
1152
|
+
if (!recipe2) return INERT;
|
|
1153
|
+
const loopRecipe = recipe2;
|
|
996
1154
|
const isChain = loopRecipe.order === "chain_loop";
|
|
997
1155
|
const opening = volume ?? loopRecipe.volume ?? 0;
|
|
998
1156
|
const smoothing = loopRecipe.smoothing ?? LOOP_SMOOTHING;
|
|
@@ -1003,12 +1161,12 @@ var GameAudio = (() => {
|
|
|
1003
1161
|
return nodes !== void 0;
|
|
1004
1162
|
},
|
|
1005
1163
|
rewire() {
|
|
1006
|
-
nodes?.
|
|
1007
|
-
nodes?.
|
|
1164
|
+
nodes?.out.disconnect();
|
|
1165
|
+
nodes?.out.connect(host.output(loopRecipe.bus));
|
|
1008
1166
|
},
|
|
1009
1167
|
stop() {
|
|
1010
1168
|
nodes?.stop();
|
|
1011
|
-
nodes?.
|
|
1169
|
+
nodes?.out.disconnect();
|
|
1012
1170
|
nodes = void 0;
|
|
1013
1171
|
state = createLoopState(loopRecipe);
|
|
1014
1172
|
host.unregister(entry);
|
|
@@ -1028,16 +1186,168 @@ var GameAudio = (() => {
|
|
|
1028
1186
|
state = createLoopState({ ...loopRecipe, volume: opening }, true);
|
|
1029
1187
|
};
|
|
1030
1188
|
if (isChain) open();
|
|
1189
|
+
let position;
|
|
1190
|
+
let cutoff;
|
|
1191
|
+
const placed = loopRecipe.falloff !== void 0 || loopRecipe.pan === true;
|
|
1031
1192
|
return {
|
|
1032
1193
|
set(next) {
|
|
1033
1194
|
if (isChain && !nodes) open();
|
|
1034
1195
|
const context = host.ready();
|
|
1035
1196
|
if (!context) return;
|
|
1197
|
+
position = next.position ?? position;
|
|
1198
|
+
cutoff = next.cutoff ?? cutoff;
|
|
1036
1199
|
const action = state.set(next);
|
|
1037
1200
|
if (!action) return;
|
|
1038
1201
|
nodes ?? (nodes = create(context, 0));
|
|
1039
|
-
|
|
1202
|
+
const listener = placed && position ? host.listener?.() : void 0;
|
|
1203
|
+
const distance = listener && position ? listenerDistance(listener, position, host.distance) : 0;
|
|
1204
|
+
const level = listener ? falloffGain(loopRecipe.falloff, action.volume, distance) : action.volume;
|
|
1205
|
+
nodes.gain.gain.setTargetAtTime(level, context.currentTime, smoothing.volume);
|
|
1040
1206
|
if (action.frequency !== void 0 && nodes.frequency) nodes.frequency.setTargetAtTime(action.frequency, context.currentTime, smoothing.frequency);
|
|
1207
|
+
if (cutoff !== void 0 && nodes.cutoff) nodes.cutoff.setTargetAtTime(cutoff / cutoffDivisor(loopRecipe.falloff, distance), context.currentTime, smoothing.frequency);
|
|
1208
|
+
if (listener && position && nodes.panner) nodes.panner.pan.setTargetAtTime(panFor(listener, position), context.currentTime, smoothing.frequency);
|
|
1209
|
+
},
|
|
1210
|
+
stop: entry.stop
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
// src/webaudio/sample-loop.ts
|
|
1215
|
+
var DEFAULT_LOOP_CROSSFADE = 0.25;
|
|
1216
|
+
var LOOKAHEAD = 1.5;
|
|
1217
|
+
var VOLUME_SMOOTHING = 0.05;
|
|
1218
|
+
function loopCrossfade(sound) {
|
|
1219
|
+
if (!sound.loop) return void 0;
|
|
1220
|
+
return sound.loop === true ? DEFAULT_LOOP_CROSSFADE : Math.max(0, sound.loop.crossfade ?? DEFAULT_LOOP_CROSSFADE);
|
|
1221
|
+
}
|
|
1222
|
+
var CROSSFADE_STEPS = 8;
|
|
1223
|
+
var equalPowerIn = (t) => Math.sin(Math.max(0, Math.min(1, t)) * Math.PI / 2);
|
|
1224
|
+
var ramp2 = (param, direction, at, seconds) => {
|
|
1225
|
+
const value = (t) => direction === "in" ? equalPowerIn(t) : equalPowerIn(1 - t);
|
|
1226
|
+
param.setValueAtTime(value(0), at);
|
|
1227
|
+
for (let step = 1; step <= CROSSFADE_STEPS; step++) param.linearRampToValueAtTime(value(step / CROSSFADE_STEPS), at + seconds * step / CROSSFADE_STEPS);
|
|
1228
|
+
};
|
|
1229
|
+
function createSampleLoopHandle(sound, host, volume = 0) {
|
|
1230
|
+
const crossfade = loopCrossfade(sound) ?? DEFAULT_LOOP_CROSSFADE;
|
|
1231
|
+
let level = volume;
|
|
1232
|
+
let stopped = false;
|
|
1233
|
+
let fallback;
|
|
1234
|
+
let master;
|
|
1235
|
+
let segments = [];
|
|
1236
|
+
let last;
|
|
1237
|
+
let timer;
|
|
1238
|
+
const entry = {
|
|
1239
|
+
get created() {
|
|
1240
|
+
return master !== void 0;
|
|
1241
|
+
},
|
|
1242
|
+
rewire() {
|
|
1243
|
+
master?.disconnect();
|
|
1244
|
+
master?.connect(host.output(sound.bus));
|
|
1245
|
+
},
|
|
1246
|
+
stop() {
|
|
1247
|
+
stopped = true;
|
|
1248
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1249
|
+
timer = void 0;
|
|
1250
|
+
for (const segment of segments) {
|
|
1251
|
+
try {
|
|
1252
|
+
segment.source.stop();
|
|
1253
|
+
} catch {
|
|
1254
|
+
}
|
|
1255
|
+
segment.source.disconnect();
|
|
1256
|
+
segment.gain.disconnect();
|
|
1257
|
+
}
|
|
1258
|
+
segments = [];
|
|
1259
|
+
master?.disconnect();
|
|
1260
|
+
master = void 0;
|
|
1261
|
+
fallback?.stop();
|
|
1262
|
+
fallback = void 0;
|
|
1263
|
+
host.unregister(entry);
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
const nextBuffer = () => {
|
|
1267
|
+
const takes2 = sound.close;
|
|
1268
|
+
const take = pickTake(takes2.length, last, host.random);
|
|
1269
|
+
last = take;
|
|
1270
|
+
const ref = takes2[take];
|
|
1271
|
+
return ref ? host.buffer(ref.url) : void 0;
|
|
1272
|
+
};
|
|
1273
|
+
const schedule = (context, output, at, first) => {
|
|
1274
|
+
const buffer = nextBuffer();
|
|
1275
|
+
if (!buffer) return void 0;
|
|
1276
|
+
const source = context.createBufferSource();
|
|
1277
|
+
source.buffer = buffer;
|
|
1278
|
+
const gain = context.createGain();
|
|
1279
|
+
source.connect(gain);
|
|
1280
|
+
gain.connect(output);
|
|
1281
|
+
const fade = Math.min(crossfade, buffer.duration / 2);
|
|
1282
|
+
if (buffer.duration < 2 * crossfade || sound.close.length === 1) {
|
|
1283
|
+
source.loop = true;
|
|
1284
|
+
if (!first) ramp2(gain.gain, "in", at, Math.max(1e-3, fade));
|
|
1285
|
+
source.start(at);
|
|
1286
|
+
segments.push({ source, gain, end: Number.POSITIVE_INFINITY });
|
|
1287
|
+
return void 0;
|
|
1288
|
+
}
|
|
1289
|
+
if (first) gain.gain.setValueAtTime(1, at);
|
|
1290
|
+
else ramp2(gain.gain, "in", at, fade);
|
|
1291
|
+
const end3 = at + buffer.duration;
|
|
1292
|
+
ramp2(gain.gain, "out", end3 - fade, fade);
|
|
1293
|
+
source.start(at);
|
|
1294
|
+
source.stop(end3);
|
|
1295
|
+
segments.push({ source, gain, end: end3 });
|
|
1296
|
+
source.onended = () => {
|
|
1297
|
+
segments = segments.filter((segment) => segment.source !== source);
|
|
1298
|
+
source.disconnect();
|
|
1299
|
+
gain.disconnect();
|
|
1300
|
+
};
|
|
1301
|
+
return end3 - fade;
|
|
1302
|
+
};
|
|
1303
|
+
const pump = (context, output, at, first) => {
|
|
1304
|
+
if (stopped) return;
|
|
1305
|
+
let next = schedule(context, output, at, first);
|
|
1306
|
+
while (next !== void 0 && next < context.currentTime + LOOKAHEAD) next = schedule(context, output, Math.max(next, context.currentTime), false);
|
|
1307
|
+
if (next === void 0) return;
|
|
1308
|
+
const wait = Math.max(0, (next - context.currentTime - LOOKAHEAD / 2) * 1e3);
|
|
1309
|
+
timer = setTimeout(() => {
|
|
1310
|
+
timer = void 0;
|
|
1311
|
+
pump(context, output, next, false);
|
|
1312
|
+
}, wait);
|
|
1313
|
+
};
|
|
1314
|
+
const fileLevel = () => level * (sound.gain ?? 1);
|
|
1315
|
+
const startFiles = () => {
|
|
1316
|
+
if (stopped || master || !host.isReady(sound)) return master !== void 0;
|
|
1317
|
+
const context = host.ready();
|
|
1318
|
+
if (!context) return false;
|
|
1319
|
+
master = context.createGain();
|
|
1320
|
+
master.gain.setValueAtTime(fileLevel(), context.currentTime);
|
|
1321
|
+
master.connect(host.output(sound.bus));
|
|
1322
|
+
host.register(entry);
|
|
1323
|
+
pump(context, master, context.currentTime, true);
|
|
1324
|
+
if (fallback) {
|
|
1325
|
+
fallback.set({ volume: 0 });
|
|
1326
|
+
const old = fallback;
|
|
1327
|
+
fallback = void 0;
|
|
1328
|
+
setTimeout(() => old.stop(), VOLUME_SMOOTHING * 6e3);
|
|
1329
|
+
}
|
|
1330
|
+
return true;
|
|
1331
|
+
};
|
|
1332
|
+
const ensure = () => {
|
|
1333
|
+
if (stopped || master) return;
|
|
1334
|
+
if (startFiles()) return;
|
|
1335
|
+
if (!fallback) {
|
|
1336
|
+
fallback = host.fallback(level);
|
|
1337
|
+
void host.load(sound).then(() => {
|
|
1338
|
+
if (level > 0 || master) startFiles();
|
|
1339
|
+
}).catch(() => void 0);
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
if (volume > 0) ensure();
|
|
1343
|
+
return {
|
|
1344
|
+
set(next) {
|
|
1345
|
+
if (stopped) return;
|
|
1346
|
+
if (next.volume !== void 0) level = host.muted(sound.bus) ? 0 : Math.max(0, next.volume);
|
|
1347
|
+
if (level > 0) ensure();
|
|
1348
|
+
const context = host.ready();
|
|
1349
|
+
if (master && context) master.gain.setTargetAtTime(fileLevel(), context.currentTime, VOLUME_SMOOTHING);
|
|
1350
|
+
fallback?.set(next.volume === void 0 ? next : { ...next, volume: level });
|
|
1041
1351
|
},
|
|
1042
1352
|
stop: entry.stop
|
|
1043
1353
|
};
|
|
@@ -1064,6 +1374,58 @@ var GameAudio = (() => {
|
|
|
1064
1374
|
return store.buffer;
|
|
1065
1375
|
}
|
|
1066
1376
|
|
|
1377
|
+
// ../game-contracts/dist/index.js
|
|
1378
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
1379
|
+
var DEFERRED_QUEUE_ID = {
|
|
1380
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
1381
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
1382
|
+
AUDIO_VOICES: "audio.voices",
|
|
1383
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
1384
|
+
};
|
|
1385
|
+
var DEFERRED_PRIORITY = {
|
|
1386
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
1387
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
1388
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
1389
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
1390
|
+
};
|
|
1391
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
1392
|
+
var GAIT_IDS = ["walk", "run"];
|
|
1393
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
1394
|
+
var BODY_SOUND_IDS = [
|
|
1395
|
+
"jump",
|
|
1396
|
+
"cloth_rustle",
|
|
1397
|
+
"body_fall",
|
|
1398
|
+
"fall_damage",
|
|
1399
|
+
"player_hurt",
|
|
1400
|
+
"player_breath_run",
|
|
1401
|
+
"player_death",
|
|
1402
|
+
"bite",
|
|
1403
|
+
"grab",
|
|
1404
|
+
"punch_swing",
|
|
1405
|
+
"punch_hit_body",
|
|
1406
|
+
"punch_hit_face",
|
|
1407
|
+
"punch_hit_object",
|
|
1408
|
+
"kick_swing",
|
|
1409
|
+
"kick_hit",
|
|
1410
|
+
"kick_hit_object",
|
|
1411
|
+
"shove_two_hands",
|
|
1412
|
+
"knife_swing",
|
|
1413
|
+
"knife_stab",
|
|
1414
|
+
"knife_slash",
|
|
1415
|
+
"knife_hit_object",
|
|
1416
|
+
"blunt_swing",
|
|
1417
|
+
"blunt_hit",
|
|
1418
|
+
"blunt_hit_object",
|
|
1419
|
+
"axe_swing",
|
|
1420
|
+
"axe_chop",
|
|
1421
|
+
"axe_hit_object"
|
|
1422
|
+
];
|
|
1423
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
1424
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
1425
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing2) => `land_${surface}_${landing2}`));
|
|
1426
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
1427
|
+
var SWING_LEAD_SECONDS = { punch: 0.07, kick: 0.09, shove: 0, blade: 0.05, blunt: 0.1, chop: 0.11 };
|
|
1428
|
+
|
|
1067
1429
|
// src/webaudio/engine-queue.ts
|
|
1068
1430
|
var nowMs = () => typeof performance === "undefined" ? Date.now() : performance.now();
|
|
1069
1431
|
function scheduleTask(task) {
|
|
@@ -1083,23 +1445,28 @@ var GameAudio = (() => {
|
|
|
1083
1445
|
const maxLatencyMs = options.maxLatencyMs ?? 250;
|
|
1084
1446
|
let jobs = [];
|
|
1085
1447
|
let scheduled = false;
|
|
1448
|
+
let attached = false;
|
|
1449
|
+
const runNext = () => {
|
|
1450
|
+
const job = jobs.shift();
|
|
1451
|
+
if (nowMs() - job.queuedAt > maxLatencyMs) job.drop();
|
|
1452
|
+
else job.run();
|
|
1453
|
+
};
|
|
1086
1454
|
const drain = () => {
|
|
1087
1455
|
scheduled = false;
|
|
1456
|
+
if (attached) return;
|
|
1088
1457
|
const began = nowMs();
|
|
1089
1458
|
while (jobs.length > 0) {
|
|
1090
|
-
|
|
1091
|
-
if (nowMs() - job.queuedAt > maxLatencyMs) job.drop();
|
|
1092
|
-
else job.run();
|
|
1459
|
+
runNext();
|
|
1093
1460
|
if (nowMs() - began >= budgetMs) break;
|
|
1094
1461
|
}
|
|
1095
1462
|
if (jobs.length > 0) schedule();
|
|
1096
1463
|
};
|
|
1097
1464
|
const schedule = () => {
|
|
1098
|
-
if (scheduled) return;
|
|
1465
|
+
if (scheduled || attached) return;
|
|
1099
1466
|
scheduled = true;
|
|
1100
1467
|
scheduleTask(drain);
|
|
1101
1468
|
};
|
|
1102
|
-
|
|
1469
|
+
const queue = {
|
|
1103
1470
|
push(job) {
|
|
1104
1471
|
jobs.push({ ...job, queuedAt: nowMs() });
|
|
1105
1472
|
schedule();
|
|
@@ -1110,8 +1477,33 @@ var GameAudio = (() => {
|
|
|
1110
1477
|
},
|
|
1111
1478
|
get size() {
|
|
1112
1479
|
return jobs.length;
|
|
1480
|
+
},
|
|
1481
|
+
deferredQueue: () => deferredQueue
|
|
1482
|
+
};
|
|
1483
|
+
const deferredQueue = {
|
|
1484
|
+
id: DEFERRED_QUEUE_ID.AUDIO_VOICES,
|
|
1485
|
+
pending: () => jobs.length,
|
|
1486
|
+
run(deadline, clock) {
|
|
1487
|
+
let ran = 0;
|
|
1488
|
+
while (jobs.length > 0) {
|
|
1489
|
+
runNext();
|
|
1490
|
+
ran++;
|
|
1491
|
+
if (clock() >= deadline) break;
|
|
1492
|
+
}
|
|
1493
|
+
return ran;
|
|
1494
|
+
},
|
|
1495
|
+
flush() {
|
|
1496
|
+
while (jobs.length > 0) runNext();
|
|
1497
|
+
},
|
|
1498
|
+
attach() {
|
|
1499
|
+
attached = true;
|
|
1500
|
+
},
|
|
1501
|
+
detach() {
|
|
1502
|
+
attached = false;
|
|
1503
|
+
if (jobs.length > 0) schedule();
|
|
1113
1504
|
}
|
|
1114
1505
|
};
|
|
1506
|
+
return queue;
|
|
1115
1507
|
}
|
|
1116
1508
|
|
|
1117
1509
|
// src/webaudio/realize-game.ts
|
|
@@ -1294,7 +1686,7 @@ var GameAudio = (() => {
|
|
|
1294
1686
|
|
|
1295
1687
|
// src/webaudio/realize-layered.ts
|
|
1296
1688
|
var end2 = (layer, start) => start + layer.duration + layer.tail;
|
|
1297
|
-
function
|
|
1689
|
+
function outputStage2(plan, layer, target) {
|
|
1298
1690
|
const { context } = target;
|
|
1299
1691
|
const level = gainNode(context, layer.level);
|
|
1300
1692
|
let node = level;
|
|
@@ -1326,7 +1718,7 @@ var GameAudio = (() => {
|
|
|
1326
1718
|
let tail = source;
|
|
1327
1719
|
for (const filter of filters) tail = tail.connect(filter);
|
|
1328
1720
|
tail.connect(envelope2);
|
|
1329
|
-
envelope2.connect(
|
|
1721
|
+
envelope2.connect(outputStage2(plan, layer, target));
|
|
1330
1722
|
source.start(time, layer.source.kind === "noise" ? layer.source.offset : 0);
|
|
1331
1723
|
source.stop(end2(layer, time));
|
|
1332
1724
|
return [source];
|
|
@@ -1343,7 +1735,7 @@ var GameAudio = (() => {
|
|
|
1343
1735
|
const envelope2 = context.createGain();
|
|
1344
1736
|
applyEnvelope(envelope2.gain, layer.envelope, time);
|
|
1345
1737
|
oscillator.connect(envelope2);
|
|
1346
|
-
envelope2.connect(
|
|
1738
|
+
envelope2.connect(outputStage2(plan, layer, target));
|
|
1347
1739
|
oscillator.start(time);
|
|
1348
1740
|
oscillator.stop(end2(layer, time));
|
|
1349
1741
|
return [oscillator];
|
|
@@ -1375,7 +1767,7 @@ var GameAudio = (() => {
|
|
|
1375
1767
|
const envelope2 = context.createGain();
|
|
1376
1768
|
applyEnvelope(envelope2.gain, layer.envelope, time);
|
|
1377
1769
|
mix.connect(envelope2);
|
|
1378
|
-
envelope2.connect(
|
|
1770
|
+
envelope2.connect(outputStage2(plan, layer, target));
|
|
1379
1771
|
const stop = end2(layer, time);
|
|
1380
1772
|
oscillator.start(time);
|
|
1381
1773
|
vibrato.start(time);
|
|
@@ -1488,45 +1880,292 @@ var GameAudio = (() => {
|
|
|
1488
1880
|
return BUILDERS[plan.order](plan, target);
|
|
1489
1881
|
}
|
|
1490
1882
|
|
|
1491
|
-
// src/
|
|
1492
|
-
var
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1883
|
+
// src/variation.ts
|
|
1884
|
+
var tuneAutomation = (automation, rate) => {
|
|
1885
|
+
const tuned = { ...automation };
|
|
1886
|
+
if (automation.value !== void 0) tuned.value = automation.value * rate;
|
|
1887
|
+
if (automation.from !== void 0) tuned.from = automation.from * rate;
|
|
1888
|
+
if (automation.to !== void 0) tuned.to = automation.to * rate;
|
|
1889
|
+
if (automation.at !== void 0) tuned.at = automation.at / rate;
|
|
1890
|
+
return tuned;
|
|
1891
|
+
};
|
|
1892
|
+
var tuneFilter = (filter, rate) => ({ ...filter, frequency: tuneAutomation(filter.frequency, rate) });
|
|
1893
|
+
var tuneSource = (source, rate) => {
|
|
1894
|
+
switch (source.kind) {
|
|
1895
|
+
case "noise":
|
|
1896
|
+
return source;
|
|
1897
|
+
case "osc":
|
|
1898
|
+
return { ...source, frequency: tuneAutomation(source.frequency, rate) };
|
|
1899
|
+
case "formant_voice":
|
|
1900
|
+
return {
|
|
1901
|
+
...source,
|
|
1902
|
+
frequency: tuneAutomation(source.frequency, rate),
|
|
1903
|
+
formants: source.formants.map((formant) => ({ ...formant, frequency: formant.frequency * rate })),
|
|
1904
|
+
breath: { ...source.breath, frequency: source.breath.frequency * rate }
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
var tuneModulator = (modulator, rate) => ({
|
|
1909
|
+
...modulator,
|
|
1910
|
+
rate: modulator.rate * rate,
|
|
1911
|
+
...modulator.target === "frequency" ? { depth: modulator.depth * rate } : {}
|
|
1912
|
+
});
|
|
1913
|
+
var tuneLayer = (layer, rate) => ({
|
|
1914
|
+
...layer,
|
|
1915
|
+
at: layer.at / rate,
|
|
1916
|
+
duration: layer.duration / rate,
|
|
1917
|
+
tail: layer.tail / rate,
|
|
1918
|
+
source: tuneSource(layer.source, rate),
|
|
1919
|
+
...layer.filters ? { filters: { ...layer.filters, bank: layer.filters.bank.map((filter) => tuneFilter(filter, rate)) } } : {},
|
|
1920
|
+
modulators: layer.modulators.map((modulator) => tuneModulator(modulator, rate)),
|
|
1921
|
+
envelope: layer.envelope.map((point) => ({ ...point, time: point.time / rate }))
|
|
1922
|
+
});
|
|
1923
|
+
function retunePlan(plan, rate) {
|
|
1924
|
+
if (rate === 1 || !(rate > 0)) return plan;
|
|
1925
|
+
return { ...plan, length: plan.length / rate, layers: plan.layers.map((layer) => tuneLayer(layer, rate)) };
|
|
1926
|
+
}
|
|
1927
|
+
function createSetPicker() {
|
|
1928
|
+
const last = /* @__PURE__ */ new Map();
|
|
1929
|
+
return {
|
|
1930
|
+
pick(set, random) {
|
|
1931
|
+
const count = set.variants.length;
|
|
1932
|
+
const previous = last.get(set.id);
|
|
1933
|
+
let index;
|
|
1934
|
+
if (count === 1) index = 0;
|
|
1935
|
+
else if (set.repeat || previous === void 0) index = Math.min(count - 1, Math.floor(random() * count));
|
|
1936
|
+
else {
|
|
1937
|
+
index = Math.min(count - 2, Math.floor(random() * (count - 1)));
|
|
1938
|
+
if (index >= previous) index += 1;
|
|
1939
|
+
}
|
|
1940
|
+
last.set(set.id, index);
|
|
1941
|
+
const [min, max] = set.rate ?? [1, 1];
|
|
1942
|
+
const rate = min === max ? min : min + random() * (max - min);
|
|
1943
|
+
return { id: set.variants[index], rate };
|
|
1944
|
+
},
|
|
1945
|
+
reset: () => last.clear()
|
|
1524
1946
|
};
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// src/webaudio/sample-store.ts
|
|
1950
|
+
function fetchLoader(baseUrl) {
|
|
1951
|
+
return async (url2) => {
|
|
1952
|
+
const target = baseUrl ? new URL(url2, baseUrl).toString() : url2;
|
|
1953
|
+
const response = await fetch(target);
|
|
1954
|
+
if (!response.ok) throw new Error(`${response.status} ${response.statusText} for ${target}`);
|
|
1955
|
+
return response.arrayBuffer();
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
function inlineLoader(files) {
|
|
1959
|
+
return async (url2) => {
|
|
1960
|
+
const text = files[url2];
|
|
1961
|
+
if (text === void 0) throw new Error(`no inline file for ${url2}`);
|
|
1962
|
+
const base64 = text.startsWith("data:") ? text.slice(text.indexOf(",") + 1) : text;
|
|
1963
|
+
const binary = atob(base64);
|
|
1964
|
+
const bytes = new Uint8Array(binary.length);
|
|
1965
|
+
for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
|
|
1966
|
+
return bytes.buffer;
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
var decode = (context, bytes) => new Promise((resolve, reject) => {
|
|
1970
|
+
const result = context.decodeAudioData(bytes, resolve, reject);
|
|
1971
|
+
result?.catch?.(reject);
|
|
1972
|
+
});
|
|
1973
|
+
function createSampleStore(loader = fetchLoader()) {
|
|
1974
|
+
const buffers = /* @__PURE__ */ new Map();
|
|
1975
|
+
const pending = /* @__PURE__ */ new Map();
|
|
1976
|
+
const failed = /* @__PURE__ */ new Map();
|
|
1977
|
+
let generation = 0;
|
|
1978
|
+
const loadOne = (url2, context) => {
|
|
1979
|
+
const existing = buffers.get(url2);
|
|
1980
|
+
if (existing) return Promise.resolve(existing);
|
|
1981
|
+
const inFlight = pending.get(url2);
|
|
1982
|
+
if (inFlight) return inFlight;
|
|
1983
|
+
const started = generation;
|
|
1984
|
+
failed.delete(url2);
|
|
1985
|
+
const promise = loader(url2).then((bytes) => decode(context, bytes)).then((buffer) => {
|
|
1986
|
+
if (started === generation) buffers.set(url2, buffer);
|
|
1987
|
+
return buffer;
|
|
1988
|
+
}).catch((error) => {
|
|
1989
|
+
if (started === generation) failed.set(url2, error instanceof Error ? error.message : String(error));
|
|
1990
|
+
throw error;
|
|
1991
|
+
}).finally(() => {
|
|
1992
|
+
if (pending.get(url2) === promise) pending.delete(url2);
|
|
1993
|
+
});
|
|
1994
|
+
pending.set(url2, promise);
|
|
1995
|
+
return promise;
|
|
1996
|
+
};
|
|
1997
|
+
return {
|
|
1998
|
+
status(url2) {
|
|
1999
|
+
if (buffers.has(url2)) return "ready";
|
|
2000
|
+
if (pending.has(url2)) return "loading";
|
|
2001
|
+
if (failed.has(url2)) return "failed";
|
|
2002
|
+
return "none";
|
|
2003
|
+
},
|
|
2004
|
+
buffer: (url2) => buffers.get(url2),
|
|
2005
|
+
ready: (urls) => urls.every((url2) => buffers.has(url2)),
|
|
2006
|
+
seconds: (url2) => buffers.get(url2)?.duration,
|
|
2007
|
+
async load(urls, context) {
|
|
2008
|
+
const results = await Promise.allSettled(urls.map((url2) => loadOne(url2, context)));
|
|
2009
|
+
const loaded = [];
|
|
2010
|
+
const errors = [];
|
|
2011
|
+
results.forEach((result, index) => {
|
|
2012
|
+
const url2 = urls[index];
|
|
2013
|
+
if (result.status === "fulfilled") loaded.push(url2);
|
|
2014
|
+
else errors.push({ url: url2, error: result.reason instanceof Error ? result.reason.message : String(result.reason) });
|
|
2015
|
+
});
|
|
2016
|
+
return { loaded, failed: errors };
|
|
2017
|
+
},
|
|
2018
|
+
clear() {
|
|
2019
|
+
generation++;
|
|
2020
|
+
buffers.clear();
|
|
2021
|
+
pending.clear();
|
|
2022
|
+
failed.clear();
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// src/webaudio/realize-sample.ts
|
|
2028
|
+
function realizeSample(plan, target) {
|
|
2029
|
+
const context = target.context;
|
|
2030
|
+
let head = target.output;
|
|
2031
|
+
if (plan.pan !== void 0 && typeof context.createStereoPanner === "function") {
|
|
2032
|
+
const panner = context.createStereoPanner();
|
|
2033
|
+
panner.pan.value = plan.pan;
|
|
2034
|
+
panner.connect(head);
|
|
2035
|
+
head = panner;
|
|
2036
|
+
}
|
|
2037
|
+
if (plan.cutoff < OPEN_CUTOFF) {
|
|
2038
|
+
const lowpass = context.createBiquadFilter();
|
|
2039
|
+
lowpass.type = "lowpass";
|
|
2040
|
+
lowpass.frequency.value = plan.cutoff;
|
|
2041
|
+
lowpass.Q.value = 0.7;
|
|
2042
|
+
lowpass.connect(head);
|
|
2043
|
+
head = lowpass;
|
|
2044
|
+
}
|
|
2045
|
+
const voice2 = context.createGain();
|
|
2046
|
+
voice2.connect(head);
|
|
2047
|
+
head = voice2;
|
|
2048
|
+
const sources = [];
|
|
2049
|
+
for (const layer of plan.layers) {
|
|
2050
|
+
const buffer = target.buffer(layer.url);
|
|
2051
|
+
if (!buffer) continue;
|
|
2052
|
+
const source = context.createBufferSource();
|
|
2053
|
+
source.buffer = buffer;
|
|
2054
|
+
source.playbackRate.value = layer.rate;
|
|
2055
|
+
const gain = gainNode(context, layer.gain);
|
|
2056
|
+
source.connect(gain);
|
|
2057
|
+
gain.connect(head);
|
|
2058
|
+
source.start(target.time + layer.at);
|
|
2059
|
+
sources.push(source);
|
|
2060
|
+
}
|
|
2061
|
+
const realized = voiceOf(sources);
|
|
2062
|
+
return {
|
|
2063
|
+
...realized,
|
|
2064
|
+
fade(at, seconds) {
|
|
2065
|
+
voice2.gain.setValueAtTime(1, at);
|
|
2066
|
+
voice2.gain.linearRampToValueAtTime(0, at + seconds);
|
|
2067
|
+
for (const source of sources) {
|
|
2068
|
+
try {
|
|
2069
|
+
source.stop(at + seconds);
|
|
2070
|
+
} catch {
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
function sampleLength(plan, seconds) {
|
|
2077
|
+
let length = 0;
|
|
2078
|
+
for (const layer of plan.layers) length = Math.max(length, layer.at + (seconds(layer.url) ?? 0) / layer.rate);
|
|
2079
|
+
return length;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// src/webaudio/engine.ts
|
|
2083
|
+
function limiterCurve2(knee, ceiling, range, points = 2049) {
|
|
2084
|
+
const curve = new Float32Array(points);
|
|
2085
|
+
const room = Math.max(1e-6, ceiling - knee);
|
|
2086
|
+
for (let index = 0; index < points; index++) {
|
|
2087
|
+
const value = (index / (points - 1) * 2 - 1) * range;
|
|
2088
|
+
const size = Math.abs(value);
|
|
2089
|
+
const bent = size <= knee ? size : knee + room * Math.tanh((size - knee) / room);
|
|
2090
|
+
curve[index] = Math.sign(value) * bent;
|
|
2091
|
+
}
|
|
2092
|
+
return curve;
|
|
2093
|
+
}
|
|
2094
|
+
var usesNoise = (recipe2) => recipe2.layers.some((layer) => layer.source.kind !== "osc");
|
|
2095
|
+
var planUsesNoise = (plan) => plan.layers.some((layer) => layer.source.kind !== "osc");
|
|
2096
|
+
function createAudioEngine(options = {}) {
|
|
2097
|
+
const seed = options.seed ?? 1;
|
|
2098
|
+
const registry = createSoundRegistry(options.banks);
|
|
2099
|
+
const voices = createVoiceManager({ ...options.groups ? { groups: options.groups } : {}, ...options.maxVoices === void 0 ? {} : { maxVoices: options.maxVoices } });
|
|
2100
|
+
const engineRandom = createRng(seed);
|
|
2101
|
+
const shared = createNoiseStore(engineRandom);
|
|
2102
|
+
const busSettings = /* @__PURE__ */ new Map();
|
|
2103
|
+
const busNodes = /* @__PURE__ */ new Map();
|
|
2104
|
+
const meters = /* @__PURE__ */ new Map();
|
|
2105
|
+
const active = /* @__PURE__ */ new Map();
|
|
2106
|
+
const loops = /* @__PURE__ */ new Set();
|
|
2107
|
+
const named = /* @__PURE__ */ new Map();
|
|
2108
|
+
let mix = resolveMix(options.mix ?? DEFAULT_MIX, options.profiles);
|
|
2109
|
+
let context = null;
|
|
2110
|
+
let chain = null;
|
|
2111
|
+
let listener = DEFAULT_LISTENER;
|
|
2112
|
+
let lastTime = 0;
|
|
2113
|
+
let environment = options.environment ?? "outdoor";
|
|
2114
|
+
const sampleLimiters = /* @__PURE__ */ new Map();
|
|
2115
|
+
const sampleOutput = (bus) => {
|
|
2116
|
+
const setting = options.samples?.limiter;
|
|
2117
|
+
if (setting === false || !context) return outputFor(bus);
|
|
2118
|
+
const existing = sampleLimiters.get(bus);
|
|
2119
|
+
if (existing) return existing;
|
|
2120
|
+
const range = 4;
|
|
2121
|
+
const input = context.createGain();
|
|
2122
|
+
input.gain.value = 1 / range;
|
|
2123
|
+
const shaper = context.createWaveShaper();
|
|
2124
|
+
shaper.curve = limiterCurve2(setting?.knee ?? 0.5, setting?.ceiling ?? 0.891, range);
|
|
2125
|
+
ensureBus(bus);
|
|
2126
|
+
input.connect(shaper);
|
|
2127
|
+
shaper.connect(outputFor(bus));
|
|
2128
|
+
sampleLimiters.set(bus, input);
|
|
2129
|
+
return input;
|
|
2130
|
+
};
|
|
2131
|
+
const chokes = /* @__PURE__ */ new Map();
|
|
2132
|
+
const choked = (id) => {
|
|
2133
|
+
const list = (chokes.get(id) ?? []).filter((entry) => active.has(entry.id));
|
|
2134
|
+
chokes.set(id, list);
|
|
2135
|
+
return list;
|
|
2136
|
+
};
|
|
2137
|
+
const watchers = /* @__PURE__ */ new Set();
|
|
2138
|
+
const announce = (event) => {
|
|
2139
|
+
options.onVoiceStart?.(event);
|
|
2140
|
+
for (const watcher of watchers) watcher(event);
|
|
2141
|
+
};
|
|
2142
|
+
const sources = [];
|
|
2143
|
+
const baseLoader = options.samples?.loader ?? fetchLoader(options.samples?.baseUrl);
|
|
2144
|
+
const sampleStore = createSampleStore((url2) => (sources.find((source) => source.accepts(url2))?.loader ?? baseLoader)(url2));
|
|
2145
|
+
const memory = /* @__PURE__ */ new Map();
|
|
2146
|
+
const latencyOf = (audio) => {
|
|
2147
|
+
const live = audio;
|
|
2148
|
+
return (live.baseLatency ?? 0) + (live.outputLatency ?? 0);
|
|
2149
|
+
};
|
|
2150
|
+
const outputFor = (bus) => busNodes.get(bus) ?? chain?.master;
|
|
2151
|
+
const watched = /* @__PURE__ */ new Set();
|
|
2152
|
+
const meterOf = (bus) => {
|
|
2153
|
+
const existing = meters.get(bus);
|
|
2154
|
+
if (existing) return existing;
|
|
2155
|
+
const node = busNodes.get(bus);
|
|
2156
|
+
if (!context || !node || typeof context.createAnalyser !== "function") return void 0;
|
|
2157
|
+
const analyser = context.createAnalyser();
|
|
2158
|
+
analyser.fftSize = 1024;
|
|
2159
|
+
node.connect(analyser);
|
|
2160
|
+
const made = { analyser, data: new Float32Array(analyser.fftSize) };
|
|
2161
|
+
meters.set(bus, made);
|
|
2162
|
+
return made;
|
|
2163
|
+
};
|
|
2164
|
+
const ensureBus = (bus) => {
|
|
2165
|
+
if (!context || !chain || busNodes.has(bus)) return;
|
|
2166
|
+
const node = context.createGain();
|
|
2167
|
+
node.connect(chain.master);
|
|
2168
|
+
busNodes.set(bus, node);
|
|
1530
2169
|
if (watched.has(bus)) meterOf(bus);
|
|
1531
2170
|
};
|
|
1532
2171
|
const ready = () => {
|
|
@@ -1552,7 +2191,7 @@ var GameAudio = (() => {
|
|
|
1552
2191
|
lastTime = context.currentTime;
|
|
1553
2192
|
if (elapsed > 0) for (const id of voices.advance(elapsed)) active.delete(id);
|
|
1554
2193
|
};
|
|
1555
|
-
const inputFor = (
|
|
2194
|
+
const inputFor = (recipe2, playOptions, random) => ({
|
|
1556
2195
|
random,
|
|
1557
2196
|
listener,
|
|
1558
2197
|
noiseSeconds: mix.noise.seconds,
|
|
@@ -1561,34 +2200,48 @@ var GameAudio = (() => {
|
|
|
1561
2200
|
...playOptions.distance === void 0 ? {} : { distance: playOptions.distance },
|
|
1562
2201
|
...playOptions.position ? { position: playOptions.position } : {},
|
|
1563
2202
|
...playOptions.params ? { params: playOptions.params } : {},
|
|
1564
|
-
...options.occlusion && playOptions.position &&
|
|
2203
|
+
...options.occlusion && playOptions.position && recipe2.falloff?.model !== "none" ? { occlusion: options.occlusion(playOptions.position) } : {}
|
|
1565
2204
|
});
|
|
1566
2205
|
const startQueue = options.deferredStart ? createStartQueue(options.deferredStart) : null;
|
|
1567
|
-
const build = (plan, store, delay) => {
|
|
2206
|
+
const build = (plan, store, delay, requestedAt, fallbackOf) => {
|
|
1568
2207
|
const audio = context;
|
|
1569
|
-
|
|
2208
|
+
const time = audio.currentTime + delay;
|
|
2209
|
+
const realized = realize(plan, {
|
|
1570
2210
|
context: audio,
|
|
1571
2211
|
output: outputFor(plan.bus),
|
|
1572
2212
|
...chain?.wet ? { wet: chain.wet } : {},
|
|
1573
2213
|
noise: () => noiseBuffer(store, audio, mix.noise.seconds),
|
|
1574
|
-
time
|
|
2214
|
+
time
|
|
1575
2215
|
});
|
|
2216
|
+
announce({
|
|
2217
|
+
id: plan.id,
|
|
2218
|
+
kind: "recipe",
|
|
2219
|
+
...fallbackOf ? { fallbackOf } : {},
|
|
2220
|
+
requestedAt,
|
|
2221
|
+
startAt: time,
|
|
2222
|
+
outputLatency: latencyOf(audio),
|
|
2223
|
+
level: plan.level,
|
|
2224
|
+
distance: plan.distance,
|
|
2225
|
+
...plan.pan === void 0 ? {} : { pan: plan.pan }
|
|
2226
|
+
});
|
|
2227
|
+
return realized;
|
|
1576
2228
|
};
|
|
1577
|
-
const deferVoice = (plan, store, voiceId, delay) => {
|
|
1578
|
-
|
|
2229
|
+
const deferVoice = (plan, store, voiceId, delay, fallbackOf) => {
|
|
2230
|
+
const requestedAt = context?.currentTime ?? 0;
|
|
2231
|
+
let built2 = null;
|
|
1579
2232
|
let cancelled = false;
|
|
1580
2233
|
const pending = {
|
|
1581
2234
|
get sources() {
|
|
1582
|
-
return
|
|
2235
|
+
return built2?.sources ?? [];
|
|
1583
2236
|
},
|
|
1584
2237
|
stop() {
|
|
1585
2238
|
cancelled = true;
|
|
1586
|
-
|
|
2239
|
+
built2?.stop();
|
|
1587
2240
|
}
|
|
1588
2241
|
};
|
|
1589
2242
|
startQueue.push({
|
|
1590
2243
|
run() {
|
|
1591
|
-
if (!cancelled && context)
|
|
2244
|
+
if (!cancelled && context) built2 = build(plan, store, delay, requestedAt, fallbackOf);
|
|
1592
2245
|
},
|
|
1593
2246
|
drop() {
|
|
1594
2247
|
if (voiceId === void 0) return;
|
|
@@ -1598,13 +2251,14 @@ var GameAudio = (() => {
|
|
|
1598
2251
|
});
|
|
1599
2252
|
return pending;
|
|
1600
2253
|
};
|
|
1601
|
-
const start = (plan, store, voiceId, delay = 0) => {
|
|
1602
|
-
const realized = startQueue ? deferVoice(plan, store, voiceId, delay) : build(plan, store, delay);
|
|
2254
|
+
const start = (plan, store, voiceId, delay = 0, fallbackOf, urgent = false) => {
|
|
2255
|
+
const realized = startQueue && !urgent ? deferVoice(plan, store, voiceId, delay, fallbackOf) : build(plan, store, delay, context?.currentTime ?? 0, fallbackOf);
|
|
1603
2256
|
if (voiceId === void 0) return null;
|
|
1604
2257
|
voices.setLength(voiceId, plan.length + delay);
|
|
1605
2258
|
active.set(voiceId, realized);
|
|
1606
2259
|
return {
|
|
1607
2260
|
id: voiceId,
|
|
2261
|
+
kind: "recipe",
|
|
1608
2262
|
plan,
|
|
1609
2263
|
stop() {
|
|
1610
2264
|
realized.stop();
|
|
@@ -1613,8 +2267,8 @@ var GameAudio = (() => {
|
|
|
1613
2267
|
}
|
|
1614
2268
|
};
|
|
1615
2269
|
};
|
|
1616
|
-
const admit = (
|
|
1617
|
-
const decision = voices.request({ ...
|
|
2270
|
+
const admit = (recipe2, gain, distance) => {
|
|
2271
|
+
const decision = voices.request({ ...recipe2.group ? { group: recipe2.group } : {}, priority: recipe2.priority ?? busPriority(recipe2.bus), gain, distance, length: 0 });
|
|
1618
2272
|
if (!decision.accepted) return null;
|
|
1619
2273
|
for (const id of decision.evicted) {
|
|
1620
2274
|
active.get(id)?.stop();
|
|
@@ -1622,22 +2276,107 @@ var GameAudio = (() => {
|
|
|
1622
2276
|
}
|
|
1623
2277
|
return decision.id;
|
|
1624
2278
|
};
|
|
1625
|
-
const
|
|
1626
|
-
|
|
1627
|
-
if (
|
|
2279
|
+
const picker = createSetPicker();
|
|
2280
|
+
const resolve = (id, random, chooser = picker) => {
|
|
2281
|
+
if (registry.sound(id)) return { id, rate: 1 };
|
|
2282
|
+
const set = registry.set(id);
|
|
2283
|
+
return set ? chooser.pick(set, random) : { id, rate: 1 };
|
|
2284
|
+
};
|
|
2285
|
+
const loadSounds = (sounds) => {
|
|
2286
|
+
const audio = ready();
|
|
2287
|
+
if (!audio) return Promise.resolve({ loaded: [], failed: sounds.flatMap(sampleUrls).map((url2) => ({ url: url2, error: "no audio context" })) });
|
|
2288
|
+
return sampleStore.load([...new Set(sounds.flatMap(sampleUrls))], audio);
|
|
2289
|
+
};
|
|
2290
|
+
const sampleInput = (playOptions, random, withMemory) => ({
|
|
2291
|
+
random,
|
|
2292
|
+
listener,
|
|
2293
|
+
environment: playOptions.environment ?? environment,
|
|
2294
|
+
...withMemory ? { memory } : {},
|
|
2295
|
+
...options.distance ? { distanceMode: options.distance } : {},
|
|
2296
|
+
...playOptions.volume === void 0 ? {} : { volume: playOptions.volume },
|
|
2297
|
+
...playOptions.intensity === void 0 ? {} : { intensity: playOptions.intensity },
|
|
2298
|
+
...playOptions.distance === void 0 ? {} : { distance: playOptions.distance },
|
|
2299
|
+
...playOptions.position ? { position: playOptions.position } : {},
|
|
2300
|
+
...playOptions.occlusion !== void 0 ? { occlusion: playOptions.occlusion } : options.occlusion && playOptions.position ? { occlusion: options.occlusion(playOptions.position) } : {}
|
|
2301
|
+
});
|
|
2302
|
+
const playSample = (sample, playOptions, random, store) => {
|
|
2303
|
+
if (busSettings.get(sample.bus)?.muted) return null;
|
|
2304
|
+
if (!sampleStore.ready(sampleUrls(sample))) {
|
|
2305
|
+
if (options.samples?.autoLoad !== false && ready()) void loadSounds([sample]).catch(() => void 0);
|
|
2306
|
+
if (sample.fallback && sample.fallback !== sample.id) return playWith(sample.fallback, playOptions, random, store, sample.id);
|
|
2307
|
+
return registry.sound(sample.id) ? void 0 : null;
|
|
2308
|
+
}
|
|
2309
|
+
const plan = planSample(sample, sampleInput(playOptions, playOptions.seed === void 0 ? random : createRng(playOptions.seed), true));
|
|
2310
|
+
if (!plan) return null;
|
|
2311
|
+
const audio = ready();
|
|
2312
|
+
if (!audio) return null;
|
|
2313
|
+
unlockContext(audio);
|
|
2314
|
+
advance();
|
|
2315
|
+
const voiceId = admit(plan, plan.level, plan.distance);
|
|
2316
|
+
if (voiceId === null) return null;
|
|
2317
|
+
const requestedAt = audio.currentTime;
|
|
2318
|
+
const time = requestedAt + (playOptions.delay ?? 0);
|
|
2319
|
+
const chokeList = sample.choke ? choked(sample.id) : void 0;
|
|
2320
|
+
const realized = realizeSample(plan, { context: audio, output: sampleOutput(plan.bus), buffer: (url2) => sampleStore.buffer(url2), time });
|
|
2321
|
+
announce({
|
|
2322
|
+
id: plan.id,
|
|
2323
|
+
kind: "sample",
|
|
2324
|
+
requestedAt,
|
|
2325
|
+
startAt: time,
|
|
2326
|
+
outputLatency: latencyOf(audio),
|
|
2327
|
+
level: plan.level,
|
|
2328
|
+
distance: plan.distance,
|
|
2329
|
+
...plan.pan === void 0 ? {} : { pan: plan.pan },
|
|
2330
|
+
layers: plan.layers.map((layer) => ({ role: layer.role, url: layer.url, take: layer.take, rate: layer.rate })),
|
|
2331
|
+
...plan.tier ? { tier: plan.tier } : {}
|
|
2332
|
+
});
|
|
2333
|
+
voices.setLength(voiceId, sampleLength(plan, (url2) => sampleStore.seconds(url2)) + (playOptions.delay ?? 0));
|
|
2334
|
+
active.set(voiceId, realized);
|
|
2335
|
+
if (chokeList && sample.choke) {
|
|
2336
|
+
chokeList.push({ id: voiceId, voice: realized });
|
|
2337
|
+
while (chokeList.length > Math.max(1, sample.choke.voices)) {
|
|
2338
|
+
const oldest = chokeList.shift();
|
|
2339
|
+
if (!oldest) break;
|
|
2340
|
+
oldest.voice.fade(time, sample.choke.fade ?? 0.03);
|
|
2341
|
+
voices.release(oldest.id);
|
|
2342
|
+
active.delete(oldest.id);
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
return {
|
|
2346
|
+
id: voiceId,
|
|
2347
|
+
kind: "sample",
|
|
2348
|
+
plan,
|
|
2349
|
+
stop() {
|
|
2350
|
+
realized.stop();
|
|
2351
|
+
voices.release(voiceId);
|
|
2352
|
+
active.delete(voiceId);
|
|
2353
|
+
}
|
|
2354
|
+
};
|
|
2355
|
+
};
|
|
2356
|
+
const playWith = (asked, playOptions, streamRandom, store, fallbackOf) => {
|
|
2357
|
+
const sample = fallbackOf === void 0 ? registry.sample(asked) : void 0;
|
|
2358
|
+
if (sample) {
|
|
2359
|
+
const played = playSample(sample, playOptions, streamRandom, store);
|
|
2360
|
+
if (played !== void 0) return played;
|
|
2361
|
+
}
|
|
2362
|
+
const seeded = playOptions.seed === void 0 ? null : createRng(playOptions.seed);
|
|
2363
|
+
const { id, rate } = resolve(asked, seeded ?? streamRandom);
|
|
2364
|
+
const random = seeded ?? streamRandom;
|
|
2365
|
+
const recipe2 = registry.sound(id);
|
|
2366
|
+
if (!recipe2 || busSettings.get(recipe2.bus)?.muted) return null;
|
|
1628
2367
|
const distance = playOptions.distance ?? (playOptions.position ? listenerDistance(listener, playOptions.position, options.distance) : 0);
|
|
1629
|
-
const level = falloffGain(
|
|
1630
|
-
const silent = isSilent(
|
|
1631
|
-
if (silent && !
|
|
2368
|
+
const level = falloffGain(recipe2.falloff, playOptions.volume ?? 1, distance);
|
|
2369
|
+
const silent = isSilent(recipe2.falloff, level);
|
|
2370
|
+
if (silent && !recipe2.keepSilent) return null;
|
|
1632
2371
|
const audio = ready();
|
|
1633
2372
|
if (!audio) return null;
|
|
1634
2373
|
unlockContext(audio);
|
|
1635
2374
|
advance();
|
|
1636
|
-
const voiceId = silent ? void 0 : admit(
|
|
2375
|
+
const voiceId = silent ? void 0 : admit(recipe2, level, distance);
|
|
1637
2376
|
if (voiceId === null) return null;
|
|
1638
|
-
if (!silent && usesNoise(
|
|
1639
|
-
const plan = planSound(
|
|
1640
|
-
return plan ? start(plan, store, voiceId, playOptions.delay) : null;
|
|
2377
|
+
if (!silent && usesNoise(recipe2)) prepareNoise(store, audio, mix.noise.seconds);
|
|
2378
|
+
const plan = planSound(recipe2, inputFor(recipe2, playOptions, random));
|
|
2379
|
+
return plan ? start(retunePlan(plan, rate), store, voiceId, playOptions.delay, fallbackOf, playOptions.urgent) : null;
|
|
1641
2380
|
};
|
|
1642
2381
|
const randomFor = (playOptions) => {
|
|
1643
2382
|
if (playOptions.channel === void 0) return engineRandom;
|
|
@@ -1647,9 +2386,11 @@ var GameAudio = (() => {
|
|
|
1647
2386
|
named.set(playOptions.channel, stream);
|
|
1648
2387
|
return stream;
|
|
1649
2388
|
};
|
|
1650
|
-
const planWith = (
|
|
1651
|
-
const
|
|
1652
|
-
|
|
2389
|
+
const planWith = (asked, playOptions, random) => {
|
|
2390
|
+
const { id, rate } = resolve(asked, random, createSetPicker());
|
|
2391
|
+
const recipe2 = registry.sound(id);
|
|
2392
|
+
const plan = recipe2 ? planSound(recipe2, inputFor(recipe2, playOptions, random)) : null;
|
|
2393
|
+
return plan ? retunePlan(plan, rate) : null;
|
|
1653
2394
|
};
|
|
1654
2395
|
const loopHost = {
|
|
1655
2396
|
ready,
|
|
@@ -1657,24 +2398,73 @@ var GameAudio = (() => {
|
|
|
1657
2398
|
prepareNoise: () => context && prepareNoise(shared, context, mix.noise.seconds),
|
|
1658
2399
|
noise: () => noiseBuffer(shared, context, mix.noise.seconds),
|
|
1659
2400
|
register: (loop) => void loops.add(loop),
|
|
1660
|
-
unregister: (loop) => void loops.delete(loop)
|
|
2401
|
+
unregister: (loop) => void loops.delete(loop),
|
|
2402
|
+
listener: () => listener,
|
|
2403
|
+
...options.distance ? { distance: options.distance } : {}
|
|
1661
2404
|
};
|
|
1662
2405
|
return {
|
|
1663
2406
|
registry,
|
|
1664
2407
|
register: (bank) => registry.register(bank),
|
|
1665
2408
|
plan: (id, playOptions = {}) => planWith(id, playOptions, createRng(playOptions.seed ?? seed)),
|
|
2409
|
+
planSample(id, playOptions = {}) {
|
|
2410
|
+
const sample = registry.sample(id);
|
|
2411
|
+
return sample ? planSample(sample, sampleInput(playOptions, createRng(playOptions.seed ?? seed), false)) : null;
|
|
2412
|
+
},
|
|
2413
|
+
loadSamples(ids) {
|
|
2414
|
+
const chosen = (ids ?? registry.sampleIds()).map((id) => registry.sample(id)).filter((sample) => sample !== void 0);
|
|
2415
|
+
return loadSounds(chosen);
|
|
2416
|
+
},
|
|
2417
|
+
sampleStatus(id) {
|
|
2418
|
+
const sample = registry.sample(id);
|
|
2419
|
+
if (!sample) return "none";
|
|
2420
|
+
const statuses = sampleUrls(sample).map((url2) => sampleStore.status(url2));
|
|
2421
|
+
if (statuses.every((status) => status === "ready")) return "ready";
|
|
2422
|
+
if (statuses.includes("failed")) return "failed";
|
|
2423
|
+
if (statuses.includes("loading")) return "loading";
|
|
2424
|
+
return statuses.includes("ready") ? "loading" : "none";
|
|
2425
|
+
},
|
|
2426
|
+
setEnvironment(next) {
|
|
2427
|
+
environment = next;
|
|
2428
|
+
},
|
|
2429
|
+
output: () => chain?.master ?? null,
|
|
2430
|
+
addSampleSource(accepts, loader) {
|
|
2431
|
+
sources.push({ accepts, loader });
|
|
2432
|
+
},
|
|
2433
|
+
watchVoices(listener2) {
|
|
2434
|
+
watchers.add(listener2);
|
|
2435
|
+
return () => void watchers.delete(listener2);
|
|
2436
|
+
},
|
|
1666
2437
|
play: (id, playOptions = {}) => playWith(id, playOptions, randomFor(playOptions), shared),
|
|
1667
2438
|
playPlan(plan, playOptions = {}) {
|
|
1668
2439
|
const audio = ready();
|
|
1669
2440
|
if (!audio) return null;
|
|
1670
2441
|
advance();
|
|
1671
|
-
const
|
|
1672
|
-
const voiceId = plan.silent ? void 0 : admit(
|
|
2442
|
+
const recipe2 = { id: plan.id, bus: plan.bus, layers: [], sources: [], priority: plan.priority, ...plan.group ? { group: plan.group } : {} };
|
|
2443
|
+
const voiceId = plan.silent ? void 0 : admit(recipe2, plan.level, plan.distance);
|
|
1673
2444
|
if (voiceId === null) return null;
|
|
1674
2445
|
if (planUsesNoise(plan)) prepareNoise(shared, audio, mix.noise.seconds);
|
|
1675
2446
|
return start(plan, shared, voiceId, playOptions.delay);
|
|
1676
2447
|
},
|
|
1677
|
-
loop
|
|
2448
|
+
loop(id, loopOptions = {}) {
|
|
2449
|
+
const sample = registry.sample(id);
|
|
2450
|
+
if (!sample?.loop) return createLoopHandle(registry.loop(id), loopHost, loopOptions.volume);
|
|
2451
|
+
return createSampleLoopHandle(
|
|
2452
|
+
sample,
|
|
2453
|
+
{
|
|
2454
|
+
ready,
|
|
2455
|
+
output: sampleOutput,
|
|
2456
|
+
buffer: (url2) => sampleStore.buffer(url2),
|
|
2457
|
+
isReady: (sound) => sampleStore.ready(sampleUrls(sound)),
|
|
2458
|
+
load: (sound) => options.samples?.autoLoad === false ? Promise.resolve() : loadSounds([sound]),
|
|
2459
|
+
fallback: (volume) => createLoopHandle(registry.loop(sample.fallback ?? sample.id) ?? registry.loop(sample.id), loopHost, volume),
|
|
2460
|
+
random: engineRandom,
|
|
2461
|
+
register: loopHost.register,
|
|
2462
|
+
unregister: loopHost.unregister,
|
|
2463
|
+
muted: (bus) => busSettings.get(bus)?.muted === true
|
|
2464
|
+
},
|
|
2465
|
+
loopOptions.volume
|
|
2466
|
+
);
|
|
2467
|
+
},
|
|
1678
2468
|
channel(channelOptions) {
|
|
1679
2469
|
const random = channelOptions.random ?? (channelOptions.seed === void 0 ? engineRandom : createRng(channelOptions.seed));
|
|
1680
2470
|
const store = channelOptions.ownNoise ? createNoiseStore(random) : shared;
|
|
@@ -1731,6 +2521,7 @@ var GameAudio = (() => {
|
|
|
1731
2521
|
for (const sample of meter.data) sum += sample * sample;
|
|
1732
2522
|
return Math.sqrt(sum / meter.data.length);
|
|
1733
2523
|
},
|
|
2524
|
+
deferredQueue: () => startQueue?.deferredQueue() ?? null,
|
|
1734
2525
|
stats() {
|
|
1735
2526
|
advance();
|
|
1736
2527
|
const voiceStats = voices.stats();
|
|
@@ -1754,33 +2545,1737 @@ var GameAudio = (() => {
|
|
|
1754
2545
|
busNodes.clear();
|
|
1755
2546
|
meters.clear();
|
|
1756
2547
|
shared.reset();
|
|
2548
|
+
sampleStore.clear();
|
|
2549
|
+
memory.clear();
|
|
2550
|
+
sampleLimiters.clear();
|
|
2551
|
+
chokes.clear();
|
|
1757
2552
|
}
|
|
1758
2553
|
};
|
|
1759
2554
|
}
|
|
1760
2555
|
|
|
1761
|
-
// src/
|
|
1762
|
-
|
|
1763
|
-
|
|
2556
|
+
// src/measure/analyze.ts
|
|
2557
|
+
var dbOf = (amplitude) => amplitude > 0 ? 20 * Math.log10(amplitude) : -Infinity;
|
|
2558
|
+
var clampIndex = (channels, index) => Math.max(0, Math.min(channels[0]?.length ?? 0, Math.round(index)));
|
|
2559
|
+
function peakOf(channels, start = 0, end3 = Number.POSITIVE_INFINITY) {
|
|
2560
|
+
let peak = 0;
|
|
2561
|
+
const from = clampIndex(channels, start);
|
|
2562
|
+
for (const channel of channels) {
|
|
2563
|
+
const to = Math.min(channel.length, end3);
|
|
2564
|
+
for (let index = from; index < to; index++) {
|
|
2565
|
+
const value = Math.abs(channel[index]);
|
|
2566
|
+
if (value > peak) peak = value;
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
return peak;
|
|
2570
|
+
}
|
|
2571
|
+
function peakIndex(channels, start = 0, end3 = Number.POSITIVE_INFINITY) {
|
|
2572
|
+
let peak = -1;
|
|
2573
|
+
let at = -1;
|
|
2574
|
+
const from = clampIndex(channels, start);
|
|
2575
|
+
for (const channel of channels) {
|
|
2576
|
+
const to = Math.min(channel.length, end3);
|
|
2577
|
+
for (let index = from; index < to; index++) {
|
|
2578
|
+
const value = Math.abs(channel[index]);
|
|
2579
|
+
if (value > peak) {
|
|
2580
|
+
peak = value;
|
|
2581
|
+
at = index;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
return at;
|
|
2586
|
+
}
|
|
2587
|
+
function onsetIndex(channels, start = 0, threshold = 1e-3) {
|
|
2588
|
+
const length = channels[0]?.length ?? 0;
|
|
2589
|
+
for (let index = clampIndex(channels, start); index < length; index++) {
|
|
2590
|
+
for (const channel of channels) if (Math.abs(channel[index]) >= threshold) return index;
|
|
2591
|
+
}
|
|
2592
|
+
return -1;
|
|
2593
|
+
}
|
|
2594
|
+
function rmsDb(channels, start, end3) {
|
|
2595
|
+
let sum = 0;
|
|
2596
|
+
let count = 0;
|
|
2597
|
+
const from = clampIndex(channels, start);
|
|
2598
|
+
for (const channel of channels) {
|
|
2599
|
+
const to = Math.min(channel.length, Math.round(end3));
|
|
2600
|
+
for (let index = from; index < to; index++) {
|
|
2601
|
+
const value = channel[index];
|
|
2602
|
+
sum += value * value;
|
|
2603
|
+
count++;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
return count === 0 ? -Infinity : dbOf(Math.sqrt(sum / count));
|
|
2607
|
+
}
|
|
2608
|
+
function centroidHz(channels, sampleRate, start, size = 2048) {
|
|
2609
|
+
const from = clampIndex(channels, start);
|
|
2610
|
+
const frame = new Float64Array(size);
|
|
2611
|
+
for (const channel of channels) {
|
|
2612
|
+
for (let index = 0; index < size; index++) frame[index] = frame[index] + (channel[from + index] ?? 0);
|
|
2613
|
+
}
|
|
2614
|
+
for (let index = 0; index < size; index++) frame[index] = frame[index] * (0.5 - 0.5 * Math.cos(2 * Math.PI * index / (size - 1)));
|
|
2615
|
+
let weighted = 0;
|
|
2616
|
+
let total = 0;
|
|
2617
|
+
const bins = size / 2;
|
|
2618
|
+
for (let bin = 1; bin < bins; bin++) {
|
|
2619
|
+
let re = 0;
|
|
2620
|
+
let im = 0;
|
|
2621
|
+
const step = 2 * Math.PI * bin / size;
|
|
2622
|
+
for (let index = 0; index < size; index++) {
|
|
2623
|
+
const value = frame[index];
|
|
2624
|
+
re += value * Math.cos(step * index);
|
|
2625
|
+
im -= value * Math.sin(step * index);
|
|
2626
|
+
}
|
|
2627
|
+
const magnitude = Math.hypot(re, im);
|
|
2628
|
+
weighted += magnitude * (bin * sampleRate / size);
|
|
2629
|
+
total += magnitude;
|
|
2630
|
+
}
|
|
2631
|
+
return total > 0 ? weighted / total : 0;
|
|
2632
|
+
}
|
|
2633
|
+
function balanceOf(left, right, start, end3) {
|
|
2634
|
+
let l = 0;
|
|
2635
|
+
let r = 0;
|
|
2636
|
+
const to = Math.min(left.length, right.length, Math.round(end3));
|
|
2637
|
+
for (let index = Math.max(0, Math.round(start)); index < to; index++) {
|
|
2638
|
+
l += left[index] ** 2;
|
|
2639
|
+
r += right[index] ** 2;
|
|
2640
|
+
}
|
|
2641
|
+
return l + r > 0 ? (r - l) / (r + l) : 0;
|
|
2642
|
+
}
|
|
2643
|
+
function ringSeconds(channels, sampleRate, start, floorDb = -60) {
|
|
2644
|
+
const window = Math.max(1, Math.round(sampleRate * 0.01));
|
|
2645
|
+
const length = channels[0]?.length ?? 0;
|
|
2646
|
+
let last = clampIndex(channels, start);
|
|
2647
|
+
for (let index = last; index < length; index += window) {
|
|
2648
|
+
if (dbOf(peakOf(channels, index, index + window)) > floorDb) last = index + window;
|
|
2649
|
+
}
|
|
2650
|
+
return (last - start) / sampleRate;
|
|
2651
|
+
}
|
|
2652
|
+
function countHits(channels, sampleRate, threshold) {
|
|
2653
|
+
const window = Math.max(1, Math.round(sampleRate * 2e-3));
|
|
2654
|
+
const length = channels[0]?.length ?? 0;
|
|
2655
|
+
const envelope2 = [];
|
|
2656
|
+
for (let index = 0; index < length; index += window) envelope2.push(peakOf(channels, index, index + window));
|
|
2657
|
+
const history = 10;
|
|
2658
|
+
const refractory = Math.round(0.03 / 2e-3);
|
|
2659
|
+
let hits = 0;
|
|
2660
|
+
let quietUntil = -1;
|
|
2661
|
+
for (let index = 0; index < envelope2.length; index++) {
|
|
2662
|
+
const level = envelope2[index];
|
|
2663
|
+
if (index < quietUntil || level < threshold) continue;
|
|
2664
|
+
let sum = 0;
|
|
2665
|
+
for (let back = Math.max(0, index - history); back < index; back++) sum += envelope2[back];
|
|
2666
|
+
const before = index === 0 ? 0 : sum / Math.min(history, index);
|
|
2667
|
+
if (level >= 2 * before) {
|
|
2668
|
+
hits++;
|
|
2669
|
+
quietUntil = index + refractory;
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2672
|
+
return hits;
|
|
2673
|
+
}
|
|
2674
|
+
function endDropDb(channels, sampleRate, seconds = 5e-3) {
|
|
2675
|
+
const length = channels[0]?.length ?? 0;
|
|
2676
|
+
const whole = peakOf(channels);
|
|
2677
|
+
if (whole === 0) return -Infinity;
|
|
2678
|
+
return dbOf(peakOf(channels, length - Math.round(sampleRate * seconds), length) / whole);
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
// src/measure/criteria.ts
|
|
2682
|
+
var CRITERIA = ["C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10"];
|
|
2683
|
+
var CRITERIA_TARGETS = {
|
|
2684
|
+
/** C1: event to the first sample, and onset to the peak (one 60 fps frame). */
|
|
2685
|
+
syncMs: 20,
|
|
2686
|
+
peakAfterOnsetMs: 1e3 / 60,
|
|
2687
|
+
/** C3: distances measured, metres. */
|
|
2688
|
+
distances: [1, 10, 50, 200],
|
|
2689
|
+
/** C5: plays, distinct takes and the pitch range (fraction). */
|
|
2690
|
+
plays: 10,
|
|
2691
|
+
minTakes: 4,
|
|
2692
|
+
pitch: [0.03, 0.05],
|
|
2693
|
+
/** C6: the highest peak, dBFS. */
|
|
2694
|
+
peakDb: -1,
|
|
2695
|
+
/** C8: the end of each file against its peak, dB. */
|
|
2696
|
+
endDropDb: -40,
|
|
2697
|
+
/** C9: a burst of rapid fire. */
|
|
2698
|
+
burst: 20,
|
|
2699
|
+
burstSpacing: 0.06
|
|
2700
|
+
};
|
|
2701
|
+
var EVENT_AT = 0.2;
|
|
2702
|
+
var offlineFactory = (options) => options.createOfflineContext ?? ((channels, length, sampleRate) => {
|
|
2703
|
+
const Constructor = globalThis.OfflineAudioContext;
|
|
2704
|
+
if (!Constructor) throw new Error("no OfflineAudioContext here: the harness runs in a browser");
|
|
2705
|
+
return new Constructor(channels, length, sampleRate);
|
|
2706
|
+
});
|
|
2707
|
+
async function render(options, seconds, act, engineExtras = {}) {
|
|
2708
|
+
const sampleRate = options.sampleRate ?? 48e3;
|
|
2709
|
+
const context = offlineFactory(options)(2, Math.ceil(seconds * sampleRate), sampleRate);
|
|
2710
|
+
const events = [];
|
|
2711
|
+
const engine = createAudioEngine({
|
|
2712
|
+
banks: options.banks,
|
|
2713
|
+
createContext: () => context,
|
|
2714
|
+
samples: { loader: options.loader, autoLoad: false },
|
|
2715
|
+
onVoiceStart: (event) => events.push(event),
|
|
2716
|
+
...options.mix ? { mix: options.mix } : {},
|
|
2717
|
+
...engineExtras.occlusion ? { occlusion: engineExtras.occlusion } : {},
|
|
2718
|
+
...engineExtras.environment ? { environment: engineExtras.environment } : {}
|
|
2719
|
+
});
|
|
2720
|
+
const ids = [.../* @__PURE__ */ new Set([options.sound, ...(options.actions ?? []).map((action) => action.play), ...options.loudnessOrder ?? []])].filter((id) => engine.registry.sample(id));
|
|
2721
|
+
const report = await engine.loadSamples(ids);
|
|
2722
|
+
if (report.failed.length > 0) throw new Error(`files did not load: ${report.failed.map((entry) => `${entry.url} (${entry.error})`).join(", ")}`);
|
|
2723
|
+
const handles = act(engine);
|
|
2724
|
+
const buffer = await context.startRendering();
|
|
2725
|
+
const channels = Array.from({ length: buffer.numberOfChannels }, (_, index) => buffer.getChannelData(index));
|
|
2726
|
+
return { channels, sampleRate, events, handles };
|
|
2727
|
+
}
|
|
2728
|
+
var ms = (seconds) => `${(seconds * 1e3).toFixed(1)} ms`;
|
|
2729
|
+
var db = (value) => Number.isFinite(value) ? `${value.toFixed(1)} dB` : "\u2212\u221E";
|
|
2730
|
+
var decreasing = (values) => values.every((value, index) => index === 0 || value < values[index - 1]);
|
|
2731
|
+
async function c1(options) {
|
|
2732
|
+
const result = await render(options, 1.2, (engine) => engine.play(options.sound, { distance: 1, delay: EVENT_AT }) ? 1 : 0);
|
|
2733
|
+
const onset = onsetIndex(result.channels, 0, 1e-3);
|
|
2734
|
+
const event = result.events.find((entry) => entry.id === options.sound);
|
|
2735
|
+
if (onset < 0 || !event) return { id: "C1", pass: false, value: "sem som", target: `\u2264 ${CRITERIA_TARGETS.syncMs} ms` };
|
|
2736
|
+
const delay = onset / result.sampleRate - EVENT_AT + (event.startAt - event.requestedAt - EVENT_AT) + (options.baseLatency ?? 0);
|
|
2737
|
+
const peak = peakIndex(result.channels, onset, onset + Math.round(result.sampleRate * 0.25));
|
|
2738
|
+
const toPeak = (peak - onset) / result.sampleRate;
|
|
2739
|
+
const pass = delay <= CRITERIA_TARGETS.syncMs / 1e3 && toPeak <= CRITERIA_TARGETS.peakAfterOnsetMs / 1e3;
|
|
1764
2740
|
return {
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
2741
|
+
id: "C1",
|
|
2742
|
+
pass,
|
|
2743
|
+
value: `${ms(delay)}, pico +${ms(toPeak)}`,
|
|
2744
|
+
target: `\u2264 ${CRITERIA_TARGETS.syncMs} ms; pico no quadro do contato`,
|
|
2745
|
+
data: { delay, toPeak, baseLatency: options.baseLatency ?? 0, outputLatency: options.outputLatency ?? 0 }
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
async function c2(options) {
|
|
2749
|
+
const actions = options.actions ?? [{ action: options.sound, play: options.sound, expect: options.sound }];
|
|
2750
|
+
const result = await render(options, 0.5, (engine) => {
|
|
2751
|
+
let played = 0;
|
|
2752
|
+
for (const action of actions) if (engine.play(action.play, { distance: 1, ...action.options })) played++;
|
|
2753
|
+
return played;
|
|
2754
|
+
});
|
|
2755
|
+
const wrong = actions.filter((action, index) => {
|
|
2756
|
+
const event = result.events[index];
|
|
2757
|
+
return !event || (event.fallbackOf ?? event.id) !== action.expect || event.kind !== "sample";
|
|
2758
|
+
});
|
|
2759
|
+
return {
|
|
2760
|
+
id: "C2",
|
|
2761
|
+
pass: wrong.length === 0,
|
|
2762
|
+
value: `${actions.length - wrong.length}/${actions.length} certas`,
|
|
2763
|
+
target: "100% das a\xE7\xF5es batem com a tabela (arquivo, n\xE3o o substituto)",
|
|
2764
|
+
data: { wrong: wrong.map((action) => action.action), events: result.events.map((event) => `${event.kind}:${event.id}`) }
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
async function c3(options, sound) {
|
|
2768
|
+
const levels = [];
|
|
2769
|
+
const brightness = [];
|
|
2770
|
+
for (const distance of CRITERIA_TARGETS.distances) {
|
|
2771
|
+
const result = await render(options, 1.2, (engine) => engine.play(options.sound, { position: [0, 0, -distance], seed: 1, delay: EVENT_AT }) ? 1 : 0);
|
|
2772
|
+
const onset = onsetIndex(result.channels, 0, 1e-5);
|
|
2773
|
+
levels.push(onset < 0 ? -Infinity : rmsDb(result.channels, onset, onset + result.sampleRate * 0.3));
|
|
2774
|
+
brightness.push(onset < 0 ? 0 : centroidHz(result.channels, result.sampleRate, onset));
|
|
2775
|
+
}
|
|
2776
|
+
const far = planSample(sound, { random: createRng(1), distance: CRITERIA_TARGETS.distances.at(-1) });
|
|
2777
|
+
const switched = (far?.farMix ?? 0) === 1 && (far?.layers.some((layer) => layer.role === "far") ?? false);
|
|
2778
|
+
const pass = decreasing(levels) && decreasing(brightness) && switched;
|
|
2779
|
+
return {
|
|
2780
|
+
id: "C3",
|
|
2781
|
+
pass,
|
|
2782
|
+
value: `${levels.map((level) => db(level)).join(" \u203A ")}; ${brightness.map((hz) => `${Math.round(hz)} Hz`).join(" \u203A ")}${switched ? "; longe = far" : "; sem camada far"}`,
|
|
2783
|
+
target: "cai e escurece com a dist\xE2ncia; troca para a vers\xE3o de longe depois de ~50 m",
|
|
2784
|
+
data: { distances: CRITERIA_TARGETS.distances, levels, brightness, switched }
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
async function c4(options) {
|
|
2788
|
+
const side = async (x) => {
|
|
2789
|
+
const result = await render(options, 0.8, (engine) => engine.play(options.sound, { position: [x, 0, -2], seed: 1, delay: EVENT_AT }) ? 1 : 0);
|
|
2790
|
+
const [left2, right2] = result.channels;
|
|
2791
|
+
return balanceOf(left2, right2, 0, left2.length);
|
|
2792
|
+
};
|
|
2793
|
+
const right = await side(10);
|
|
2794
|
+
const left = await side(-10);
|
|
2795
|
+
const bright = async (occluded) => {
|
|
2796
|
+
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 } : {});
|
|
2797
|
+
const onset = onsetIndex(result.channels, 0, 1e-5);
|
|
2798
|
+
return onset < 0 ? 0 : centroidHz(result.channels, result.sampleRate, onset);
|
|
2799
|
+
};
|
|
2800
|
+
const clear = await bright(false);
|
|
2801
|
+
const wall = await bright(true);
|
|
2802
|
+
const pass = right > 0.2 && left < -0.2 && wall < clear * 0.7;
|
|
2803
|
+
return {
|
|
2804
|
+
id: "C4",
|
|
2805
|
+
pass,
|
|
2806
|
+
value: `dir ${right.toFixed(2)} esq ${left.toFixed(2)}; parede ${Math.round(wall)} Hz de ${Math.round(clear)} Hz`,
|
|
2807
|
+
target: "lado certo; atr\xE1s da parede fica abafado",
|
|
2808
|
+
data: { right, left, clear, wall }
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
async function c5(options, sound) {
|
|
2812
|
+
const result = await render(options, 0.3 * CRITERIA_TARGETS.plays + 1, (engine) => {
|
|
2813
|
+
let played = 0;
|
|
2814
|
+
for (let index = 0; index < CRITERIA_TARGETS.plays; index++) if (engine.play(options.sound, { distance: 1, delay: 0.1 + index * 0.3 })) played++;
|
|
2815
|
+
return played;
|
|
2816
|
+
});
|
|
2817
|
+
const close = result.events.map((event) => event.layers?.find((layer) => layer.role === "close"));
|
|
2818
|
+
const takes2 = close.map((layer) => layer?.url ?? "");
|
|
2819
|
+
const repeats = takes2.filter((take, index) => index > 0 && take === takes2[index - 1]).length;
|
|
2820
|
+
const distinct = new Set(takes2).size;
|
|
2821
|
+
const rates = close.map((layer) => layer?.rate ?? 1);
|
|
2822
|
+
const spread = (Math.max(...rates) - Math.min(...rates)) / 2;
|
|
2823
|
+
const pitch = sound.pitch ?? 0.04;
|
|
2824
|
+
const pass = distinct >= CRITERIA_TARGETS.minTakes && repeats === 0 && pitch >= CRITERIA_TARGETS.pitch[0] && pitch <= CRITERIA_TARGETS.pitch[1] && spread > 0.01;
|
|
2825
|
+
return {
|
|
2826
|
+
id: "C5",
|
|
2827
|
+
pass,
|
|
2828
|
+
value: `${distinct} tomadas, ${repeats} repeti\xE7\xF5es seguidas, tom \xB1${(pitch * 100).toFixed(0)}%`,
|
|
2829
|
+
target: `\u2265 ${CRITERIA_TARGETS.minTakes} varia\xE7\xF5es, nunca a mesma duas vezes, tom \xB13\u20135%`,
|
|
2830
|
+
data: { takes: takes2, rates }
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
async function c6(options) {
|
|
2834
|
+
const peakAt = async (id) => {
|
|
2835
|
+
const result = await render(options, 1.2, (engine) => engine.play(id, { distance: 1, seed: 1, delay: EVENT_AT }) ? 1 : 0);
|
|
2836
|
+
const onset = onsetIndex(result.channels, 0, 1e-5);
|
|
2837
|
+
return { peak: dbOf(peakOf(result.channels)), rms: onset < 0 ? -Infinity : rmsDb(result.channels, onset, onset + result.sampleRate * 0.3) };
|
|
2838
|
+
};
|
|
2839
|
+
const own = await peakAt(options.sound);
|
|
2840
|
+
const order = options.loudnessOrder ?? [];
|
|
2841
|
+
const loudness = [];
|
|
2842
|
+
for (const id of order) loudness.push((await peakAt(id)).rms);
|
|
2843
|
+
const ordered = order.length < 2 || decreasing(loudness);
|
|
2844
|
+
const pass = own.peak <= CRITERIA_TARGETS.peakDb && ordered;
|
|
2845
|
+
return {
|
|
2846
|
+
id: "C6",
|
|
2847
|
+
pass,
|
|
2848
|
+
value: `pico ${db(own.peak)}, RMS ${db(own.rms)}${order.length > 1 ? `; ordem ${ordered ? "ok" : "errada"}` : ""}`,
|
|
2849
|
+
target: "tiro > explos\xE3o > impacto > passo; pico \u2264 \u22121 dBFS",
|
|
2850
|
+
data: { peak: own.peak, rms: own.rms, order, loudness }
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
async function c7(options, sound) {
|
|
2854
|
+
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" };
|
|
2855
|
+
const at = async (intensity) => {
|
|
2856
|
+
const result = await render(options, 1.2, (engine) => engine.play(options.sound, { distance: 1, seed: 1, intensity, delay: EVENT_AT }) ? 1 : 0);
|
|
2857
|
+
const onset = onsetIndex(result.channels, 0, 1e-5);
|
|
2858
|
+
const event = result.events[0];
|
|
2859
|
+
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 ?? "" };
|
|
2860
|
+
};
|
|
2861
|
+
const light = await at(0.1);
|
|
2862
|
+
const heavy = await at(0.9);
|
|
2863
|
+
const pass = light.tier !== heavy.tier && light.files !== heavy.files && heavy.rms > light.rms;
|
|
2864
|
+
return {
|
|
2865
|
+
id: "C7",
|
|
2866
|
+
pass,
|
|
2867
|
+
value: `${light.tier} ${db(light.rms)} \u2192 ${heavy.tier} ${db(heavy.rms)}`,
|
|
2868
|
+
target: "golpe fraco x forte troca a camada (leve/m\xE9dio/forte), n\xE3o s\xF3 o volume",
|
|
2869
|
+
data: { light, heavy }
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2872
|
+
async function c8(options, sound) {
|
|
2873
|
+
const sampleRate = options.sampleRate ?? 48e3;
|
|
2874
|
+
const decoder = offlineFactory(options)(1, sampleRate, sampleRate);
|
|
2875
|
+
const drops = [];
|
|
2876
|
+
for (const url2 of sampleUrls(sound)) {
|
|
2877
|
+
const buffer = await decoder.decodeAudioData(await options.loader(url2));
|
|
2878
|
+
drops.push({ url: url2, drop: endDropDb([buffer.getChannelData(0)], buffer.sampleRate) });
|
|
2879
|
+
}
|
|
2880
|
+
const worst = drops.reduce((max, entry) => Math.max(max, entry.drop), -Infinity);
|
|
2881
|
+
const ring = async (environment) => {
|
|
2882
|
+
const result = await render(options, 3, (engine) => engine.play(options.sound, { distance: 1, seed: 1, environment, delay: EVENT_AT }) ? 1 : 0);
|
|
2883
|
+
return ringSeconds(result.channels, result.sampleRate, Math.round(EVENT_AT * result.sampleRate));
|
|
2884
|
+
};
|
|
2885
|
+
const indoor = await ring("indoor");
|
|
2886
|
+
const outdoor = await ring("outdoor");
|
|
2887
|
+
const hasTails = Boolean(sound.tail?.indoor?.length && sound.tail?.outdoor?.length);
|
|
2888
|
+
const pass = worst <= CRITERIA_TARGETS.endDropDb && hasTails && outdoor > indoor;
|
|
2889
|
+
return {
|
|
2890
|
+
id: "C8",
|
|
2891
|
+
pass,
|
|
2892
|
+
value: `fim ${db(worst)}; cauda dentro ${indoor.toFixed(2)} s, fora ${outdoor.toFixed(2)} s${hasTails ? "" : " (sem as duas caudas)"}`,
|
|
2893
|
+
target: "n\xE3o corta seco; cauda de interior x exterior coerente",
|
|
2894
|
+
data: { drops, indoor, outdoor }
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
async function c9(options) {
|
|
2898
|
+
const { burst, burstSpacing } = CRITERIA_TARGETS;
|
|
2899
|
+
const first = 0.1;
|
|
2900
|
+
const result = await render(options, burst * burstSpacing + 1.5, (engine) => {
|
|
2901
|
+
let played = 0;
|
|
2902
|
+
for (let index = 0; index < burst; index++) if (engine.play(options.sound, { distance: 1, delay: first + index * burstSpacing })) played++;
|
|
2903
|
+
return played;
|
|
2904
|
+
});
|
|
2905
|
+
const peak = dbOf(peakOf(result.channels));
|
|
2906
|
+
const slots = [];
|
|
2907
|
+
for (let index = 0; index < burst; index++) {
|
|
2908
|
+
const at = Math.round((first + index * burstSpacing) * result.sampleRate);
|
|
2909
|
+
slots.push(rmsDb(result.channels, at, at + Math.round(burstSpacing * result.sampleRate)));
|
|
2910
|
+
}
|
|
2911
|
+
const sorted = [...slots].sort((a, b) => a - b);
|
|
2912
|
+
const median = sorted[Math.floor(sorted.length / 2)];
|
|
2913
|
+
const vanished = slots.filter((level) => level < median - 6).length;
|
|
2914
|
+
const buildUp = slots.slice(-5).reduce((sum, level) => sum + level, 0) / 5 - slots[0];
|
|
2915
|
+
const pass = result.handles === burst && vanished === 0 && buildUp <= 6 && peak <= CRITERIA_TARGETS.peakDb;
|
|
2916
|
+
return {
|
|
2917
|
+
id: "C9",
|
|
2918
|
+
pass,
|
|
2919
|
+
value: `${result.handles}/${burst} tocaram, ${vanished} sumiram, ac\xFAmulo ${buildUp >= 0 ? "+" : ""}${buildUp.toFixed(1)} dB, pico ${db(peak)}`,
|
|
2920
|
+
target: "rajada sem amontoar (ac\xFAmulo \u2264 6 dB) nem sumir; pico \u2264 \u22121 dBFS",
|
|
2921
|
+
data: { handles: result.handles, slots, vanished, buildUp, peak }
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
async function measureCriteria(options, only = CRITERIA) {
|
|
2925
|
+
const probe = createAudioEngine({ banks: options.banks, createContext: () => null });
|
|
2926
|
+
const sound = probe.registry.sample(options.sound);
|
|
2927
|
+
if (!sound) throw new Error(`${options.sound} is not a sample sound of these banks`);
|
|
2928
|
+
const results = [];
|
|
2929
|
+
for (const id of only) {
|
|
2930
|
+
if (id === "C1") results.push(await c1(options));
|
|
2931
|
+
else if (id === "C2") results.push(await c2(options));
|
|
2932
|
+
else if (id === "C3") results.push(await c3(options, sound));
|
|
2933
|
+
else if (id === "C4") results.push(await c4(options));
|
|
2934
|
+
else if (id === "C5") results.push(await c5(options, sound));
|
|
2935
|
+
else if (id === "C6") results.push(await c6(options));
|
|
2936
|
+
else if (id === "C7") results.push(await c7(options, sound));
|
|
2937
|
+
else if (id === "C8") results.push(await c8(options, sound));
|
|
2938
|
+
else if (id === "C9") results.push(await c9(options));
|
|
2939
|
+
else results.push({ id: "C10", pass: null, value: "gravar e ouvir", target: "aprovado pelo ouvido do dono (print + grava\xE7\xE3o na 4280)" });
|
|
2940
|
+
}
|
|
2941
|
+
return results;
|
|
2942
|
+
}
|
|
2943
|
+
async function recordOutput(engine, seconds, act) {
|
|
2944
|
+
engine.unlock();
|
|
2945
|
+
const output = engine.output();
|
|
2946
|
+
const Recorder = globalThis.MediaRecorder;
|
|
2947
|
+
const context = output?.context;
|
|
2948
|
+
if (!output || !Recorder || !context || typeof context.createMediaStreamDestination !== "function") return null;
|
|
2949
|
+
const tap = context.createMediaStreamDestination();
|
|
2950
|
+
output.connect(tap);
|
|
2951
|
+
const recorder = new Recorder(tap.stream);
|
|
2952
|
+
const chunks = [];
|
|
2953
|
+
recorder.ondataavailable = (event) => chunks.push(event.data);
|
|
2954
|
+
const done = new Promise((resolve) => {
|
|
2955
|
+
recorder.onstop = () => resolve();
|
|
2956
|
+
});
|
|
2957
|
+
recorder.start();
|
|
2958
|
+
act();
|
|
2959
|
+
await new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
|
|
2960
|
+
recorder.stop();
|
|
2961
|
+
await done;
|
|
2962
|
+
output.disconnect(tap);
|
|
2963
|
+
return new Blob(chunks, { type: recorder.mimeType || "audio/webm" });
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
// src/catalog.ts
|
|
2967
|
+
var SFX_CATEGORIES = ["armas", "impactos", "explosoes-fogo", "personagem", "veiculos", "itens-portas", "ambiente"];
|
|
2968
|
+
var entries = (category, list) => list.map(([id, priority, current]) => ({ id, category, priority, ...current ? { current } : {} }));
|
|
2969
|
+
var SFX_CATALOG = [
|
|
2970
|
+
...entries("armas", [
|
|
2971
|
+
["pistol_22lr", 2, "sfx_pistol"],
|
|
2972
|
+
["pistol_9mm", 1, "sfx_pistol"],
|
|
2973
|
+
["pistol_45", 1, "sfx_pistol"],
|
|
2974
|
+
["revolver_38_357", 2, "sfx_pistol"],
|
|
2975
|
+
["revolver_44_50ae", 3, "sfx_pistol"],
|
|
2976
|
+
["smg_9mm_auto", 1, "sfx_pistol"],
|
|
2977
|
+
["shotgun_12", 1, "sfx_shotgun"],
|
|
2978
|
+
["rifle_5_56", 1, "sfx_rifle"],
|
|
2979
|
+
["rifle_7_62x39", 1, "sfx_rifle"],
|
|
2980
|
+
["rifle_auto_burst", 1, "sfx_rifle"],
|
|
2981
|
+
["rifle_308_3006", 2, "sfx_rifle"],
|
|
2982
|
+
["sniper_338_300wm", 2, "sfx_rifle"],
|
|
2983
|
+
["antimateriel_50bmg", 3, "sfx_rifle"],
|
|
2984
|
+
["suppressed_pistol", 2],
|
|
2985
|
+
["suppressed_rifle", 2],
|
|
2986
|
+
["gunshot_far_pistol", 1],
|
|
2987
|
+
["gunshot_far_rifle", 1],
|
|
2988
|
+
["gunshot_far_shotgun", 1],
|
|
2989
|
+
["gunshot_far_heavy", 2],
|
|
2990
|
+
["gunshot_tail_indoor", 1],
|
|
2991
|
+
["gunshot_tail_outdoor", 1],
|
|
2992
|
+
["bullet_crack_by", 2],
|
|
2993
|
+
["bullet_whiz", 2],
|
|
2994
|
+
["ricochet_metal", 2, "ping"],
|
|
2995
|
+
["dry_fire", 1],
|
|
2996
|
+
["mag_out", 1],
|
|
2997
|
+
["mag_in", 1],
|
|
2998
|
+
["slide_pull_release", 1],
|
|
2999
|
+
["pump_cycle", 1],
|
|
3000
|
+
["casing_drop_concreto_pistol", 1],
|
|
3001
|
+
["casing_drop_concreto_rifle", 1],
|
|
3002
|
+
["casing_drop_concreto_shell", 1],
|
|
3003
|
+
["casing_drop_madeira_pistol", 1],
|
|
3004
|
+
["casing_drop_madeira_rifle", 1],
|
|
3005
|
+
["casing_drop_madeira_shell", 1],
|
|
3006
|
+
["casing_drop_metal_pistol", 1],
|
|
3007
|
+
["casing_drop_metal_rifle", 1],
|
|
3008
|
+
["casing_drop_metal_shell", 1],
|
|
3009
|
+
["casing_drop_terra_pistol", 1],
|
|
3010
|
+
["casing_drop_terra_rifle", 1],
|
|
3011
|
+
["casing_drop_terra_shell", 1],
|
|
3012
|
+
["rocket_fire", 2]
|
|
3013
|
+
]),
|
|
3014
|
+
...entries("explosoes-fogo", [
|
|
3015
|
+
["explosion_grenade", 1, "boom"],
|
|
3016
|
+
["explosion_big", 1, "boom_big"],
|
|
3017
|
+
["explosion_car", 2, "boom_big"],
|
|
3018
|
+
["explosion_far", 1],
|
|
3019
|
+
["debris_rain_stone", 1],
|
|
3020
|
+
["molotov_break_ignite", 1, "glass_shatter"],
|
|
3021
|
+
["fire_ignite", 1, "hiss"],
|
|
3022
|
+
["fire_loop_small", 1],
|
|
3023
|
+
["fire_loop_large", 1],
|
|
3024
|
+
["fire_extinguish", 2, "hiss"],
|
|
3025
|
+
["gas_leak_hiss", 2],
|
|
3026
|
+
["structure_collapse", 2, "crumble"]
|
|
3027
|
+
]),
|
|
3028
|
+
...entries("personagem", [
|
|
3029
|
+
["footstep_concrete_walk", 1, "sfx_step"],
|
|
3030
|
+
["footstep_wood_walk", 1, "sfx_step"],
|
|
3031
|
+
["footstep_dirt_walk", 1, "sfx_step"],
|
|
3032
|
+
["footstep_grass_walk", 1, "sfx_step"],
|
|
3033
|
+
["footstep_gravel_walk", 1, "sfx_step"],
|
|
3034
|
+
["land_concrete", 1, "sfx_step"],
|
|
3035
|
+
["punch_swing", 1],
|
|
3036
|
+
["punch_hit_body", 1, "sfx_flesh"],
|
|
3037
|
+
["kick_hit", 1, "sfx_flesh"],
|
|
3038
|
+
["knife_stab", 1],
|
|
3039
|
+
["blunt_hit", 1],
|
|
3040
|
+
["bite", 1, "sfx_flesh"],
|
|
3041
|
+
["body_fall", 1],
|
|
3042
|
+
["player_hurt", 2]
|
|
3043
|
+
]),
|
|
3044
|
+
...entries("veiculos", [
|
|
3045
|
+
["engine_loop_car", 1],
|
|
3046
|
+
["engine_start", 1],
|
|
3047
|
+
["crash_light", 1, "crash"],
|
|
3048
|
+
["crash_heavy", 1, "crash"],
|
|
3049
|
+
["car_door_open", 1, "latch"],
|
|
3050
|
+
["car_door_close", 1, "shut_metal"],
|
|
3051
|
+
["horn_car", 2, "horn"],
|
|
3052
|
+
["tire_skid_asphalt", 2]
|
|
3053
|
+
]),
|
|
3054
|
+
...entries("itens-portas", [
|
|
3055
|
+
["item_pickup_metal", 1],
|
|
3056
|
+
["can_open", 1],
|
|
3057
|
+
["can_crush", 1],
|
|
3058
|
+
["door_wood_open", 1, "latch"],
|
|
3059
|
+
["door_wood_close", 1, "shut_wood"],
|
|
3060
|
+
["door_creak", 1, "creak_wood"],
|
|
3061
|
+
["door_locked_rattle", 1, "rattle"],
|
|
3062
|
+
["drawer_open", 2, "slide"],
|
|
3063
|
+
["fridge_close", 2, "shut_metal"]
|
|
3064
|
+
]),
|
|
3065
|
+
...entries("ambiente", [
|
|
3066
|
+
["rain_loop", 2],
|
|
3067
|
+
["wind_loop", 2],
|
|
3068
|
+
["thunder_near", 2],
|
|
3069
|
+
["thunder_far", 2],
|
|
3070
|
+
["water_splash", 2]
|
|
3071
|
+
])
|
|
3072
|
+
];
|
|
3073
|
+
var SFX_MATERIALS = [
|
|
3074
|
+
["steel", "metal"],
|
|
3075
|
+
["aluminium", "metal"],
|
|
3076
|
+
["wood", "wood"],
|
|
3077
|
+
["plywood", "wood"],
|
|
3078
|
+
["mdf", "wood"],
|
|
3079
|
+
["glass", "glass"],
|
|
3080
|
+
["tempered_glass", "glass"],
|
|
3081
|
+
["ceramic", "glass"],
|
|
3082
|
+
["concrete", "masonry"],
|
|
3083
|
+
["brick", "masonry"],
|
|
3084
|
+
["plaster", "masonry"],
|
|
3085
|
+
["plastic", "soft"],
|
|
3086
|
+
["fabric", "soft"],
|
|
3087
|
+
["paper", "soft"],
|
|
3088
|
+
["foliage", "soft"],
|
|
3089
|
+
["soil", "soft"],
|
|
3090
|
+
["flesh", "soft"]
|
|
3091
|
+
];
|
|
3092
|
+
var SFX_BLOWS = ["bullet", "blunt", "blade", "break", "drag"];
|
|
3093
|
+
var CURRENT_BY_GROUP = {
|
|
3094
|
+
metal: { bullet: "clang", blunt: "clang", blade: "clang", break: "clang", drag: "drag_metal" },
|
|
3095
|
+
wood: { bullet: "wood_hit", blunt: "wood_hit", blade: "wood_hit", break: "crack", drag: "drag_wood" },
|
|
3096
|
+
glass: { bullet: "ping", blunt: "ping", break: "glass_shatter", drag: "drag_glass" },
|
|
3097
|
+
masonry: { bullet: "chip", blunt: "chip", blade: "chip", break: "crumble", drag: "drag_masonry" },
|
|
3098
|
+
soft: { bullet: "thud", blunt: "thud", blade: "thud", break: "thud", drag: "drag_soft" }
|
|
3099
|
+
};
|
|
3100
|
+
var impactSoundId = (material, blow) => `impact_${material}_${blow}`;
|
|
3101
|
+
var SFX_IMPACTS = SFX_MATERIALS.flatMap(
|
|
3102
|
+
([material, group]) => SFX_BLOWS.map((blow) => {
|
|
3103
|
+
const current = CURRENT_BY_GROUP[group]?.[blow];
|
|
3104
|
+
return { id: impactSoundId(material, blow), category: "impactos", priority: ["steel", "wood", "glass", "concrete", "brick", "soil", "flesh"].includes(material) && blow === "bullet" ? 1 : 2, ...current ? { current } : {} };
|
|
3105
|
+
})
|
|
3106
|
+
);
|
|
3107
|
+
function sfxState(entry, has) {
|
|
3108
|
+
if (has.sample(entry.id)) return "file";
|
|
3109
|
+
if (entry.current && has.sound(entry.current) || has.sound(entry.id)) return "synth";
|
|
3110
|
+
return "missing";
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
// src/manifest.ts
|
|
3114
|
+
var SDK_LICENSES = ["CC0", "CC-BY"];
|
|
3115
|
+
var SFX_LAYERS = ["close", "far", "tail_in", "tail_out"];
|
|
3116
|
+
var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
|
|
3117
|
+
function parseSfxName(name) {
|
|
3118
|
+
const match = /^(.*?)(?:_(close|far|tail_in|tail_out))?(?:_(\d+))?$/.exec(name);
|
|
3119
|
+
const id = match?.[1] || name;
|
|
3120
|
+
const layer = match?.[2] ?? "close";
|
|
3121
|
+
const take = match?.[3] ? Number(match[3]) : 1;
|
|
3122
|
+
return { id, layer, take };
|
|
3123
|
+
}
|
|
3124
|
+
function splitTier(id) {
|
|
3125
|
+
const match = /^(.*)_(light|medium|heavy)$/.exec(id);
|
|
3126
|
+
return match ? { base: match[1], tier: match[2] } : { base: id };
|
|
3127
|
+
}
|
|
3128
|
+
var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry) => ({ url: `${baseUrl}${entry.file}` }));
|
|
3129
|
+
function sampleBankFromManifest(manifest, options) {
|
|
3130
|
+
const baseUrl = options.baseUrl ?? "";
|
|
3131
|
+
const samples = [];
|
|
3132
|
+
const tiersOf = /* @__PURE__ */ new Map();
|
|
3133
|
+
for (const sound of manifest.sounds) {
|
|
3134
|
+
const { base, tier } = splitTier(sound.id);
|
|
3135
|
+
if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound]);
|
|
3136
|
+
}
|
|
3137
|
+
const bases = /* @__PURE__ */ new Map();
|
|
3138
|
+
for (const sound of manifest.sounds) {
|
|
3139
|
+
if (!splitTier(sound.id).tier) bases.set(sound.id, sound);
|
|
3140
|
+
}
|
|
3141
|
+
for (const [base, tiers] of tiersOf) {
|
|
3142
|
+
if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
|
|
3143
|
+
}
|
|
3144
|
+
for (const sound of bases.values()) {
|
|
3145
|
+
const numbers = options.sounds?.[sound.id] ?? options.defaults?.(sound);
|
|
3146
|
+
const close = refsOf(sound.layers.close, baseUrl);
|
|
3147
|
+
if (!numbers || close.length === 0) continue;
|
|
3148
|
+
const tiers = (tiersOf.get(sound.id) ?? []).map((tier) => {
|
|
3149
|
+
const name = splitTier(tier.id).tier;
|
|
3150
|
+
const tierFar = refsOf(tier.layers.far, baseUrl);
|
|
3151
|
+
return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
|
|
3152
|
+
}).sort((a, b) => a.from - b.from);
|
|
3153
|
+
const far = refsOf(sound.layers.far, baseUrl);
|
|
3154
|
+
const indoor = refsOf(sound.layers.tail_in, baseUrl);
|
|
3155
|
+
const outdoor = refsOf(sound.layers.tail_out, baseUrl);
|
|
3156
|
+
const files = [sound, ...tiersOf.get(sound.id) ?? []].flatMap((entry) => Object.values(entry.layers).flatMap((entries2) => entries2 ?? []));
|
|
3157
|
+
samples.push({
|
|
3158
|
+
id: sound.id,
|
|
3159
|
+
bus: numbers.bus,
|
|
3160
|
+
close,
|
|
3161
|
+
...far.length > 0 ? { far } : {},
|
|
3162
|
+
...tiers.length > 0 ? { tiers } : {},
|
|
3163
|
+
...numbers.crossover ? { crossover: numbers.crossover } : {},
|
|
3164
|
+
...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
|
|
3165
|
+
...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
|
|
3166
|
+
...numbers.gain === void 0 ? {} : { gain: numbers.gain },
|
|
3167
|
+
...numbers.falloff ? { falloff: numbers.falloff } : {},
|
|
3168
|
+
...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
|
|
3169
|
+
...numbers.group ? { group: numbers.group } : {},
|
|
3170
|
+
...numbers.priority === void 0 ? {} : { priority: numbers.priority },
|
|
3171
|
+
...numbers.fallback ? { fallback: numbers.fallback } : {},
|
|
3172
|
+
sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
|
|
3173
|
+
});
|
|
3174
|
+
}
|
|
3175
|
+
return { id: options.id, samples };
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
// src/kit-samples.ts
|
|
3179
|
+
var KIT_CATEGORY_BUS = {
|
|
3180
|
+
armas: "weapons",
|
|
3181
|
+
impactos: "world",
|
|
3182
|
+
"explosoes-fogo": "world",
|
|
3183
|
+
personagem: "world",
|
|
3184
|
+
veiculos: "world",
|
|
3185
|
+
"itens-portas": "world",
|
|
3186
|
+
ambiente: "ambience"
|
|
3187
|
+
};
|
|
3188
|
+
var VOICE_IDS = /^(player_(hurt|death|effort|breath)|scream|zombie_)/;
|
|
3189
|
+
var KIT_SAMPLE_ALIASES = {
|
|
3190
|
+
// a house door: the latch giving, the hinge, the leaf meeting the frame, a locked one shaken; a drawer on its runners
|
|
3191
|
+
latch: "metal_latch",
|
|
3192
|
+
creak_wood: "door_creak",
|
|
3193
|
+
shut_wood: "door_wood_shut",
|
|
3194
|
+
rattle: "door_locked_rattle",
|
|
3195
|
+
// a drawer stays on its recipe: the recorded runs (1 to 1.9 s) outlast a drawer's pull
|
|
3196
|
+
// an item taken in the hand (game-destruction-three grab_* keys)
|
|
3197
|
+
grab_hard: "item_pickup_generic",
|
|
3198
|
+
grab_soft: "item_pickup_leather"
|
|
3199
|
+
};
|
|
3200
|
+
function kitSampleDefaults(sound) {
|
|
3201
|
+
const bus = VOICE_IDS.test(sound.id) ? "voices" : KIT_CATEGORY_BUS[sound.category];
|
|
3202
|
+
if (!bus) return void 0;
|
|
3203
|
+
return { bus, pitch: sound.category === "ambiente" || /_loop/.test(sound.id) ? 0 : 0.04 };
|
|
3204
|
+
}
|
|
3205
|
+
function withAliases(manifest, aliases) {
|
|
3206
|
+
const byId = new Map(manifest.sounds.map((sound) => [sound.id, sound]));
|
|
3207
|
+
const extra = [];
|
|
3208
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
3209
|
+
const sound = byId.get(target);
|
|
3210
|
+
if (sound && !byId.has(alias)) extra.push({ ...sound, id: alias });
|
|
3211
|
+
}
|
|
3212
|
+
return { ...manifest, sounds: [...manifest.sounds, ...extra] };
|
|
3213
|
+
}
|
|
3214
|
+
function kitSampleBank(manifest, options = {}) {
|
|
3215
|
+
return sampleBankFromManifest(withAliases(manifest, options.aliases ?? KIT_SAMPLE_ALIASES), {
|
|
3216
|
+
id: options.id ?? "kit_samples",
|
|
3217
|
+
baseUrl: options.baseUrl ?? "",
|
|
3218
|
+
defaults: kitSampleDefaults
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
var isFileUrl = (url2) => {
|
|
3222
|
+
const page = globalThis.location?.href;
|
|
3223
|
+
try {
|
|
3224
|
+
return new URL(url2, page).protocol === "file:";
|
|
3225
|
+
} catch {
|
|
3226
|
+
return false;
|
|
3227
|
+
}
|
|
3228
|
+
};
|
|
3229
|
+
var fetchJson = async (url2) => {
|
|
3230
|
+
if (isFileUrl(url2)) throw new Error(`${url2}: file:// is not fetched`);
|
|
3231
|
+
const response = await fetch(url2);
|
|
3232
|
+
if (!response.ok) throw new Error(`${url2}: ${response.status}`);
|
|
3233
|
+
return await response.json();
|
|
3234
|
+
};
|
|
3235
|
+
async function loadKitSamples(engine, options = {}) {
|
|
3236
|
+
const baseUrl = options.baseUrl ?? "";
|
|
3237
|
+
let manifest;
|
|
3238
|
+
try {
|
|
3239
|
+
manifest = await (options.fetchManifest ?? fetchJson)(`${baseUrl}manifest.json`);
|
|
3240
|
+
} catch {
|
|
3241
|
+
return null;
|
|
3242
|
+
}
|
|
3243
|
+
const bank = kitSampleBank(manifest, options);
|
|
3244
|
+
engine.register(bank);
|
|
3245
|
+
if (options.preload && engine.loadSamples) void engine.loadSamples(options.preload).catch(() => void 0);
|
|
3246
|
+
return bank;
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
// src/data/game-sfx.json
|
|
3250
|
+
var game_sfx_default = {
|
|
3251
|
+
sources: ["jogo:L62089-62107"],
|
|
3252
|
+
note: "The game's sfx table P: [lowpass cutoff Hz, peak gain, seconds]. Played as a noise burst with the game's distance curve (falloff game_sfx) and a 0.05 s tail. Team names in `team`.",
|
|
3253
|
+
classes: [
|
|
3254
|
+
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
3255
|
+
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
3256
|
+
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
3257
|
+
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
3258
|
+
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
3259
|
+
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
3260
|
+
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
3261
|
+
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
3262
|
+
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
3263
|
+
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
3264
|
+
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
3265
|
+
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
3266
|
+
],
|
|
3267
|
+
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
3268
|
+
};
|
|
3269
|
+
|
|
3270
|
+
// src/recipes/noise-class.ts
|
|
3271
|
+
var GAME_SFX = game_sfx_default;
|
|
3272
|
+
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
3273
|
+
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
3274
|
+
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
3275
|
+
return {
|
|
3276
|
+
id,
|
|
3277
|
+
bus: row.bus,
|
|
3278
|
+
order: "burst",
|
|
3279
|
+
duration: row.seconds,
|
|
3280
|
+
tail: 0.05,
|
|
3281
|
+
layers: [
|
|
3282
|
+
{
|
|
3283
|
+
source: { kind: "noise", offset: "random" },
|
|
3284
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
3285
|
+
envelope: [
|
|
3286
|
+
[0, row.gain, "set"],
|
|
3287
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
3288
|
+
]
|
|
3289
|
+
}
|
|
3290
|
+
],
|
|
3291
|
+
falloff: DISTANCE_CURVES.game_sfx,
|
|
3292
|
+
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
3293
|
+
};
|
|
3294
|
+
}
|
|
3295
|
+
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
3296
|
+
|
|
3297
|
+
// src/recipes/scene.ts
|
|
3298
|
+
var ATTACK = 2e-3;
|
|
3299
|
+
function lengthOf(d, attack) {
|
|
3300
|
+
if (typeof d === "number") return attack + d;
|
|
3301
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
3302
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
3303
|
+
}
|
|
3304
|
+
var envelope = (attack) => [
|
|
3305
|
+
[0, 1e-4, "set", "fixed"],
|
|
3306
|
+
[attack, 1, "exp"],
|
|
3307
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
3308
|
+
];
|
|
3309
|
+
function sceneNoise(o) {
|
|
3310
|
+
const a = o.a ?? ATTACK;
|
|
3311
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
3312
|
+
return {
|
|
3313
|
+
filters: {
|
|
3314
|
+
mode: "serial",
|
|
3315
|
+
bank: [{ type: o.type ?? "lowpass", frequency: o.f2 === void 0 ? { set: o.f } : { set: o.f, to: o.f2, curve: "exp", over }, q: o.q ?? 0.7 }]
|
|
3316
|
+
},
|
|
3317
|
+
duration: lengthOf(o.d, a),
|
|
3318
|
+
gain: o.vol,
|
|
3319
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
3320
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
3321
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
3322
|
+
envelope: envelope(a)
|
|
3323
|
+
};
|
|
3324
|
+
}
|
|
3325
|
+
function sceneTone(o) {
|
|
3326
|
+
return {
|
|
3327
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
3328
|
+
duration: lengthOf(o.d, ATTACK),
|
|
3329
|
+
gain: o.vol,
|
|
3330
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
3331
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
3332
|
+
envelope: envelope(ATTACK)
|
|
3333
|
+
};
|
|
3334
|
+
}
|
|
3335
|
+
function sceneVoice(o) {
|
|
3336
|
+
return {
|
|
3337
|
+
duration: lengthOf(o.d, 0),
|
|
3338
|
+
gain: o.vol,
|
|
3339
|
+
wet: 0.45,
|
|
3340
|
+
source: {
|
|
3341
|
+
kind: "formant_voice",
|
|
3342
|
+
wave: o.wave ?? "sawtooth",
|
|
3343
|
+
frequency: { from: o.f0, to: o.f1, curve: "linear", over: "duration" },
|
|
3344
|
+
vibrato: { rate: [4, 10], depth: 0.08 },
|
|
3345
|
+
formants: [
|
|
3346
|
+
{ frequency: o.fA, q: 4 },
|
|
3347
|
+
{ frequency: o.fB, q: 6 }
|
|
3348
|
+
],
|
|
3349
|
+
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
3350
|
+
mix: 3.2
|
|
3351
|
+
},
|
|
3352
|
+
envelope: [
|
|
3353
|
+
[0, 1e-4, "set", "fixed"],
|
|
3354
|
+
[0.1, 1, "exp"],
|
|
3355
|
+
["0.6d", 1, "set"],
|
|
3356
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
3357
|
+
]
|
|
3358
|
+
};
|
|
3359
|
+
}
|
|
3360
|
+
var sceneMany = (count, make) => Array.from({ length: count }, make);
|
|
3361
|
+
function sceneRecipe(id, layers, line, options = {}) {
|
|
3362
|
+
return {
|
|
3363
|
+
id,
|
|
3364
|
+
bus: options.bus ?? "world",
|
|
3365
|
+
pan: true,
|
|
3366
|
+
layers,
|
|
3367
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
3368
|
+
...options.vars ? { vars: options.vars } : {},
|
|
3369
|
+
...options.group ? { group: options.group } : {},
|
|
3370
|
+
sources: [`cena:${line}`]
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
|
|
3374
|
+
// src/library/crowd_rumble.json
|
|
3375
|
+
var crowd_rumble_default = {
|
|
3376
|
+
id: "crowd_rumble",
|
|
3377
|
+
bus: "ambience",
|
|
3378
|
+
order: "game_loop",
|
|
3379
|
+
source: { kind: "noise", loop: true },
|
|
3380
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 160 } }] },
|
|
3381
|
+
smoothing: { volume: 0.15, frequency: 0.08 },
|
|
3382
|
+
startAbove: 2e-3,
|
|
3383
|
+
sources: ["jogo:L62116 horda: noise through a 160 Hz lowpass", "jogo:L70424 level min(0.16, near \xD7 0.0016)", "temporary home until the crowd package (Q12)"]
|
|
3384
|
+
};
|
|
3385
|
+
|
|
3386
|
+
// src/library/engine_saw.json
|
|
3387
|
+
var engine_saw_default = {
|
|
3388
|
+
id: "engine_saw",
|
|
3389
|
+
bus: "world",
|
|
3390
|
+
order: "game_loop",
|
|
3391
|
+
source: { kind: "osc", wave: "sawtooth", loop: true },
|
|
3392
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 400 } }] },
|
|
3393
|
+
smoothing: { volume: 0.15, frequency: 0.08 },
|
|
3394
|
+
startAbove: 2e-3,
|
|
3395
|
+
sources: [
|
|
3396
|
+
"jogo:L62115 motor: sawtooth through a 400 Hz lowpass",
|
|
3397
|
+
"jogo:L70421 level 0.035 + speed \xD7 0.003, frequency 38 + speed \xD7 7 (the host drives `set`)",
|
|
3398
|
+
"temporary home until the vehicles package (Q12)"
|
|
3399
|
+
]
|
|
3400
|
+
};
|
|
3401
|
+
|
|
3402
|
+
// src/library/horn.json
|
|
3403
|
+
var horn_default = {
|
|
3404
|
+
id: "horn",
|
|
3405
|
+
bus: "world",
|
|
3406
|
+
order: "chord",
|
|
3407
|
+
duration: 0.6,
|
|
3408
|
+
tail: 0.02,
|
|
3409
|
+
layers: [
|
|
3410
|
+
{ source: { kind: "osc", wave: "square", frequency: { set: 415 } }, envelope: [[0, 0.08, "set"], [0.6, 1e-4, "set", "fixed"]] },
|
|
3411
|
+
{ source: { kind: "osc", wave: "square", frequency: { set: 523 } }, envelope: [[0, 0.08, "set"], [0.6, 1e-4, "set", "fixed"]] }
|
|
3412
|
+
],
|
|
3413
|
+
falloff: { model: "none" },
|
|
3414
|
+
sources: ["jogo:L70272-70276 buzina: squares at 415 and 523 Hz, 0.08 for 0.6 s", "temporary home until the vehicles package (Q12)"]
|
|
3415
|
+
};
|
|
3416
|
+
|
|
3417
|
+
// src/library/radio_static.json
|
|
3418
|
+
var radio_static_default = {
|
|
3419
|
+
id: "radio_static",
|
|
3420
|
+
bus: "world",
|
|
3421
|
+
order: "static",
|
|
3422
|
+
duration: 0.6,
|
|
3423
|
+
layers: [
|
|
3424
|
+
{
|
|
3425
|
+
source: { kind: "noise", offset: "random" },
|
|
3426
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: 1800 }, q: 0.8 }] },
|
|
3427
|
+
envelope: [[0, 0.06, "set"], ["1d", 1e-3, "exp", "fixed"]]
|
|
3428
|
+
}
|
|
3429
|
+
],
|
|
3430
|
+
falloff: { model: "none" },
|
|
3431
|
+
sources: ["jogo:L69998-70004 chiado: noise through a 1800 Hz bandpass (Q 0.8), 0.06 falling over 0.6 s", "temporary home until the props or radio package (Q12)"]
|
|
3432
|
+
};
|
|
3433
|
+
|
|
3434
|
+
// src/library/rotor_blades.json
|
|
3435
|
+
var rotor_blades_default = {
|
|
3436
|
+
id: "rotor_blades",
|
|
3437
|
+
bus: "world",
|
|
3438
|
+
order: "game_loop",
|
|
3439
|
+
source: { kind: "noise", loop: true },
|
|
3440
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 300 } }] },
|
|
3441
|
+
modulators: [{ target: "gain", rate: 11, depth: 0.5, base: 0.5 }],
|
|
3442
|
+
smoothing: { volume: 0.15, frequency: 0.08 },
|
|
3443
|
+
startAbove: 2e-3,
|
|
3444
|
+
sources: [
|
|
3445
|
+
"jogo:L62116-62120 rotor: noise through a 300 Hz lowpass, blade beat as an 11 Hz LFO of 0.5 on a 0.5 gain stage",
|
|
3446
|
+
"jogo:L70426 level min(0.5, 30 / (distance + 10))",
|
|
3447
|
+
"temporary home until the vehicles package (Q12)"
|
|
3448
|
+
]
|
|
3449
|
+
};
|
|
3450
|
+
|
|
3451
|
+
// src/library/siren.json
|
|
3452
|
+
var siren_default = {
|
|
3453
|
+
id: "siren",
|
|
3454
|
+
bus: "world",
|
|
3455
|
+
order: "siren",
|
|
3456
|
+
duration: 9,
|
|
3457
|
+
tail: 0.2,
|
|
3458
|
+
layers: [
|
|
3459
|
+
{
|
|
3460
|
+
wet: 1.5,
|
|
3461
|
+
source: { kind: "osc", wave: "sine", frequency: { set: 850 } },
|
|
3462
|
+
modulators: [{ target: "frequency", rate: 0.18, depth: 280 }],
|
|
3463
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 1400 } }] },
|
|
3464
|
+
envelope: [[0, 1e-4, "set", "fixed"], [2, 0.035, "exp"], [6, 0.035, "set"], [9, 1e-4, "exp", "fixed"]]
|
|
3465
|
+
}
|
|
3466
|
+
],
|
|
3467
|
+
falloff: { model: "none" },
|
|
3468
|
+
sources: ["cena:L1369 siren: 850 Hz sine swept \xB1280 Hz at 0.18 Hz, 1400 Hz lowpass, 0.035 for 9 s, reverb send 1.5", "temporary home until the vehicles package (Q12)"]
|
|
3469
|
+
};
|
|
3470
|
+
|
|
3471
|
+
// src/library/index.ts
|
|
3472
|
+
var LIBRARY_SOUNDS = [horn_default, radio_static_default, siren_default];
|
|
3473
|
+
var LIBRARY_LOOPS = [engine_saw_default, rotor_blades_default, crowd_rumble_default];
|
|
3474
|
+
var LIBRARY_BANK = { id: "library", sounds: LIBRARY_SOUNDS, loops: LIBRARY_LOOPS };
|
|
3475
|
+
|
|
3476
|
+
// src/recipes/foley.ts
|
|
3477
|
+
var FOLEY_FALLOFF = {
|
|
3478
|
+
model: "inverse_square",
|
|
3479
|
+
k: 0.02,
|
|
3480
|
+
cutoffK: 0.04,
|
|
3481
|
+
minGain: 4e-3
|
|
3482
|
+
};
|
|
3483
|
+
var vary = (f, pct = 0.04) => [Math.round(f * (1 - pct)), Math.round(f * (1 + pct))];
|
|
3484
|
+
var foley = (id, layers, note) => ({
|
|
3485
|
+
id,
|
|
3486
|
+
bus: "world",
|
|
3487
|
+
pan: true,
|
|
3488
|
+
layers,
|
|
3489
|
+
falloff: FOLEY_FALLOFF,
|
|
3490
|
+
sources: [`sdk: ${note}`]
|
|
3491
|
+
});
|
|
3492
|
+
var click = (f, vol, delay = 0) => [
|
|
3493
|
+
sceneNoise({
|
|
3494
|
+
type: "bandpass",
|
|
3495
|
+
f: vary(f, 0.08),
|
|
3496
|
+
q: 4,
|
|
3497
|
+
d: [0.018, 0.03],
|
|
3498
|
+
vol: [vol * 0.85, vol * 1.1],
|
|
3499
|
+
delay
|
|
3500
|
+
}),
|
|
3501
|
+
sceneTone({
|
|
3502
|
+
f: vary(f * 0.8, 0.06),
|
|
3503
|
+
f2: Math.round(f * 0.62),
|
|
3504
|
+
d: [0.015, 0.025],
|
|
3505
|
+
vol: vol * 0.18,
|
|
3506
|
+
delay
|
|
3507
|
+
})
|
|
3508
|
+
];
|
|
3509
|
+
var meet = (body, panel, vol, latch) => [
|
|
3510
|
+
sceneTone({
|
|
3511
|
+
f: vary(body),
|
|
3512
|
+
f2: Math.round(body * 0.5),
|
|
3513
|
+
d: [0.12, 0.16],
|
|
3514
|
+
vol: [vol * 0.9, vol * 1.1]
|
|
3515
|
+
}),
|
|
3516
|
+
sceneNoise({
|
|
3517
|
+
type: "bandpass",
|
|
3518
|
+
f: vary(panel, 0.06),
|
|
3519
|
+
q: 1.2,
|
|
3520
|
+
d: [0.08, 0.12],
|
|
3521
|
+
vol: [vol * 0.9, vol * 1.1],
|
|
3522
|
+
wet: 0.25
|
|
3523
|
+
}),
|
|
3524
|
+
...click(latch, vol * 0.45, [0.012, 0.028])
|
|
3525
|
+
];
|
|
3526
|
+
var LEAF_FOLEY = [
|
|
3527
|
+
// a wooden house door or wardrobe door: latch, a short creak, the leaf on the frame (the hard slam adds the frame rattling)
|
|
3528
|
+
foley("door_wood_open", click(2400, 0.4), "the latch of a wooden door giving"),
|
|
3529
|
+
foley(
|
|
3530
|
+
"door_creak",
|
|
3531
|
+
[
|
|
3532
|
+
sceneTone({ f: [190, 240], f2: 310, d: [0.4, 0.55], vol: [0.04, 0.06] }),
|
|
3533
|
+
sceneNoise({
|
|
3534
|
+
type: "bandpass",
|
|
3535
|
+
f: [480, 560],
|
|
3536
|
+
q: 6,
|
|
3537
|
+
a: 0.05,
|
|
3538
|
+
d: [0.35, 0.5],
|
|
3539
|
+
vol: [0.1, 0.14]
|
|
3540
|
+
})
|
|
3541
|
+
],
|
|
3542
|
+
"a wooden hinge turning"
|
|
3543
|
+
),
|
|
3544
|
+
foley("door_wood_close", meet(120, 600, 0.55, 2400), "a wooden leaf meeting its frame"),
|
|
3545
|
+
foley(
|
|
3546
|
+
"door_wood_slam",
|
|
3547
|
+
[
|
|
3548
|
+
...meet(110, 560, 0.85, 2300),
|
|
3549
|
+
...sceneMany(
|
|
3550
|
+
3,
|
|
3551
|
+
() => sceneNoise({
|
|
3552
|
+
type: "bandpass",
|
|
3553
|
+
f: [900, 1500],
|
|
3554
|
+
q: 3,
|
|
3555
|
+
d: 0.03,
|
|
3556
|
+
vol: [0.08, 0.14],
|
|
3557
|
+
delay: [0.05, 0.18]
|
|
3558
|
+
})
|
|
3559
|
+
)
|
|
3560
|
+
],
|
|
3561
|
+
"a wooden door slammed: the frame and the hinges rattle after the hit"
|
|
3562
|
+
),
|
|
3563
|
+
// a metal door or gate: a hollow panel that rings a little
|
|
3564
|
+
foley("door_metal_open_close", [...meet(160, 900, 0.55, 2e3), sceneTone({ f: vary(1250), f2: 1150, d: [0.1, 0.16], vol: 0.06, wet: 0.3 })], "a metal door or gate meeting its frame"),
|
|
3565
|
+
foley(
|
|
3566
|
+
"door_creak_metal",
|
|
3567
|
+
[
|
|
3568
|
+
sceneTone({ f: [620, 760], f2: 900, d: [0.3, 0.4], vol: [0.03, 0.045] }),
|
|
3569
|
+
sceneNoise({
|
|
3570
|
+
type: "bandpass",
|
|
3571
|
+
f: [1300, 1500],
|
|
3572
|
+
q: 8,
|
|
3573
|
+
a: 0.04,
|
|
3574
|
+
d: [0.25, 0.35],
|
|
3575
|
+
vol: [0.07, 0.09]
|
|
3576
|
+
})
|
|
3577
|
+
],
|
|
3578
|
+
"a metal hinge turning"
|
|
3579
|
+
),
|
|
3580
|
+
// the handle of a locked door shaken: the latch knocking in its keeper, five to seven times in half a second
|
|
3581
|
+
foley(
|
|
3582
|
+
"door_locked_rattle",
|
|
3583
|
+
[
|
|
3584
|
+
...sceneMany(
|
|
3585
|
+
6,
|
|
3586
|
+
() => sceneNoise({
|
|
3587
|
+
type: "bandpass",
|
|
3588
|
+
f: [1600, 2600],
|
|
3589
|
+
q: 3,
|
|
3590
|
+
d: [0.025, 0.04],
|
|
3591
|
+
vol: [0.22, 0.34],
|
|
3592
|
+
delay: [0, 0.45]
|
|
3593
|
+
})
|
|
3594
|
+
),
|
|
3595
|
+
...sceneMany(
|
|
3596
|
+
3,
|
|
3597
|
+
() => sceneTone({
|
|
3598
|
+
f: [170, 210],
|
|
3599
|
+
f2: 120,
|
|
3600
|
+
d: 0.05,
|
|
3601
|
+
vol: [0.12, 0.18],
|
|
3602
|
+
delay: [0.02, 0.4]
|
|
3603
|
+
})
|
|
3604
|
+
)
|
|
3605
|
+
],
|
|
3606
|
+
"the handle of a locked door shaken: latch knocks and the leaf thumping in its frame"
|
|
3607
|
+
),
|
|
3608
|
+
// a fridge: the rubber seal lets go with a soft suck, the bottles in the door clink; closing it is a soft thump and the seal pulling shut
|
|
3609
|
+
foley(
|
|
3610
|
+
"fridge_open",
|
|
3611
|
+
[
|
|
3612
|
+
sceneNoise({
|
|
3613
|
+
type: "lowpass",
|
|
3614
|
+
f: [320, 380],
|
|
3615
|
+
a: 0.03,
|
|
3616
|
+
d: [0.14, 0.2],
|
|
3617
|
+
vol: [0.32, 0.4]
|
|
3618
|
+
}),
|
|
3619
|
+
sceneNoise({
|
|
3620
|
+
type: "bandpass",
|
|
3621
|
+
f: [800, 950],
|
|
3622
|
+
f2: 1400,
|
|
3623
|
+
q: 2,
|
|
3624
|
+
a: 0.02,
|
|
3625
|
+
d: 0.12,
|
|
3626
|
+
vol: [0.08, 0.12]
|
|
3627
|
+
}),
|
|
3628
|
+
...sceneMany(
|
|
3629
|
+
2,
|
|
3630
|
+
() => sceneTone({
|
|
3631
|
+
f: [2600, 4200],
|
|
3632
|
+
d: [0.04, 0.08],
|
|
3633
|
+
vol: [0.015, 0.03],
|
|
3634
|
+
delay: [0.08, 0.22]
|
|
3635
|
+
})
|
|
3636
|
+
)
|
|
3637
|
+
],
|
|
3638
|
+
"a fridge door: the seal letting go and the bottles in the door"
|
|
3639
|
+
),
|
|
3640
|
+
foley(
|
|
3641
|
+
"fridge_close",
|
|
3642
|
+
[
|
|
3643
|
+
sceneTone({ f: vary(85), f2: 45, d: [0.1, 0.13], vol: [0.38, 0.46] }),
|
|
3644
|
+
sceneNoise({
|
|
3645
|
+
type: "lowpass",
|
|
3646
|
+
f: [520, 620],
|
|
3647
|
+
d: [0.08, 0.12],
|
|
3648
|
+
vol: [0.3, 0.36]
|
|
3649
|
+
}),
|
|
3650
|
+
sceneNoise({
|
|
3651
|
+
type: "lowpass",
|
|
3652
|
+
f: [260, 320],
|
|
3653
|
+
a: 0.02,
|
|
3654
|
+
d: 0.1,
|
|
3655
|
+
vol: [0.12, 0.18],
|
|
3656
|
+
delay: [0.04, 0.07]
|
|
3657
|
+
}),
|
|
3658
|
+
...sceneMany(
|
|
3659
|
+
2,
|
|
3660
|
+
() => sceneTone({
|
|
3661
|
+
f: [2600, 4200],
|
|
3662
|
+
d: [0.04, 0.07],
|
|
3663
|
+
vol: [0.015, 0.03],
|
|
3664
|
+
delay: [0.03, 0.12]
|
|
3665
|
+
})
|
|
3666
|
+
)
|
|
3667
|
+
],
|
|
3668
|
+
"a fridge door shut: a soft thump, the seal pulling and the bottles"
|
|
3669
|
+
),
|
|
3670
|
+
// a microwave: the spring catch of the door, plastic on plastic
|
|
3671
|
+
foley(
|
|
3672
|
+
"microwave_open",
|
|
3673
|
+
[
|
|
3674
|
+
...click(1800, 0.34),
|
|
3675
|
+
sceneTone({
|
|
3676
|
+
f: [3e3, 3400],
|
|
3677
|
+
f2: 2800,
|
|
3678
|
+
d: 0.05,
|
|
3679
|
+
vol: 0.025,
|
|
3680
|
+
delay: [0.01, 0.02]
|
|
3681
|
+
})
|
|
3682
|
+
],
|
|
3683
|
+
"the spring catch of a microwave door"
|
|
3684
|
+
),
|
|
3685
|
+
foley(
|
|
3686
|
+
"microwave_close",
|
|
3687
|
+
[
|
|
3688
|
+
sceneNoise({
|
|
3689
|
+
type: "bandpass",
|
|
3690
|
+
f: [1200, 1450],
|
|
3691
|
+
q: 2.5,
|
|
3692
|
+
d: [0.04, 0.06],
|
|
3693
|
+
vol: [0.36, 0.44]
|
|
3694
|
+
}),
|
|
3695
|
+
sceneTone({ f: vary(180), f2: 120, d: 0.05, vol: [0.16, 0.22] }),
|
|
3696
|
+
...click(2200, 0.2, [8e-3, 0.016])
|
|
3697
|
+
],
|
|
3698
|
+
"a microwave door clacking shut"
|
|
3699
|
+
),
|
|
3700
|
+
foley("microwave_beep", [sceneTone({ wave: "square", f: 2e3, d: 0.12, vol: 0.05 })], "the beep of a microwave"),
|
|
3701
|
+
// drawers and sliding leaves: the runners, then the stop
|
|
3702
|
+
foley(
|
|
3703
|
+
"drawer_open",
|
|
3704
|
+
[
|
|
3705
|
+
sceneNoise({
|
|
3706
|
+
type: "bandpass",
|
|
3707
|
+
f: [620, 780],
|
|
3708
|
+
q: 2,
|
|
3709
|
+
a: 0.04,
|
|
3710
|
+
d: [0.28, 0.36],
|
|
3711
|
+
vol: [0.18, 0.24]
|
|
3712
|
+
}),
|
|
3713
|
+
sceneNoise({ type: "bandpass", f: [2e3, 2400], q: 5, d: 0.28, vol: 0.04 }),
|
|
3714
|
+
...click(1400, 0.16, [0.28, 0.34])
|
|
3715
|
+
],
|
|
3716
|
+
"a drawer on its runners and its stop"
|
|
3717
|
+
),
|
|
3718
|
+
foley(
|
|
3719
|
+
"drawer_close",
|
|
3720
|
+
[
|
|
3721
|
+
sceneNoise({
|
|
3722
|
+
type: "bandpass",
|
|
3723
|
+
f: [620, 780],
|
|
3724
|
+
q: 2,
|
|
3725
|
+
a: 0.03,
|
|
3726
|
+
d: [0.2, 0.28],
|
|
3727
|
+
vol: [0.18, 0.24]
|
|
3728
|
+
}),
|
|
3729
|
+
sceneTone({
|
|
3730
|
+
f: vary(150),
|
|
3731
|
+
f2: 90,
|
|
3732
|
+
d: 0.08,
|
|
3733
|
+
vol: [0.22, 0.3],
|
|
3734
|
+
delay: [0.2, 0.26]
|
|
3735
|
+
})
|
|
3736
|
+
],
|
|
3737
|
+
"a drawer pushed home"
|
|
3738
|
+
)
|
|
3739
|
+
];
|
|
3740
|
+
var ITEM_FOLEY = [
|
|
3741
|
+
// the hand closing on the item: a touch of skin and cloth, then the item's own small sound
|
|
3742
|
+
foley(
|
|
3743
|
+
"item_pickup_metal",
|
|
3744
|
+
[
|
|
3745
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
3746
|
+
sceneTone({
|
|
3747
|
+
f: [1900, 2600],
|
|
3748
|
+
f2: 1700,
|
|
3749
|
+
d: [0.05, 0.08],
|
|
3750
|
+
vol: [0.06, 0.09],
|
|
3751
|
+
delay: [0.01, 0.03]
|
|
3752
|
+
})
|
|
3753
|
+
],
|
|
3754
|
+
"picking up a metal thing"
|
|
3755
|
+
),
|
|
3756
|
+
foley(
|
|
3757
|
+
"item_pickup_plastic",
|
|
3758
|
+
[
|
|
3759
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
3760
|
+
sceneNoise({
|
|
3761
|
+
type: "bandpass",
|
|
3762
|
+
f: [1500, 1900],
|
|
3763
|
+
q: 3,
|
|
3764
|
+
d: 0.03,
|
|
3765
|
+
vol: [0.15, 0.21],
|
|
3766
|
+
delay: [0.01, 0.03]
|
|
3767
|
+
})
|
|
3768
|
+
],
|
|
3769
|
+
"picking up a plastic thing"
|
|
3770
|
+
),
|
|
3771
|
+
foley(
|
|
3772
|
+
"item_pickup_glass",
|
|
3773
|
+
[
|
|
3774
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.15 }),
|
|
3775
|
+
sceneTone({
|
|
3776
|
+
f: [3200, 4200],
|
|
3777
|
+
d: [0.05, 0.08],
|
|
3778
|
+
vol: [0.038, 0.06],
|
|
3779
|
+
delay: [0.01, 0.03]
|
|
3780
|
+
})
|
|
3781
|
+
],
|
|
3782
|
+
"picking up a glass thing"
|
|
3783
|
+
),
|
|
3784
|
+
foley(
|
|
3785
|
+
"item_pickup_paper",
|
|
3786
|
+
[
|
|
3787
|
+
sceneNoise({
|
|
3788
|
+
type: "highpass",
|
|
3789
|
+
f: [2600, 3400],
|
|
3790
|
+
a: 0.01,
|
|
3791
|
+
d: [0.1, 0.14],
|
|
3792
|
+
vol: [0.12, 0.18]
|
|
3793
|
+
}),
|
|
3794
|
+
sceneNoise({ type: "bandpass", f: [800, 1e3], q: 1, d: 0.05, vol: 0.12 })
|
|
3795
|
+
],
|
|
3796
|
+
"picking up paper or cardboard"
|
|
3797
|
+
),
|
|
3798
|
+
foley(
|
|
3799
|
+
"item_pickup_fabric",
|
|
3800
|
+
[
|
|
3801
|
+
sceneNoise({
|
|
3802
|
+
type: "bandpass",
|
|
3803
|
+
f: [900, 1300],
|
|
3804
|
+
q: 0.8,
|
|
3805
|
+
a: 0.02,
|
|
3806
|
+
d: [0.12, 0.16],
|
|
3807
|
+
vol: [0.15, 0.21]
|
|
3808
|
+
})
|
|
3809
|
+
],
|
|
3810
|
+
"picking up cloth"
|
|
3811
|
+
),
|
|
3812
|
+
foley(
|
|
3813
|
+
"item_pickup_wood",
|
|
3814
|
+
[
|
|
3815
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
3816
|
+
sceneNoise({
|
|
3817
|
+
type: "bandpass",
|
|
3818
|
+
f: [900, 1100],
|
|
3819
|
+
q: 2,
|
|
3820
|
+
d: 0.04,
|
|
3821
|
+
vol: [0.15, 0.21],
|
|
3822
|
+
delay: [0.01, 0.03]
|
|
3823
|
+
})
|
|
3824
|
+
],
|
|
3825
|
+
"picking up a wooden thing"
|
|
3826
|
+
),
|
|
3827
|
+
foley(
|
|
3828
|
+
"item_pickup_food",
|
|
3829
|
+
[
|
|
3830
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
3831
|
+
sceneNoise({
|
|
3832
|
+
type: "lowpass",
|
|
3833
|
+
f: [500, 650],
|
|
3834
|
+
d: 0.05,
|
|
3835
|
+
vol: 0.12,
|
|
3836
|
+
delay: [0.01, 0.03]
|
|
3837
|
+
})
|
|
3838
|
+
],
|
|
3839
|
+
"picking up food"
|
|
3840
|
+
),
|
|
3841
|
+
foley(
|
|
3842
|
+
"item_throw",
|
|
3843
|
+
[
|
|
3844
|
+
sceneNoise({
|
|
3845
|
+
type: "bandpass",
|
|
3846
|
+
f: [450, 650],
|
|
3847
|
+
f2: 1400,
|
|
3848
|
+
q: 1.5,
|
|
3849
|
+
a: 0.05,
|
|
3850
|
+
d: 0.18,
|
|
3851
|
+
vol: [0.1, 0.14]
|
|
3852
|
+
})
|
|
3853
|
+
],
|
|
3854
|
+
"the arm throwing something: air"
|
|
3855
|
+
),
|
|
3856
|
+
// a can: the tab cracks, the gas hisses out; drinking is gulps; crushing it crumples the sheet
|
|
3857
|
+
foley(
|
|
3858
|
+
"can_open",
|
|
3859
|
+
[
|
|
3860
|
+
...click(3200, 0.36),
|
|
3861
|
+
sceneNoise({
|
|
3862
|
+
type: "highpass",
|
|
3863
|
+
f: [3600, 4400],
|
|
3864
|
+
a: 5e-3,
|
|
3865
|
+
d: [0.22, 0.3],
|
|
3866
|
+
vol: [0.16, 0.22],
|
|
3867
|
+
delay: [0.012, 0.02]
|
|
3868
|
+
}),
|
|
3869
|
+
...sceneMany(5, () => sceneTone({ f: [4e3, 7e3], d: 0.02, vol: 0.01, delay: [0.05, 0.4] }))
|
|
3870
|
+
],
|
|
3871
|
+
"the tab of a can and the gas hissing out"
|
|
3872
|
+
),
|
|
3873
|
+
foley(
|
|
3874
|
+
"can_crush",
|
|
3875
|
+
[
|
|
3876
|
+
sceneNoise({
|
|
3877
|
+
type: "bandpass",
|
|
3878
|
+
f: [1600, 2200],
|
|
3879
|
+
q: 1.2,
|
|
3880
|
+
d: [0.18, 0.25],
|
|
3881
|
+
vol: [0.3, 0.38]
|
|
3882
|
+
}),
|
|
3883
|
+
...sceneMany(
|
|
3884
|
+
6,
|
|
3885
|
+
() => sceneTone({
|
|
3886
|
+
f: [1200, 3400],
|
|
3887
|
+
f2: 900,
|
|
3888
|
+
d: 0.03,
|
|
3889
|
+
vol: [0.03, 0.06],
|
|
3890
|
+
delay: [0, 0.2]
|
|
3891
|
+
})
|
|
3892
|
+
)
|
|
3893
|
+
],
|
|
3894
|
+
"a can crushed in the hand"
|
|
3895
|
+
),
|
|
3896
|
+
foley(
|
|
3897
|
+
"can_puncture_spray",
|
|
3898
|
+
[
|
|
3899
|
+
sceneNoise({
|
|
3900
|
+
type: "highpass",
|
|
3901
|
+
f: [2400, 3e3],
|
|
3902
|
+
a: 5e-3,
|
|
3903
|
+
d: [0.5, 0.7],
|
|
3904
|
+
vol: [0.2, 0.26]
|
|
3905
|
+
}),
|
|
3906
|
+
sceneNoise({ type: "bandpass", f: [600, 800], q: 2, d: 0.4, vol: 0.06 })
|
|
3907
|
+
],
|
|
3908
|
+
"a can holed: the jet hissing out"
|
|
3909
|
+
),
|
|
3910
|
+
foley(
|
|
3911
|
+
"bottle_open",
|
|
3912
|
+
[
|
|
3913
|
+
...sceneMany(
|
|
3914
|
+
5,
|
|
3915
|
+
() => sceneNoise({
|
|
3916
|
+
type: "bandpass",
|
|
3917
|
+
f: [2200, 3e3],
|
|
3918
|
+
q: 4,
|
|
3919
|
+
d: 8e-3,
|
|
3920
|
+
vol: [0.1, 0.16],
|
|
3921
|
+
delay: [0, 0.18]
|
|
3922
|
+
})
|
|
3923
|
+
),
|
|
3924
|
+
sceneNoise({
|
|
3925
|
+
type: "highpass",
|
|
3926
|
+
f: 3800,
|
|
3927
|
+
a: 5e-3,
|
|
3928
|
+
d: 0.12,
|
|
3929
|
+
vol: [0.06, 0.1],
|
|
3930
|
+
delay: [0.18, 0.22]
|
|
3931
|
+
})
|
|
3932
|
+
],
|
|
3933
|
+
"the screw cap of a bottle turning off"
|
|
3934
|
+
),
|
|
3935
|
+
foley(
|
|
3936
|
+
"drink_gulp",
|
|
3937
|
+
[
|
|
3938
|
+
sceneNoise({
|
|
3939
|
+
type: "lowpass",
|
|
3940
|
+
f: [280, 360],
|
|
3941
|
+
a: 0.02,
|
|
3942
|
+
d: [0.1, 0.14],
|
|
3943
|
+
vol: [0.24, 0.3]
|
|
3944
|
+
}),
|
|
3945
|
+
sceneTone({ f: [140, 170], f2: 85, d: [0.08, 0.11], vol: [0.12, 0.16] })
|
|
3946
|
+
],
|
|
3947
|
+
"a gulp"
|
|
3948
|
+
),
|
|
3949
|
+
foley(
|
|
3950
|
+
"eat_crunch",
|
|
3951
|
+
[
|
|
3952
|
+
...sceneMany(
|
|
3953
|
+
4,
|
|
3954
|
+
() => sceneNoise({
|
|
3955
|
+
type: "bandpass",
|
|
3956
|
+
f: [1800, 3200],
|
|
3957
|
+
q: 1.5,
|
|
3958
|
+
d: [0.02, 0.04],
|
|
3959
|
+
vol: [0.12, 0.2],
|
|
3960
|
+
delay: [0, 0.12]
|
|
3961
|
+
})
|
|
3962
|
+
)
|
|
3963
|
+
],
|
|
3964
|
+
"a bite of something crunchy"
|
|
3965
|
+
),
|
|
3966
|
+
foley(
|
|
3967
|
+
"eat_chew",
|
|
3968
|
+
[
|
|
3969
|
+
sceneNoise({
|
|
3970
|
+
type: "lowpass",
|
|
3971
|
+
f: [450, 600],
|
|
3972
|
+
a: 0.03,
|
|
3973
|
+
d: [0.1, 0.14],
|
|
3974
|
+
vol: [0.12, 0.16]
|
|
3975
|
+
}),
|
|
3976
|
+
sceneNoise({
|
|
3977
|
+
type: "bandpass",
|
|
3978
|
+
f: [1100, 1400],
|
|
3979
|
+
q: 2,
|
|
3980
|
+
d: 0.04,
|
|
3981
|
+
vol: 0.04,
|
|
3982
|
+
delay: [0.03, 0.06]
|
|
3983
|
+
})
|
|
3984
|
+
],
|
|
3985
|
+
"chewing"
|
|
3986
|
+
),
|
|
3987
|
+
foley(
|
|
3988
|
+
"bandage_wrap",
|
|
3989
|
+
[
|
|
3990
|
+
sceneNoise({
|
|
3991
|
+
type: "bandpass",
|
|
3992
|
+
f: [1400, 1800],
|
|
3993
|
+
f2: 2400,
|
|
3994
|
+
q: 1,
|
|
3995
|
+
a: 0.04,
|
|
3996
|
+
d: [0.3, 0.4],
|
|
3997
|
+
vol: [0.12, 0.16]
|
|
3998
|
+
})
|
|
3999
|
+
],
|
|
4000
|
+
"a bandage unrolled round a limb"
|
|
4001
|
+
),
|
|
4002
|
+
foley(
|
|
4003
|
+
"pills_shake",
|
|
4004
|
+
[
|
|
4005
|
+
...sceneMany(
|
|
4006
|
+
8,
|
|
4007
|
+
() => sceneTone({
|
|
4008
|
+
f: [2400, 3600],
|
|
4009
|
+
d: 0.015,
|
|
4010
|
+
vol: [0.03, 0.05],
|
|
4011
|
+
delay: [0, 0.25]
|
|
4012
|
+
})
|
|
4013
|
+
),
|
|
4014
|
+
sceneNoise({ type: "bandpass", f: [1500, 1900], q: 2, d: 0.25, vol: 0.05 })
|
|
4015
|
+
],
|
|
4016
|
+
"pills shaken in their bottle"
|
|
4017
|
+
),
|
|
4018
|
+
foley(
|
|
4019
|
+
"medkit_use",
|
|
4020
|
+
[
|
|
4021
|
+
...click(1700, 0.24),
|
|
4022
|
+
sceneNoise({
|
|
4023
|
+
type: "bandpass",
|
|
4024
|
+
f: [1e3, 1400],
|
|
4025
|
+
q: 1,
|
|
4026
|
+
a: 0.03,
|
|
4027
|
+
d: [0.25, 0.32],
|
|
4028
|
+
vol: [0.08, 0.12],
|
|
4029
|
+
delay: [0.05, 0.08]
|
|
4030
|
+
})
|
|
4031
|
+
],
|
|
4032
|
+
"a first aid kit opened and rummaged"
|
|
4033
|
+
),
|
|
4034
|
+
foley("flashlight_click", click(2600, 0.3), "the switch of a flashlight")
|
|
4035
|
+
];
|
|
4036
|
+
var FOLEY_BANK = {
|
|
4037
|
+
id: "foley",
|
|
4038
|
+
sounds: [...LEAF_FOLEY, ...ITEM_FOLEY]
|
|
4039
|
+
};
|
|
4040
|
+
var PICKUP_CLASSES = ["metal", "plastic", "glass", "paper", "fabric", "wood", "food"];
|
|
4041
|
+
var LEAF_FOLEY_SETS = {
|
|
4042
|
+
wood_door: {
|
|
4043
|
+
open: "door_wood_open",
|
|
4044
|
+
turn: "door_creak",
|
|
4045
|
+
close: "door_wood_close",
|
|
4046
|
+
slam: "door_wood_slam",
|
|
4047
|
+
locked: "door_locked_rattle"
|
|
4048
|
+
},
|
|
4049
|
+
metal_door: {
|
|
4050
|
+
open: "door_wood_open",
|
|
4051
|
+
turn: "door_creak_metal",
|
|
4052
|
+
close: "door_metal_open_close",
|
|
4053
|
+
locked: "door_locked_rattle"
|
|
4054
|
+
},
|
|
4055
|
+
fridge: {
|
|
4056
|
+
open: "fridge_open",
|
|
4057
|
+
close: "fridge_close",
|
|
4058
|
+
locked: "door_locked_rattle"
|
|
4059
|
+
},
|
|
4060
|
+
microwave: {
|
|
4061
|
+
open: "microwave_open",
|
|
4062
|
+
close: "microwave_close",
|
|
4063
|
+
locked: "door_locked_rattle"
|
|
4064
|
+
},
|
|
4065
|
+
drawer: {
|
|
4066
|
+
open: "drawer_open",
|
|
4067
|
+
close: "drawer_close",
|
|
4068
|
+
locked: "door_locked_rattle"
|
|
4069
|
+
}
|
|
4070
|
+
};
|
|
4071
|
+
|
|
4072
|
+
// src/recipes/body-foley.ts
|
|
4073
|
+
var BODY_FOLEY_TAKES = 4;
|
|
4074
|
+
var TAKES2 = [
|
|
4075
|
+
{ f: 1, t: 1, v: 1 },
|
|
4076
|
+
{ f: 1.08, t: 0.9, v: 0.92 },
|
|
4077
|
+
{ f: 0.93, t: 1.12, v: 1.05 },
|
|
4078
|
+
{ f: 1.03, t: 1.05, v: 0.88 }
|
|
4079
|
+
];
|
|
4080
|
+
var FOOTSTEP_FALLOFF = { model: "inverse_square", k: 0.03, cutoffK: 0.03, minGain: 4e-3 };
|
|
4081
|
+
var BODY_FALLOFF = { model: "inverse_square", k: 0.012, cutoffK: 0.015, minGain: 4e-3 };
|
|
4082
|
+
var SURFACES = {
|
|
4083
|
+
concrete: { heel: { f: 95, d: 0.05, vol: 0.55 }, roll: { type: "bandpass", f: 2300, q: 1.1, d: 0.05, vol: 0.38 }, grains: { count: 2, f: 4200, q: 2, spread: 0.04, vol: 0.08 } },
|
|
4084
|
+
asphalt: { heel: { f: 90, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 1700, q: 0.9, d: 0.06, vol: 0.36 }, grains: { count: 4, f: 3600, q: 2.5, spread: 0.06, vol: 0.1 } },
|
|
4085
|
+
wood: { heel: { f: 130, d: 0.08, vol: 0.55 }, roll: { type: "lowpass", f: 1300, q: 0.8, d: 0.06, vol: 0.3 }, ring: [{ f: 210, d: 0.1, vol: 0.18 }, { f: 470, d: 0.06, vol: 0.06 }] },
|
|
4086
|
+
tile: { heel: { f: 110, d: 0.04, vol: 0.45 }, roll: { type: "bandpass", f: 3600, q: 2, d: 0.03, vol: 0.42 }, ring: [{ f: 1900, d: 0.03, vol: 0.05 }] },
|
|
4087
|
+
dirt: { heel: { f: 75, d: 0.06, vol: 0.45 }, roll: { type: "lowpass", f: 750, q: 0.7, d: 0.09, vol: 0.4 }, grains: { count: 3, f: 1800, q: 1.5, spread: 0.07, vol: 0.06 } },
|
|
4088
|
+
grass: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "highpass", f: 2600, q: 0.7, d: 0.13, vol: 0.28 }, grains: { count: 4, f: 5200, q: 1.2, spread: 0.1, vol: 0.07 } },
|
|
4089
|
+
gravel: { heel: { f: 80, d: 0.05, vol: 0.4 }, roll: { type: "lowpass", f: 950, q: 0.8, d: 0.1, vol: 0.3 }, grains: { count: 8, f: 2600, q: 3, spread: 0.13, vol: 0.2 } },
|
|
4090
|
+
sand: { heel: { f: 65, d: 0.06, vol: 0.3 }, roll: { type: "bandpass", f: 1500, q: 0.6, d: 0.16, vol: 0.3 }, grains: { count: 5, f: 4800, q: 1.5, spread: 0.12, vol: 0.05 } },
|
|
4091
|
+
metal: { heel: { f: 120, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 2800, q: 1.5, d: 0.03, vol: 0.25 }, ring: [{ f: 420, d: 0.25, vol: 0.16 }, { f: 1130, d: 0.18, vol: 0.09 }, { f: 2470, d: 0.1, vol: 0.04 }] },
|
|
4092
|
+
water: { heel: { f: 70, d: 0.04, vol: 0.25 }, roll: { type: "bandpass", f: 3e3, q: 1.2, d: 0.1, vol: 0.18 }, splash: { f: 1100, f2: 380, d: 0.22, vol: 0.55 }, grains: { count: 4, f: 2400, q: 6, spread: 0.18, vol: 0.12 } },
|
|
4093
|
+
glass: { heel: { f: 90, d: 0.04, vol: 0.4 }, roll: { type: "highpass", f: 4500, q: 0.8, d: 0.06, vol: 0.2 }, grains: { count: 9, f: 6200, q: 5, spread: 0.12, vol: 0.22 }, ring: [{ f: 3900, d: 0.04, vol: 0.04 }, { f: 5300, d: 0.03, vol: 0.03 }] },
|
|
4094
|
+
carpet: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "lowpass", f: 420, q: 0.7, d: 0.07, vol: 0.3 } }
|
|
4095
|
+
};
|
|
4096
|
+
var GAITS = {
|
|
4097
|
+
walk: { vol: 1, bright: 1, toe: 0.075, short: 1 },
|
|
4098
|
+
run: { vol: 1.35, bright: 1.25, toe: 0.035, short: 0.75 }
|
|
4099
|
+
};
|
|
4100
|
+
var grainLayers = (g, take, start, scale) => Array.from(
|
|
4101
|
+
{ length: g.count },
|
|
4102
|
+
(_, i) => sceneNoise({ type: "bandpass", f: [g.f * take.f * 0.85, g.f * take.f * 1.15], q: g.q, d: [8e-3, 0.02], vol: g.vol * scale * take.v, delay: start + (i + 0.5) / g.count * g.spread * take.t })
|
|
4103
|
+
);
|
|
4104
|
+
var ringLayers = (rings, take, scale, at = 0) => rings.map((r) => sceneTone({ f: r.f * take.f, d: r.d * take.t, vol: r.vol * scale * take.v, delay: at }));
|
|
4105
|
+
function footLayers(surface, take, gait, weight = 1) {
|
|
4106
|
+
const s = SURFACES[surface];
|
|
4107
|
+
const toe = gait.toe * take.t;
|
|
4108
|
+
return [
|
|
4109
|
+
sceneTone({ f: s.heel.f * take.f * weight ** -0.3, f2: s.heel.f * take.f * 0.6, d: s.heel.d * gait.short * take.t * weight ** 0.5, vol: s.heel.vol * gait.vol * take.v * weight ** 0.5 }),
|
|
4110
|
+
sceneNoise({ type: "lowpass", f: 500 * gait.bright, d: 0.02 * take.t, vol: 0.18 * gait.vol * take.v * weight ** 0.5 }),
|
|
4111
|
+
sceneNoise({ type: s.roll.type, f: [s.roll.f * take.f * gait.bright * 0.92, s.roll.f * take.f * gait.bright * 1.08], q: s.roll.q, d: s.roll.d * gait.short * take.t * weight ** 0.3, vol: s.roll.vol * gait.vol * take.v, delay: toe }),
|
|
4112
|
+
...s.grains ? grainLayers(s.grains, take, toe * 0.5, gait.vol * weight ** 0.5) : [],
|
|
4113
|
+
...s.ring ? ringLayers(s.ring, take, gait.vol * weight ** 0.5) : [],
|
|
4114
|
+
...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
|
|
4115
|
+
];
|
|
4116
|
+
}
|
|
4117
|
+
var quieter = (level, layers) => layers.map((layer) => {
|
|
4118
|
+
const gain = layer.gain ?? 1;
|
|
4119
|
+
if (typeof gain === "number") return { ...layer, gain: gain * level };
|
|
4120
|
+
if (Array.isArray(gain)) return { ...layer, gain: [gain[0] * level, gain[1] * level] };
|
|
4121
|
+
return layer;
|
|
4122
|
+
});
|
|
4123
|
+
var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
|
|
4124
|
+
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
4125
|
+
function takes(id, layersOf, falloff, rate = [0.96, 1.04], bus) {
|
|
4126
|
+
const sounds = TAKES2.map((take, index) => recipe(takeId(id, index), layersOf(take, index), falloff, bus));
|
|
4127
|
+
return { sounds, set: { id, variants: sounds.map((sound) => sound.id), rate } };
|
|
4128
|
+
}
|
|
4129
|
+
var footstep = (surface, gait) => takes(footstepSoundId(surface, gait), (take) => footLayers(surface, take, GAITS[gait]), FOOTSTEP_FALLOFF);
|
|
4130
|
+
var LANDINGS = { light: { weight: 1.4, cloth: 0.12 }, heavy: { weight: 2.4, cloth: 0.22 } };
|
|
4131
|
+
var LANDING_LEVEL = 0.65;
|
|
4132
|
+
var landing = (surface, landing2) => takes(
|
|
4133
|
+
`land_${surface}_${landing2}`,
|
|
4134
|
+
(take) => quieter(LANDING_LEVEL, [
|
|
4135
|
+
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
4136
|
+
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
4137
|
+
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer) => ({ ...layer, at: (typeof layer.at === "number" ? layer.at : 0) + 0.018 * take.t })),
|
|
4138
|
+
sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
|
|
4139
|
+
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
4140
|
+
]),
|
|
4141
|
+
FOOTSTEP_FALLOFF
|
|
4142
|
+
);
|
|
4143
|
+
var whoosh = (blow, from, to, d, vol, q = 1.6) => (take) => [
|
|
4144
|
+
// the air: a band sweeping up as the limb speeds up; it peaks `SWING_LEAD_SECONDS` in, the moment before the contact, then dies away
|
|
4145
|
+
sceneNoise({ type: "bandpass", f: from * take.f, f2: to * take.f, q, a: SWING_LEAD_SECONDS[blow], d: d * take.t, vol: vol * take.v }),
|
|
4146
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, a: SWING_LEAD_SECONDS[blow], d: d * take.t * 0.8, vol: vol * 0.35 * take.v })
|
|
4147
|
+
];
|
|
4148
|
+
var fleshHit = (o) => (take) => [
|
|
4149
|
+
sceneNoise({ type: "bandpass", f: o.slapF * take.f, q: 1.2, d: 0.03 * take.t, vol: o.slap * take.v }),
|
|
4150
|
+
sceneNoise({ type: "highpass", f: 3500 * take.f, d: 0.012, vol: o.slap * 0.4 * take.v }),
|
|
4151
|
+
sceneTone({ f: o.thudF * take.f, f2: o.thudF * 0.5, d: o.thudD * take.t, vol: o.thud * take.v }),
|
|
4152
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, d: o.thudD * 1.2 * take.t, vol: o.thud * 0.5 * take.v }),
|
|
4153
|
+
...o.crack ? [sceneNoise({ type: "highpass", f: 2500, d: 0.015, vol: o.crack * take.v, delay: 6e-3 }), sceneTone({ wave: "square", f: 900 * take.f, f2: 300, d: 0.02, vol: o.crack * 0.15 * take.v, delay: 6e-3 })] : [],
|
|
4154
|
+
...o.wet ? [sceneNoise({ type: "bandpass", f: 1400 * take.f, f2: 500, q: 2.5, d: 0.12 * take.t, vol: o.wet * take.v, delay: 0.01 })] : []
|
|
4155
|
+
];
|
|
4156
|
+
var knock = (o) => (take) => [
|
|
4157
|
+
sceneNoise({ type: "bandpass", f: o.clickF * take.f, q: 1.5, d: 0.018, vol: o.click * take.v }),
|
|
4158
|
+
...o.tones.map(([f, d, vol]) => sceneTone({ f: f * take.f, d: d * take.t, vol: vol * take.v }))
|
|
4159
|
+
];
|
|
4160
|
+
var voice = (o) => (take) => [
|
|
4161
|
+
sceneVoice({ f0: o.f0 * take.f, f1: o.f1 * take.f, d: o.d * take.t, fA: o.fA * take.f, fB: o.fB * take.f, noise: o.noise, vol: o.vol * take.v })
|
|
4162
|
+
];
|
|
4163
|
+
var BODY = {
|
|
4164
|
+
jump: (take) => [
|
|
4165
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, f2: 1700 * take.f, q: 1, a: 0.03, d: 0.12, vol: 0.18 * take.v }),
|
|
4166
|
+
sceneNoise({ type: "bandpass", f: 2200 * take.f, q: 0.8, d: 0.04, vol: 0.12 * take.v }),
|
|
4167
|
+
sceneTone({ f: 85 * take.f, f2: 60, d: 0.04, vol: 0.2 * take.v })
|
|
4168
|
+
],
|
|
4169
|
+
cloth_rustle: (take) => [
|
|
4170
|
+
{ ...sceneNoise({ type: "bandpass", f: 2400 * take.f, q: 0.8, a: 0.06, d: 0.22 * take.t, vol: 0.12 * take.v }), modulators: [{ target: "gain", wave: "triangle", rate: [9, 14], depth: 0.5 }] }
|
|
4171
|
+
],
|
|
4172
|
+
body_fall: (take) => [
|
|
4173
|
+
sceneTone({ f: 58 * take.f, f2: 35, d: 0.28 * take.t, vol: 0.9 * take.v }),
|
|
4174
|
+
sceneNoise({ type: "lowpass", f: 480 * take.f, d: 0.3 * take.t, vol: 0.55 * take.v }),
|
|
4175
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, q: 1, d: 0.05, vol: 0.3 * take.v }),
|
|
4176
|
+
// the limbs a moment later, and the clothes
|
|
4177
|
+
sceneTone({ f: 75 * take.f, f2: 45, d: 0.12, vol: 0.4 * take.v, delay: 0.13 * take.t }),
|
|
4178
|
+
sceneNoise({ type: "bandpass", f: 2200, q: 0.8, d: 0.2, vol: 0.12 * take.v, delay: 0.05 })
|
|
4179
|
+
],
|
|
4180
|
+
fall_damage: (take) => [
|
|
4181
|
+
...BODY.body_fall(take),
|
|
4182
|
+
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
4183
|
+
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer) => ({ ...layer, at: 0.08 }))
|
|
4184
|
+
],
|
|
4185
|
+
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
4186
|
+
player_breath_run: (take) => [
|
|
4187
|
+
sceneNoise({ type: "bandpass", f: 1200 * take.f, q: 1, a: 0.08, d: 0.22 * take.t, vol: 0.25 * take.v }),
|
|
4188
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, q: 1, a: 0.06, d: 0.26 * take.t, vol: 0.3 * take.v, delay: 0.3 * take.t })
|
|
4189
|
+
],
|
|
4190
|
+
player_death: voice({ f0: 135, f1: 68, d: 1, fA: 560, fB: 980, noise: 0.35, vol: 0.4 }),
|
|
4191
|
+
bite: (take) => [
|
|
4192
|
+
sceneNoise({ type: "highpass", f: 2600, d: 0.015, vol: 0.4 * take.v }),
|
|
4193
|
+
sceneNoise({ type: "bandpass", f: 1600 * take.f, f2: 450, q: 2.2, d: 0.16 * take.t, vol: 0.55 * take.v, delay: 0.01 }),
|
|
4194
|
+
sceneNoise({ type: "bandpass", f: 3200 * take.f, f2: 1800, q: 1.2, d: 0.22 * take.t, vol: 0.25 * take.v, delay: 0.09 }),
|
|
4195
|
+
sceneTone({ f: 120 * take.f, f2: 70, d: 0.06, vol: 0.3 * take.v })
|
|
4196
|
+
],
|
|
4197
|
+
grab: (take) => [
|
|
4198
|
+
sceneNoise({ type: "bandpass", f: 1900 * take.f, q: 0.9, a: 4e-3, d: 0.13 * take.t, vol: 0.32 * take.v }),
|
|
4199
|
+
sceneTone({ f: 95 * take.f, f2: 60, d: 0.07, vol: 0.3 * take.v }),
|
|
4200
|
+
sceneNoise({ type: "lowpass", f: 700, d: 0.08, vol: 0.2 * take.v })
|
|
4201
|
+
],
|
|
4202
|
+
punch_swing: whoosh("punch", 450, 1500, 0.16, 0.9),
|
|
4203
|
+
punch_hit_body: fleshHit({ slap: 0.55, slapF: 1500, thud: 0.6, thudF: 115, thudD: 0.09 }),
|
|
4204
|
+
punch_hit_face: fleshHit({ slap: 0.75, slapF: 2300, thud: 0.45, thudF: 150, thudD: 0.07, crack: 0.25 }),
|
|
4205
|
+
punch_hit_object: knock({ clickF: 1800, click: 0.3, tones: [[210, 0.04, 0.25]] }),
|
|
4206
|
+
kick_swing: whoosh("kick", 280, 950, 0.22, 1, 1.3),
|
|
4207
|
+
kick_hit: fleshHit({ slap: 0.45, slapF: 1100, thud: 0.85, thudF: 82, thudD: 0.14 }),
|
|
4208
|
+
kick_hit_object: knock({ clickF: 1e3, click: 0.3, tones: [[92, 0.08, 0.5]] }),
|
|
4209
|
+
shove_two_hands: (take) => [
|
|
4210
|
+
sceneNoise({ type: "bandpass", f: 950 * take.f, q: 0.9, a: 0.01, d: 0.13 * take.t, vol: 0.38 * take.v }),
|
|
4211
|
+
sceneTone({ f: 100 * take.f, f2: 60, d: 0.1 * take.t, vol: 0.45 * take.v }),
|
|
4212
|
+
sceneNoise({ type: "bandpass", f: 2300, q: 0.8, d: 0.16, vol: 0.12 * take.v, delay: 0.03 })
|
|
4213
|
+
],
|
|
4214
|
+
knife_swing: whoosh("blade", 1900, 4600, 0.12, 1.1, 2.2),
|
|
4215
|
+
knife_stab: fleshHit({ slap: 0.2, slapF: 1200, thud: 0.4, thudF: 160, thudD: 0.06, wet: 0.5 }),
|
|
4216
|
+
knife_slash: (take) => [
|
|
4217
|
+
sceneNoise({ type: "highpass", f: 3200 * take.f, f2: 1800, d: 0.13 * take.t, vol: 0.35 * take.v }),
|
|
4218
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, f2: 600, q: 2.5, d: 0.12 * take.t, vol: 0.35 * take.v, delay: 0.02 })
|
|
4219
|
+
],
|
|
4220
|
+
knife_hit_object: knock({ clickF: 3200, click: 0.25, tones: [[2800, 0.08, 0.07], [4150, 0.06, 0.05]] }),
|
|
4221
|
+
blunt_swing: whoosh("blunt", 220, 760, 0.28, 1.1, 1.5),
|
|
4222
|
+
blunt_hit: fleshHit({ slap: 0.35, slapF: 900, thud: 1, thudF: 70, thudD: 0.18, crack: 0.3 }),
|
|
4223
|
+
blunt_hit_object: knock({ clickF: 1400, click: 0.35, tones: [[300, 0.12, 0.25], [760, 0.08, 0.12]] }),
|
|
4224
|
+
axe_swing: whoosh("chop", 190, 620, 0.3, 1.2, 1.4),
|
|
4225
|
+
axe_chop: fleshHit({ slap: 0.3, slapF: 1400, thud: 0.75, thudF: 140, thudD: 0.1, crack: 0.35, wet: 0.45 }),
|
|
4226
|
+
axe_hit_object: knock({ clickF: 2200, click: 0.4, tones: [[1500, 0.15, 0.1], [2300, 0.1, 0.06], [140, 0.1, 0.35]] })
|
|
4227
|
+
};
|
|
4228
|
+
var BODY_BUS = { player_hurt: "voices", player_death: "voices", player_breath_run: "voices", fall_damage: "voices" };
|
|
4229
|
+
var built = [
|
|
4230
|
+
...SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstep(surface, gait))),
|
|
4231
|
+
...SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((l) => landing(surface, l))),
|
|
4232
|
+
...BODY_SOUND_IDS.map((id) => takes(id, BODY[id], BODY_FALLOFF, id.endsWith("_swing") ? [0.94, 1.06] : [0.96, 1.04], BODY_BUS[id]))
|
|
4233
|
+
];
|
|
4234
|
+
var BODY_FOLEY_BANK = {
|
|
4235
|
+
id: "body_foley",
|
|
4236
|
+
sounds: built.flatMap((entry) => entry.sounds),
|
|
4237
|
+
sets: built.map((entry) => entry.set)
|
|
4238
|
+
};
|
|
4239
|
+
var BODY_FOLEY_SET_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
4240
|
+
|
|
4241
|
+
// src/webaudio/sink.ts
|
|
4242
|
+
function createAudioSink(engine) {
|
|
4243
|
+
const playing = /* @__PURE__ */ new Map();
|
|
4244
|
+
return {
|
|
4245
|
+
engine,
|
|
4246
|
+
play(request) {
|
|
4247
|
+
const handle = engine.play(request.sound, {
|
|
4248
|
+
...request.position ? { position: request.position } : {},
|
|
4249
|
+
...request.volume === void 0 ? {} : { volume: request.volume },
|
|
4250
|
+
...request.params ? { params: request.params } : {},
|
|
4251
|
+
...request.seed === void 0 ? {} : { seed: request.seed },
|
|
4252
|
+
...request.delay === void 0 ? {} : { delay: request.delay },
|
|
4253
|
+
...request.urgent ? { urgent: true } : {}
|
|
4254
|
+
});
|
|
4255
|
+
if (!handle) return null;
|
|
4256
|
+
playing.set(handle.id, handle);
|
|
4257
|
+
return { id: handle.id };
|
|
4258
|
+
},
|
|
4259
|
+
stop(handle) {
|
|
4260
|
+
playing.get(handle.id)?.stop();
|
|
4261
|
+
playing.delete(handle.id);
|
|
4262
|
+
},
|
|
4263
|
+
loop(sound, options) {
|
|
4264
|
+
const loop = engine.loop(sound);
|
|
4265
|
+
let position = options?.position;
|
|
4266
|
+
return {
|
|
4267
|
+
set: (state) => {
|
|
4268
|
+
position = state.position ?? position;
|
|
4269
|
+
const cutoff = state.params?.["cutoff"];
|
|
4270
|
+
loop.set({
|
|
4271
|
+
...state.volume === void 0 ? {} : { volume: state.volume },
|
|
4272
|
+
...state.frequency === void 0 ? {} : { frequency: state.frequency },
|
|
4273
|
+
...position ? { position } : {},
|
|
4274
|
+
...cutoff === void 0 ? {} : { cutoff }
|
|
4275
|
+
});
|
|
4276
|
+
},
|
|
4277
|
+
stop: () => loop.stop()
|
|
4278
|
+
};
|
|
1784
4279
|
},
|
|
1785
4280
|
setListener(listener) {
|
|
1786
4281
|
engine.setListener(listener);
|
|
@@ -1843,7 +4338,7 @@ var GameAudio = (() => {
|
|
|
1843
4338
|
determinism: "The same seed gives the same sound plan, another seed another one",
|
|
1844
4339
|
limiter: "The voice limiter holds a storm of voices to its group rule and its global cap"
|
|
1845
4340
|
},
|
|
1846
|
-
mixes: { game: "Game", art_scene: "Art scene" },
|
|
4341
|
+
mixes: { game: "Game", art_scene: "Art scene", kit: "Kit (art scene + limiter)" },
|
|
1847
4342
|
sheet: { title: "Sound plan", level: "level", distance: "distance", pan: "pan", length: "seconds", silent: "too far to be heard", layer: "layer", none: "no sound chosen" }
|
|
1848
4343
|
};
|
|
1849
4344
|
var PT_BR = {
|
|
@@ -1897,7 +4392,7 @@ var GameAudio = (() => {
|
|
|
1897
4392
|
determinism: "A mesma semente d\xE1 o mesmo plano de som, outra semente d\xE1 outro",
|
|
1898
4393
|
limiter: "O limite de vozes segura uma tempestade de vozes na regra do grupo e no teto global"
|
|
1899
4394
|
},
|
|
1900
|
-
mixes: { game: "Jogo", art_scene: "Cena de Arte" },
|
|
4395
|
+
mixes: { game: "Jogo", art_scene: "Cena de Arte", kit: "Kit (Cena de Arte + limitador)" },
|
|
1901
4396
|
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" }
|
|
1902
4397
|
};
|
|
1903
4398
|
var audioBenchTextOf = (locale) => locale === "en" ? EN : PT_BR;
|
|
@@ -1971,7 +4466,7 @@ var GameAudio = (() => {
|
|
|
1971
4466
|
distance: 10,
|
|
1972
4467
|
bearing: 0,
|
|
1973
4468
|
volume: 1,
|
|
1974
|
-
mix:
|
|
4469
|
+
mix: DEFAULT_MIX,
|
|
1975
4470
|
seed: options.seed ?? 1,
|
|
1976
4471
|
source: "bench",
|
|
1977
4472
|
loop: NONE,
|