waa-play 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +41 -89
  2. package/dist/adapters.cjs +6 -6
  3. package/dist/adapters.d.cts +1 -1
  4. package/dist/adapters.d.ts +1 -1
  5. package/dist/adapters.js +1 -1
  6. package/dist/buffer.cjs +5 -5
  7. package/dist/buffer.d.cts +1 -1
  8. package/dist/buffer.d.ts +1 -1
  9. package/dist/buffer.js +1 -1
  10. package/dist/{chunk-T74FBKTY.js → chunk-2FGUFHZM.js} +2 -2
  11. package/dist/{chunk-CPAT75WD.cjs → chunk-3VTU5OX5.cjs} +2 -2
  12. package/dist/{chunk-2DL7CAEP.js → chunk-7JUVBZ6B.js} +2 -2
  13. package/dist/{chunk-D5CD5KQZ.cjs → chunk-BRS7LZVH.cjs} +2 -2
  14. package/dist/{chunk-QWNV2BZ5.cjs → chunk-F6WXD3XW.cjs} +2 -2
  15. package/dist/{chunk-C2ASIYN5.js → chunk-FESPIMZM.js} +3 -7
  16. package/dist/{chunk-GYH2JSCY.js → chunk-FY273Z3I.js} +2 -2
  17. package/dist/{chunk-SIMLANWE.cjs → chunk-G37HMZEX.cjs} +1028 -955
  18. package/dist/{chunk-2FFORBOP.js → chunk-GDBOHOGF.js} +1027 -955
  19. package/dist/{chunk-5J7S6QV3.cjs → chunk-HIF3UAF3.cjs} +2 -2
  20. package/dist/{chunk-CRODJ4KS.js → chunk-HTN52U23.js} +13 -6
  21. package/dist/{chunk-X4IFO7U7.js → chunk-HYRDCTBO.js} +143 -116
  22. package/dist/{chunk-VKT7YCWK.js → chunk-JIHPQAEA.js} +6 -3
  23. package/dist/chunk-KVKW7W66.cjs +148 -0
  24. package/dist/{chunk-4LNVRSTM.cjs → chunk-OIY6I4TU.cjs} +3 -7
  25. package/dist/{chunk-7S5KWTZ6.cjs → chunk-OZN5X4N6.cjs} +6 -3
  26. package/dist/{chunk-CJJC6ASU.js → chunk-PL4J3NR7.js} +2 -2
  27. package/dist/{chunk-IMNRPYBM.js → chunk-QFJQU7TQ.js} +10 -10
  28. package/dist/{chunk-M5PDY5EZ.cjs → chunk-QGZGERGK.cjs} +2 -2
  29. package/dist/{chunk-QFFQQMU4.cjs → chunk-VOSIA3GF.cjs} +13 -6
  30. package/dist/{chunk-CTUCTTIE.cjs → chunk-VY4UMZMJ.cjs} +145 -118
  31. package/dist/{chunk-LETS7FKB.js → chunk-YFK7ETCF.js} +2 -2
  32. package/dist/context.d.cts +1 -1
  33. package/dist/context.d.ts +1 -1
  34. package/dist/emitter.cjs +2 -2
  35. package/dist/emitter.js +1 -1
  36. package/dist/engine-7DCOERRN.js +4 -0
  37. package/dist/engine-ALWPAIX6.cjs +17 -0
  38. package/dist/fade.cjs +5 -5
  39. package/dist/fade.d.cts +1 -1
  40. package/dist/fade.d.ts +1 -1
  41. package/dist/fade.js +1 -1
  42. package/dist/index.cjs +44 -44
  43. package/dist/index.d.cts +7 -7
  44. package/dist/index.d.ts +7 -7
  45. package/dist/index.js +10 -10
  46. package/dist/nodes.cjs +11 -11
  47. package/dist/nodes.js +1 -1
  48. package/dist/play.cjs +3 -3
  49. package/dist/play.d.cts +1 -1
  50. package/dist/play.d.ts +1 -1
  51. package/dist/play.js +2 -2
  52. package/dist/player.cjs +11 -11
  53. package/dist/player.d.cts +1 -1
  54. package/dist/player.d.ts +1 -1
  55. package/dist/player.js +10 -10
  56. package/dist/scheduler.cjs +3 -3
  57. package/dist/scheduler.d.cts +1 -1
  58. package/dist/scheduler.d.ts +1 -1
  59. package/dist/scheduler.js +1 -1
  60. package/dist/stretcher.cjs +3 -3
  61. package/dist/stretcher.d.cts +4 -4
  62. package/dist/stretcher.d.ts +4 -4
  63. package/dist/stretcher.js +2 -2
  64. package/dist/synth.cjs +4 -4
  65. package/dist/synth.js +1 -1
  66. package/dist/{types-DUrbEbPl.d.cts → types-BYC6m7Q0.d.cts} +6 -6
  67. package/dist/{types-DUrbEbPl.d.ts → types-BYC6m7Q0.d.ts} +6 -6
  68. package/dist/waveform.cjs +4 -4
  69. package/dist/waveform.d.cts +1 -1
  70. package/dist/waveform.d.ts +1 -1
  71. package/dist/waveform.js +1 -1
  72. package/package.json +14 -6
  73. package/dist/adapters.cjs.map +0 -1
  74. package/dist/adapters.js.map +0 -1
  75. package/dist/buffer.cjs.map +0 -1
  76. package/dist/buffer.js.map +0 -1
  77. package/dist/chunk-2DL7CAEP.js.map +0 -1
  78. package/dist/chunk-2FFORBOP.js.map +0 -1
  79. package/dist/chunk-37CPPRLV.js.map +0 -1
  80. package/dist/chunk-4LNVRSTM.cjs.map +0 -1
  81. package/dist/chunk-5J7S6QV3.cjs.map +0 -1
  82. package/dist/chunk-6UTN73HG.cjs.map +0 -1
  83. package/dist/chunk-7S5KWTZ6.cjs.map +0 -1
  84. package/dist/chunk-C2ASIYN5.js.map +0 -1
  85. package/dist/chunk-CJJC6ASU.js.map +0 -1
  86. package/dist/chunk-CPAT75WD.cjs.map +0 -1
  87. package/dist/chunk-CRODJ4KS.js.map +0 -1
  88. package/dist/chunk-CTUCTTIE.cjs.map +0 -1
  89. package/dist/chunk-D5CD5KQZ.cjs.map +0 -1
  90. package/dist/chunk-GYH2JSCY.js.map +0 -1
  91. package/dist/chunk-IMNRPYBM.js.map +0 -1
  92. package/dist/chunk-LETS7FKB.js.map +0 -1
  93. package/dist/chunk-M5PDY5EZ.cjs.map +0 -1
  94. package/dist/chunk-QFFQQMU4.cjs.map +0 -1
  95. package/dist/chunk-QWNV2BZ5.cjs.map +0 -1
  96. package/dist/chunk-SIMLANWE.cjs.map +0 -1
  97. package/dist/chunk-T74FBKTY.js.map +0 -1
  98. package/dist/chunk-VKT7YCWK.js.map +0 -1
  99. package/dist/chunk-X4IFO7U7.js.map +0 -1
  100. package/dist/chunk-XZBMBZA3.cjs +0 -148
  101. package/dist/chunk-XZBMBZA3.cjs.map +0 -1
  102. package/dist/context.cjs.map +0 -1
  103. package/dist/context.js.map +0 -1
  104. package/dist/emitter.cjs.map +0 -1
  105. package/dist/emitter.js.map +0 -1
  106. package/dist/engine-QUMYW73L.cjs +0 -13
  107. package/dist/engine-QUMYW73L.cjs.map +0 -1
  108. package/dist/engine-TYI7OX7O.js +0 -4
  109. package/dist/engine-TYI7OX7O.js.map +0 -1
  110. package/dist/fade.cjs.map +0 -1
  111. package/dist/fade.js.map +0 -1
  112. package/dist/index.cjs.map +0 -1
  113. package/dist/index.js.map +0 -1
  114. package/dist/nodes.cjs.map +0 -1
  115. package/dist/nodes.js.map +0 -1
  116. package/dist/play.cjs.map +0 -1
  117. package/dist/play.js.map +0 -1
  118. package/dist/player.cjs.map +0 -1
  119. package/dist/player.js.map +0 -1
  120. package/dist/scheduler.cjs.map +0 -1
  121. package/dist/scheduler.js.map +0 -1
  122. package/dist/stretcher.cjs.map +0 -1
  123. package/dist/stretcher.js.map +0 -1
  124. package/dist/synth.cjs.map +0 -1
  125. package/dist/synth.js.map +0 -1
  126. package/dist/waveform.cjs.map +0 -1
  127. package/dist/waveform.js.map +0 -1
@@ -58,15 +58,15 @@ interface PlaybackSnapshot {
58
58
  }
59
59
  /** Event map emitted by a Playback instance. */
60
60
  interface PlaybackEventMap {
61
- play: void;
62
- pause: void;
63
- resume: void;
61
+ play: undefined;
62
+ pause: undefined;
63
+ resume: undefined;
64
64
  seek: {
65
65
  position: number;
66
66
  };
67
- stop: void;
68
- ended: void;
69
- loop: void;
67
+ stop: undefined;
68
+ ended: undefined;
69
+ loop: undefined;
70
70
  statechange: {
71
71
  state: PlaybackState;
72
72
  };
@@ -58,15 +58,15 @@ interface PlaybackSnapshot {
58
58
  }
59
59
  /** Event map emitted by a Playback instance. */
60
60
  interface PlaybackEventMap {
61
- play: void;
62
- pause: void;
63
- resume: void;
61
+ play: undefined;
62
+ pause: undefined;
63
+ resume: undefined;
64
64
  seek: {
65
65
  position: number;
66
66
  };
67
- stop: void;
68
- ended: void;
69
- loop: void;
67
+ stop: undefined;
68
+ ended: undefined;
69
+ loop: undefined;
70
70
  statechange: {
71
71
  state: PlaybackState;
72
72
  };
package/dist/waveform.cjs CHANGED
@@ -1,20 +1,20 @@
1
1
  'use strict';
2
2
 
3
- var chunkQFFQQMU4_cjs = require('./chunk-QFFQQMU4.cjs');
3
+ var chunkVOSIA3GF_cjs = require('./chunk-VOSIA3GF.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "extractPeakPairs", {
8
8
  enumerable: true,
9
- get: function () { return chunkQFFQQMU4_cjs.extractPeakPairs; }
9
+ get: function () { return chunkVOSIA3GF_cjs.extractPeakPairs; }
10
10
  });
11
11
  Object.defineProperty(exports, "extractPeaks", {
12
12
  enumerable: true,
13
- get: function () { return chunkQFFQQMU4_cjs.extractPeaks; }
13
+ get: function () { return chunkVOSIA3GF_cjs.extractPeaks; }
14
14
  });
15
15
  Object.defineProperty(exports, "extractRMS", {
16
16
  enumerable: true,
17
- get: function () { return chunkQFFQQMU4_cjs.extractRMS; }
17
+ get: function () { return chunkVOSIA3GF_cjs.extractRMS; }
18
18
  });
19
19
  //# sourceMappingURL=waveform.cjs.map
20
20
  //# sourceMappingURL=waveform.cjs.map
@@ -1,4 +1,4 @@
1
- import { E as ExtractPeaksOptions, P as PeakPair } from './types-DUrbEbPl.cjs';
1
+ import { E as ExtractPeaksOptions, P as PeakPair } from './types-BYC6m7Q0.cjs';
2
2
 
3
3
  /**
4
4
  * Extract normalised peak amplitude values from an `AudioBuffer`.
@@ -1,4 +1,4 @@
1
- import { E as ExtractPeaksOptions, P as PeakPair } from './types-DUrbEbPl.js';
1
+ import { E as ExtractPeaksOptions, P as PeakPair } from './types-BYC6m7Q0.js';
2
2
 
3
3
  /**
4
4
  * Extract normalised peak amplitude values from an `AudioBuffer`.
package/dist/waveform.js CHANGED
@@ -1,3 +1,3 @@
1
- export { extractPeakPairs, extractPeaks, extractRMS } from './chunk-CRODJ4KS.js';
1
+ export { extractPeakPairs, extractPeaks, extractRMS } from './chunk-HTN52U23.js';
2
2
  //# sourceMappingURL=waveform.js.map
3
3
  //# sourceMappingURL=waveform.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "waa-play",
3
- "version": "0.2.0",
4
- "description": "Convenient composable building blocks for Web Audio API. Time-stretch, streaming playback, waveform extraction, BYO AudioContext, zero dependencies.",
3
+ "version": "0.2.2",
4
+ "description": "Web Audio API modules with WSOLA time-stretching, chunk-based streaming, and waveform extraction",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -92,15 +92,20 @@
92
92
  },
93
93
  "sideEffects": false,
94
94
  "files": [
95
- "dist"
95
+ "dist",
96
+ "!dist/**/*.map"
96
97
  ],
97
98
  "scripts": {
98
99
  "build": "tsup",
99
100
  "dev": "tsup --watch",
100
101
  "test": "vitest run",
102
+ "test:unit": "vitest run --project=unit",
103
+ "test:browser": "vitest run --project=browser",
101
104
  "test:watch": "vitest",
102
105
  "typecheck": "tsc --noEmit",
103
- "lint": "tsc --noEmit",
106
+ "lint": "biome lint .",
107
+ "format": "biome format --write .",
108
+ "check": "biome check .",
104
109
  "prepublishOnly": "npm run build"
105
110
  },
106
111
  "keywords": [
@@ -123,10 +128,13 @@
123
128
  },
124
129
  "homepage": "https://ivgtr.github.io/waa/",
125
130
  "bugs": "https://github.com/ivgtr/waa/issues",
126
- "dependencies": {},
127
131
  "devDependencies": {
132
+ "@biomejs/biome": "^2.3.14",
133
+ "@vitest/browser": "^4.0.18",
134
+ "@vitest/browser-playwright": "^4.0.18",
135
+ "playwright": "^1.58.2",
128
136
  "tsup": "^8.4.0",
129
137
  "typescript": "^5.7.0",
130
- "vitest": "^2.1.0"
138
+ "vitest": "^4.0.18"
131
139
  }
