@adatechnology/game-audio 0.5.0 → 0.6.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.
@@ -324,6 +324,17 @@ Só CC0 e CC-BY entram no SDK; quem usa um som CC-BY credita o autor abaixo.
324
324
  | explosoes-fogo/fire_loop_01.ogg | https://freesound.org/people/theoneandtruelybitch/sounds/698209/ | theoneandtruelybitch | CC0 |
325
325
  | explosoes-fogo/fire_loop_03.ogg | https://freesound.org/people/kyles/sounds/454019/ | kyles | CC0 |
326
326
  | explosoes-fogo/fire_loop_04.ogg | https://freesound.org/people/SKrafft/sounds/681366/ | SKrafft | CC0 |
327
+ | explosoes-fogo/fire_loop_gas_01.ogg | https://freesound.org/people/DarkSidedGenXer/sounds/654360/ | DarkSidedGenXer | CC0 |
328
+ | explosoes-fogo/fire_loop_gas_02.ogg | https://freesound.org/people/Dr.%20Macak/sounds/491300/ | Dr. Macak | CC0 |
329
+ | explosoes-fogo/fire_loop_gas_03.ogg | https://freesound.org/people/SyntaxSeed/sounds/244230/ | SyntaxSeed | CC0 |
330
+ | explosoes-fogo/fire_loop_gas_04.ogg | https://freesound.org/people/rombart/sounds/197800/ | rombart | CC0 |
331
+ | explosoes-fogo/fire_loop_liquid_01.ogg | https://freesound.org/people/SGAK/sounds/87564/ | SGAK | CC0 |
332
+ | explosoes-fogo/fire_loop_liquid_02.ogg | https://freesound.org/people/florianreichelt/sounds/563765/ | florianreichelt | CC0 |
333
+ | explosoes-fogo/fire_loop_liquid_03.ogg | https://freesound.org/people/Aegersum/sounds/387924/ | Aegersum | CC0 |
334
+ | explosoes-fogo/fire_loop_plastic_01.ogg | https://freesound.org/people/jc144940/sounds/178731/ | jc144940 | CC0 |
335
+ | explosoes-fogo/fire_loop_plastic_02.ogg | https://freesound.org/people/jc144940/sounds/178733/ | jc144940 | CC0 |
336
+ | explosoes-fogo/fire_loop_plastic_03.ogg | https://freesound.org/people/jc144940/sounds/178729/ | jc144940 | CC0 |
337
+ | explosoes-fogo/fire_loop_plastic_04.ogg | https://freesound.org/people/jc144940/sounds/178738/ | jc144940 | CC0 |
327
338
  | explosoes-fogo/fire_loop_small_01.ogg | https://opengameart.org/content/fireplace-sound-loop | PagDev | CC0 |
328
339
  | explosoes-fogo/fire_pop_01.ogg | https://freesound.org/people/AntumDeluge/sounds/188038/ | AntumDeluge | CC0 |
329
340
  | explosoes-fogo/fire_pop_02.ogg | https://freesound.org/people/AntumDeluge/sounds/188038/ | AntumDeluge | CC0 |
@@ -3093,6 +3093,140 @@
3093
3093
  ]
3094
3094
  }
3095
3095
  },
