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
@@ -8,7 +8,7 @@ function computeSnapshot(playback) {
8
8
  const position = playback.getCurrentTime();
9
9
  const duration = playback.getDuration();
10
10
  const progress = playback.getProgress();
11
- const getter = playback["_getStretcherSnapshot"];
11
+ const getter = playback._getStretcherSnapshot;
12
12
  let stretcher;
13
13
  if (typeof getter === "function") {
14
14
  stretcher = getter();
@@ -74,6 +74,9 @@ function whenEnded(playback) {
74
74
  });
75
75
  }
76
76
  function whenPosition(playback, position) {
77
+ if (playback.getCurrentTime() >= position) {
78
+ return Promise.resolve();
79
+ }
77
80
  return new Promise((resolve) => {
78
81
  const unsub = playback.on("timeupdate", ({ position: current }) => {
79
82
  if (current >= position) {
@@ -89,5 +92,5 @@ exports.onFrame = onFrame;
89
92
  exports.subscribeSnapshot = subscribeSnapshot;
90
93
  exports.whenEnded = whenEnded;
91
94
  exports.whenPosition = whenPosition;
92
- //# sourceMappingURL=chunk-7S5KWTZ6.cjs.map
93
- //# sourceMappingURL=chunk-7S5KWTZ6.cjs.map
95
+ //# sourceMappingURL=chunk-OZN5X4N6.cjs.map
96
+ //# sourceMappingURL=chunk-OZN5X4N6.cjs.map
@@ -69,5 +69,5 @@ function disconnectChain(...nodes) {
69
69
  }
70
70
 
71
71
  export { chain, createAnalyser, createCompressor, createFilter, createGain, createPanner, disconnectChain, getFrequencyData, getFrequencyDataByte, rampGain };
72
- //# sourceMappingURL=chunk-CJJC6ASU.js.map
73
- //# sourceMappingURL=chunk-CJJC6ASU.js.map
72
+ //# sourceMappingURL=chunk-PL4J3NR7.js.map
73
+ //# sourceMappingURL=chunk-PL4J3NR7.js.map
@@ -1,12 +1,12 @@
1
- import { createScheduler, createClock } from './chunk-2DL7CAEP.js';
2
- import { createSineBuffer, createNoiseBuffer, createClickBuffer } from './chunk-LETS7FKB.js';
3
- import { getSnapshot, subscribeSnapshot, onFrame, whenEnded, whenPosition } from './chunk-VKT7YCWK.js';
1
+ import { createScheduler, createClock } from './chunk-7JUVBZ6B.js';
2
+ import { createSineBuffer, createNoiseBuffer, createClickBuffer } from './chunk-YFK7ETCF.js';
3
+ import { getSnapshot, subscribeSnapshot, onFrame, whenEnded, whenPosition } from './chunk-JIHPQAEA.js';
4
4
  import { createContext, resumeContext, ensureRunning, now } from './chunk-37CPPRLV.js';
5
- import { loadBuffer, loadBufferFromBlob, loadBuffers, getBufferInfo } from './chunk-T74FBKTY.js';
6
- import { play } from './chunk-X4IFO7U7.js';
7
- import { createGain, createAnalyser, createFilter, createPanner, createCompressor, rampGain, getFrequencyData, getFrequencyDataByte, chain, disconnectChain } from './chunk-CJJC6ASU.js';
8
- import { extractPeaks, extractPeakPairs, extractRMS } from './chunk-CRODJ4KS.js';
9
- import { fadeIn, fadeOut, crossfade, autoFade } from './chunk-C2ASIYN5.js';
5
+ import { loadBuffer, loadBufferFromBlob, loadBuffers, getBufferInfo } from './chunk-2FGUFHZM.js';
6
+ import { play } from './chunk-HYRDCTBO.js';
7
+ import { createGain, createAnalyser, createFilter, createPanner, createCompressor, rampGain, getFrequencyData, getFrequencyDataByte, chain, disconnectChain } from './chunk-PL4J3NR7.js';
8
+ import { extractPeaks, extractPeakPairs, extractRMS } from './chunk-HTN52U23.js';
9
+ import { fadeIn, fadeOut, crossfade, autoFade } from './chunk-FESPIMZM.js';
10
10
 
11
11
  // src/player.ts
12
12
  var WaaPlayer = class {
@@ -142,5 +142,5 @@ var WaaPlayer = class {
142
142
  };
143
143
 
144
144
  export { WaaPlayer };
145
- //# sourceMappingURL=chunk-IMNRPYBM.js.map
146
- //# sourceMappingURL=chunk-IMNRPYBM.js.map
145
+ //# sourceMappingURL=chunk-QFJQU7TQ.js.map
146
+ //# sourceMappingURL=chunk-QFJQU7TQ.js.map
@@ -80,5 +80,5 @@ exports.disconnectChain = disconnectChain;
80
80
  exports.getFrequencyData = getFrequencyData;
81
81
  exports.getFrequencyDataByte = getFrequencyDataByte;
82
82
  exports.rampGain = rampGain;
83
- //# sourceMappingURL=chunk-M5PDY5EZ.cjs.map
84
- //# sourceMappingURL=chunk-M5PDY5EZ.cjs.map
83
+ //# sourceMappingURL=chunk-QGZGERGK.cjs.map
84
+ //# sourceMappingURL=chunk-QGZGERGK.cjs.map
@@ -1,10 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  // src/waveform.ts
4
+ function calcBlockSize(dataLength, resolution) {
5
+ return Math.max(1, Math.floor(dataLength / resolution));
6
+ }
4
7
  function extractPeaks(buffer, options) {
5
8
  const { resolution = 200, channel = 0 } = options ?? {};
6
9
  const data = buffer.getChannelData(channel);
7
- const blockSize = Math.floor(data.length / resolution);
10
+ const blockSize = calcBlockSize(data.length, resolution);
8
11
  const peaks = [];
9
12
  for (let i = 0; i < resolution; i++) {
10
13
  const start = i * blockSize;
@@ -21,7 +24,7 @@ function extractPeaks(buffer, options) {
21
24
  function extractPeakPairs(buffer, options) {
22
25
  const { resolution = 200, channel = 0 } = options ?? {};
23
26
  const data = buffer.getChannelData(channel);
24
- const blockSize = Math.floor(data.length / resolution);
27
+ const blockSize = calcBlockSize(data.length, resolution);
25
28
  const pairs = [];
26
29
  for (let i = 0; i < resolution; i++) {
27
30
  const start = i * blockSize;
@@ -40,6 +43,9 @@ function extractPeakPairs(buffer, options) {
40
43
  function extractRMS(buffer, options) {
41
44
  const { resolution = 200, channel = 0 } = options ?? {};
42
45
  if (channel === -1) {
46
+ if (buffer.numberOfChannels === 0) {
47
+ return [];
48
+ }
43
49
  const allChannels = [];
44
50
  for (let ch = 0; ch < buffer.numberOfChannels; ch++) {
45
51
  allChannels.push(extractRMS(buffer, { resolution, channel: ch }));
@@ -53,17 +59,18 @@ function extractRMS(buffer, options) {
53
59
  });
54
60
  }
55
61
  const data = buffer.getChannelData(channel);
56
- const blockSize = Math.floor(data.length / resolution);
62
+ const blockSize = calcBlockSize(data.length, resolution);
57
63
  const rms = [];
58
64
  for (let i = 0; i < resolution; i++) {
59
65
  const start = i * blockSize;
60
66
  const end = Math.min(start + blockSize, data.length);
61
67
  let sumSq = 0;
68
+ const count = end - start;
62
69
  for (let j = start; j < end; j++) {
63
70
  const s = data[j];
64
71
  sumSq += s * s;
65
72
  }
66
- rms.push(Math.sqrt(sumSq / (end - start)));
73
+ rms.push(count > 0 ? Math.sqrt(sumSq / count) : 0);
67
74
  }
68
75
  return rms;
69
76
  }
@@ -71,5 +78,5 @@ function extractRMS(buffer, options) {
71
78
  exports.extractPeakPairs = extractPeakPairs;
72
79
  exports.extractPeaks = extractPeaks;
73
80
  exports.extractRMS = extractRMS;
74
- //# sourceMappingURL=chunk-QFFQQMU4.cjs.map
75
- //# sourceMappingURL=chunk-QFFQQMU4.cjs.map
81
+ //# sourceMappingURL=chunk-VOSIA3GF.cjs.map
82
+ //# sourceMappingURL=chunk-VOSIA3GF.cjs.map
@@ -1,6 +1,60 @@
1
1
  'use strict';
2
2
 
3
- var chunk5J7S6QV3_cjs = require('./chunk-5J7S6QV3.cjs');
3
+ var chunkHIF3UAF3_cjs = require('./chunk-HIF3UAF3.cjs');
4
+
5
+ // src/playback-position.ts
6
+ function calcLoopPosition(elapsed, loopStart, loopEnd) {
7
+ const loopDur = loopEnd - loopStart;
8
+ if (loopDur <= 0) return null;
9
+ const offset = elapsed - loopStart;
10
+ return (offset % loopDur + loopDur) % loopDur + loopStart;
11
+ }
12
+ function calcPlaybackPosition(state, elapsed, duration, pausedAt, isLooping, loopStart, loopEnd) {
13
+ if (state === "paused") return pausedAt;
14
+ if (state === "stopped") return 0;
15
+ if (isLooping) {
16
+ const looped = calcLoopPosition(elapsed, loopStart ?? 0, loopEnd ?? duration);
17
+ if (looped !== null) return looped;
18
+ }
19
+ return Math.min(Math.max(elapsed, 0), duration);
20
+ }
21
+
22
+ // src/playback-state.ts
23
+ function createPlaybackStateManager(opts) {
24
+ let state = opts.initialState;
25
+ let timerId = null;
26
+ let disposed = false;
27
+ function getState() {
28
+ return state;
29
+ }
30
+ function setState(next) {
31
+ if (state === next) return false;
32
+ state = next;
33
+ opts.onStateChange(next);
34
+ return true;
35
+ }
36
+ function startTimer() {
37
+ if (timerId !== null) return;
38
+ timerId = setInterval(() => {
39
+ if (state !== "playing" || disposed) return;
40
+ opts.onTimerTick();
41
+ }, opts.timerInterval);
42
+ }
43
+ function stopTimer() {
44
+ if (timerId !== null) {
45
+ clearInterval(timerId);
46
+ timerId = null;
47
+ }
48
+ }
49
+ function isDisposed() {
50
+ return disposed;
51
+ }
52
+ function markDisposed() {
53
+ disposed = true;
54
+ stopTimer();
55
+ }
56
+ return { getState, setState, startTimer, stopTimer, isDisposed, markDisposed };
57
+ }
4
58
 
5
59
  // src/play.ts
6
60
  function play(ctx, buffer, options) {
@@ -18,16 +72,24 @@ function play(ctx, buffer, options) {
18
72
  destination = ctx.destination,
19
73
  timeupdateInterval = 50
20
74
  } = options ?? {};
21
- const emitter = chunk5J7S6QV3_cjs.createEmitter();
75
+ const emitter = chunkHIF3UAF3_cjs.createEmitter();
22
76
  const duration = buffer.duration;
23
- let state = "stopped";
24
77
  let sourceNode = null;
25
78
  let startedAt = 0;
26
79
  let pausedAt = initialOffset;
27
- let currentRate = initialRate;
80
+ let currentRate = initialRate > 0 ? initialRate : 1;
28
81
  let isLooping = loop;
29
- let timerId = null;
30
- let disposed = false;
82
+ const sm = createPlaybackStateManager({
83
+ initialState: "stopped",
84
+ onStateChange: (next) => emitter.emit("statechange", { state: next }),
85
+ onTimerTick: () => {
86
+ emitter.emit("timeupdate", {
87
+ position: getCurrentTime(),
88
+ duration
89
+ });
90
+ },
91
+ timerInterval: timeupdateInterval
92
+ });
31
93
  function createSource() {
32
94
  const src = ctx.createBufferSource();
33
95
  src.buffer = buffer;
@@ -64,90 +126,63 @@ function play(ctx, buffer, options) {
64
126
  }
65
127
  }
66
128
  function handleEnded() {
67
- if (state !== "playing") return;
129
+ if (sm.getState() !== "playing") return;
68
130
  if (isLooping) {
69
131
  emitter.emit("loop", void 0);
70
132
  return;
71
133
  }
72
- setState("stopped");
134
+ sm.setState("stopped");
73
135
  pausedAt = 0;
74
- stopTimer();
136
+ sm.stopTimer();
75
137
  emitter.emit("ended", void 0);
76
138
  }
77
- function setState(next) {
78
- if (state === next) return;
79
- state = next;
80
- emitter.emit("statechange", { state: next });
81
- }
82
- function startTimer() {
83
- if (timerId !== null) return;
84
- timerId = setInterval(() => {
85
- if (state !== "playing") return;
86
- emitter.emit("timeupdate", {
87
- position: getCurrentTime(),
88
- duration
89
- });
90
- }, timeupdateInterval);
91
- }
92
- function stopTimer() {
93
- if (timerId !== null) {
94
- clearInterval(timerId);
95
- timerId = null;
96
- }
97
- }
98
139
  function getCurrentTime() {
99
- if (state === "playing") {
100
- const elapsed = (ctx.currentTime - startedAt) * currentRate;
101
- if (isLooping) {
102
- const loopDur = (loopEnd ?? duration) - (loopStart ?? 0);
103
- return (elapsed - (loopStart ?? 0)) % loopDur + (loopStart ?? 0);
104
- }
105
- return Math.min(elapsed, duration);
106
- }
107
- if (state === "paused") return pausedAt;
108
- return 0;
140
+ const state = sm.getState();
141
+ const elapsed = state === "playing" ? (ctx.currentTime - startedAt) * currentRate : 0;
142
+ return calcPlaybackPosition(state, elapsed, duration, pausedAt, isLooping, loopStart, loopEnd);
109
143
  }
110
144
  function pause() {
111
- if (state !== "playing" || disposed) return;
145
+ if (sm.getState() !== "playing" || sm.isDisposed()) return;
112
146
  pausedAt = getCurrentTime();
113
147
  stopSource();
114
- stopTimer();
115
- setState("paused");
148
+ sm.stopTimer();
149
+ sm.setState("paused");
116
150
  emitter.emit("pause", void 0);
117
151
  }
118
152
  function resume() {
119
- if (state !== "paused" || disposed) return;
153
+ if (sm.getState() !== "paused" || sm.isDisposed()) return;
120
154
  startSource(pausedAt);
121
- setState("playing");
122
- startTimer();
155
+ sm.setState("playing");
156
+ sm.startTimer();
123
157
  emitter.emit("resume", void 0);
124
158
  }
125
159
  function togglePlayPause() {
126
- if (state === "playing") pause();
127
- else if (state === "paused") resume();
160
+ if (sm.getState() === "playing") pause();
161
+ else if (sm.getState() === "paused") resume();
128
162
  }
129
163
  function seek(position) {
130
- if (disposed) return;
164
+ if (sm.isDisposed()) return;
131
165
  const clamped = Math.max(0, Math.min(position, duration));
132
- const wasPlaying = state === "playing";
166
+ const wasPlaying = sm.getState() === "playing";
133
167
  stopSource();
134
- stopTimer();
168
+ sm.stopTimer();
135
169
  pausedAt = clamped;
136
170
  if (wasPlaying) {
137
171
  startSource(clamped);
138
- startTimer();
172
+ sm.startTimer();
139
173
  }
140
174
  emitter.emit("seek", { position: clamped });
141
175
  }
142
176
  function stop() {
143
- if (state === "stopped" || disposed) return;
177
+ if (sm.getState() === "stopped" || sm.isDisposed()) return;
144
178
  stopSource();
145
- stopTimer();
179
+ sm.stopTimer();
146
180
  pausedAt = 0;
147
- setState("stopped");
181
+ sm.setState("stopped");
148
182
  emitter.emit("stop", void 0);
149
183
  }
150
184
  function setPlaybackRate(rate) {
185
+ if (rate <= 0) return;
151
186
  const position = getCurrentTime();
152
187
  currentRate = rate;
153
188
  if (sourceNode) {
@@ -162,18 +197,17 @@ function play(ctx, buffer, options) {
162
197
  }
163
198
  }
164
199
  function dispose() {
165
- if (disposed) return;
166
- disposed = true;
200
+ if (sm.isDisposed()) return;
201
+ sm.markDisposed();
167
202
  stopSource();
168
- stopTimer();
169
203
  emitter.clear();
170
204
  }
171
205
  startSource(initialOffset);
172
- setState("playing");
173
- startTimer();
206
+ sm.setState("playing");
207
+ sm.startTimer();
174
208
  emitter.emit("play", void 0);
175
209
  return {
176
- getState: () => state,
210
+ getState: () => sm.getState(),
177
211
  getCurrentTime,
178
212
  getDuration: () => duration,
179
213
  getProgress: () => duration > 0 ? getCurrentTime() / duration : 0,
@@ -198,19 +232,27 @@ function createStretchedPlayback(ctx, buffer, options) {
198
232
  destination = ctx.destination,
199
233
  timeupdateInterval = 50
200
234
  } = options;
201
- const emitter = chunk5J7S6QV3_cjs.createEmitter();
235
+ const emitter = chunkHIF3UAF3_cjs.createEmitter();
202
236
  const duration = buffer.duration;
203
- let state = "playing";
204
237
  let engineInstance = null;
205
- let timerId = null;
206
- let disposed = false;
207
- let currentRate = initialRate;
238
+ let currentRate = initialRate > 0 ? initialRate : 1;
208
239
  let isLooping = loop;
209
240
  let pendingSeek = null;
241
+ const sm = createPlaybackStateManager({
242
+ initialState: "playing",
243
+ onStateChange: (next) => emitter.emit("statechange", { state: next }),
244
+ onTimerTick: () => {
245
+ emitter.emit("timeupdate", {
246
+ position: getCurrentTime(),
247
+ duration
248
+ });
249
+ },
250
+ timerInterval: timeupdateInterval
251
+ });
210
252
  emitter.emit("statechange", { state: "playing" });
211
253
  emitter.emit("play", void 0);
212
- import('./engine-QUMYW73L.cjs').then(({ createStretcherEngine }) => {
213
- if (disposed) return;
254
+ import('./engine-ALWPAIX6.cjs').then(({ createStretcherEngine }) => {
255
+ if (sm.isDisposed()) return;
214
256
  engineInstance = createStretcherEngine(ctx, buffer, {
215
257
  tempo: currentRate,
216
258
  offset: initialOffset,
@@ -220,60 +262,48 @@ function createStretchedPlayback(ctx, buffer, options) {
220
262
  timeupdateInterval
221
263
  });
222
264
  engineInstance.on("buffering", (data) => {
223
- if (disposed) return;
265
+ if (sm.isDisposed()) return;
224
266
  emitter.emit("buffering", data);
225
267
  });
226
268
  engineInstance.on("buffered", (data) => {
227
- if (disposed) return;
269
+ if (sm.isDisposed()) return;
228
270
  emitter.emit("buffered", data);
229
271
  });
230
272
  engineInstance.on("loop", () => {
231
- if (disposed) return;
273
+ if (sm.isDisposed()) return;
232
274
  emitter.emit("loop", void 0);
233
275
  });
234
276
  engineInstance.on("ended", () => {
235
- if (disposed) return;
236
- state = "stopped";
237
- stopTimer();
238
- emitter.emit("statechange", { state: "stopped" });
277
+ if (sm.isDisposed()) return;
278
+ if (sm.getState() === "stopped") return;
279
+ sm.stopTimer();
280
+ sm.setState("stopped");
239
281
  emitter.emit("ended", void 0);
240
282
  });
241
283
  engineInstance.on("error", (data) => {
242
- if (disposed) return;
284
+ if (sm.isDisposed()) return;
243
285
  if (data.fatal) {
244
- state = "stopped";
245
- emitter.emit("statechange", { state: "stopped" });
286
+ sm.setState("stopped");
246
287
  emitter.emit("ended", void 0);
247
288
  }
248
289
  });
249
290
  engineInstance.start();
250
- startTimer();
291
+ sm.startTimer();
251
292
  if (pendingSeek !== null) {
252
293
  engineInstance.seek(pendingSeek);
253
294
  pendingSeek = null;
254
295
  }
255
- if (state === "paused") {
296
+ if (sm.getState() === "paused") {
256
297
  engineInstance.pause();
257
- } else if (state === "stopped") {
298
+ } else if (sm.getState() === "stopped") {
258
299
  engineInstance.stop();
259
300
  }
301
+ }).catch(() => {
302
+ if (sm.isDisposed()) return;
303
+ sm.stopTimer();
304
+ sm.setState("stopped");
305
+ emitter.emit("ended", void 0);
260
306
  });
261
- function startTimer() {
262
- if (timerId !== null) return;
263
- timerId = setInterval(() => {
264
- if (state !== "playing" || disposed) return;
265
- emitter.emit("timeupdate", {
266
- position: getCurrentTime(),
267
- duration
268
- });
269
- }, timeupdateInterval);
270
- }
271
- function stopTimer() {
272
- if (timerId !== null) {
273
- clearInterval(timerId);
274
- timerId = null;
275
- }
276
- }
277
307
  function getCurrentTime() {
278
308
  if (pendingSeek !== null) {
279
309
  return pendingSeek;
@@ -284,27 +314,25 @@ function createStretchedPlayback(ctx, buffer, options) {
284
314
  return initialOffset;
285
315
  }
286
316
  function pause() {
287
- if (state !== "playing" || disposed) return;
288
- state = "paused";
317
+ if (sm.getState() !== "playing" || sm.isDisposed()) return;
289
318
  engineInstance?.pause();
290
- stopTimer();
291
- emitter.emit("statechange", { state: "paused" });
319
+ sm.stopTimer();
320
+ sm.setState("paused");
292
321
  emitter.emit("pause", void 0);
293
322
  }
294
323
  function resume() {
295
- if (state !== "paused" || disposed) return;
296
- state = "playing";
324
+ if (sm.getState() !== "paused" || sm.isDisposed()) return;
297
325
  engineInstance?.resume();
298
- startTimer();
299
- emitter.emit("statechange", { state: "playing" });
326
+ sm.startTimer();
327
+ sm.setState("playing");
300
328
  emitter.emit("resume", void 0);
301
329
  }
302
330
  function togglePlayPause() {
303
- if (state === "playing") pause();
304
- else if (state === "paused") resume();
331
+ if (sm.getState() === "playing") pause();
332
+ else if (sm.getState() === "paused") resume();
305
333
  }
306
334
  function seek(position) {
307
- if (disposed) return;
335
+ if (sm.isDisposed()) return;
308
336
  const clamped = Math.max(0, Math.min(position, duration));
309
337
  if (engineInstance) {
310
338
  engineInstance.seek(clamped);
@@ -314,14 +342,14 @@ function createStretchedPlayback(ctx, buffer, options) {
314
342
  emitter.emit("seek", { position: clamped });
315
343
  }
316
344
  function stop() {
317
- if (state === "stopped" || disposed) return;
318
- state = "stopped";
345
+ if (sm.getState() === "stopped" || sm.isDisposed()) return;
319
346
  engineInstance?.stop();
320
- stopTimer();
321
- emitter.emit("statechange", { state: "stopped" });
347
+ sm.stopTimer();
348
+ sm.setState("stopped");
322
349
  emitter.emit("stop", void 0);
323
350
  }
324
351
  function setPlaybackRate(rate) {
352
+ if (rate <= 0) return;
325
353
  currentRate = rate;
326
354
  if (engineInstance) {
327
355
  engineInstance.setTempo(rate);
@@ -332,9 +360,8 @@ function createStretchedPlayback(ctx, buffer, options) {
332
360
  engineInstance?.setLoop(value);
333
361
  }
334
362
  function dispose() {
335
- if (disposed) return;
336
- disposed = true;
337
- stopTimer();
363
+ if (sm.isDisposed()) return;
364
+ sm.markDisposed();
338
365
  engineInstance?.dispose();
339
366
  emitter.clear();
340
367
  }
@@ -343,7 +370,7 @@ function createStretchedPlayback(ctx, buffer, options) {
343
370
  return engineInstance.getSnapshot();
344
371
  }
345
372
  const playback = {
346
- getState: () => state,
373
+ getState: () => sm.getState(),
347
374
  getCurrentTime,
348
375
  getDuration: () => duration,
349
376
  getProgress: () => duration > 0 ? getCurrentTime() / duration : 0,
@@ -363,5 +390,5 @@ function createStretchedPlayback(ctx, buffer, options) {
363
390
  }
364
391
 
365
392
  exports.play = play;
366
- //# sourceMappingURL=chunk-CTUCTTIE.cjs.map
367
- //# sourceMappingURL=chunk-CTUCTTIE.cjs.map
393
+ //# sourceMappingURL=chunk-VY4UMZMJ.cjs.map
394
+ //# sourceMappingURL=chunk-VY4UMZMJ.cjs.map
@@ -29,5 +29,5 @@ function createClickBuffer(ctx, frequency, duration) {
29
29
  }
30
30
 
31
31
  export { createClickBuffer, createNoiseBuffer, createSineBuffer };
32
- //# sourceMappingURL=chunk-LETS7FKB.js.map
33
- //# sourceMappingURL=chunk-LETS7FKB.js.map
32
+ //# sourceMappingURL=chunk-YFK7ETCF.js.map
33
+ //# sourceMappingURL=chunk-YFK7ETCF.js.map
@@ -1,4 +1,4 @@
1
- import { a as CreateContextOptions } from './types-DUrbEbPl.cjs';
1
+ import { a as CreateContextOptions } from './types-BYC6m7Q0.cjs';
2
2
 
3
3
  /**
4
4
  * Create an `AudioContext` with optional configuration.
package/dist/context.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as CreateContextOptions } from './types-DUrbEbPl.js';
1
+ import { a as CreateContextOptions } from './types-BYC6m7Q0.js';
2
2
 
3
3
  /**
4
4
  * Create an `AudioContext` with optional configuration.
package/dist/emitter.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunk5J7S6QV3_cjs = require('./chunk-5J7S6QV3.cjs');
3
+ var chunkHIF3UAF3_cjs = require('./chunk-HIF3UAF3.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "createEmitter", {
8
8
  enumerable: true,
9
- get: function () { return chunk5J7S6QV3_cjs.createEmitter; }
9
+ get: function () { return chunkHIF3UAF3_cjs.createEmitter; }
10
10
  });
11
11
  //# sourceMappingURL=emitter.cjs.map
12
12
  //# sourceMappingURL=emitter.cjs.map
package/dist/emitter.js CHANGED
@@ -1,3 +1,3 @@
1
- export { createEmitter } from './chunk-GYH2JSCY.js';
1
+ export { createEmitter } from './chunk-FY273Z3I.js';
2
2
  //# sourceMappingURL=emitter.js.map
3
3
  //# sourceMappingURL=emitter.js.map
@@ -0,0 +1,4 @@
1
+ export { createStretcherEngine, trimOverlap } from './chunk-GDBOHOGF.js';
2
+ import './chunk-FY273Z3I.js';
3
+ //# sourceMappingURL=engine-7DCOERRN.js.map
4
+ //# sourceMappingURL=engine-7DCOERRN.js.map
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ var chunkG37HMZEX_cjs = require('./chunk-G37HMZEX.cjs');
4
+ require('./chunk-HIF3UAF3.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "createStretcherEngine", {
9
+ enumerable: true,
10
+ get: function () { return chunkG37HMZEX_cjs.createStretcherEngine; }
11
+ });
12
+ Object.defineProperty(exports, "trimOverlap", {
13
+ enumerable: true,
14
+ get: function () { return chunkG37HMZEX_cjs.trimOverlap; }
15
+ });
16
+ //# sourceMappingURL=engine-ALWPAIX6.cjs.map
17
+ //# sourceMappingURL=engine-ALWPAIX6.cjs.map
package/dist/fade.cjs CHANGED
@@ -1,24 +1,24 @@
1
1
  'use strict';
2
2
 
3
- var chunk4LNVRSTM_cjs = require('./chunk-4LNVRSTM.cjs');
3
+ var chunkOIY6I4TU_cjs = require('./chunk-OIY6I4TU.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "autoFade", {
8
8
  enumerable: true,
9
- get: function () { return chunk4LNVRSTM_cjs.autoFade; }
9
+ get: function () { return chunkOIY6I4TU_cjs.autoFade; }
10
10
  });
11
11
  Object.defineProperty(exports, "crossfade", {
12
12
  enumerable: true,
13
- get: function () { return chunk4LNVRSTM_cjs.crossfade; }
13
+ get: function () { return chunkOIY6I4TU_cjs.crossfade; }
14
14
  });
15
15
  Object.defineProperty(exports, "fadeIn", {
16
16
  enumerable: true,
17
- get: function () { return chunk4LNVRSTM_cjs.fadeIn; }
17
+ get: function () { return chunkOIY6I4TU_cjs.fadeIn; }
18
18
  });
19
19
  Object.defineProperty(exports, "fadeOut", {
20
20
  enumerable: true,
21
- get: function () { return chunk4LNVRSTM_cjs.fadeOut; }
21
+ get: function () { return chunkOIY6I4TU_cjs.fadeOut; }
22
22
  });
23
23
  //# sourceMappingURL=fade.cjs.map
24
24
  //# sourceMappingURL=fade.cjs.map
package/dist/fade.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { e as Playback, A as AutoFadeOptions, b as CrossfadeOptions, c as FadeOptions } from './types-DUrbEbPl.cjs';
1
+ import { e as Playback, A as AutoFadeOptions, b as CrossfadeOptions, c as FadeOptions } from './types-BYC6m7Q0.cjs';
2
2
 
3
3
  /**
4
4
  * Fade a `GainNode` in from 0 to `target`.