@adatechnology/game-audio 0.3.3 → 0.3.5

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/dist/index.js CHANGED
@@ -986,6 +986,56 @@ function noiseBuffer(store, context, seconds) {
986
986
  return store.buffer;
987
987
  }
988
988
 
989
+ // src/webaudio/engine-queue.ts
990
+ var nowMs = () => typeof performance === "undefined" ? Date.now() : performance.now();
991
+ function scheduleTask(task) {
992
+ if (typeof MessageChannel === "undefined") {
993
+ setTimeout(task, 0);
994
+ return;
995
+ }
996
+ const channel = new MessageChannel();
997
+ channel.port1.onmessage = () => {
998
+ channel.port1.close();
999
+ task();
1000
+ };
1001
+ channel.port2.postMessage(0);
1002
+ }
1003
+ function createStartQueue(options = {}) {
1004
+ const budgetMs = options.budgetMs ?? 2;
1005
+ const maxLatencyMs = options.maxLatencyMs ?? 250;
1006
+ let jobs = [];
1007
+ let scheduled = false;
1008
+ const drain = () => {
1009
+ scheduled = false;
1010
+ const began = nowMs();
1011
+ while (jobs.length > 0) {
1012
+ const job = jobs.shift();
1013
+ if (nowMs() - job.queuedAt > maxLatencyMs) job.drop();
1014
+ else job.run();
1015
+ if (nowMs() - began >= budgetMs) break;
1016
+ }
1017
+ if (jobs.length > 0) schedule();
1018
+ };
1019
+ const schedule = () => {
1020
+ if (scheduled) return;
1021
+ scheduled = true;
1022
+ scheduleTask(drain);
1023
+ };
1024
+ return {
1025
+ push(job) {
1026
+ jobs.push({ ...job, queuedAt: nowMs() });
1027
+ schedule();
1028
+ },
1029
+ clear() {
1030
+ for (const job of jobs) job.drop();
1031
+ jobs = [];
1032
+ },
1033
+ get size() {
1034
+ return jobs.length;
1035
+ }
1036
+ };
1037
+ }
1038
+
989
1039
  // src/webaudio/realize-game.ts
990
1040
  var end = (layer, start) => start + layer.duration + layer.tail;
991
1041
  var firstFilter = (layer) => layer.filters?.bank[0];
@@ -1435,15 +1485,43 @@ function createAudioEngine(options = {}) {
1435
1485
  ...playOptions.params ? { params: playOptions.params } : {},
1436
1486
  ...options.occlusion && playOptions.position && recipe.falloff?.model !== "none" ? { occlusion: options.occlusion(playOptions.position) } : {}
1437
1487
  });
1438
- const start = (plan, store, voiceId, delay = 0) => {
1488
+ const startQueue = options.deferredStart ? createStartQueue(options.deferredStart) : null;
1489
+ const build = (plan, store, delay) => {
1439
1490
  const audio = context;
1440
- const realized = realize(plan, {
1491
+ return realize(plan, {
1441
1492
  context: audio,
1442
1493
  output: outputFor(plan.bus),
1443
1494
  ...chain?.wet ? { wet: chain.wet } : {},
1444
1495
  noise: () => noiseBuffer(store, audio, mix.noise.seconds),
1445
1496
  time: audio.currentTime + delay
1446
1497
  });
1498
+ };
1499
+ const deferVoice = (plan, store, voiceId, delay) => {
1500
+ let built = null;
1501
+ let cancelled = false;
1502
+ const pending = {
1503
+ get sources() {
1504
+ return built?.sources ?? [];
1505
+ },
1506
+ stop() {
1507
+ cancelled = true;
1508
+ built?.stop();
1509
+ }
1510
+ };
1511
+ startQueue.push({
1512
+ run() {
1513
+ if (!cancelled && context) built = build(plan, store, delay);
1514
+ },
1515
+ drop() {
1516
+ if (voiceId === void 0) return;
1517
+ voices.release(voiceId);
1518
+ active.delete(voiceId);
1519
+ }
1520
+ });
1521
+ return pending;
1522
+ };
1523
+ const start = (plan, store, voiceId, delay = 0) => {
1524
+ const realized = startQueue ? deferVoice(plan, store, voiceId, delay) : build(plan, store, delay);
1447
1525
  if (voiceId === void 0) return null;
1448
1526
  voices.setLength(voiceId, plan.length + delay);
1449
1527
  active.set(voiceId, realized);
@@ -1559,6 +1637,12 @@ function createAudioEngine(options = {}) {
1559
1637
  const audio = ready();
1560
1638
  if (audio) unlockContext(audio);
1561
1639
  },
1640
+ warmUp() {
1641
+ const audio = ready();
1642
+ if (!audio) return false;
1643
+ noiseBuffer(shared, audio, mix.noise.seconds);
1644
+ return true;
1645
+ },
1562
1646
  level(bus) {
1563
1647
  watched.add(bus);
1564
1648
  ensureBus(bus);
@@ -1582,6 +1666,7 @@ function createAudioEngine(options = {}) {
1582
1666
  };
1583
1667
  },
1584
1668
  dispose() {
1669
+ startQueue?.clear();
1585
1670
  for (const id of active.keys()) voices.release(id);
1586
1671
  for (const loop of [...loops]) loop.stop();
1587
1672
  active.clear();