3096
+ {
3097
+ "id": "fire_loop_gas",
3098
+ "category": "explosoes-fogo",
3099
+ "layers": {
3100
+ "close": [
3101
+ {
3102
+ "file": "explosoes-fogo/fire_loop_gas_01.ogg",
3103
+ "sampleRate": 48000,
3104
+ "channels": 2,
3105
+ "peak": -1.21,
3106
+ "seconds": 16,
3107
+ "source": "https://freesound.org/people/DarkSidedGenXer/sounds/654360/",
3108
+ "author": "DarkSidedGenXer",
3109
+ "license": "CC0"
3110
+ },
3111
+ {
3112
+ "file": "explosoes-fogo/fire_loop_gas_02.ogg",
3113
+ "sampleRate": 48000,
3114
+ "channels": 2,
3115
+ "peak": -1.06,
3116
+ "seconds": 16,
3117
+ "source": "https://freesound.org/people/Dr.%20Macak/sounds/491300/",
3118
+ "author": "Dr. Macak",
3119
+ "license": "CC0"
3120
+ },
3121
+ {
3122
+ "file": "explosoes-fogo/fire_loop_gas_03.ogg",
3123
+ "sampleRate": 48000,
3124
+ "channels": 2,
3125
+ "peak": -1.16,
3126
+ "seconds": 12.093,
3127
+ "source": "https://freesound.org/people/SyntaxSeed/sounds/244230/",
3128
+ "author": "SyntaxSeed",
3129
+ "license": "CC0"
3130
+ },
3131
+ {
3132
+ "file": "explosoes-fogo/fire_loop_gas_04.ogg",
3133
+ "sampleRate": 48000,
3134
+ "channels": 2,
3135
+ "peak": -1.15,
3136
+ "seconds": 16,
3137
+ "source": "https://freesound.org/people/rombart/sounds/197800/",
3138
+ "author": "rombart",
3139
+ "license": "CC0"
3140
+ }
3141
+ ]
3142
+ }
3143
+ },
3144
+ {
3145
+ "id": "fire_loop_liquid",
3146
+ "category": "explosoes-fogo",
3147
+ "layers": {
3148
+ "close": [
3149
+ {
3150
+ "file": "explosoes-fogo/fire_loop_liquid_01.ogg",
3151
+ "sampleRate": 48000,
3152
+ "channels": 2,
3153
+ "peak": -0.96,
3154
+ "seconds": 16,
3155
+ "source": "https://freesound.org/people/SGAK/sounds/87564/",
3156
+ "author": "SGAK",
3157
+ "license": "CC0"
3158
+ },
3159
+ {
3160
+ "file": "explosoes-fogo/fire_loop_liquid_02.ogg",
3161
+ "sampleRate": 48000,
3162
+ "channels": 2,
3163
+ "peak": -1.12,
3164
+ "seconds": 15.933,
3165
+ "source": "https://freesound.org/people/florianreichelt/sounds/563765/",
3166
+ "author": "florianreichelt",
3167
+ "license": "CC0"
3168
+ },
3169
+ {
3170
+ "file": "explosoes-fogo/fire_loop_liquid_03.ogg",
3171
+ "sampleRate": 48000,
3172
+ "channels": 2,
3173
+ "peak": -1.02,
3174
+ "seconds": 16,
3175
+ "source": "https://freesound.org/people/Aegersum/sounds/387924/",
3176
+ "author": "Aegersum",
3177
+ "license": "CC0"
3178
+ }
3179
+ ]
3180
+ }
3181
+ },
3182
+ {
3183
+ "id": "fire_loop_plastic",
3184
+ "category": "explosoes-fogo",
3185
+ "layers": {
3186
+ "close": [
3187
+ {
3188
+ "file": "explosoes-fogo/fire_loop_plastic_01.ogg",
3189
+ "sampleRate": 48000,
3190
+ "channels": 2,
3191
+ "peak": -1.12,
3192
+ "seconds": 5.124,
3193
+ "source": "https://freesound.org/people/jc144940/sounds/178731/",
3194
+ "author": "jc144940",
3195
+ "license": "CC0"
3196
+ },
3197
+ {
3198
+ "file": "explosoes-fogo/fire_loop_plastic_02.ogg",
3199
+ "sampleRate": 48000,
3200
+ "channels": 2,
3201
+ "peak": -1.14,
3202
+ "seconds": 9.55,
3203
+ "source": "https://freesound.org/people/jc144940/sounds/178733/",
3204
+ "author": "jc144940",
3205
+ "license": "CC0"
3206
+ },
3207
+ {
3208
+ "file": "explosoes-fogo/fire_loop_plastic_03.ogg",
3209
+ "sampleRate": 48000,
3210
+ "channels": 2,
3211
+ "peak": -1.36,
3212
+ "seconds": 10.675,
3213
+ "source": "https://freesound.org/people/jc144940/sounds/178729/",
3214
+ "author": "jc144940",
3215
+ "license": "CC0"
3216
+ },
3217
+ {
3218
+ "file": "explosoes-fogo/fire_loop_plastic_04.ogg",
3219
+ "sampleRate": 48000,
3220
+ "channels": 2,
3221
+ "peak": -0.97,
3222
+ "seconds": 4.924,
3223
+ "source": "https://freesound.org/people/jc144940/sounds/178738/",
3224
+ "author": "jc144940",
3225
+ "license": "CC0"
3226
+ }
3227
+ ]
3228
+ }
3229
+ },
3096
3230
  {
3097
3231
  "id": "fire_loop_small",
3098
3232
  "category": "explosoes-fogo",
@@ -2047,10 +2047,12 @@ function createAudioEngine(options = {}) {
2047
2047
  noise: () => noiseBuffer(store, audio, mix.noise.seconds),
2048
2048
  time
2049
2049
  });