132
140
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"adapters.cjs"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"adapters.js"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"buffer.cjs"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"buffer.js"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/scheduler.ts"],"names":[],"mappings":";AA6BO,SAAS,eAAA,CACd,KACA,OAAA,EACW;AACX,EAAA,MAAM,EAAE,SAAA,GAAY,GAAA,EAAK,WAAW,EAAA,EAAG,GAAI,WAAW,EAAC;AAEvD,EAAA,MAAM,SAA2B,EAAC;AAClC,EAAA,IAAI,OAAA,GAAiD,IAAA;AAErD,EAAA,SAAS,IAAA,GAAO;AACd,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,GAAc,SAAA;AAClC,IAAA,KAAA,IAAS,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC3C,MAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,MAAA,IAAI,GAAA,CAAI,QAAQ,OAAA,EAAS;AACvB,QAAA,GAAA,CAAI,QAAA,CAAS,IAAI,IAAI,CAAA;AACrB,QAAA,MAAA,CAAO,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,QAAA,CAAS,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU;AAC3B,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,UAAU,CAAA;AAAA,IACpC,CAAA;AAAA,IACA,OAAO,EAAA,EAAI;AACT,MAAA,MAAM,MAAM,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAC/C,MAAA,IAAI,GAAA,KAAQ,EAAA,EAAI,MAAA,CAAO,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IACtC,CAAA;AAAA,IACA,KAAA,GAAQ;AACN,MAAA,IAAI,YAAY,IAAA,EAAM;AACtB,MAAA,OAAA,GAAU,WAAA,CAAY,MAAM,QAAQ,CAAA;AAAA,IACtC,CAAA;AAAA,IACA,IAAA,GAAO;AACL,MAAA,IAAI,YAAY,IAAA,EAAM;AACpB,QAAA,aAAA,CAAc,OAAO,CAAA;AACrB,QAAA,OAAA,GAAU,IAAA;AAAA,MACZ;AAAA,IACF,CAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,IAAA,CAAK,IAAA,EAAK;AACV,MAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAAA,IAClB;AAAA,GACF;AACF;AAsBO,SAAS,WAAA,CACd,KACA,OAAA,EACO;AACP,EAAA,IAAI,GAAA,GAAM,SAAS,GAAA,IAAO,GAAA;AAC1B,EAAA,MAAM,YAAY,GAAA,CAAI,WAAA;AAEtB,EAAA,SAAS,cAAA,GAAiB;AACxB,IAAA,OAAO,EAAA,GAAK,GAAA;AAAA,EACd;AAEA,EAAA,OAAO;AAAA,IACL,WAAW,IAAA,EAAsB;AAC/B,MAAA,OAAO,SAAA,GAAY,OAAO,cAAA,EAAe;AAAA,IAC3C,CAAA;AAAA,IACA,cAAA,GAAyB;AACvB,MAAA,OAAA,CAAQ,GAAA,CAAI,WAAA,GAAc,SAAA,IAAa,cAAA,EAAe;AAAA,IACxD,CAAA;AAAA,IACA,eAAA,GAA0B;AACxB,MAAA,MAAM,OAAA,GAAU,KAAK,cAAA,EAAe;AACpC,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA;AAC9B,MAAA,OAAO,KAAK,UAAA,CAAW,IAAA,KAAS,OAAA,GAAU,IAAA,GAAO,IAAI,IAAI,CAAA;AAAA,IAC3D,CAAA;AAAA,IACA,OAAO,KAAA,EAAe;AACpB,MAAA,GAAA,GAAM,KAAA;AAAA,IACR,CAAA;AAAA,IACA,MAAA,GAAiB;AACf,MAAA,OAAO,GAAA;AAAA,IACT;AAAA,GACF;AACF","file":"chunk-2DL7CAEP.js","sourcesContent":["// ---------------------------------------------------------------------------\n// M8: Scheduler & Clock\n// ---------------------------------------------------------------------------\n\nimport type { ClockOptions, ScheduledEvent, SchedulerOptions } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Scheduler\n// ---------------------------------------------------------------------------\n\nexport interface Scheduler {\n /** Schedule a callback at a specific AudioContext time. */\n schedule(id: string, time: number, callback: (time: number) => void): void;\n /** Remove a scheduled event by id. */\n cancel(id: string): void;\n /** Start the scheduler loop. */\n start(): void;\n /** Stop the scheduler loop. */\n stop(): void;\n /** Dispose of all resources. */\n dispose(): void;\n}\n\n/**\n * Create a lookahead-based event scheduler.\n *\n * Uses `setInterval` to check upcoming events and fire callbacks\n * slightly before their scheduled time, enabling sample-accurate timing.\n */\nexport function createScheduler(\n ctx: AudioContext,\n options?: SchedulerOptions,\n): Scheduler {\n const { lookahead = 0.1, interval = 25 } = options ?? {};\n\n const events: ScheduledEvent[] = [];\n let timerId: ReturnType<typeof setInterval> | null = null;\n\n function tick() {\n const horizon = ctx.currentTime + lookahead;\n for (let i = events.length - 1; i >= 0; i--) {\n const evt = events[i]!;\n if (evt.time <= horizon) {\n evt.callback(evt.time);\n events.splice(i, 1);\n }\n }\n }\n\n return {\n schedule(id, time, callback) {\n events.push({ id, time, callback });\n },\n cancel(id) {\n const idx = events.findIndex((e) => e.id === id);\n if (idx !== -1) events.splice(idx, 1);\n },\n start() {\n if (timerId !== null) return;\n timerId = setInterval(tick, interval);\n },\n stop() {\n if (timerId !== null) {\n clearInterval(timerId);\n timerId = null;\n }\n },\n dispose() {\n this.stop();\n events.length = 0;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Clock\n// ---------------------------------------------------------------------------\n\nexport interface Clock {\n /** Convert a beat number to AudioContext time (seconds). */\n beatToTime(beat: number): number;\n /** Get the current beat based on AudioContext time. */\n getCurrentBeat(): number;\n /** Get the AudioContext time of the next beat boundary. */\n getNextBeatTime(): number;\n /** Update BPM. */\n setBpm(bpm: number): void;\n /** Get current BPM. */\n getBpm(): number;\n}\n\n/**\n * Create a BPM-based clock tied to an `AudioContext`.\n */\nexport function createClock(\n ctx: AudioContext,\n options?: ClockOptions,\n): Clock {\n let bpm = options?.bpm ?? 120;\n const startTime = ctx.currentTime;\n\n function secondsPerBeat() {\n return 60 / bpm;\n }\n\n return {\n beatToTime(beat: number): number {\n return startTime + beat * secondsPerBeat();\n },\n getCurrentBeat(): number {\n return (ctx.currentTime - startTime) / secondsPerBeat();\n },\n getNextBeatTime(): number {\n const current = this.getCurrentBeat();\n const next = Math.ceil(current);\n return this.beatToTime(next === current ? next + 1 : next);\n },\n setBpm(value: number) {\n bpm = value;\n },\n getBpm(): number {\n return bpm;\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/stretcher/constants.ts","../src/stretcher/chunk-splitter.ts","../src/stretcher/worker-inline.ts","../src/stretcher/worker-manager.ts","../src/stretcher/wsola.ts","../src/stretcher/main-thread-processor.ts","../src/stretcher/priority-queue.ts","../src/stretcher/conversion-scheduler.ts","../src/stretcher/chunk-player.ts","../src/stretcher/buffer-monitor.ts","../src/stretcher/engine.ts"],"names":["extractChunkData","chunk"],"mappings":"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","file":"chunk-2FFORBOP.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Stretcher: Constants\n// ---------------------------------------------------------------------------\n\n// Chunk splitting\nexport const CHUNK_DURATION_SEC = 8;\nexport const OVERLAP_SEC = 0.2;\nexport const CROSSFADE_SEC = 0.1;\n\n// WSOLA algorithm parameters\nexport const WSOLA_FRAME_SIZE = 1024;\nexport const WSOLA_HOP_SIZE = 512;\nexport const WSOLA_TOLERANCE = 2048;\n\n// Priority scheduling weights\nexport const PRIORITY_FORWARD_WEIGHT = 1.0;\nexport const PRIORITY_BACKWARD_WEIGHT = 2.5;\nexport const CANCEL_DISTANCE_THRESHOLD = 6;\n\n// Buffer health thresholds (seconds)\nexport const BUFFER_HEALTHY_SEC = 30;\nexport const BUFFER_LOW_SEC = 10;\nexport const BUFFER_CRITICAL_SEC = 3;\nexport const BUFFER_RESUME_SEC = 5;\n\n// Memory management\nexport const KEEP_AHEAD_CHUNKS = 19;\nexport const KEEP_AHEAD_SECONDS = 150;\nexport const KEEP_BEHIND_CHUNKS = 8;\nexport const KEEP_BEHIND_SECONDS = 60;\n\n// Worker pool\nexport const WORKER_POOL_SIZE = 2;\n\n// Error recovery\nexport const MAX_WORKER_CRASHES = 3;\nexport const MAX_CHUNK_RETRIES = 3;\n\n// Estimation\nexport const ESTIMATOR_WINDOW_SIZE = 10;\n\n// Playback lookahead\nexport const LOOKAHEAD_INTERVAL_MS = 200;\nexport const LOOKAHEAD_THRESHOLD_SEC = 1.5;\n","// ---------------------------------------------------------------------------\n// Stretcher: Chunk splitter\n// ---------------------------------------------------------------------------\n\nimport { CHUNK_DURATION_SEC, OVERLAP_SEC } from \"./constants.js\";\nimport type { ChunkInfo } from \"./types.js\";\n\n/**\n * Split an AudioBuffer's sample range into chunks with overlap.\n *\n * @param totalSamples - Total number of samples in the buffer\n * @param sampleRate - Sample rate of the buffer\n * @param chunkDurationSec - Duration of each chunk in seconds\n * @param overlapSec - Overlap between adjacent chunks in seconds\n * @returns Array of ChunkInfo objects\n */\nexport function splitIntoChunks(\n totalSamples: number,\n sampleRate: number,\n chunkDurationSec: number = CHUNK_DURATION_SEC,\n overlapSec: number = OVERLAP_SEC,\n): ChunkInfo[] {\n if (totalSamples <= 0 || sampleRate <= 0) {\n return [];\n }\n\n const chunkSamples = Math.round(chunkDurationSec * sampleRate);\n const overlapSamples = Math.round(overlapSec * sampleRate);\n\n if (chunkSamples <= 0) {\n return [];\n }\n\n // If the entire buffer fits in one chunk, return a single chunk\n if (totalSamples <= chunkSamples) {\n return [\n {\n index: 0,\n state: \"pending\",\n inputStartSample: 0,\n inputEndSample: totalSamples,\n overlapBefore: 0,\n overlapAfter: 0,\n outputBuffer: null,\n outputLength: 0,\n priority: 0,\n retryCount: 0,\n },\n ];\n }\n\n const chunks: ChunkInfo[] = [];\n let start = 0;\n let index = 0;\n\n while (start < totalSamples) {\n const isFirst = index === 0;\n const nominalEnd = Math.min(start + chunkSamples, totalSamples);\n const isLast = nominalEnd >= totalSamples;\n\n // Overlap regions\n const overlapBefore = isFirst ? 0 : Math.min(overlapSamples, start);\n const overlapAfter = isLast\n ? 0\n : Math.min(overlapSamples, totalSamples - nominalEnd);\n\n // Actual input range includes overlap\n const inputStart = start - overlapBefore;\n const inputEnd = Math.min(nominalEnd + overlapAfter, totalSamples);\n\n chunks.push({\n index,\n state: \"pending\",\n inputStartSample: inputStart,\n inputEndSample: inputEnd,\n overlapBefore,\n overlapAfter,\n outputBuffer: null,\n outputLength: 0,\n priority: 0,\n retryCount: 0,\n });\n\n start = nominalEnd;\n index++;\n }\n\n return chunks;\n}\n\n/**\n * Extract channel data for a specific chunk from an AudioBuffer.\n */\nexport function extractChunkData(\n buffer: AudioBuffer,\n chunk: ChunkInfo,\n): Float32Array[] {\n const channels: Float32Array[] = [];\n const length = chunk.inputEndSample - chunk.inputStartSample;\n\n for (let ch = 0; ch < buffer.numberOfChannels; ch++) {\n const fullChannel = buffer.getChannelData(ch);\n const chunkData = new Float32Array(length);\n chunkData.set(\n fullChannel.subarray(chunk.inputStartSample, chunk.inputEndSample),\n );\n channels.push(chunkData);\n }\n\n return channels;\n}\n\n/**\n * Get the chunk index that contains the given sample position.\n */\nexport function getChunkIndexForSample(\n chunks: ChunkInfo[],\n sample: number,\n): number {\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i]!;\n const nominalStart = chunk.inputStartSample + chunk.overlapBefore;\n const nominalEnd = chunk.inputEndSample - chunk.overlapAfter;\n if (sample >= nominalStart && sample < nominalEnd) {\n return i;\n }\n }\n // If past the end, return last chunk\n return Math.max(0, chunks.length - 1);\n}\n\n/**\n * Get the chunk index that contains the given time position (seconds).\n */\nexport function getChunkIndexForTime(\n chunks: ChunkInfo[],\n timeSeconds: number,\n sampleRate: number,\n): number {\n const sample = Math.round(timeSeconds * sampleRate);\n return getChunkIndexForSample(chunks, sample);\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Inline Worker source code\n// ---------------------------------------------------------------------------\n// This file contains the WSOLA algorithm as a self-contained JavaScript string\n// for execution inside a Web Worker. The logic mirrors wsola.ts.\n// ---------------------------------------------------------------------------\n\nimport {\n WSOLA_FRAME_SIZE,\n WSOLA_HOP_SIZE,\n WSOLA_TOLERANCE,\n} from \"./constants.js\";\n\nfunction getWorkerCode(): string {\n // Embed constants directly into the worker code\n return `\"use strict\";\n\nvar FRAME_SIZE = ${WSOLA_FRAME_SIZE};\nvar HOP_SIZE = ${WSOLA_HOP_SIZE};\nvar TOLERANCE = ${WSOLA_TOLERANCE};\n\nfunction createHannWindow(size) {\n var w = new Float32Array(size);\n for (var i = 0; i < size; i++) {\n w[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (size - 1)));\n }\n return w;\n}\n\nfunction findBestOffset(ref, search, overlapSize, maxOffset) {\n var bestOffset = 0;\n var bestCorr = -Infinity;\n var searchLen = search.length;\n var refLen = ref.length;\n var len = Math.min(overlapSize, refLen);\n\n for (var offset = 0; offset <= maxOffset; offset++) {\n if (offset + len > searchLen) break;\n var corr = 0;\n var normRef = 0;\n var normSearch = 0;\n for (var i = 0; i < len; i++) {\n var r = ref[i];\n var s = search[offset + i];\n corr += r * s;\n normRef += r * r;\n normSearch += s * s;\n }\n var denom = Math.sqrt(normRef * normSearch);\n var ncc = denom > 1e-10 ? corr / denom : 0;\n if (ncc > bestCorr) {\n bestCorr = ncc;\n bestOffset = offset;\n }\n }\n return bestOffset;\n}\n\nfunction wsolaTimeStretch(channels, tempo, sampleRate) {\n if (channels.length === 0) {\n return { output: [], length: 0 };\n }\n\n var inputLength = channels[0].length;\n if (inputLength === 0) {\n return { output: channels.map(function() { return new Float32Array(0); }), length: 0 };\n }\n\n var synthesisHop = HOP_SIZE;\n var analysisHop = Math.round(HOP_SIZE * tempo);\n var numFrames = Math.floor((inputLength - FRAME_SIZE) / analysisHop) + 1;\n\n if (numFrames <= 0) {\n return {\n output: channels.map(function(ch) { return new Float32Array(ch); }),\n length: inputLength\n };\n }\n\n var estimatedOutputLength = (numFrames - 1) * synthesisHop + FRAME_SIZE;\n var outputChannels = channels.map(function() {\n return new Float32Array(estimatedOutputLength);\n });\n var windowFunc = createHannWindow(FRAME_SIZE);\n var normBuffer = new Float32Array(estimatedOutputLength);\n\n var prevOutputFrame = channels.map(function() {\n return new Float32Array(FRAME_SIZE);\n });\n\n var inputPos = 0;\n var outputPos = 0;\n var actualOutputLength = 0;\n\n for (var frame = 0; frame < numFrames; frame++) {\n if (cancelled) return null;\n if (inputPos + FRAME_SIZE > inputLength) break;\n\n var actualInputPos = inputPos;\n\n if (frame > 0 && TOLERANCE > 0) {\n var searchStart = Math.max(0, inputPos - TOLERANCE);\n var searchEnd = Math.min(inputLength - FRAME_SIZE, inputPos + TOLERANCE);\n var searchRange = searchEnd - searchStart;\n\n if (searchRange > 0) {\n var refChannel = prevOutputFrame[0];\n var inputChannel = channels[0];\n\n var overlapStart = FRAME_SIZE - synthesisHop;\n var overlapSize = Math.min(synthesisHop, FRAME_SIZE - overlapStart);\n\n var refSlice = refChannel.subarray(overlapStart, overlapStart + overlapSize);\n var searchSlice = inputChannel.subarray(searchStart, searchEnd + overlapSize);\n\n var bestOffset = findBestOffset(\n refSlice, searchSlice, overlapSize,\n Math.min(searchRange, searchSlice.length - overlapSize)\n );\n\n actualInputPos = searchStart + bestOffset;\n }\n }\n\n for (var ch = 0; ch < channels.length; ch++) {\n var input = channels[ch];\n var output = outputChannels[ch];\n var prevFrame = prevOutputFrame[ch];\n for (var i = 0; i < FRAME_SIZE; i++) {\n var inIdx = actualInputPos + i;\n if (inIdx >= inputLength) break;\n var outIdx = outputPos + i;\n if (outIdx >= estimatedOutputLength) break;\n var sample = input[inIdx];\n output[outIdx] += sample * windowFunc[i];\n prevFrame[i] = sample;\n }\n }\n\n for (var i = 0; i < FRAME_SIZE; i++) {\n var outIdx = outputPos + i;\n if (outIdx >= estimatedOutputLength) break;\n normBuffer[outIdx] += windowFunc[i];\n }\n\n inputPos += analysisHop;\n outputPos += synthesisHop;\n actualOutputLength = Math.min(outputPos + FRAME_SIZE, estimatedOutputLength);\n }\n\n for (var ch = 0; ch < outputChannels.length; ch++) {\n var output = outputChannels[ch];\n for (var i = 0; i < actualOutputLength; i++) {\n var norm = normBuffer[i];\n if (norm > 1e-8) {\n output[i] /= norm;\n }\n }\n }\n\n var trimmedOutput = outputChannels.map(function(ch) {\n return ch.slice(0, actualOutputLength);\n });\n\n return { output: trimmedOutput, length: actualOutputLength };\n}\n\nvar cancelled = false;\n\nself.onmessage = function(e) {\n var msg = e.data;\n if (msg.type === \"cancel\") {\n cancelled = true;\n return;\n }\n if (msg.type === \"convert\") {\n cancelled = false;\n try {\n var result = wsolaTimeStretch(msg.inputData, msg.tempo, msg.sampleRate);\n if (cancelled || result === null) {\n self.postMessage({ type: \"cancelled\", chunkIndex: msg.chunkIndex });\n } else {\n self.postMessage(\n { type: \"result\", chunkIndex: msg.chunkIndex, outputData: result.output, outputLength: result.length },\n result.output.map(function(ch) { return ch.buffer; })\n );\n }\n } catch (err) {\n self.postMessage({ type: \"error\", chunkIndex: msg.chunkIndex, error: String(err) });\n }\n }\n};\n`;\n}\n\n/**\n * Create a Blob URL for the inline WSOLA Worker.\n */\nexport function createWorkerURL(): string {\n const code = getWorkerCode();\n const blob = new Blob([code], { type: \"application/javascript\" });\n return URL.createObjectURL(blob);\n}\n\n/**\n * Revoke a previously created Worker Blob URL.\n */\nexport function revokeWorkerURL(url: string): void {\n URL.revokeObjectURL(url);\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Worker manager (pool)\n// ---------------------------------------------------------------------------\n\nimport { MAX_WORKER_CRASHES, WORKER_POOL_SIZE } from \"./constants.js\";\nimport { createWorkerURL, revokeWorkerURL } from \"./worker-inline.js\";\nimport type { WorkerManager, WorkerResponse } from \"./types.js\";\n\ninterface WorkerSlot {\n worker: Worker | null;\n busy: boolean;\n currentChunkIndex: number | null;\n crashCount: number;\n}\n\n/**\n * Create a Worker manager that uses a pool of Workers for parallel conversion.\n */\nexport function createWorkerManager(\n onResult: (response: WorkerResponse) => void,\n onError: (response: WorkerResponse) => void,\n maxCrashes: number = MAX_WORKER_CRASHES,\n poolSize: number = WORKER_POOL_SIZE,\n onAllDead?: () => void,\n): WorkerManager {\n let workerURL: string | null = null;\n let terminated = false;\n const postTimes = new Map<number, number>();\n\n const slots: WorkerSlot[] = [];\n\n function ensureWorkerURL(): string {\n if (!workerURL) {\n workerURL = createWorkerURL();\n }\n return workerURL;\n }\n\n function isAllDead(): boolean {\n return slots.every((s) => s.worker === null);\n }\n\n function spawnWorkerForSlot(slot: WorkerSlot): void {\n if (terminated) return;\n\n const url = ensureWorkerURL();\n let worker: Worker;\n try {\n worker = new Worker(url);\n } catch {\n // Blob URL Worker not supported (e.g. iOS Safari 14-, strict CSP)\n slot.worker = null;\n return;\n }\n\n worker.onmessage = (e: MessageEvent<WorkerResponse>) => {\n const response = e.data;\n\n if (response.type === \"result\" || response.type === \"cancelled\") {\n slot.busy = false;\n slot.currentChunkIndex = null;\n }\n\n if (response.type === \"error\") {\n slot.busy = false;\n slot.currentChunkIndex = null;\n onError(response);\n return;\n }\n\n onResult(response);\n };\n\n worker.onerror = (e: ErrorEvent) => {\n e.preventDefault();\n slot.busy = false;\n const failedChunkIndex = slot.currentChunkIndex;\n slot.currentChunkIndex = null;\n\n slot.crashCount++;\n\n if (failedChunkIndex !== null) {\n onError({\n type: \"error\",\n chunkIndex: failedChunkIndex,\n error: `Worker crashed: ${e.message}`,\n });\n }\n\n // Cleanup crashed worker\n if (slot.worker) {\n slot.worker.onmessage = null;\n slot.worker.onerror = null;\n slot.worker.terminate();\n slot.worker = null;\n }\n\n // Auto-respawn if under crash limit\n if (slot.crashCount < maxCrashes) {\n spawnWorkerForSlot(slot);\n } else {\n onError({\n type: \"error\",\n chunkIndex: failedChunkIndex ?? -1,\n error: `Worker crashed ${slot.crashCount} times, giving up`,\n });\n if (isAllDead()) {\n onAllDead?.();\n }\n }\n };\n\n slot.worker = worker;\n }\n\n // Initialize pool\n for (let i = 0; i < poolSize; i++) {\n const slot: WorkerSlot = {\n worker: null,\n busy: false,\n currentChunkIndex: null,\n crashCount: 0,\n };\n slots.push(slot);\n spawnWorkerForSlot(slot);\n }\n\n // If all Workers failed to spawn, notify immediately\n if (isAllDead()) {\n onAllDead?.();\n }\n\n function findFreeSlot(): WorkerSlot | null {\n for (const slot of slots) {\n if (!slot.busy && slot.worker) {\n return slot;\n }\n }\n return null;\n }\n\n function findSlotByChunk(chunkIndex: number): WorkerSlot | null {\n for (const slot of slots) {\n if (slot.busy && slot.currentChunkIndex === chunkIndex) {\n return slot;\n }\n }\n return null;\n }\n\n return {\n postConvert(\n chunkIndex: number,\n inputData: Float32Array[],\n tempo: number,\n sampleRate: number,\n ): void {\n if (terminated) return;\n\n const slot = findFreeSlot();\n if (!slot || !slot.worker) return;\n\n slot.busy = true;\n slot.currentChunkIndex = chunkIndex;\n postTimes.set(chunkIndex, performance.now());\n\n // Transfer the buffers for zero-copy\n const transferables = inputData.map((ch) => ch.buffer);\n slot.worker.postMessage(\n { type: \"convert\", chunkIndex, inputData, tempo, sampleRate },\n transferables,\n );\n },\n\n cancelCurrent(): void {\n if (terminated) return;\n for (const slot of slots) {\n if (slot.busy && slot.worker && slot.currentChunkIndex !== null) {\n slot.worker.postMessage({ type: \"cancel\", chunkIndex: slot.currentChunkIndex });\n }\n }\n },\n\n cancelChunk(chunkIndex: number): void {\n if (terminated) return;\n const slot = findSlotByChunk(chunkIndex);\n if (slot && slot.worker) {\n slot.worker.postMessage({ type: \"cancel\", chunkIndex });\n }\n },\n\n isBusy(): boolean {\n return slots.every((s) => s.busy || !s.worker);\n },\n\n hasCapacity(): boolean {\n return findFreeSlot() !== null;\n },\n\n getCurrentChunkIndex(): number | null {\n // Return the first busy slot's chunk index for backwards compat\n for (const slot of slots) {\n if (slot.busy && slot.currentChunkIndex !== null) {\n return slot.currentChunkIndex;\n }\n }\n return null;\n },\n\n getLastPostTime(): number | null {\n // Return the most recent post time across all chunks\n let latest: number | null = null;\n for (const t of postTimes.values()) {\n if (latest === null || t > latest) {\n latest = t;\n }\n }\n return latest;\n },\n\n getPostTimeForChunk(chunkIndex: number): number | null {\n return postTimes.get(chunkIndex) ?? null;\n },\n\n terminate(): void {\n if (terminated) return;\n terminated = true;\n for (const slot of slots) {\n if (slot.worker) {\n slot.worker.onmessage = null;\n slot.worker.onerror = null;\n slot.worker.terminate();\n slot.worker = null;\n }\n }\n if (workerURL) {\n revokeWorkerURL(workerURL);\n workerURL = null;\n }\n postTimes.clear();\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: WSOLA time-stretching algorithm (reference implementation)\n// ---------------------------------------------------------------------------\n\nimport { WSOLA_FRAME_SIZE, WSOLA_HOP_SIZE, WSOLA_TOLERANCE } from \"./constants.js\";\n\n/**\n * Create a Hann window of the given size.\n */\nexport function createHannWindow(size: number): Float32Array {\n const window = new Float32Array(size);\n for (let i = 0; i < size; i++) {\n window[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (size - 1)));\n }\n return window;\n}\n\n/**\n * Find the best overlap offset using normalized cross-correlation.\n * Searches within [0, maxOffset] range relative to the search buffer start.\n * Returns the offset that maximizes correlation.\n *\n * @param ref - Reference segment (typically the tail of the previous output frame)\n * @param search - Search region from the input signal\n * @param overlapSize - Number of samples to compare in the overlap region\n * @param maxOffset - Maximum offset to search\n */\nexport function findBestOffset(\n ref: Float32Array,\n search: Float32Array,\n overlapSize: number,\n maxOffset: number,\n): number {\n let bestOffset = 0;\n let bestCorr = -Infinity;\n\n const searchLen = search.length;\n const refLen = ref.length;\n const len = Math.min(overlapSize, refLen);\n\n for (let offset = 0; offset <= maxOffset; offset++) {\n if (offset + len > searchLen) break;\n\n let corr = 0;\n let normRef = 0;\n let normSearch = 0;\n for (let i = 0; i < len; i++) {\n const r = ref[i]!;\n const s = search[offset + i]!;\n corr += r * s;\n normRef += r * r;\n normSearch += s * s;\n }\n\n // Normalized cross-correlation\n const denom = Math.sqrt(normRef * normSearch);\n const ncc = denom > 1e-10 ? corr / denom : 0;\n\n if (ncc > bestCorr) {\n bestCorr = ncc;\n bestOffset = offset;\n }\n }\n\n return bestOffset;\n}\n\nexport interface WsolaResult {\n output: Float32Array[];\n length: number;\n}\n\n/**\n * Perform WSOLA time-stretching on multi-channel audio data.\n *\n * @param channels - Array of Float32Array, one per channel\n * @param tempo - Speed multiplier (> 1 = faster, < 1 = slower)\n * @param sampleRate - Sample rate of the audio\n * @param frameSize - Analysis frame size (default: WSOLA_FRAME_SIZE)\n * @param hopSize - Analysis hop size (default: WSOLA_HOP_SIZE)\n * @param tolerance - Search tolerance for cross-correlation (default: WSOLA_TOLERANCE)\n */\nexport function wsolaTimeStretch(\n channels: Float32Array[],\n tempo: number,\n _sampleRate: number,\n frameSize: number = WSOLA_FRAME_SIZE,\n hopSize: number = WSOLA_HOP_SIZE,\n tolerance: number = WSOLA_TOLERANCE,\n): WsolaResult {\n if (channels.length === 0) {\n return { output: [], length: 0 };\n }\n\n const inputLength = channels[0]!.length;\n if (inputLength === 0) {\n return { output: channels.map(() => new Float32Array(0)), length: 0 };\n }\n\n // WSOLA: synthesisHop is fixed, analysisHop varies with tempo\n const synthesisHop = hopSize;\n const analysisHop = Math.round(hopSize * tempo);\n\n // Estimate output length: number of frames determined by how far we can read in input\n const numFrames = Math.floor((inputLength - frameSize) / analysisHop) + 1;\n if (numFrames <= 0) {\n // Input too short for even one frame — return a copy\n return {\n output: channels.map((ch) => new Float32Array(ch)),\n length: inputLength,\n };\n }\n\n const estimatedOutputLength = (numFrames - 1) * synthesisHop + frameSize;\n const outputChannels = channels.map(\n () => new Float32Array(estimatedOutputLength),\n );\n const windowFunc = createHannWindow(frameSize);\n\n // Normalization buffer for overlap-add\n const normBuffer = new Float32Array(estimatedOutputLength);\n\n // Buffer to hold the previous output frame (for cross-correlation reference)\n const prevOutputFrame = channels.map(() => new Float32Array(frameSize));\n\n let inputPos = 0;\n let outputPos = 0;\n let actualOutputLength = 0;\n\n for (let frame = 0; frame < numFrames; frame++) {\n if (inputPos + frameSize > inputLength) break;\n\n // Find best offset using cross-correlation against the previous output frame\n let actualInputPos = inputPos;\n\n if (frame > 0 && tolerance > 0) {\n // Search region: [inputPos - tolerance, inputPos + tolerance]\n const searchStart = Math.max(0, inputPos - tolerance);\n const searchEnd = Math.min(inputLength - frameSize, inputPos + tolerance);\n const searchRange = searchEnd - searchStart;\n\n if (searchRange > 0) {\n const refChannel = prevOutputFrame[0]!;\n const inputChannel = channels[0]!;\n\n // The overlap region is synthesisHop samples from the end of the previous frame\n // prevOutputFrame contains the previous frame (frameSize samples)\n // The overlap region starts at (frameSize - synthesisHop) in the previous frame\n const overlapStart = frameSize - synthesisHop;\n const overlapSize = Math.min(synthesisHop, frameSize - overlapStart);\n\n const refSlice = refChannel.subarray(\n overlapStart,\n overlapStart + overlapSize,\n );\n\n // Search buffer: extract the region to search in\n const searchSlice = inputChannel.subarray(\n searchStart,\n searchEnd + overlapSize,\n );\n\n const bestOffset = findBestOffset(\n refSlice,\n searchSlice,\n overlapSize,\n Math.min(searchRange, searchSlice.length - overlapSize),\n );\n\n actualInputPos = searchStart + bestOffset;\n }\n }\n\n // Extract the current frame and apply window, overlap-add for all channels\n for (let ch = 0; ch < channels.length; ch++) {\n const input = channels[ch]!;\n const output = outputChannels[ch]!;\n const prevFrame = prevOutputFrame[ch]!;\n\n for (let i = 0; i < frameSize; i++) {\n const inIdx = actualInputPos + i;\n if (inIdx >= inputLength) break;\n const outIdx = outputPos + i;\n if (outIdx >= estimatedOutputLength) break;\n\n const sample = input[inIdx]!;\n output[outIdx]! += sample * windowFunc[i]!;\n prevFrame[i] = sample;\n }\n }\n\n // Accumulate normalization\n for (let i = 0; i < frameSize; i++) {\n const outIdx = outputPos + i;\n if (outIdx >= estimatedOutputLength) break;\n normBuffer[outIdx]! += windowFunc[i]!;\n }\n\n inputPos += analysisHop;\n outputPos += synthesisHop;\n actualOutputLength = Math.min(outputPos + frameSize, estimatedOutputLength);\n }\n\n // Normalize output\n for (let ch = 0; ch < outputChannels.length; ch++) {\n const output = outputChannels[ch]!;\n for (let i = 0; i < actualOutputLength; i++) {\n const norm = normBuffer[i]!;\n if (norm > 1e-8) {\n output[i]! /= norm;\n }\n }\n }\n\n // Trim output to actual length\n const trimmedOutput = outputChannels.map((ch) =>\n ch.subarray(0, actualOutputLength),\n );\n\n return { output: trimmedOutput, length: actualOutputLength };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Main-thread WSOLA processor (fallback for environments without\n// Worker support, e.g. iOS Safari 14-, strict CSP)\n// ---------------------------------------------------------------------------\n\nimport { wsolaTimeStretch } from \"./wsola.js\";\nimport type { WorkerManager, WorkerResponse } from \"./types.js\";\n\n/**\n * Create a WorkerManager-compatible processor that runs WSOLA on the main\n * thread. Used as a fallback when Blob URL Workers are not available.\n */\nexport function createMainThreadProcessor(\n onResult: (response: WorkerResponse) => void,\n onError: (response: WorkerResponse) => void,\n): WorkerManager {\n let terminated = false;\n const postTimes = new Map<number, number>();\n\n // Track the current conversion so it can be cancelled\n let currentChunkIndex: number | null = null;\n let cancelledChunks = new Set<number>();\n let busy = false;\n\n return {\n postConvert(\n chunkIndex: number,\n inputData: Float32Array[],\n tempo: number,\n sampleRate: number,\n ): void {\n if (terminated) return;\n\n busy = true;\n currentChunkIndex = chunkIndex;\n postTimes.set(chunkIndex, performance.now());\n\n // Run asynchronously to avoid blocking the caller\n setTimeout(() => {\n if (terminated) return;\n\n if (cancelledChunks.has(chunkIndex)) {\n cancelledChunks.delete(chunkIndex);\n busy = false;\n currentChunkIndex = null;\n onResult({ type: \"cancelled\", chunkIndex });\n return;\n }\n\n try {\n const result = wsolaTimeStretch(inputData, tempo, sampleRate);\n\n if (cancelledChunks.has(chunkIndex)) {\n cancelledChunks.delete(chunkIndex);\n busy = false;\n currentChunkIndex = null;\n onResult({ type: \"cancelled\", chunkIndex });\n return;\n }\n\n busy = false;\n currentChunkIndex = null;\n onResult({\n type: \"result\",\n chunkIndex,\n outputData: result.output,\n outputLength: result.length,\n });\n } catch (err) {\n busy = false;\n currentChunkIndex = null;\n onError({\n type: \"error\",\n chunkIndex,\n error: String(err),\n });\n }\n }, 0);\n },\n\n cancelCurrent(): void {\n if (terminated) return;\n if (currentChunkIndex !== null) {\n cancelledChunks.add(currentChunkIndex);\n }\n },\n\n cancelChunk(chunkIndex: number): void {\n if (terminated) return;\n cancelledChunks.add(chunkIndex);\n },\n\n isBusy(): boolean {\n return busy;\n },\n\n hasCapacity(): boolean {\n return !busy;\n },\n\n getCurrentChunkIndex(): number | null {\n return currentChunkIndex;\n },\n\n getLastPostTime(): number | null {\n let latest: number | null = null;\n for (const t of postTimes.values()) {\n if (latest === null || t > latest) {\n latest = t;\n }\n }\n return latest;\n },\n\n getPostTimeForChunk(chunkIndex: number): number | null {\n return postTimes.get(chunkIndex) ?? null;\n },\n\n terminate(): void {\n if (terminated) return;\n terminated = true;\n cancelledChunks.clear();\n postTimes.clear();\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Generic min-heap priority queue\n// ---------------------------------------------------------------------------\n\nimport type { PriorityQueue } from \"./types.js\";\n\n/**\n * Create a min-heap based priority queue.\n *\n * @param compareFn - Returns negative if a has higher priority (lower value) than b\n */\nexport function createPriorityQueue<T>(\n compareFn: (a: T, b: T) => number,\n): PriorityQueue<T> {\n const heap: T[] = [];\n\n function parent(i: number): number {\n return Math.floor((i - 1) / 2);\n }\n\n function left(i: number): number {\n return 2 * i + 1;\n }\n\n function right(i: number): number {\n return 2 * i + 2;\n }\n\n function swap(i: number, j: number): void {\n const tmp = heap[i]!;\n heap[i] = heap[j]!;\n heap[j] = tmp;\n }\n\n function siftUp(i: number): void {\n while (i > 0) {\n const p = parent(i);\n if (compareFn(heap[i]!, heap[p]!) < 0) {\n swap(i, p);\n i = p;\n } else {\n break;\n }\n }\n }\n\n function siftDown(i: number): void {\n const n = heap.length;\n while (true) {\n let smallest = i;\n const l = left(i);\n const r = right(i);\n\n if (l < n && compareFn(heap[l]!, heap[smallest]!) < 0) {\n smallest = l;\n }\n if (r < n && compareFn(heap[r]!, heap[smallest]!) < 0) {\n smallest = r;\n }\n\n if (smallest !== i) {\n swap(i, smallest);\n i = smallest;\n } else {\n break;\n }\n }\n }\n\n function heapify(): void {\n for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) {\n siftDown(i);\n }\n }\n\n return {\n enqueue(item: T): void {\n heap.push(item);\n siftUp(heap.length - 1);\n },\n\n dequeue(): T | undefined {\n if (heap.length === 0) return undefined;\n const min = heap[0]!;\n const last = heap.pop()!;\n if (heap.length > 0) {\n heap[0] = last;\n siftDown(0);\n }\n return min;\n },\n\n peek(): T | undefined {\n return heap[0];\n },\n\n remove(predicate: (item: T) => boolean): boolean {\n const idx = heap.findIndex(predicate);\n if (idx === -1) return false;\n\n if (idx === heap.length - 1) {\n heap.pop();\n } else {\n heap[idx] = heap.pop()!;\n // Re-heapify from this position\n siftDown(idx);\n siftUp(idx);\n }\n return true;\n },\n\n rebuild(): void {\n heapify();\n },\n\n clear(): void {\n heap.length = 0;\n },\n\n size(): number {\n return heap.length;\n },\n\n toArray(): T[] {\n return [...heap];\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Conversion scheduler\n// ---------------------------------------------------------------------------\n\nimport {\n PRIORITY_FORWARD_WEIGHT,\n PRIORITY_BACKWARD_WEIGHT,\n CANCEL_DISTANCE_THRESHOLD,\n MAX_CHUNK_RETRIES,\n KEEP_AHEAD_CHUNKS,\n KEEP_AHEAD_SECONDS,\n KEEP_BEHIND_CHUNKS,\n KEEP_BEHIND_SECONDS,\n CHUNK_DURATION_SEC,\n} from \"./constants.js\";\nimport { createPriorityQueue } from \"./priority-queue.js\";\nimport type {\n ChunkInfo,\n ConversionScheduler,\n ConversionSchedulerOptions,\n WorkerManager,\n} from \"./types.js\";\n\ninterface TempoCache {\n tempo: number;\n chunks: Array<{ outputBuffer: Float32Array[] | null; outputLength: number }>;\n}\n\n/**\n * Create a conversion scheduler that manages chunk priorities and dispatching.\n */\nexport function createConversionScheduler(\n chunks: ChunkInfo[],\n workerManager: WorkerManager,\n extractChunkData: (chunkIndex: number) => Float32Array[],\n sampleRate: number,\n tempo: number,\n options?: Partial<ConversionSchedulerOptions>,\n onChunkReady?: (chunkIndex: number) => void,\n onChunkFailed?: (chunkIndex: number, error: string) => void,\n): ConversionScheduler {\n const forwardWeight = options?.forwardWeight ?? PRIORITY_FORWARD_WEIGHT;\n const backwardWeight = options?.backwardWeight ?? PRIORITY_BACKWARD_WEIGHT;\n const cancelDistThreshold =\n options?.cancelDistanceThreshold ?? CANCEL_DISTANCE_THRESHOLD;\n const keepAhead = options?.keepAheadChunks ?? Math.max(\n KEEP_AHEAD_CHUNKS,\n Math.ceil(KEEP_AHEAD_SECONDS / CHUNK_DURATION_SEC),\n );\n const keepBehind = options?.keepBehindChunks ?? Math.max(\n KEEP_BEHIND_CHUNKS,\n Math.ceil(KEEP_BEHIND_SECONDS / CHUNK_DURATION_SEC),\n );\n\n function isInActiveWindow(chunkIndex: number, playheadIndex: number): boolean {\n const dist = chunkIndex - playheadIndex;\n return dist <= keepAhead && dist >= -keepBehind;\n }\n\n let currentTempo = tempo;\n let currentChunkIdx = 0;\n let previousTempoCache: TempoCache | null = null;\n let disposed = false;\n\n const queue = createPriorityQueue<ChunkInfo>(\n (a, b) => a.priority - b.priority,\n );\n\n function calcPriority(chunkIndex: number, playheadIndex: number): number {\n const distance = chunkIndex - playheadIndex;\n if (distance >= 0) {\n return distance * forwardWeight;\n }\n return Math.abs(distance) * backwardWeight;\n }\n\n function updatePriorities(playheadIndex: number): void {\n currentChunkIdx = playheadIndex;\n queue.clear();\n\n for (const chunk of chunks) {\n if (\n chunk.state === \"pending\" ||\n chunk.state === \"queued\" ||\n chunk.state === \"failed\"\n ) {\n chunk.priority = calcPriority(chunk.index, playheadIndex);\n chunk.state = \"queued\";\n queue.enqueue(chunk);\n } else if (chunk.state === \"evicted\" && isInActiveWindow(chunk.index, playheadIndex)) {\n chunk.state = \"queued\";\n chunk.retryCount = 0;\n chunk.priority = calcPriority(chunk.index, playheadIndex);\n queue.enqueue(chunk);\n }\n }\n\n // Cancel converting chunks that are too far from playhead\n for (const chunk of chunks) {\n if (chunk.state === \"converting\") {\n const dist = Math.abs(chunk.index - playheadIndex);\n if (dist > cancelDistThreshold) {\n workerManager.cancelChunk(chunk.index);\n }\n }\n }\n }\n\n function dispatchNext(): void {\n if (disposed) return;\n\n while (workerManager.hasCapacity()) {\n let nextChunk = queue.dequeue();\n while (nextChunk && nextChunk.state === \"ready\") {\n nextChunk = queue.dequeue();\n }\n if (!nextChunk) return;\n\n if (\n nextChunk.state !== \"queued\" &&\n nextChunk.state !== \"pending\" &&\n nextChunk.state !== \"failed\"\n ) {\n continue;\n }\n\n nextChunk.state = \"converting\";\n const data = extractChunkData(nextChunk.index);\n workerManager.postConvert(\n nextChunk.index,\n data,\n currentTempo,\n sampleRate,\n );\n }\n }\n\n function handleResult(\n chunkIndex: number,\n outputData: Float32Array[],\n outputLength: number,\n ): void {\n const chunk = chunks[chunkIndex];\n if (!chunk) return;\n chunk.state = \"ready\";\n chunk.outputBuffer = outputData;\n chunk.outputLength = outputLength;\n onChunkReady?.(chunkIndex);\n dispatchNext();\n }\n\n function handleError(chunkIndex: number, error: string): void {\n const chunk = chunks[chunkIndex];\n if (!chunk) return;\n\n chunk.retryCount++;\n if (chunk.retryCount < MAX_CHUNK_RETRIES) {\n chunk.state = \"queued\";\n chunk.priority = calcPriority(chunk.index, currentChunkIdx);\n queue.enqueue(chunk);\n } else {\n chunk.state = \"failed\";\n onChunkFailed?.(chunkIndex, error);\n }\n dispatchNext();\n }\n\n function handleSeek(newChunkIndex: number): void {\n // Cancel converting chunks that are far from the new playhead\n for (const chunk of chunks) {\n if (chunk.state === \"converting\") {\n const dist = Math.abs(chunk.index - newChunkIndex);\n if (dist > cancelDistThreshold) {\n workerManager.cancelChunk(chunk.index);\n }\n }\n }\n\n updatePriorities(newChunkIndex);\n dispatchNext();\n }\n\n function handleTempoChange(newTempo: number): void {\n // Save current results as previous tempo cache (window内のみ保持)\n previousTempoCache = {\n tempo: currentTempo,\n chunks: chunks.map((c) => {\n if (isInActiveWindow(c.index, currentChunkIdx) && c.outputBuffer) {\n return { outputBuffer: c.outputBuffer, outputLength: c.outputLength };\n }\n return { outputBuffer: null, outputLength: 0 };\n }),\n };\n\n currentTempo = newTempo;\n workerManager.cancelCurrent();\n\n for (const chunk of chunks) {\n if (chunk.state === \"evicted\") continue;\n\n if (isInActiveWindow(chunk.index, currentChunkIdx)) {\n chunk.outputBuffer = null;\n chunk.outputLength = 0;\n chunk.state = \"pending\";\n chunk.retryCount = 0;\n } else {\n chunk.outputBuffer = null;\n chunk.outputLength = 0;\n chunk.state = \"evicted\";\n }\n }\n\n updatePriorities(currentChunkIdx);\n dispatchNext();\n }\n\n function restorePreviousTempo(): boolean {\n if (!previousTempoCache) return false;\n\n currentTempo = previousTempoCache.tempo;\n\n // Restore cached buffers\n for (let i = 0; i < chunks.length; i++) {\n const cached = previousTempoCache.chunks[i];\n const chunk = chunks[i];\n if (chunk && cached?.outputBuffer) {\n chunk.outputBuffer = cached.outputBuffer;\n chunk.outputLength = cached.outputLength;\n chunk.state = \"ready\";\n }\n }\n\n previousTempoCache = null;\n\n // Cancel all current conversions and re-evaluate remaining\n workerManager.cancelCurrent();\n\n updatePriorities(currentChunkIdx);\n dispatchNext();\n return true;\n }\n\n function start(playheadIndex: number): void {\n updatePriorities(playheadIndex);\n dispatchNext();\n }\n\n return {\n start,\n updatePriorities,\n handleSeek,\n handleTempoChange,\n restorePreviousTempo,\n dispatchNext,\n getChunks: () => chunks,\n dispose(): void {\n disposed = true;\n queue.clear();\n },\n // Expose internal handlers for the engine to wire up\n _handleResult: handleResult,\n _handleError: handleError,\n } as ConversionScheduler & {\n _handleResult: typeof handleResult;\n _handleError: typeof handleError;\n };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Chunk player with double-buffering and gapless playback\n// ---------------------------------------------------------------------------\n\nimport { CROSSFADE_SEC, LOOKAHEAD_INTERVAL_MS, LOOKAHEAD_THRESHOLD_SEC } from \"./constants.js\";\nimport type { ChunkPlayer, ChunkPlayerOptions } from \"./types.js\";\n\nconst CURVE_LENGTH = 256;\n\nfunction createEqualPowerCurve(fadeIn: boolean): Float32Array {\n const curve = new Float32Array(CURVE_LENGTH);\n for (let i = 0; i < CURVE_LENGTH; i++) {\n const t = i / (CURVE_LENGTH - 1);\n curve[i] = fadeIn ? Math.sin(t * Math.PI / 2) : Math.cos(t * Math.PI / 2);\n }\n return curve;\n}\n\nconst fadeInCurve = createEqualPowerCurve(true);\nconst fadeOutCurve = createEqualPowerCurve(false);\n\n/**\n * Create a chunk player that manages gapless playback of converted chunks.\n */\nexport function createChunkPlayer(\n ctx: AudioContext,\n options: ChunkPlayerOptions,\n): ChunkPlayer {\n const destination = options.destination ?? ctx.destination;\n const through = options.through ?? [];\n const crossfadeSec = options.crossfadeSec ?? CROSSFADE_SEC;\n\n let currentSource: AudioBufferSourceNode | null = null;\n let nextSource: AudioBufferSourceNode | null = null;\n let currentGain: GainNode | null = null;\n let nextGain: GainNode | null = null;\n\n // Position tracking\n let playStartCtxTime = 0; // ctx.currentTime when playback started\n let playStartOffset = 0; // offset within the chunk at start\n let currentChunkDuration = 0;\n let paused = false;\n let pausedPosition = 0;\n let stopped = true;\n\n let lookaheadTimer: ReturnType<typeof setInterval> | null = null;\n let transitionTimerId: ReturnType<typeof setTimeout> | null = null;\n let onChunkEnded: (() => void) | null = null;\n let onNeedNext: (() => void) | null = null;\n let onTransition: (() => void) | null = null;\n let disposed = false;\n\n function connectToDestination(node: AudioNode): void {\n if (through.length > 0) {\n node.connect(through[0]!);\n for (let i = 0; i < through.length - 1; i++) {\n through[i]!.connect(through[i + 1]!);\n }\n through[through.length - 1]!.connect(destination);\n } else {\n node.connect(destination);\n }\n }\n\n function createSourceFromBuffer(\n buffer: AudioBuffer,\n gain: GainNode,\n ): AudioBufferSourceNode {\n const src = ctx.createBufferSource();\n src.buffer = buffer;\n src.connect(gain);\n connectToDestination(gain);\n return src;\n }\n\n function stopCurrentSource(): void {\n if (currentSource) {\n currentSource.onended = null;\n try {\n currentSource.stop();\n } catch {\n // Already stopped\n }\n currentSource.disconnect();\n currentSource = null;\n }\n if (currentGain) {\n currentGain.disconnect();\n currentGain = null;\n }\n }\n\n function stopNextSource(): void {\n if (nextSource) {\n nextSource.onended = null;\n try {\n nextSource.stop();\n } catch {\n // Already stopped\n }\n nextSource.disconnect();\n nextSource = null;\n }\n if (nextGain) {\n nextGain.disconnect();\n nextGain = null;\n }\n }\n\n function startLookahead(): void {\n if (lookaheadTimer !== null) return;\n lookaheadTimer = setInterval(() => {\n if (paused || stopped || disposed) return;\n\n const pos = getElapsedInChunk();\n const remaining = currentChunkDuration - pos;\n\n if (remaining <= LOOKAHEAD_THRESHOLD_SEC && !nextSource) {\n onNeedNext?.();\n }\n }, LOOKAHEAD_INTERVAL_MS);\n }\n\n function stopLookahead(): void {\n if (lookaheadTimer !== null) {\n clearInterval(lookaheadTimer);\n lookaheadTimer = null;\n }\n }\n\n function cancelTransition(): void {\n if (transitionTimerId !== null) {\n clearTimeout(transitionTimerId);\n transitionTimerId = null;\n }\n }\n\n function getElapsedInChunk(): number {\n if (paused) return pausedPosition;\n if (stopped) return 0;\n return (ctx.currentTime - playStartCtxTime) + playStartOffset;\n }\n\n function playChunk(\n buffer: AudioBuffer,\n _startTime: number,\n offsetInChunk: number = 0,\n ): void {\n cancelTransition();\n stopCurrentSource();\n stopNextSource();\n\n currentGain = ctx.createGain();\n currentSource = createSourceFromBuffer(buffer, currentGain);\n currentChunkDuration = buffer.duration;\n playStartOffset = offsetInChunk;\n playStartCtxTime = ctx.currentTime;\n paused = false;\n stopped = false;\n\n currentSource.onended = () => {\n if (!disposed && !paused && !stopped) {\n onChunkEnded?.();\n }\n };\n\n currentSource.start(0, offsetInChunk);\n\n // Apply equal-power fade-in\n if (crossfadeSec > 0) {\n currentGain.gain.setValueCurveAtTime(fadeInCurve, ctx.currentTime, crossfadeSec);\n }\n\n startLookahead();\n }\n\n function scheduleNext(buffer: AudioBuffer, startTime: number): void {\n if (disposed) return;\n\n stopNextSource();\n\n nextGain = ctx.createGain();\n nextSource = createSourceFromBuffer(buffer, nextGain);\n\n nextSource.onended = () => {\n if (!disposed && !paused && !stopped) {\n onChunkEnded?.();\n }\n };\n\n nextSource.start(startTime - crossfadeSec);\n\n // Equal-power crossfade: fade out current, fade in next\n if (crossfadeSec > 0 && currentGain) {\n currentGain.gain.setValueCurveAtTime(fadeOutCurve, startTime - crossfadeSec, crossfadeSec);\n nextGain.gain.setValueCurveAtTime(fadeInCurve, startTime - crossfadeSec, crossfadeSec);\n }\n\n // After transition, promote next to current\n const transitionDelay = Math.max(\n 0,\n (startTime - ctx.currentTime) * 1000 + 50,\n );\n cancelTransition();\n transitionTimerId = setTimeout(() => {\n transitionTimerId = null;\n if (disposed) return;\n stopCurrentSource();\n currentSource = nextSource;\n currentGain = nextGain;\n nextSource = null;\n nextGain = null;\n\n currentChunkDuration = buffer.duration;\n playStartOffset = 0;\n playStartCtxTime = startTime - crossfadeSec;\n\n onTransition?.();\n }, transitionDelay);\n }\n\n function handleSeek(buffer: AudioBuffer, offsetInChunk: number): void {\n playChunk(buffer, 0, offsetInChunk);\n }\n\n function pause(): void {\n if (paused || stopped || disposed) return;\n pausedPosition = getElapsedInChunk();\n paused = true;\n cancelTransition();\n stopCurrentSource();\n stopNextSource();\n stopLookahead();\n }\n\n function resume(): void {\n // Resume needs a new buffer — the engine will call playChunk again.\n // paused フラグは playChunk() が解除する。\n if (!paused || disposed) return;\n }\n\n function stop(): void {\n if (stopped || disposed) return;\n stopped = true;\n paused = false;\n pausedPosition = 0;\n cancelTransition();\n stopCurrentSource();\n stopNextSource();\n stopLookahead();\n }\n\n function getCurrentPosition(): number {\n return getElapsedInChunk();\n }\n\n function hasNextScheduled(): boolean {\n return nextSource !== null;\n }\n\n return {\n playChunk,\n scheduleNext,\n hasNextScheduled,\n handleSeek,\n pause,\n resume,\n stop,\n getCurrentPosition,\n setOnChunkEnded(callback: () => void): void {\n onChunkEnded = callback;\n },\n setOnNeedNext(callback: () => void): void {\n onNeedNext = callback;\n },\n setOnTransition(callback: () => void): void {\n onTransition = callback;\n },\n dispose(): void {\n if (disposed) return;\n disposed = true;\n cancelTransition();\n stopCurrentSource();\n stopNextSource();\n stopLookahead();\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Buffer health monitor\n// ---------------------------------------------------------------------------\n\nimport {\n BUFFER_HEALTHY_SEC,\n BUFFER_LOW_SEC,\n BUFFER_CRITICAL_SEC,\n BUFFER_RESUME_SEC,\n CHUNK_DURATION_SEC,\n} from \"./constants.js\";\nimport type { BufferHealth, BufferMonitor, BufferMonitorOptions, ChunkInfo } from \"./types.js\";\n\n/**\n * Create a buffer health monitor with hysteresis.\n */\nexport function createBufferMonitor(\n options?: Partial<BufferMonitorOptions>,\n): BufferMonitor {\n const healthySec = options?.healthySec ?? BUFFER_HEALTHY_SEC;\n const lowSec = options?.lowSec ?? BUFFER_LOW_SEC;\n const criticalSec = options?.criticalSec ?? BUFFER_CRITICAL_SEC;\n const resumeSec = options?.resumeSec ?? BUFFER_RESUME_SEC;\n const chunkDurSec = options?.chunkDurationSec ?? CHUNK_DURATION_SEC;\n\n function getAheadSeconds(\n currentChunkIndex: number,\n chunks: ChunkInfo[],\n ): number {\n let aheadSec = 0;\n for (let i = currentChunkIndex; i < chunks.length; i++) {\n const chunk = chunks[i];\n if (!chunk || chunk.state !== \"ready\") break;\n aheadSec += chunkDurSec;\n }\n return aheadSec;\n }\n\n function getHealth(\n currentChunkIndex: number,\n chunks: ChunkInfo[],\n ): BufferHealth {\n const ahead = getAheadSeconds(currentChunkIndex, chunks);\n\n if (ahead >= healthySec) return \"healthy\";\n if (ahead >= lowSec) return \"low\";\n if (ahead >= criticalSec) return \"critical\";\n return \"empty\";\n }\n\n function shouldEnterBuffering(\n currentChunkIndex: number,\n chunks: ChunkInfo[],\n ): boolean {\n const ahead = getAheadSeconds(currentChunkIndex, chunks);\n if (ahead >= criticalSec) return false;\n\n // Also check if the next chunk is ready\n const nextChunk = chunks[currentChunkIndex + 1];\n if (nextChunk && nextChunk.state === \"ready\") return false;\n\n // Current chunk must not be ready either (if we're at the boundary)\n const currentChunk = chunks[currentChunkIndex];\n if (!currentChunk || currentChunk.state !== \"ready\") return true;\n\n return ahead < criticalSec;\n }\n\n function shouldExitBuffering(\n currentChunkIndex: number,\n chunks: ChunkInfo[],\n ): boolean {\n // カレントチャンクが ready でなければ buffering を抜けない\n const currentChunk = chunks[currentChunkIndex];\n if (!currentChunk || currentChunk.state !== \"ready\") return false;\n\n const ahead = getAheadSeconds(currentChunkIndex, chunks);\n if (ahead >= resumeSec) return true;\n\n // Also exit if the next chunk has become ready\n const nextChunk = chunks[currentChunkIndex + 1];\n if (nextChunk && nextChunk.state === \"ready\") return true;\n\n // If all chunks are done\n const allReady = chunks.every(\n (c) => c.state === \"ready\" || c.state === \"skipped\",\n );\n if (allReady) return true;\n\n return false;\n }\n\n return {\n getHealth,\n getAheadSeconds,\n shouldEnterBuffering,\n shouldExitBuffering,\n };\n}\n","// ---------------------------------------------------------------------------\n// Stretcher: Engine — integrates all components\n// ---------------------------------------------------------------------------\n\nimport { createEmitter } from \"../emitter.js\";\nimport { CHUNK_DURATION_SEC, OVERLAP_SEC, CROSSFADE_SEC, KEEP_AHEAD_CHUNKS, KEEP_AHEAD_SECONDS, KEEP_BEHIND_CHUNKS, KEEP_BEHIND_SECONDS, WORKER_POOL_SIZE, LOOKAHEAD_THRESHOLD_SEC } from \"./constants.js\";\nimport { splitIntoChunks, extractChunkData, getChunkIndexForTime } from \"./chunk-splitter.js\";\nimport { createWorkerManager } from \"./worker-manager.js\";\nimport { createMainThreadProcessor } from \"./main-thread-processor.js\";\nimport { createConversionScheduler } from \"./conversion-scheduler.js\";\nimport { createChunkPlayer } from \"./chunk-player.js\";\nimport { createBufferMonitor } from \"./buffer-monitor.js\";\nimport { createConversionEstimator } from \"./conversion-estimator.js\";\nimport type {\n ChunkInfo,\n StretcherEngine,\n StretcherEngineOptions,\n StretcherEvents,\n StretcherPlaybackState,\n StretcherSnapshotExtension,\n StretcherStatus,\n WorkerManager,\n WorkerResponse,\n} from \"./types.js\";\n\n/**\n * Trim overlap regions from WSOLA output so adjacent chunks don't double-play.\n */\nfunction trimOverlap(\n outputData: Float32Array[],\n outputLength: number,\n chunk: ChunkInfo,\n sampleRate: number,\n): { data: Float32Array[]; length: number } {\n const inputLength = chunk.inputEndSample - chunk.inputStartSample;\n if (inputLength === 0 || outputLength === 0) {\n return { data: outputData, length: outputLength };\n }\n\n const ratio = outputLength / inputLength;\n const crossfadeKeep = Math.round(CROSSFADE_SEC * sampleRate);\n const overlapBeforeOutput = Math.round(chunk.overlapBefore * ratio);\n const overlapAfterOutput = Math.round(chunk.overlapAfter * ratio);\n const keepBefore = chunk.overlapBefore > 0 ? Math.min(crossfadeKeep, overlapBeforeOutput) : 0;\n const trimStart = overlapBeforeOutput - keepBefore;\n const trimEnd = overlapAfterOutput;\n const newLength = outputLength - trimStart - trimEnd;\n\n if (newLength <= 0) {\n return { data: outputData, length: outputLength };\n }\n\n return {\n data: outputData.map(ch => ch.slice(trimStart, trimStart + newLength)),\n length: newLength,\n };\n}\n\nfunction getCrossfadeStart(chunk: ChunkInfo): number {\n return chunk.overlapBefore > 0 ? CROSSFADE_SEC : 0;\n}\n\n/**\n * Create the stretcher engine that orchestrates all components.\n */\nexport function createStretcherEngine(\n ctx: AudioContext,\n buffer: AudioBuffer,\n options: StretcherEngineOptions,\n): StretcherEngine {\n const {\n tempo: initialTempo,\n offset = 0,\n loop: initialLoop = false,\n through = [],\n destination = ctx.destination,\n } = options;\n\n const emitter = createEmitter<StretcherEvents>();\n const sampleRate = buffer.sampleRate;\n const totalDuration = buffer.duration;\n\n // State\n let phase: StretcherPlaybackState = \"waiting\";\n let currentTempo = initialTempo;\n let isLooping = initialLoop;\n let disposed = false;\n let bufferingStartTime = 0;\n let currentChunkIndex = 0;\n let bufferingResumePosition: number | null = null;\n\n // Memory management window\n const keepAhead = Math.max(KEEP_AHEAD_CHUNKS, Math.ceil(KEEP_AHEAD_SECONDS / CHUNK_DURATION_SEC));\n const keepBehind = Math.max(KEEP_BEHIND_CHUNKS, Math.ceil(KEEP_BEHIND_SECONDS / CHUNK_DURATION_SEC));\n\n // Split buffer into chunks\n const chunks = splitIntoChunks(\n buffer.length,\n sampleRate,\n CHUNK_DURATION_SEC,\n OVERLAP_SEC,\n );\n\n // Estimator\n const estimator = createConversionEstimator();\n\n // Buffer monitor\n const monitor = createBufferMonitor();\n\n // Worker manager (with main-thread fallback)\n const poolSize = options.workerPoolSize ?? WORKER_POOL_SIZE;\n\n function handleWorkerResult(response: WorkerResponse): void {\n if (disposed) return;\n if (response.type === \"result\") {\n const chunk = chunks[response.chunkIndex];\n if (chunk) {\n const postTime = workerManager.getPostTimeForChunk(response.chunkIndex);\n const elapsed = postTime !== null ? performance.now() - postTime : 0;\n estimator.recordConversion(elapsed);\n const trimmed = trimOverlap(\n response.outputData!,\n response.outputLength!,\n chunk,\n sampleRate,\n );\n schedulerInternal._handleResult(\n response.chunkIndex,\n trimmed.data,\n trimmed.length,\n );\n }\n } else if (response.type === \"cancelled\") {\n const chunk = chunks[response.chunkIndex];\n if (chunk && chunk.state === \"converting\") {\n chunk.state = \"queued\";\n }\n scheduler.dispatchNext();\n }\n }\n\n function handleWorkerError(response: WorkerResponse): void {\n if (disposed) return;\n if (response.type === \"error\") {\n schedulerInternal._handleError(\n response.chunkIndex,\n response.error ?? \"Unknown error\",\n );\n }\n }\n\n function switchToMainThread(): void {\n if (disposed) return;\n const fallback = createMainThreadProcessor(handleWorkerResult, handleWorkerError);\n // Replace the workerManager reference\n workerManager.terminate();\n Object.assign(workerManager, fallback);\n }\n\n const workerManager: WorkerManager = createWorkerManager(\n handleWorkerResult,\n handleWorkerError,\n undefined,\n poolSize,\n switchToMainThread,\n );\n\n // Conversion scheduler\n const schedulerInternal = createConversionScheduler(\n chunks,\n workerManager,\n (chunkIndex: number) => extractChunkData(buffer, chunks[chunkIndex]!),\n sampleRate,\n currentTempo,\n { keepAheadChunks: keepAhead, keepBehindChunks: keepBehind },\n onChunkReady,\n onChunkFailed,\n ) as ReturnType<typeof createConversionScheduler>;\n const scheduler = schedulerInternal;\n\n // Chunk player\n const chunkPlayer = createChunkPlayer(ctx, {\n through,\n destination,\n crossfadeSec: CROSSFADE_SEC,\n });\n\n chunkPlayer.setOnChunkEnded(() => {\n if (disposed || phase === \"paused\" || phase === \"ended\") return;\n advanceToNextChunk();\n });\n\n chunkPlayer.setOnNeedNext(() => {\n if (disposed) return;\n const nextIdx = currentChunkIndex + 1;\n if (nextIdx < chunks.length) {\n const nextChunk = chunks[nextIdx]!;\n if (nextChunk.state === \"ready\" && nextChunk.outputBuffer) {\n const audioBuffer = createAudioBufferFromChunk(nextChunk);\n if (audioBuffer) {\n const curChunk = chunks[currentChunkIndex];\n const curOutputDuration = curChunk\n ? curChunk.outputLength / sampleRate\n : 0;\n const elapsed = chunkPlayer.getCurrentPosition();\n const remaining = curOutputDuration - elapsed;\n const startTime = ctx.currentTime + Math.max(0, remaining);\n chunkPlayer.scheduleNext(audioBuffer, startTime);\n }\n }\n }\n });\n\n chunkPlayer.setOnTransition(() => {\n if (disposed) return;\n // scheduleNext の transition 完了: chunk N+1 が current に昇格した\n const nextIdx = currentChunkIndex + 1;\n if (nextIdx < chunks.length) {\n currentChunkIndex = nextIdx;\n scheduler.updatePriorities(currentChunkIndex);\n evictDistantChunks();\n }\n });\n\n // --- Callbacks ---\n\n function onChunkReady(chunkIndex: number): void {\n if (disposed) return;\n\n emitter.emit(\"chunkready\", { index: chunkIndex });\n emitProgress();\n emitBufferHealth();\n\n // If we're waiting or buffering and enough chunks are ready, start/resume\n if (phase === \"waiting\" || phase === \"buffering\") {\n if (monitor.shouldExitBuffering(currentChunkIndex, chunks)) {\n exitBuffering();\n }\n }\n\n // Proactively schedule next chunk when it becomes ready (background tab resilience)\n if (phase === \"playing\" && chunkIndex === currentChunkIndex + 1) {\n if (!chunkPlayer.hasNextScheduled()) {\n const curChunk = chunks[currentChunkIndex];\n const curOutputDuration = curChunk\n ? curChunk.outputLength / sampleRate\n : 0;\n const elapsed = chunkPlayer.getCurrentPosition();\n const remaining = curOutputDuration - elapsed;\n\n if (remaining <= LOOKAHEAD_THRESHOLD_SEC) {\n const nextChunk = chunks[chunkIndex];\n if (nextChunk && nextChunk.outputBuffer) {\n const audioBuffer = createAudioBufferFromChunk(nextChunk);\n if (audioBuffer) {\n const startTime = ctx.currentTime + Math.max(0, remaining);\n chunkPlayer.scheduleNext(audioBuffer, startTime);\n }\n }\n }\n }\n }\n\n // Check if all chunks are done\n const allDone = chunks.every(\n (c) => c.state === \"ready\" || c.state === \"skipped\" || c.state === \"evicted\",\n );\n if (allDone) {\n emitter.emit(\"complete\", undefined as never);\n }\n\n evictDistantChunks();\n }\n\n function onChunkFailed(chunkIndex: number, error: string): void {\n if (disposed) return;\n const chunk = chunks[chunkIndex];\n const fatal = chunk ? chunk.retryCount >= 3 : true;\n emitter.emit(\"error\", { message: error, chunkIndex, fatal });\n }\n\n // --- Playback helpers ---\n\n function createAudioBufferFromChunk(chunk: ChunkInfo): AudioBuffer | null {\n if (!chunk.outputBuffer || chunk.outputLength === 0) return null;\n\n const numChannels = chunk.outputBuffer.length;\n const audioBuf = ctx.createBuffer(\n numChannels,\n chunk.outputLength,\n sampleRate,\n );\n\n for (let ch = 0; ch < numChannels; ch++) {\n const channelData = chunk.outputBuffer[ch]!;\n audioBuf.getChannelData(ch).set(channelData.subarray(0, chunk.outputLength));\n }\n\n return audioBuf;\n }\n\n function playCurrentChunk(offsetInBuffer: number = 0): void {\n const chunk = chunks[currentChunkIndex];\n if (!chunk || chunk.state !== \"ready\" || !chunk.outputBuffer) return;\n\n const audioBuf = createAudioBufferFromChunk(chunk);\n if (!audioBuf) return;\n\n chunkPlayer.playChunk(audioBuf, ctx.currentTime, offsetInBuffer);\n }\n\n function advanceToNextChunk(): void {\n const nextIdx = currentChunkIndex + 1;\n if (nextIdx >= chunks.length) {\n if (isLooping) {\n currentChunkIndex = 0;\n scheduler.handleSeek(0);\n const chunk = chunks[0];\n if (chunk && chunk.state === \"ready\") {\n playCurrentChunk();\n } else {\n bufferingResumePosition = 0;\n enterBuffering(\"seek\");\n }\n emitter.emit(\"loop\", undefined as never);\n evictDistantChunks();\n return;\n }\n // Reached the end\n phase = \"ended\";\n chunkPlayer.stop();\n emitter.emit(\"ended\", undefined as never);\n emitter.emit(\"bufferhealth\", {\n health: monitor.getHealth(currentChunkIndex, chunks),\n aheadSeconds: monitor.getAheadSeconds(currentChunkIndex, chunks),\n });\n return;\n }\n\n currentChunkIndex = nextIdx;\n scheduler.updatePriorities(currentChunkIndex);\n\n const chunk = chunks[currentChunkIndex];\n if (chunk && chunk.state === \"ready\") {\n playCurrentChunk(getCrossfadeStart(chunk));\n } else {\n const nextChunk = chunks[currentChunkIndex]!;\n const nominalStartSample = nextChunk.inputStartSample + nextChunk.overlapBefore;\n bufferingResumePosition = nominalStartSample / sampleRate;\n enterBuffering(\"underrun\");\n }\n\n evictDistantChunks();\n }\n\n function enterBuffering(\n reason: \"initial\" | \"seek\" | \"tempo-change\" | \"underrun\",\n ): void {\n if (phase === \"ended\") return;\n // Allow re-entering buffering for tempo-change and seek even if already buffering\n if (phase === \"buffering\" && reason !== \"tempo-change\" && reason !== \"seek\") return;\n phase = \"buffering\";\n bufferingStartTime = performance.now();\n chunkPlayer.pause();\n emitter.emit(\"buffering\", { reason });\n }\n\n function exitBuffering(): void {\n const stallDuration = performance.now() - bufferingStartTime;\n phase = \"playing\";\n emitter.emit(\"buffered\", { stallDuration });\n\n if (bufferingResumePosition !== null) {\n const resumePos = bufferingResumePosition;\n bufferingResumePosition = null;\n\n const chunk = chunks[currentChunkIndex];\n if (chunk && chunk.state === \"ready\" && chunk.outputBuffer) {\n const nominalStartSample = chunk.inputStartSample + chunk.overlapBefore;\n const nominalStartSec = nominalStartSample / sampleRate;\n const offsetInOriginal = resumePos - nominalStartSec;\n const offsetInOutput = Math.max(0, offsetInOriginal / currentTempo);\n const outputDurationSec = chunk.outputLength / sampleRate;\n\n const MIN_PLAYABLE_SEC = 0.05;\n if (outputDurationSec > 0 && offsetInOutput >= outputDurationSec - MIN_PLAYABLE_SEC) {\n advanceToNextChunk();\n return;\n }\n\n playCurrentChunk(getCrossfadeStart(chunk) + offsetInOutput);\n } else {\n const cfChunk = chunks[currentChunkIndex];\n const cfStart = cfChunk ? getCrossfadeStart(cfChunk) : 0;\n playCurrentChunk(cfStart);\n }\n } else {\n const chunk = chunks[currentChunkIndex];\n const cfStart = chunk ? getCrossfadeStart(chunk) : 0;\n playCurrentChunk(cfStart);\n }\n }\n\n // --- Memory management ---\n\n function evictDistantChunks(): void {\n for (const chunk of chunks) {\n if (chunk.state !== \"ready\") continue;\n\n const dist = chunk.index - currentChunkIndex;\n if (dist > keepAhead || dist < -keepBehind) {\n chunk.outputBuffer = null;\n chunk.outputLength = 0;\n chunk.state = \"evicted\";\n }\n }\n }\n\n // --- Status & events ---\n\n function emitProgress(): void {\n const readyCount = chunks.filter((c) => c.state === \"ready\").length;\n const total = chunks.length;\n emitter.emit(\"progress\", {\n total,\n ready: readyCount,\n progress: total > 0 ? readyCount / total : 0,\n });\n }\n\n function emitBufferHealth(): void {\n emitter.emit(\"bufferhealth\", {\n health: monitor.getHealth(currentChunkIndex, chunks),\n aheadSeconds: monitor.getAheadSeconds(currentChunkIndex, chunks),\n });\n }\n\n function getPositionInOriginalBuffer(): number {\n if (phase === \"ended\") return totalDuration;\n if (phase === \"waiting\") return offset;\n if (phase === \"buffering\" && bufferingResumePosition !== null) {\n return bufferingResumePosition;\n }\n\n const chunk = chunks[currentChunkIndex];\n if (!chunk) return 0;\n\n // Nominal start time of this chunk in the original buffer\n const nominalStartSample = chunk.inputStartSample + chunk.overlapBefore;\n const nominalStartSec = nominalStartSample / sampleRate;\n\n // Position within the current chunk (in output time)\n const posInChunk = chunkPlayer.getCurrentPosition();\n\n // Subtract the crossfade overlap kept at the start of non-first chunks\n const crossfadeOffset = chunk.overlapBefore > 0 ? CROSSFADE_SEC : 0;\n const adjustedPosInChunk = Math.max(0, posInChunk - crossfadeOffset);\n\n // Convert output position back to original buffer time\n // output duration = input duration / tempo\n const posInOriginal = adjustedPosInChunk * currentTempo;\n\n return Math.min(nominalStartSec + posInOriginal, totalDuration);\n }\n\n function getStatus(): StretcherStatus {\n const readyCount = chunks.filter((c) => c.state === \"ready\").length;\n const convertingCount = chunks.filter(\n (c) => c.state === \"converting\",\n ).length;\n const total = chunks.length;\n\n return {\n phase,\n conversion: {\n total,\n ready: readyCount,\n converting: convertingCount,\n progress: total > 0 ? readyCount / total : 0,\n },\n buffer: {\n health: monitor.getHealth(currentChunkIndex, chunks),\n aheadSeconds: monitor.getAheadSeconds(currentChunkIndex, chunks),\n },\n playback: {\n position: getPositionInOriginalBuffer(),\n duration: totalDuration,\n tempo: currentTempo,\n },\n };\n }\n\n function getSnapshot(): StretcherSnapshotExtension {\n const readyCount = chunks.filter((c) => c.state === \"ready\").length;\n const total = chunks.length;\n const convertingCount = chunks.filter(\n (c) => c.state === \"converting\",\n ).length;\n\n const windowStart = Math.max(0, currentChunkIndex - keepBehind);\n const windowEnd = Math.min(total - 1, currentChunkIndex + keepAhead);\n const windowSize = windowEnd - windowStart + 1;\n const readyInWindow = chunks\n .slice(windowStart, windowEnd + 1)\n .filter((c) => c.state === \"ready\").length;\n\n return {\n tempo: currentTempo,\n converting: convertingCount > 0,\n conversionProgress: total > 0 ? readyCount / total : 0,\n bufferHealth: monitor.getHealth(currentChunkIndex, chunks),\n aheadSeconds: monitor.getAheadSeconds(currentChunkIndex, chunks),\n buffering: phase === \"buffering\" || phase === \"waiting\",\n chunkStates: chunks.map((c) => c.state),\n currentChunkIndex,\n activeWindowStart: windowStart,\n activeWindowEnd: windowEnd,\n totalChunks: total,\n windowConversionProgress: windowSize > 0 ? readyInWindow / windowSize : 0,\n };\n }\n\n // --- Public API ---\n\n function start(): void {\n if (disposed) return;\n\n currentChunkIndex = getChunkIndexForTime(chunks, offset, sampleRate);\n bufferingResumePosition = offset;\n phase = \"waiting\";\n enterBuffering(\"initial\");\n\n scheduler.start(currentChunkIndex);\n }\n\n function pause(): void {\n if (disposed || phase === \"ended\") return;\n phase = \"paused\";\n chunkPlayer.pause();\n }\n\n function resume(): void {\n if (disposed || phase !== \"paused\") return;\n\n const chunk = chunks[currentChunkIndex];\n if (chunk && chunk.state === \"ready\") {\n const resumePosition = chunkPlayer.getCurrentPosition();\n phase = \"playing\";\n chunkPlayer.resume();\n playCurrentChunk(resumePosition);\n } else {\n enterBuffering(\"underrun\");\n }\n }\n\n function seek(position: number): void {\n if (disposed) return;\n\n const clamped = Math.max(0, Math.min(position, totalDuration));\n const newChunkIdx = getChunkIndexForTime(chunks, clamped, sampleRate);\n currentChunkIndex = newChunkIdx;\n\n scheduler.handleSeek(newChunkIdx);\n\n const chunk = chunks[newChunkIdx];\n if (chunk && chunk.state === \"ready\") {\n // Calculate offset within the chunk\n const nominalStartSample =\n chunk.inputStartSample + chunk.overlapBefore;\n const nominalStartSec = nominalStartSample / sampleRate;\n const offsetInOriginal = clamped - nominalStartSec;\n const offsetInOutput = offsetInOriginal / currentTempo;\n\n if (phase === \"playing\" || phase === \"buffering\" || phase === \"waiting\") {\n phase = \"playing\";\n const audioBuf = createAudioBufferFromChunk(chunk);\n if (audioBuf) {\n const crossfadeStart = getCrossfadeStart(chunk);\n const bufferOffset = crossfadeStart + offsetInOutput;\n const clampedOffset = Math.min(Math.max(0, bufferOffset), audioBuf.duration - 0.001);\n chunkPlayer.handleSeek(audioBuf, clampedOffset);\n }\n }\n } else {\n bufferingResumePosition = clamped;\n enterBuffering(\"seek\");\n }\n }\n\n function stop(): void {\n if (disposed) return;\n phase = \"ended\";\n chunkPlayer.stop();\n }\n\n function setLoop(value: boolean): void {\n isLooping = value;\n }\n\n function setTempo(newTempo: number): void {\n if (disposed || phase === \"ended\" || newTempo === currentTempo) return;\n bufferingResumePosition = getPositionInOriginalBuffer();\n currentChunkIndex = getChunkIndexForTime(chunks, bufferingResumePosition, sampleRate);\n currentTempo = newTempo;\n enterBuffering(\"tempo-change\");\n scheduler.updatePriorities(currentChunkIndex);\n scheduler.handleTempoChange(newTempo);\n }\n\n function dispose(): void {\n if (disposed) return;\n disposed = true;\n chunkPlayer.dispose();\n scheduler.dispose();\n workerManager.terminate();\n emitter.clear();\n }\n\n return {\n start,\n pause,\n resume,\n seek,\n stop,\n setTempo,\n setLoop,\n getCurrentPosition: getPositionInOriginalBuffer,\n getStatus,\n getSnapshot,\n on: emitter.on.bind(emitter) as StretcherEngine[\"on\"],\n off: emitter.off.bind(emitter) as StretcherEngine[\"off\"],\n dispose,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/context.ts"],"names":[],"mappings":";AAaO,SAAS,cAAc,OAAA,EAA8C;AAC1E,EAAA,OAAO,IAAI,YAAA,CAAa;AAAA,IACtB,YAAY,OAAA,EAAS,UAAA;AAAA,IACrB,aAAa,OAAA,EAAS;AAAA,GACvB,CAAA;AACH;AAQA,eAAsB,cAAc,GAAA,EAAkC;AACpE,EAAA,IAAI,GAAA,CAAI,UAAU,WAAA,EAAa;AAC7B,IAAA,MAAM,IAAI,MAAA,EAAO;AAAA,EACnB;AACF;AAKA,eAAsB,cAAc,GAAA,EAAkC;AACpE,EAAA,IAAI,GAAA,CAAI,UAAU,SAAA,EAAW;AAC3B,IAAA,MAAM,IAAI,MAAA,EAAO;AAAA,EACnB;AACF;AAKO,SAAS,IAAI,GAAA,EAA2B;AAC7C,EAAA,OAAO,GAAA,CAAI,WAAA;AACb","file":"chunk-37CPPRLV.js","sourcesContent":["// ---------------------------------------------------------------------------\n// M1: AudioContext utilities\n// ---------------------------------------------------------------------------\n\nimport type { CreateContextOptions } from \"./types.js\";\n\n/**\n * Create an `AudioContext` with optional configuration.\n *\n * This is the only place in the library where `new AudioContext()` is called.\n * Users are encouraged to create their own context and pass it to other\n * functions — this helper exists purely for convenience.\n */\nexport function createContext(options?: CreateContextOptions): AudioContext {\n return new AudioContext({\n sampleRate: options?.sampleRate,\n latencyHint: options?.latencyHint,\n });\n}\n\n/**\n * Resume a suspended AudioContext (e.g. blocked by autoplay policy).\n *\n * Should be called inside a user-interaction event handler (click, keydown…)\n * if the context is in the `\"suspended\"` state.\n */\nexport async function resumeContext(ctx: AudioContext): Promise<void> {\n if (ctx.state === \"suspended\") {\n await ctx.resume();\n }\n}\n\n/**\n * Ensure the context is in the `\"running\"` state, resuming if necessary.\n */\nexport async function ensureRunning(ctx: AudioContext): Promise<void> {\n if (ctx.state !== \"running\") {\n await ctx.resume();\n }\n}\n\n/**\n * Shorthand for `ctx.currentTime`.\n */\nexport function now(ctx: AudioContext): number {\n return ctx.currentTime;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/fade.ts"],"names":[],"mappings":"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","file":"chunk-4LNVRSTM.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// M7: Fade utilities\n// ---------------------------------------------------------------------------\n\nimport type {\n AutoFadeOptions,\n CrossfadeOptions,\n FadeCurve,\n FadeOptions,\n Playback,\n} from \"./types.js\";\n\n/** Minimum value used for exponential ramps (cannot ramp to/from 0). */\nconst EXP_MIN = 0.0001;\n\nfunction applyRamp(\n node: GainNode,\n from: number,\n to: number,\n duration: number,\n curve: FadeCurve,\n): void {\n const param = node.gain;\n const now = node.context.currentTime;\n param.cancelScheduledValues(now);\n param.setValueAtTime(from, now);\n\n switch (curve) {\n case \"exponential\":\n param.exponentialRampToValueAtTime(\n Math.max(to, EXP_MIN),\n now + duration,\n );\n break;\n case \"equal-power\": {\n // Approximate equal-power with a setValueCurveAtTime.\n const steps = Math.max(Math.ceil(duration * 100), 2);\n const values = new Float32Array(steps);\n for (let i = 0; i < steps; i++) {\n const t = i / (steps - 1);\n const gain = from + (to - from) * Math.sin((t * Math.PI) / 2);\n values[i] = gain;\n }\n param.setValueCurveAtTime(values, now, duration);\n break;\n }\n case \"linear\":\n default:\n param.linearRampToValueAtTime(to, now + duration);\n break;\n }\n}\n\n/**\n * Fade a `GainNode` in from 0 to `target`.\n */\nexport function fadeIn(\n gain: GainNode,\n target: number,\n options?: FadeOptions,\n): void {\n const { duration = 1, curve = \"linear\" } = options ?? {};\n applyRamp(gain, 0, target, duration, curve);\n}\n\n/**\n * Fade a `GainNode` out to 0.\n */\nexport function fadeOut(gain: GainNode, options?: FadeOptions): void {\n const { duration = 1, curve = \"linear\" } = options ?? {};\n applyRamp(gain, gain.gain.value, 0, duration, curve);\n}\n\n/**\n * Crossfade between two `GainNode`s.\n */\nexport function crossfade(\n gainA: GainNode,\n gainB: GainNode,\n options?: CrossfadeOptions,\n): void {\n const { duration = 1, curve = \"linear\" } = options ?? {};\n applyRamp(gainA, gainA.gain.value, 0, duration, curve);\n applyRamp(gainB, 0, gainA.gain.value || 1, duration, curve);\n}\n\n/**\n * Automatically apply fade-in at start and/or fade-out near end of a Playback.\n * Returns a cleanup function.\n */\nexport function autoFade(\n playback: Playback,\n gain: GainNode,\n options?: AutoFadeOptions,\n): () => void {\n const {\n fadeIn: fadeInDuration = 0,\n fadeOut: fadeOutDuration = 0,\n curve = \"linear\",\n } = options ?? {};\n\n const duration = playback.getDuration();\n let fadeOutScheduled = false;\n\n // Apply fade-in immediately if playing from the start.\n if (fadeInDuration > 0) {\n applyRamp(gain, 0, 1, fadeInDuration, curve);\n }\n\n const unsub = playback.on(\"timeupdate\", ({ position }) => {\n if (\n fadeOutDuration > 0 &&\n !fadeOutScheduled &&\n position >= duration - fadeOutDuration\n ) {\n fadeOutScheduled = true;\n applyRamp(gain, gain.gain.value, 0, fadeOutDuration, curve);\n }\n });\n\n return unsub;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/emitter.ts"],"names":[],"mappings":";;;AAmCO,SAAS,aAAA,GAEK;AACnB,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA8C;AAEpE,EAAA,SAAS,OAA+B,KAAA,EAAU;AAChD,IAAA,IAAI,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA;AAC7B,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,GAAA,uBAAU,GAAA,EAAI;AACd,MAAA,SAAA,CAAU,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,CACE,OACA,OAAA,EACY;AACZ,MAAA,MAAM,GAAA,GAAM,OAAO,KAAK,CAAA;AACxB,MAAA,GAAA,CAAI,IAAI,OAAgC,CAAA;AACxC,MAAA,OAAO,MAAM;AACX,QAAA,GAAA,CAAI,OAAO,OAAgC,CAAA;AAAA,MAC7C,CAAA;AAAA,IACF,CAAA;AAAA,IAEA,GAAA,CACE,OACA,OAAA,EACM;AACN,MAAA,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA,EAAG,MAAA,CAAO,OAAgC,CAAA;AAAA,IAC/D,CAAA;AAAA,IAEA,IAAA,CAA6B,OAAU,IAAA,EAAuB;AAC5D,MAAA,MAAM,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA;AAC/B,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,KAAA,MAAW,WAAW,GAAA,EAAK;AACzB,QAAA,OAAA,CAAQ,IAAa,CAAA;AAAA,MACvB;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,KAAA,EAA4B;AAChC,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA,SAAA,CAAU,OAAO,KAAK,CAAA;AAAA,MACxB,CAAA,MAAO;AACL,QAAA,SAAA,CAAU,KAAA,EAAM;AAAA,MAClB;AAAA,IACF;AAAA,GACF;AACF","file":"chunk-5J7S6QV3.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// M4: Lightweight type-safe event emitter\n// ---------------------------------------------------------------------------\n\n/** A minimal, type-safe event emitter. */\nexport interface Emitter<Events extends Record<string, any> = Record<string, unknown>> {\n /** Subscribe to an event. Returns an unsubscribe function. */\n on<K extends keyof Events>(\n event: K,\n handler: (data: Events[K]) => void,\n ): () => void;\n\n /** Unsubscribe a handler from an event. */\n off<K extends keyof Events>(\n event: K,\n handler: (data: Events[K]) => void,\n ): void;\n\n /** Emit an event with data. */\n emit<K extends keyof Events>(event: K, data: Events[K]): void;\n\n /** Remove all listeners (optionally for a specific event). */\n clear(event?: keyof Events): void;\n}\n\n/**\n * Create a lightweight, type-safe event emitter.\n *\n * ```ts\n * const emitter = createEmitter<{ tick: number; done: void }>();\n * const unsub = emitter.on(\"tick\", (n) => console.log(n));\n * emitter.emit(\"tick\", 42);\n * unsub();\n * ```\n */\nexport function createEmitter<\n Events extends Record<string, any> = Record<string, unknown>,\n>(): Emitter<Events> {\n const listeners = new Map<keyof Events, Set<(data: never) => void>>();\n\n function getSet<K extends keyof Events>(event: K) {\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n return set;\n }\n\n return {\n on<K extends keyof Events>(\n event: K,\n handler: (data: Events[K]) => void,\n ): () => void {\n const set = getSet(event);\n set.add(handler as (data: never) => void);\n return () => {\n set.delete(handler as (data: never) => void);\n };\n },\n\n off<K extends keyof Events>(\n event: K,\n handler: (data: Events[K]) => void,\n ): void {\n listeners.get(event)?.delete(handler as (data: never) => void);\n },\n\n emit<K extends keyof Events>(event: K, data: Events[K]): void {\n const set = listeners.get(event);\n if (!set) return;\n for (const handler of set) {\n handler(data as never);\n }\n },\n\n clear(event?: keyof Events): void {\n if (event !== undefined) {\n listeners.delete(event);\n } else {\n listeners.clear();\n }\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/context.ts"],"names":[],"mappings":";;;AAaO,SAAS,cAAc,OAAA,EAA8C;AAC1E,EAAA,OAAO,IAAI,YAAA,CAAa;AAAA,IACtB,YAAY,OAAA,EAAS,UAAA;AAAA,IACrB,aAAa,OAAA,EAAS;AAAA,GACvB,CAAA;AACH;AAQA,eAAsB,cAAc,GAAA,EAAkC;AACpE,EAAA,IAAI,GAAA,CAAI,UAAU,WAAA,EAAa;AAC7B,IAAA,MAAM,IAAI,MAAA,EAAO;AAAA,EACnB;AACF;AAKA,eAAsB,cAAc,GAAA,EAAkC;AACpE,EAAA,IAAI,GAAA,CAAI,UAAU,SAAA,EAAW;AAC3B,IAAA,MAAM,IAAI,MAAA,EAAO;AAAA,EACnB;AACF;AAKO,SAAS,IAAI,GAAA,EAA2B;AAC7C,EAAA,OAAO,GAAA,CAAI,WAAA;AACb","file":"chunk-6UTN73HG.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// M1: AudioContext utilities\n// ---------------------------------------------------------------------------\n\nimport type { CreateContextOptions } from \"./types.js\";\n\n/**\n * Create an `AudioContext` with optional configuration.\n *\n * This is the only place in the library where `new AudioContext()` is called.\n * Users are encouraged to create their own context and pass it to other\n * functions — this helper exists purely for convenience.\n */\nexport function createContext(options?: CreateContextOptions): AudioContext {\n return new AudioContext({\n sampleRate: options?.sampleRate,\n latencyHint: options?.latencyHint,\n });\n}\n\n/**\n * Resume a suspended AudioContext (e.g. blocked by autoplay policy).\n *\n * Should be called inside a user-interaction event handler (click, keydown…)\n * if the context is in the `\"suspended\"` state.\n */\nexport async function resumeContext(ctx: AudioContext): Promise<void> {\n if (ctx.state === \"suspended\") {\n await ctx.resume();\n }\n}\n\n/**\n * Ensure the context is in the `\"running\"` state, resuming if necessary.\n */\nexport async function ensureRunning(ctx: AudioContext): Promise<void> {\n if (ctx.state !== \"running\") {\n await ctx.resume();\n }\n}\n\n/**\n * Shorthand for `ctx.currentTime`.\n */\nexport function now(ctx: AudioContext): number {\n return ctx.currentTime;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters.ts"],"names":[],"mappings":"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","file":"chunk-7S5KWTZ6.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// M10: Framework adapters\n// ---------------------------------------------------------------------------\n\nimport type { Playback, PlaybackSnapshot } from \"./types.js\";\n\nconst snapshotCache = new WeakMap<Playback, PlaybackSnapshot>();\nconst subscriberCount = new WeakMap<Playback, number>();\n\nfunction computeSnapshot(playback: Playback): PlaybackSnapshot {\n const state = playback.getState();\n const position = playback.getCurrentTime();\n const duration = playback.getDuration();\n const progress = playback.getProgress();\n\n const getter = (playback as unknown as Record<string, unknown>)[\"_getStretcherSnapshot\"];\n let stretcher: PlaybackSnapshot[\"stretcher\"];\n if (typeof getter === \"function\") {\n stretcher = (getter as () => PlaybackSnapshot[\"stretcher\"])();\n }\n\n const snap: PlaybackSnapshot = { state, position, duration, progress };\n if (stretcher) {\n snap.stretcher = stretcher;\n }\n return snap;\n}\n\n/**\n * Get an immutable snapshot of the current playback state.\n * Designed for use with React's `useSyncExternalStore` or similar patterns.\n *\n * Always returns a referentially stable (cached) object. The cache is updated\n * by `subscribeSnapshot` (on playback events) and `onFrame` (every animation\n * frame), so `getSnapshot` itself never computes a fresh snapshot — it only\n * reads or initialises the cache. This guarantees the reference-equality\n * contract required by `useSyncExternalStore`.\n */\nexport function getSnapshot(playback: Playback): PlaybackSnapshot {\n const cached = snapshotCache.get(playback);\n if (cached) return cached;\n\n const snap = computeSnapshot(playback);\n snapshotCache.set(playback, snap);\n return snap;\n}\n\n/**\n * Subscribe to playback state changes, calling `callback` with a fresh\n * snapshot whenever the state updates.\n *\n * Returns an unsubscribe function. Works as the `subscribe` parameter for\n * React's `useSyncExternalStore`.\n *\n * ```ts\n * // React example:\n * import { useCallback } from \"react\";\n * const subscribe = useCallback(\n * (cb: () => void) => subscribeSnapshot(playback, cb),\n * [playback],\n * );\n * const snap = useCallback(\n * () => getSnapshot(playback),\n * [playback],\n * );\n * const snapshot = useSyncExternalStore(subscribe, snap, snap);\n * ```\n */\nexport function subscribeSnapshot(\n playback: Playback,\n callback: () => void,\n): () => void {\n const count = (subscriberCount.get(playback) ?? 0) + 1;\n subscriberCount.set(playback, count);\n\n // Eagerly compute the initial snapshot so getSnapshot() has a\n // stable reference before the first event fires.\n snapshotCache.set(playback, computeSnapshot(playback));\n\n const notify = () => {\n // Pre-compute and cache the snapshot BEFORE notifying the\n // subscriber. This ensures getSnapshot() returns the same\n // reference during React's render and post-commit check.\n snapshotCache.set(playback, computeSnapshot(playback));\n callback();\n };\n\n const unsubs: Array<() => void> = [];\n unsubs.push(playback.on(\"statechange\", notify));\n unsubs.push(playback.on(\"timeupdate\", notify));\n unsubs.push(playback.on(\"seek\", notify));\n unsubs.push(playback.on(\"ended\", notify));\n\n return () => {\n for (const unsub of unsubs) unsub();\n const c = (subscriberCount.get(playback) ?? 1) - 1;\n if (c <= 0) {\n subscriberCount.delete(playback);\n } else {\n subscriberCount.set(playback, c);\n }\n };\n}\n\n/**\n * Call `callback` on every animation frame with the current playback snapshot.\n * Useful for smooth UI animations (waveform cursors, progress bars, etc.).\n *\n * Returns a `stop` function that cancels the loop.\n */\nexport function onFrame(\n playback: Playback,\n callback: (snapshot: PlaybackSnapshot) => void,\n): () => void {\n let rafId: number | null = null;\n\n function tick() {\n const snap = computeSnapshot(playback);\n snapshotCache.set(playback, snap);\n callback(snap);\n rafId = requestAnimationFrame(tick);\n }\n\n rafId = requestAnimationFrame(tick);\n\n return () => {\n if (rafId !== null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n };\n}\n\n/**\n * Return a `Promise` that resolves when the playback reaches the `\"stopped\"`\n * state via the `ended` event (natural end, not manual stop).\n */\nexport function whenEnded(playback: Playback): Promise<void> {\n return new Promise<void>((resolve) => {\n const unsub = playback.on(\"ended\", () => {\n unsub();\n resolve();\n });\n });\n}\n\n/**\n * Return a `Promise` that resolves when the playback position reaches or\n * exceeds `position` seconds.\n */\nexport function whenPosition(\n playback: Playback,\n position: number,\n): Promise<void> {\n return new Promise<void>((resolve) => {\n const unsub = playback.on(\"timeupdate\", ({ position: current }) => {\n if (current >= position) {\n unsub();\n resolve();\n }\n });\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/fade.ts"],"names":[],"mappings":"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","file":"chunk-C2ASIYN5.js","sourcesContent":["// ---------------------------------------------------------------------------\n// M7: Fade utilities\n// ---------------------------------------------------------------------------\n\nimport type {\n AutoFadeOptions,\n CrossfadeOptions,\n FadeCurve,\n FadeOptions,\n Playback,\n} from \"./types.js\";\n\n/** Minimum value used for exponential ramps (cannot ramp to/from 0). */\nconst EXP_MIN = 0.0001;\n\nfunction applyRamp(\n node: GainNode,\n from: number,\n to: number,\n duration: number,\n curve: FadeCurve,\n): void {\n const param = node.gain;\n const now = node.context.currentTime;\n param.cancelScheduledValues(now);\n param.setValueAtTime(from, now);\n\n switch (curve) {\n case \"exponential\":\n param.exponentialRampToValueAtTime(\n Math.max(to, EXP_MIN),\n now + duration,\n );\n break;\n case \"equal-power\": {\n // Approximate equal-power with a setValueCurveAtTime.\n const steps = Math.max(Math.ceil(duration * 100), 2);\n const values = new Float32Array(steps);\n for (let i = 0; i < steps; i++) {\n const t = i / (steps - 1);\n const gain = from + (to - from) * Math.sin((t * Math.PI) / 2);\n values[i] = gain;\n }\n param.setValueCurveAtTime(values, now, duration);\n break;\n }\n case \"linear\":\n default:\n param.linearRampToValueAtTime(to, now + duration);\n break;\n }\n}\n\n/**\n * Fade a `GainNode` in from 0 to `target`.\n */\nexport function fadeIn(\n gain: GainNode,\n target: number,\n options?: FadeOptions,\n): void {\n const { duration = 1, curve = \"linear\" } = options ?? {};\n applyRamp(gain, 0, target, duration, curve);\n}\n\n/**\n * Fade a `GainNode` out to 0.\n */\nexport function fadeOut(gain: GainNode, options?: FadeOptions): void {\n const { duration = 1, curve = \"linear\" } = options ?? {};\n applyRamp(gain, gain.gain.value, 0, duration, curve);\n}\n\n/**\n * Crossfade between two `GainNode`s.\n */\nexport function crossfade(\n gainA: GainNode,\n gainB: GainNode,\n options?: CrossfadeOptions,\n): void {\n const { duration = 1, curve = \"linear\" } = options ?? {};\n applyRamp(gainA, gainA.gain.value, 0, duration, curve);\n applyRamp(gainB, 0, gainA.gain.value || 1, duration, curve);\n}\n\n/**\n * Automatically apply fade-in at start and/or fade-out near end of a Playback.\n * Returns a cleanup function.\n */\nexport function autoFade(\n playback: Playback,\n gain: GainNode,\n options?: AutoFadeOptions,\n): () => void {\n const {\n fadeIn: fadeInDuration = 0,\n fadeOut: fadeOutDuration = 0,\n curve = \"linear\",\n } = options ?? {};\n\n const duration = playback.getDuration();\n let fadeOutScheduled = false;\n\n // Apply fade-in immediately if playing from the start.\n if (fadeInDuration > 0) {\n applyRamp(gain, 0, 1, fadeInDuration, curve);\n }\n\n const unsub = playback.on(\"timeupdate\", ({ position }) => {\n if (\n fadeOutDuration > 0 &&\n !fadeOutScheduled &&\n position >= duration - fadeOutDuration\n ) {\n fadeOutScheduled = true;\n applyRamp(gain, gain.gain.value, 0, fadeOutDuration, curve);\n }\n });\n\n return unsub;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/nodes.ts"],"names":[],"mappings":"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","file":"chunk-CJJC6ASU.js","sourcesContent":["// ---------------------------------------------------------------------------\n// M5: Audio node factory & graph utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Create a `GainNode` with an optional initial value.\n */\nexport function createGain(\n ctx: AudioContext,\n initialValue?: number,\n): GainNode {\n const gain = ctx.createGain();\n if (initialValue !== undefined) {\n gain.gain.value = initialValue;\n }\n return gain;\n}\n\n/**\n * Smoothly ramp a `GainNode` to a target value over `duration` seconds using\n * `linearRampToValueAtTime`. This avoids audible clicks when changing volume.\n */\nexport function rampGain(\n gain: GainNode,\n target: number,\n duration: number,\n): void {\n const now = gain.context.currentTime;\n gain.gain.cancelScheduledValues(now);\n gain.gain.setValueAtTime(gain.gain.value, now);\n gain.gain.linearRampToValueAtTime(target, now + duration);\n}\n\n/**\n * Create an `AnalyserNode`.\n */\nexport function createAnalyser(\n ctx: AudioContext,\n options?: { fftSize?: number; smoothingTimeConstant?: number },\n): AnalyserNode {\n const analyser = ctx.createAnalyser();\n if (options?.fftSize !== undefined) analyser.fftSize = options.fftSize;\n if (options?.smoothingTimeConstant !== undefined) {\n analyser.smoothingTimeConstant = options.smoothingTimeConstant;\n }\n return analyser;\n}\n\n/**\n * Get the current frequency data from an `AnalyserNode` as `Float32Array`.\n */\nexport function getFrequencyData(analyser: AnalyserNode): Float32Array {\n const data = new Float32Array(analyser.frequencyBinCount);\n analyser.getFloatFrequencyData(data);\n return data;\n}\n\n/**\n * Get the current frequency data from an `AnalyserNode` as `Uint8Array`.\n */\nexport function getFrequencyDataByte(analyser: AnalyserNode): Uint8Array {\n const data = new Uint8Array(analyser.frequencyBinCount);\n analyser.getByteFrequencyData(data);\n return data;\n}\n\n/**\n * Create a `BiquadFilterNode`.\n */\nexport function createFilter(\n ctx: AudioContext,\n options?: {\n type?: BiquadFilterType;\n frequency?: number;\n Q?: number;\n gain?: number;\n },\n): BiquadFilterNode {\n const filter = ctx.createBiquadFilter();\n if (options?.type !== undefined) filter.type = options.type;\n if (options?.frequency !== undefined) filter.frequency.value = options.frequency;\n if (options?.Q !== undefined) filter.Q.value = options.Q;\n if (options?.gain !== undefined) filter.gain.value = options.gain;\n return filter;\n}\n\n/**\n * Create a `StereoPannerNode`.\n */\nexport function createPanner(\n ctx: AudioContext,\n pan?: number,\n): StereoPannerNode {\n const panner = ctx.createStereoPanner();\n if (pan !== undefined) {\n panner.pan.value = pan;\n }\n return panner;\n}\n\n/**\n * Create a `DynamicsCompressorNode`.\n */\nexport function createCompressor(\n ctx: AudioContext,\n options?: {\n threshold?: number;\n knee?: number;\n ratio?: number;\n attack?: number;\n release?: number;\n },\n): DynamicsCompressorNode {\n const comp = ctx.createDynamicsCompressor();\n if (options?.threshold !== undefined) comp.threshold.value = options.threshold;\n if (options?.knee !== undefined) comp.knee.value = options.knee;\n if (options?.ratio !== undefined) comp.ratio.value = options.ratio;\n if (options?.attack !== undefined) comp.attack.value = options.attack;\n if (options?.release !== undefined) comp.release.value = options.release;\n return comp;\n}\n\n/**\n * Connect a series of `AudioNode`s in order (serial chain).\n *\n * ```ts\n * chain(source, gain, analyser, ctx.destination);\n * ```\n */\nexport function chain(...nodes: AudioNode[]): void {\n for (let i = 0; i < nodes.length - 1; i++) {\n nodes[i]!.connect(nodes[i + 1]!);\n }\n}\n\n/**\n * Disconnect a series of `AudioNode`s that were previously chained.\n */\nexport function disconnectChain(...nodes: AudioNode[]): void {\n for (const node of nodes) {\n try {\n node.disconnect();\n } catch {\n // Already disconnected — safe to ignore.\n }\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/buffer.ts"],"names":[],"mappings":";;;AAeA,eAAsB,UAAA,CACpB,GAAA,EACA,GAAA,EACA,OAAA,EACsB;AACtB,EAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAG,CAAA;AAChC,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,UAAU,CAAA,CAAE,CAAA;AAAA,EACpF;AAEA,EAAA,IAAI,OAAA,EAAS,cAAc,QAAA,CAAS,IAAA,IAAQ,SAAS,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA,EAAG;AAClF,IAAA,MAAM,QAAQ,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAC,CAAA;AAC3D,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,IAAA,MAAM,SAAuB,EAAC;AAC9B,IAAA,IAAI,QAAA,GAAW,CAAA;AAEf,IAAA,WAAS;AACP,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,MAAA,IAAI,IAAA,EAAM;AACV,MAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AACjB,MAAA,QAAA,IAAY,KAAA,CAAM,UAAA;AAClB,MAAA,OAAA,CAAQ,UAAA,CAAW,KAAA,GAAQ,CAAA,GAAI,QAAA,GAAW,QAAQ,CAAC,CAAA;AAAA,IACrD;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,UAAA,CAAW,QAAQ,CAAA;AACtC,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,MAAA,CAAO,GAAA,CAAI,OAAO,MAAM,CAAA;AACxB,MAAA,MAAA,IAAU,KAAA,CAAM,UAAA;AAAA,IAClB;AAEA,IAAA,OAAO,GAAA,CAAI,eAAA,CAAgB,MAAA,CAAO,MAAM,CAAA;AAAA,EAC1C;AAEA,EAAA,MAAM,WAAA,GAAc,MAAM,QAAA,CAAS,WAAA,EAAY;AAC/C,EAAA,OAAO,GAAA,CAAI,gBAAgB,WAAW,CAAA;AACxC;AAKA,eAAsB,kBAAA,CACpB,KACA,IAAA,EACsB;AACtB,EAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,WAAA,EAAY;AAC3C,EAAA,OAAO,GAAA,CAAI,gBAAgB,WAAW,CAAA;AACxC;AAaA,eAAsB,WAAA,CACpB,KACA,GAAA,EACmC;AACnC,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA;AAClC,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA;AAAA,IAC5B,QAAQ,GAAA,CAAI,OAAO,CAAC,GAAA,EAAK,GAAG,CAAA,KAAM;AAChC,MAAA,MAAM,MAAA,GAAS,MAAM,UAAA,CAAW,GAAA,EAAK,GAAG,CAAA;AACxC,MAAA,OAAO,CAAC,KAAK,MAAM,CAAA;AAAA,IACrB,CAAC;AAAA,GACH;AACA,EAAA,OAAO,IAAI,IAAI,OAAO,CAAA;AACxB;AAKO,SAAS,cAAc,MAAA,EAAiC;AAC7D,EAAA,OAAO;AAAA,IACL,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,kBAAkB,MAAA,CAAO,gBAAA;AAAA,IACzB,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,QAAQ,MAAA,CAAO;AAAA,GACjB;AACF","file":"chunk-CPAT75WD.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// M2: Audio buffer loading utilities\n// ---------------------------------------------------------------------------\n\nimport type { BufferInfo, LoadBufferOptions } from \"./types.js\";\n\n/**\n * Fetch an audio file from a URL and decode it into an `AudioBuffer`.\n *\n * ```ts\n * const buffer = await loadBuffer(ctx, \"/audio/track.mp3\", {\n * onProgress: (p) => console.log(`${(p * 100).toFixed(0)}%`),\n * });\n * ```\n */\nexport async function loadBuffer(\n ctx: AudioContext,\n url: string,\n options?: LoadBufferOptions,\n): Promise<AudioBuffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch audio: ${response.status} ${response.statusText}`);\n }\n\n if (options?.onProgress && response.body && response.headers.get(\"content-length\")) {\n const total = Number(response.headers.get(\"content-length\"));\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let received = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n received += value.byteLength;\n options.onProgress(total > 0 ? received / total : 0);\n }\n\n const merged = new Uint8Array(received);\n let offset = 0;\n for (const chunk of chunks) {\n merged.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return ctx.decodeAudioData(merged.buffer);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return ctx.decodeAudioData(arrayBuffer);\n}\n\n/**\n * Decode an `AudioBuffer` from a `Blob` or `File`.\n */\nexport async function loadBufferFromBlob(\n ctx: AudioContext,\n blob: Blob,\n): Promise<AudioBuffer> {\n const arrayBuffer = await blob.arrayBuffer();\n return ctx.decodeAudioData(arrayBuffer);\n}\n\n/**\n * Load multiple audio files in parallel.\n *\n * ```ts\n * const buffers = await loadBuffers(ctx, {\n * kick: \"/samples/kick.wav\",\n * snare: \"/samples/snare.wav\",\n * });\n * buffers.get(\"kick\"); // AudioBuffer\n * ```\n */\nexport async function loadBuffers(\n ctx: AudioContext,\n map: Record<string, string>,\n): Promise<Map<string, AudioBuffer>> {\n const entries = Object.entries(map);\n const results = await Promise.all(\n entries.map(async ([key, url]) => {\n const buffer = await loadBuffer(ctx, url);\n return [key, buffer] as const;\n }),\n );\n return new Map(results);\n}\n\n/**\n * Return metadata about an `AudioBuffer`.\n */\nexport function getBufferInfo(buffer: AudioBuffer): BufferInfo {\n return {\n duration: buffer.duration,\n numberOfChannels: buffer.numberOfChannels,\n sampleRate: buffer.sampleRate,\n length: buffer.length,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/waveform.ts"],"names":[],"mappings":"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","file":"chunk-CRODJ4KS.js","sourcesContent":["// ---------------------------------------------------------------------------\n// M6: Waveform data extraction\n// ---------------------------------------------------------------------------\n\nimport type { ExtractPeaksOptions, PeakPair } from \"./types.js\";\n\n/**\n * Extract normalised peak amplitude values from an `AudioBuffer`.\n * Returns an array of numbers in the range `[0, 1]`.\n */\nexport function extractPeaks(\n buffer: AudioBuffer,\n options?: ExtractPeaksOptions,\n): number[] {\n const { resolution = 200, channel = 0 } = options ?? {};\n const data = buffer.getChannelData(channel);\n const blockSize = Math.floor(data.length / resolution);\n const peaks: number[] = [];\n\n for (let i = 0; i < resolution; i++) {\n const start = i * blockSize;\n const end = Math.min(start + blockSize, data.length);\n let max = 0;\n for (let j = start; j < end; j++) {\n const abs = Math.abs(data[j]!);\n if (abs > max) max = abs;\n }\n peaks.push(max);\n }\n\n return peaks;\n}\n\n/**\n * Extract min/max peak pairs for detailed waveform rendering.\n */\nexport function extractPeakPairs(\n buffer: AudioBuffer,\n options?: ExtractPeaksOptions,\n): PeakPair[] {\n const { resolution = 200, channel = 0 } = options ?? {};\n const data = buffer.getChannelData(channel);\n const blockSize = Math.floor(data.length / resolution);\n const pairs: PeakPair[] = [];\n\n for (let i = 0; i < resolution; i++) {\n const start = i * blockSize;\n const end = Math.min(start + blockSize, data.length);\n let min = 0;\n let max = 0;\n for (let j = start; j < end; j++) {\n const sample = data[j]!;\n if (sample < min) min = sample;\n if (sample > max) max = sample;\n }\n pairs.push({ min, max });\n }\n\n return pairs;\n}\n\n/**\n * Extract RMS (root mean square) values representing perceived loudness.\n * Returns values in the range `[0, 1]`.\n *\n * When `channel` is set to `-1`, all channels are averaged.\n */\nexport function extractRMS(\n buffer: AudioBuffer,\n options?: ExtractPeaksOptions & { channel?: number },\n): number[] {\n const { resolution = 200, channel = 0 } = options ?? {};\n\n if (channel === -1) {\n // Average across all channels.\n const allChannels: number[][] = [];\n for (let ch = 0; ch < buffer.numberOfChannels; ch++) {\n allChannels.push(extractRMS(buffer, { resolution, channel: ch }));\n }\n return allChannels[0]!.map((_, i) => {\n let sum = 0;\n for (const ch of allChannels) {\n sum += ch[i]!;\n }\n return sum / allChannels.length;\n });\n }\n\n const data = buffer.getChannelData(channel);\n const blockSize = Math.floor(data.length / resolution);\n const rms: number[] = [];\n\n for (let i = 0; i < resolution; i++) {\n const start = i * blockSize;\n const end = Math.min(start + blockSize, data.length);\n let sumSq = 0;\n for (let j = start; j < end; j++) {\n const s = data[j]!;\n sumSq += s * s;\n }\n rms.push(Math.sqrt(sumSq / (end - start)));\n }\n\n return rms;\n}\n"]}