2050
+ const recipeBank = registry.bankOf(plan.id);
2050
2051
  announce({
2051
2052
  id: plan.id,
2052
2053
  kind: "recipe",
2053
2054
  ...fallbackOf ? { fallbackOf } : {},
2055
+ ...recipeBank ? { bank: recipeBank } : {},
2054
2056
  requestedAt,
2055
2057
  startAt: time,
2056
2058
  outputLatency: latencyOf(audio),
@@ -2152,9 +2154,11 @@ function createAudioEngine(options = {}) {
2152
2154
  const time = requestedAt + (playOptions.delay ?? 0);
2153
2155
  const chokeList = sample.choke ? choked(sample.id) : void 0;
2154
2156
  const realized = realizeSample(plan, { context: audio, output: sampleOutput(plan.bus), buffer: (url2) => sampleStore.buffer(url2), time });
2157
+ const sampleBank = registry.bankOf(plan.id);
2155
2158
  announce({
2156
2159
  id: plan.id,
2157
2160
  kind: "sample",
2161
+ ...sampleBank ? { bank: sampleBank } : {},
2158
2162
  requestedAt,
2159
2163
  startAt: time,
2160
2164
  outputLatency: latencyOf(audio),
@@ -2893,7 +2897,11 @@ var SFX_CATALOG = [
2893
2897
  ["casing_drop_terra_pistol", 1],
2894
2898
  ["casing_drop_terra_rifle", 1],
2895
2899
  ["casing_drop_terra_shell", 1],
2896
- ["rocket_fire", 2]
2900
+ ["rocket_fire", 2],
2901
+ ["smg_45_auto", 2, "sfx_pistol"],
2902
+ ["weapon_draw", 2],
2903
+ ["suppressor_attach", 3],
2904
+ ["suppressor_detach", 3]
2897
2905
  ]),
2898
2906
  ...entries("explosoes-fogo", [
2899
2907
  ["explosion_grenade", 1, "boom"],
@@ -2907,7 +2915,11 @@ var SFX_CATALOG = [
2907
2915
  ["fire_loop_large", 1],
2908
2916
  ["fire_extinguish", 2, "hiss"],
2909
2917
  ["gas_leak_hiss", 2],
2910
- ["structure_collapse", 2, "crumble"]
2918
+ ["structure_collapse", 2, "crumble"],
2919
+ ["grenade_bounce", 1],
2920
+ ["c4_plant", 2],
2921
+ ["c4_beep", 2],
2922
+ ["c4_disarm", 2]
2911
2923
  ]),
2912
2924
  ...entries("personagem", [
2913
2925
  ["footstep_concrete_walk", 1, "sfx_step"],
@@ -2923,7 +2935,19 @@ var SFX_CATALOG = [
2923
2935
  ["blunt_hit", 1],
2924
2936
  ["bite", 1, "sfx_flesh"],
2925
2937
  ["body_fall", 1],
2926
- ["player_hurt", 2]
2938
+ ["player_hurt", 2],
2939
+ ["footstep_tile_walk", 1, "sfx_step"],
2940
+ ["footstep_water_walk", 1, "sfx_step"],
2941
+ ["footstep_grate_walk", 2, "sfx_step"],
2942
+ ["footstep_duct_walk", 3, "sfx_step"],
2943
+ ["ladder_climb", 2],
2944
+ ["swim", 2],
2945
+ ["zombie_groan", 1],
2946
+ ["zombie_alert", 1],
2947
+ ["zombie_attack", 1],
2948
+ ["zombie_pain", 1],
2949
+ ["zombie_claw_hit", 1, "sfx_flesh"],
2950
+ ["zombie_claw_miss", 2]
2927
2951
  ]),
2928
2952
  ...entries("veiculos", [
2929
2953
  ["engine_loop_car", 1],
@@ -2951,7 +2975,8 @@ var SFX_CATALOG = [
2951
2975
  ["wind_loop", 2],
2952
2976
  ["thunder_near", 2],
2953
2977
  ["thunder_far", 2],
2954
- ["water_splash", 2]
2978
+ ["water_splash", 2],
2979
+ ["helicopter_loop", 3]
2955
2980
  ])
2956
2981
  ];
2957
2982
  var SFX_MATERIALS = [
@@ -3513,6 +3538,195 @@ async function recordOutput(engine, seconds, act) {
3513
3538
  return new Blob(chunks, { type: recorder.mimeType || "audio/webm" });
3514
3539
  }
3515
3540
 
3541
+ // src/manifest.ts
3542
+ var SDK_LICENSES = ["CC0", "CC-BY"];
3543
+ var SFX_LAYERS = ["close", "far", "tail_in", "tail_out"];
3544
+ var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
3545
+ function parseSfxName(name) {
3546
+ const match = /^(.*?)(?:_(close|far|tail_in|tail_out))?(?:_(\d+))?$/.exec(name);
3547
+ const id = match?.[1] || name;
3548
+ const layer = match?.[2] ?? "close";
3549
+ const take = match?.[3] ? Number(match[3]) : 1;
3550
+ return { id, layer, take };
3551
+ }
3552
+ function splitTier(id) {
3553
+ const match = /^(.*)_(light|medium|heavy)$/.exec(id);
3554
+ return match ? { base: match[1], tier: match[2] } : { base: id };
3555
+ }
3556
+ var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry) => ({ url: `${baseUrl}${entry.file}` }));
3557
+ function sampleBankFromManifest(manifest, options) {
3558
+ const baseUrl = options.baseUrl ?? "";
3559
+ const samples = [];
3560
+ const tiersOf = /* @__PURE__ */ new Map();
3561
+ for (const sound of manifest.sounds) {
3562
+ const { base, tier } = splitTier(sound.id);
3563
+ if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound]);
3564
+ }
3565
+ const bases = /* @__PURE__ */ new Map();
3566
+ for (const sound of manifest.sounds) {
3567
+ if (!splitTier(sound.id).tier) bases.set(sound.id, sound);
3568
+ }
3569
+ for (const [base, tiers] of tiersOf) {
3570
+ if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
3571
+ }
3572
+ for (const sound of bases.values()) {
3573
+ const numbers = options.sounds?.[sound.id] ?? options.defaults?.(sound);
3574
+ const close = refsOf(sound.layers.close, baseUrl);
3575
+ if (!numbers || close.length === 0) continue;
3576
+ const tiers = (tiersOf.get(sound.id) ?? []).map((tier) => {
3577
+ const name = splitTier(tier.id).tier;
3578
+ const tierFar = refsOf(tier.layers.far, baseUrl);
3579
+ return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
3580
+ }).sort((a, b) => a.from - b.from);
3581
+ const far = refsOf(sound.layers.far, baseUrl);
3582
+ const indoor = refsOf(sound.layers.tail_in, baseUrl);
3583
+ const outdoor = refsOf(sound.layers.tail_out, baseUrl);
3584
+ const files = [sound, ...tiersOf.get(sound.id) ?? []].flatMap((entry) => Object.values(entry.layers).flatMap((entries2) => entries2 ?? []));
3585
+ samples.push({
3586
+ id: sound.id,
3587
+ bus: numbers.bus,
3588
+ close,
3589
+ ...far.length > 0 ? { far } : {},
3590
+ ...tiers.length > 0 ? { tiers } : {},
3591
+ ...numbers.crossover ? { crossover: numbers.crossover } : {},
3592
+ ...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
3593
+ ...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
3594
+ ...numbers.gain === void 0 ? {} : { gain: numbers.gain },
3595
+ ...numbers.falloff ? { falloff: numbers.falloff } : {},
3596
+ ...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
3597
+ ...numbers.group ? { group: numbers.group } : {},
3598
+ ...numbers.priority === void 0 ? {} : { priority: numbers.priority },
3599
+ ...numbers.fallback ? { fallback: numbers.fallback } : {},
3600
+ sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
3601
+ });
3602
+ }
3603
+ return { id: options.id, samples };
3604
+ }
3605
+
3606
+ // src/kit-samples.ts
3607
+ var KIT_CATEGORY_BUS = {
3608
+ armas: "weapons",
3609
+ impactos: "world",
3610
+ "explosoes-fogo": "world",
3611
+ personagem: "world",
3612
+ veiculos: "world",
3613
+ "itens-portas": "world",
3614
+ ambiente: "ambience"
3615
+ };
3616
+ var VOICE_IDS = /^(player_(hurt|death|effort|breath)|scream|zombie_)/;
3617
+ var KIT_SAMPLE_ALIASES = {
3618
+ // a house door: the latch giving, the hinge, the leaf meeting the frame, a locked one shaken; a drawer on its runners
3619
+ latch: "metal_latch",
3620
+ creak_wood: "door_creak",
3621
+ shut_wood: "door_wood_shut",
3622
+ rattle: "door_locked_rattle",
3623
+ // a drawer stays on its recipe: the recorded runs (1 to 1.9 s) outlast a drawer's pull
3624
+ // an item taken in the hand (game-destruction-three grab_* keys)
3625
+ grab_hard: "item_pickup_generic",
3626
+ grab_soft: "item_pickup_leather"
3627
+ };
3628
+ function kitSampleDefaults(sound) {
3629
+ const bus = VOICE_IDS.test(sound.id) ? "voices" : KIT_CATEGORY_BUS[sound.category];
3630
+ if (!bus) return void 0;
3631
+ return { bus, pitch: sound.category === "ambiente" || /_loop/.test(sound.id) ? 0 : 0.04 };
3632
+ }
3633
+ function withAliases(manifest, aliases) {
3634
+ const byId = new Map(manifest.sounds.map((sound) => [sound.id, sound]));
3635
+ const extra = [];
3636
+ for (const [alias, target] of Object.entries(aliases)) {
3637
+ const sound = byId.get(target);
3638
+ if (sound && !byId.has(alias)) extra.push({ ...sound, id: alias });
3639
+ }
3640
+ return { ...manifest, sounds: [...manifest.sounds, ...extra] };
3641
+ }
3642
+ function kitSampleBank(manifest, options = {}) {
3643
+ return sampleBankFromManifest(withAliases(manifest, options.aliases ?? KIT_SAMPLE_ALIASES), {
3644
+ id: options.id ?? "kit_samples",
3645
+ baseUrl: options.baseUrl ?? "",
3646
+ defaults: kitSampleDefaults
3647
+ });
3648
+ }
3649
+ var isFileUrl = (url2) => {
3650
+ const page = globalThis.location?.href;
3651
+ try {
3652
+ return new URL(url2, page).protocol === "file:";
3653
+ } catch {
3654
+ return false;
3655
+ }
3656
+ };
3657
+ var fetchJson = async (url2) => {
3658
+ if (isFileUrl(url2)) throw new Error(`${url2}: file:// is not fetched`);
3659
+ const response = await fetch(url2);
3660
+ if (!response.ok) throw new Error(`${url2}: ${response.status}`);
3661
+ return await response.json();
3662
+ };
3663
+ async function loadKitSamples(engine, options = {}) {
3664
+ const baseUrl = options.baseUrl ?? "";
3665
+ let manifest;
3666
+ try {
3667
+ manifest = await (options.fetchManifest ?? fetchJson)(`${baseUrl}manifest.json`);
3668
+ } catch {
3669
+ return null;
3670
+ }
3671
+ const bank = kitSampleBank(manifest, options);
3672
+ engine.register(bank);
3673
+ if (options.preload && engine.loadSamples) void engine.loadSamples(options.preload).catch(() => void 0);
3674
+ return bank;
3675
+ }
3676
+
3677
+ // src/user-samples.ts
3678
+ var USER_SAMPLES_BANK = "user_samples";
3679
+ var KIT_SAMPLES_BANK = "kit_samples";
3680
+ var USER_SOUND_PREFIX = "user:";
3681
+ function soundSourceOf(event) {
3682
+ if (event.kind === "recipe") return "synth";
3683
+ return event.bank === USER_SAMPLES_BANK ? "user" : "sdk";
3684
+ }
3685
+ function userSampleBank(manifest, options = {}) {
3686
+ const playing = [];
3687
+ const behindKit = [];
3688
+ const sounds = [];
3689
+ for (const picked of manifest.sounds) {
3690
+ const sound = { ...picked, id: splitTier(picked.id).base };
3691
+ sounds.push({ ...sound, id: `${USER_SOUND_PREFIX}${sound.id}` });
3692
+ if (sound.role === "fallback" && options.kitHas?.(sound.id)) {
3693
+ behindKit.push(sound.id);
3694
+ continue;
3695
+ }
3696
+ sounds.push(sound);
3697
+ playing.push(sound.id);
3698
+ }
3699
+ const bank = sampleBankFromManifest(
3700
+ { sounds },
3701
+ {
3702
+ id: USER_SAMPLES_BANK,
3703
+ baseUrl: options.baseUrl ?? "",
3704
+ defaults: (sound) => kitSampleDefaults({ id: sound.id.replace(USER_SOUND_PREFIX, ""), category: sound.category })
3705
+ }
3706
+ );
3707
+ return { bank, playing, behindKit };
3708
+ }
3709
+ var fetchManifestJson = async (url2) => {
3710
+ const page = globalThis.location?.href;
3711
+ if (new URL(url2, page ?? "http://localhost/").protocol === "file:") throw new Error(`${url2}: file:// is not fetched`);
3712
+ const response = await fetch(url2);
3713
+ if (!response.ok) throw new Error(`${url2}: ${response.status}`);
3714
+ return await response.json();
3715
+ };
3716
+ async function loadUserSamples(engine, options = {}) {
3717
+ const baseUrl = options.baseUrl ?? "./sfx-local/";
3718
+ let manifest;
3719
+ try {
3720
+ manifest = await (options.fetchManifest ?? fetchManifestJson)(`${baseUrl}manifest.json`);
3721
+ } catch {
3722
+ return null;
3723
+ }
3724
+ const kitHas = options.kitHas ?? ((id) => Boolean(engine.registry?.sample(id)));
3725
+ const result = userSampleBank(manifest, { baseUrl, kitHas });
3726
+ engine.register(result.bank);
3727
+ return result;
3728
+ }
3729
+
3516
3730
  // src/bench/sound-check-locale.ts
3517
3731
  var PT = {
3518
3732
  group: "Som",
@@ -3521,6 +3735,7 @@ var PT = {
3521
3735
  category: "1 \xB7 Categoria",
3522
3736
  sound: "1 \xB7 Som",
3523
3737
  play: "1 \xB7 \u25B6 Tocar",
3738
+ play_user: "1 \xB7 \u25B6 Tocar o seu",
3524
3739
  material: "2 \xB7 Material",
3525
3740
  blow: "2 \xB7 Golpe",
3526
3741
  strike: "2 \xB7 \u25B6 Tocar golpe",
@@ -3542,6 +3757,7 @@ var PT = {
3542
3757
  approve: "5 \xB7 Aprovo (C10)"
3543
3758
  },
3544
3759
  hints: {
3760
+ play_user: "Toca a sua grava\xE7\xE3o deste som (dos seus pacotes, fora do git), mesmo quando o SDK tem uma melhor e toca na frente.",
3545
3761
  sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
3546
3762
  strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
3547
3763
  wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
@@ -3586,9 +3802,10 @@ var PT = {
3586
3802
  strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
3587
3803
  states: { file: "A", synth: "S", missing: "F" },
3588
3804
  criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
3589
- metrics: { chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
3805
+ metrics: { source: "1 \xB7 Fonte do que tocou", chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
3590
3806
  run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
3591
3807
  words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
3808
+ sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
3592
3809
  probe: "Fonte do som",
3593
3810
  wall: "Parede (oclus\xE3o)",
3594
3811
  scenarios: { pipeline: "Arquivo \u2192 decodifica \u2192 toca (round-robin, cauda)", criteria: "Crit\xE9rios C1\u2013C9 no som de calibra\xE7\xE3o", loop: "Loop de arquivo: emenda sem buraco (crossfade)", panel: "Painel: categorias, matriz, A/B e parede" }
@@ -3601,6 +3818,7 @@ var EN2 = {
3601
3818
  category: "1 \xB7 Category",
3602
3819
  sound: "1 \xB7 Sound",
3603
3820
  play: "1 \xB7 \u25B6 Play",
3821
+ play_user: "1 \xB7 \u25B6 Play yours",
3604
3822
  material: "2 \xB7 Material",
3605
3823
  blow: "2 \xB7 Blow",
3606
3824
  strike: "2 \xB7 \u25B6 Play blow",
@@ -3622,6 +3840,7 @@ var EN2 = {
3622
3840
  approve: "5 \xB7 Approve (C10)"
3623
3841
  },
3624
3842
  hints: {
3843
+ play_user: "Plays your own take of this sound (from your packs, kept out of git), even where the SDK has a better one that plays first.",
3625
3844
  sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
3626
3845
  strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
3627
3846
  wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
@@ -3656,9 +3875,10 @@ var EN2 = {
3656
3875
  environments: { indoor: "indoor", outdoor: "outdoor" },
3657
3876
  strengths: { light: "light", medium: "medium", heavy: "heavy" },
3658
3877
  criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
3659
- metrics: { chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
3878
+ metrics: { source: "1 \xB7 Source of what played", chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
3660
3879
  run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
3661
3880
  words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
3881
+ sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
3662
3882
  probe: "Sound source",
3663
3883
  wall: "Wall (occlusion)",
3664
3884
  scenarios: { pipeline: "File \u2192 decode \u2192 play (round-robin, tail)", criteria: "Criteria C1\u2013C9 on the calibration sound", loop: "File loop: seamless joins (crossfade)", panel: "Panel: categories, matrix, A/B and wall" }
@@ -3719,9 +3939,15 @@ function createSoundCheckModule(options = {}) {
3719
3939
  if (category === CALIBRATION_CATEGORY) return registry().sampleIds().filter((id) => !entryOf(id));
3720
3940
  return catalog.filter((entry) => entry.category === category).map((entry) => entry.id);
3721
3941
  };
3942
+ const sourceOfId = (id) => {
3943
+ const state = stateOf(id);
3944
+ if (state !== "file") return text.states[state];
3945
+ const own = registry().sample(`${USER_SOUND_PREFIX}${id}`) ? " +seu" : "";
3946
+ return `${text.states.file} ${text.sources[soundSourceOf({ kind: "sample", bank: registry().bankOf(id) })]}${own}`;
3947
+ };
3722
3948
  const label = (id) => {
3723
3949
  const entry = entryOf(id);
3724
- return `${id}${entry ? ` \xB7 P${entry.priority}` : ""} \xB7 ${text.states[stateOf(id)]}`;
3950
+ return `${id}${entry ? ` \xB7 P${entry.priority}` : ""} \xB7 ${sourceOfId(id)}`;
3725
3951
  };
3726
3952
  const soundOptions = () => soundsOf(chosen.category).map((id) => ({ id, name: label(id) }));
3727
3953
  const listener = () => {
@@ -3755,6 +3981,12 @@ function createSoundCheckModule(options = {}) {
3755
3981
  if (engine.sampleStatus(b) !== "ready") await engine.loadSamples([b]);
3756
3982
  playId(b, { delay });
3757
3983
  };
3984
+ const playUser = async () => {
3985
+ const own = `${USER_SOUND_PREFIX}${chosen.sound}`;
3986
+ if (!registry().sample(own)) return;
3987
+ if (engine.sampleStatus(own) !== "ready") await engine.loadSamples([own]);
3988
+ playId(own);
3989
+ };
3758
3990
  const playA = (delay = 0) => void playId(pairOf(chosen.sound).a, { delay });
3759
3991
  const placeScenery = () => {
3760
3992
  const scene = host?.scene;
@@ -3822,6 +4054,7 @@ function createSoundCheckModule(options = {}) {
3822
4054
  { kind: "choice", id: "category", name: text.controls.category, options: [...SFX_CATEGORIES, CALIBRATION_CATEGORY].map((id) => ({ id, name: text.categories[id] ?? id })), default: chosen.category },
3823
4055
  { kind: "choice", id: "sound", name: text.controls.sound, hint: text.hints.sound, options: soundOptions(), default: chosen.sound },
3824
4056
  { kind: "action", id: "play", name: text.controls.play },
4057
+ { kind: "action", id: "play_user", name: text.controls.play_user, hint: text.hints.play_user },
3825
4058
  { kind: "choice", id: "material", name: text.controls.material, options: SFX_MATERIALS.map(([id]) => ({ id, name: text.materials[id] })), default: chosen.material },
3826
4059
  { kind: "choice", id: "blow", name: text.controls.blow, options: SFX_BLOWS.map((id) => ({ id, name: text.blows[id] })), default: chosen.blow },
3827
4060
  { kind: "action", id: "strike", name: text.controls.strike, hint: text.hints.strike },
@@ -3859,7 +4092,14 @@ function createSoundCheckModule(options = {}) {
3859
4092
  const files = last.layers?.map((layer) => layer.url.split("/").pop()).join("+") ?? "";
3860
4093
  return `${last.kind}:${last.fallbackOf ? `${last.fallbackOf}\u2192` : ""}${last.id}${last.tier ? `/${last.tier}` : ""} ${files}`.trim();
3861
4094
  };
4095
+ const sourceLine = () => {
4096
+ const last = log.at(-1);
4097
+ if (!last) return text.words.none;
4098
+ const file = last.layers?.find((layer) => layer.role === "close")?.url.split("/").pop() ?? last.id;
4099
+ return `${text.sources[soundSourceOf(last)]} \xB7 ${last.id.replace(USER_SOUND_PREFIX, "")} \xB7 ${file}`;
4100
+ };
3862
4101
  const metrics = () => [
4102
+ { id: "source", name: text.metrics.source, read: sourceLine },
3863
4103
  { id: "count", name: text.metrics.count, read: counts },
3864
4104
  { id: "chosen", name: text.metrics.chosen, read: () => `${label(chosen.sound)}${registry().sample(chosen.sound) ? ` (${engine.sampleStatus(chosen.sound)})` : ""}` },
3865
4105
  { id: "matrix", name: text.metrics.matrix, read: () => `${strikeId()} \xB7 ${text.states[stateOf(strikeId())]}${pairOf(strikeId()).a ? ` \xB7 A=${pairOf(strikeId()).a}` : ""}` },
@@ -3872,6 +4112,7 @@ function createSoundCheckModule(options = {}) {
3872
4112
  ];
3873
4113
  const act = (id) => {
3874
4114
  if (id === "play") play();
4115
+ else if (id === "play_user") void playUser();
3875
4116
  else if (id === "strike") playId(preferred(strikeId()));
3876
4117
  else if (id === "burst") for (let index = 0; index < 20; index++) playId(preferred(chosen.sound), { delay: index * 0.06 });
3877
4118
  else if (id === "play_a") playA();
@@ -4152,6 +4393,24 @@ export {
4152
4393
  impactSoundId,
4153
4394
  SFX_IMPACTS,
4154
4395
  sfxState,
4396
+ SDK_LICENSES,
4397
+ SFX_LAYERS,
4398
+ SFX_TIERS,
4399
+ parseSfxName,
4400
+ splitTier,
4401
+ sampleBankFromManifest,
4402
+ KIT_CATEGORY_BUS,
4403
+ KIT_SAMPLE_ALIASES,
4404
+ kitSampleDefaults,
4405
+ withAliases,
4406
+ kitSampleBank,
4407
+ loadKitSamples,
4408
+ USER_SAMPLES_BANK,
4409
+ KIT_SAMPLES_BANK,
4410
+ USER_SOUND_PREFIX,
4411
+ soundSourceOf,
4412
+ userSampleBank,
4413
+ loadUserSamples,
4155
4414
  GAME_SFX_CLASSES,
4156
4415
  GAME_SFX_FALLBACK,
4157
4416
  noiseClassRecipe,
@@ -4167,4 +4426,4 @@ export {
4167
4426
  CALIBRATION_CATEGORY,
4168
4427
  createSoundCheckModule
4169
4428
  };
4170
- //# sourceMappingURL=chunk-7TLFY7VO.js.map
4429
+ //# sourceMappingURL=chunk-KBTUANNG.js.map