@remotion/media 4.0.355 → 4.0.357

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 (59) hide show
  1. package/dist/audio/audio-for-preview.d.ts +30 -0
  2. package/dist/audio/audio-for-preview.js +213 -0
  3. package/dist/audio/audio-for-rendering.js +63 -12
  4. package/dist/audio/audio.js +8 -50
  5. package/dist/audio/props.d.ts +12 -3
  6. package/dist/audio-extraction/audio-cache.d.ts +1 -1
  7. package/dist/audio-extraction/audio-cache.js +5 -1
  8. package/dist/audio-extraction/audio-iterator.d.ts +7 -3
  9. package/dist/audio-extraction/audio-iterator.js +35 -12
  10. package/dist/audio-extraction/audio-manager.d.ts +10 -38
  11. package/dist/audio-extraction/audio-manager.js +40 -11
  12. package/dist/audio-extraction/extract-audio.d.ts +11 -3
  13. package/dist/audio-extraction/extract-audio.js +37 -17
  14. package/dist/caches.d.ts +11 -45
  15. package/dist/convert-audiodata/apply-tonefrequency.d.ts +2 -0
  16. package/dist/convert-audiodata/apply-tonefrequency.js +43 -0
  17. package/dist/convert-audiodata/combine-audiodata.js +2 -23
  18. package/dist/convert-audiodata/convert-audiodata.d.ts +1 -5
  19. package/dist/convert-audiodata/convert-audiodata.js +16 -24
  20. package/dist/convert-audiodata/wsola.d.ts +13 -0
  21. package/dist/convert-audiodata/wsola.js +197 -0
  22. package/dist/esm/index.mjs +2265 -589
  23. package/dist/extract-frame-and-audio.d.ts +7 -7
  24. package/dist/extract-frame-and-audio.js +69 -26
  25. package/dist/get-sink-weak.d.ts +3 -8
  26. package/dist/get-sink-weak.js +3 -11
  27. package/dist/get-sink.d.ts +13 -0
  28. package/dist/get-sink.js +15 -0
  29. package/dist/get-time-in-seconds.d.ts +10 -0
  30. package/dist/get-time-in-seconds.js +25 -0
  31. package/dist/index.d.ts +13 -3
  32. package/dist/index.js +12 -2
  33. package/dist/is-network-error.d.ts +6 -0
  34. package/dist/is-network-error.js +17 -0
  35. package/dist/render-timestamp-range.d.ts +1 -0
  36. package/dist/render-timestamp-range.js +9 -0
  37. package/dist/video/media-player.d.ts +91 -0
  38. package/dist/video/media-player.js +484 -0
  39. package/dist/video/props.d.ts +37 -18
  40. package/dist/video/resolve-playback-time.d.ts +8 -0
  41. package/dist/video/resolve-playback-time.js +22 -0
  42. package/dist/video/timeout-utils.d.ts +2 -0
  43. package/dist/video/timeout-utils.js +18 -0
  44. package/dist/video/video-for-preview.d.ts +25 -0
  45. package/dist/video/video-for-preview.js +241 -0
  46. package/dist/video/video-for-rendering.d.ts +26 -2
  47. package/dist/video/video-for-rendering.js +95 -19
  48. package/dist/video/video.js +13 -18
  49. package/dist/video-extraction/extract-frame-via-broadcast-channel.d.ts +19 -6
  50. package/dist/video-extraction/extract-frame-via-broadcast-channel.js +67 -4
  51. package/dist/video-extraction/extract-frame.d.ts +21 -2
  52. package/dist/video-extraction/extract-frame.js +46 -9
  53. package/dist/video-extraction/get-frames-since-keyframe.d.ts +17 -10
  54. package/dist/video-extraction/get-frames-since-keyframe.js +77 -21
  55. package/dist/video-extraction/keyframe-bank.d.ts +3 -2
  56. package/dist/video-extraction/keyframe-bank.js +32 -12
  57. package/dist/video-extraction/keyframe-manager.d.ts +3 -8
  58. package/dist/video-extraction/keyframe-manager.js +25 -10
  59. package/package.json +4 -4
@@ -0,0 +1,197 @@
1
+ function clamp16(x) {
2
+ const y = Math.round(x);
3
+ return y < -32768 ? -32768 : y > 32767 ? 32767 : y;
4
+ }
5
+ /**
6
+ * WSOLA time-scale modification for interleaved Int16 PCM (multi-channel).
7
+ * - Preserves pitch approximately while changing tempo by factor f.
8
+ * - Works for N interleaved channels.
9
+ * - Mitigates head/tail fade-out via overlap-weight normalization and boundary reinforcement.
10
+ *
11
+ * @param input Interleaved Int16 PCM (e.g., LRLRLR... for stereo)
12
+ * @param channels Number of channels (>=1)
13
+ * @param f Tempo factor: >1 = faster/shorter, <1 = slower/longer
14
+ * @param opts Optional tuning parameters
15
+ * @returns Interleaved Int16Array with length ≈ round(input.length * f)
16
+ */
17
+ export function wsolaInt16Interleaved(input, channels, f) {
18
+ if (!Number.isFinite(f) || f <= 0)
19
+ throw new Error('f must be a positive finite number');
20
+ if (!Number.isInteger(channels) || channels <= 0)
21
+ throw new Error('channels must be a positive integer');
22
+ const n = input.length;
23
+ if (n === 0)
24
+ return new Int16Array(0);
25
+ if (n % channels !== 0)
26
+ throw new Error('input length must be a multiple of channels');
27
+ // Parameters and sensible defaults
28
+ const sampleRate = 48000;
29
+ const frameMs = 30; // 20–40 ms typical
30
+ const overlapRatio = 0.5;
31
+ const searchMs = 8; // +/- 8 ms local search
32
+ const winKind = 'hann';
33
+ const headReinf = 3;
34
+ const tailReinf = 3;
35
+ // Work per-channel
36
+ const samplesPerChannel = (n / channels) | 0;
37
+ // Frame and hop sizing
38
+ const frameSize = Math.max(128, Math.floor((sampleRate * frameMs) / 1000));
39
+ const overlap = Math.floor(frameSize * overlapRatio);
40
+ const anaHop = Math.max(1, frameSize - overlap);
41
+ const synHop = Math.max(1, Math.round(anaHop * f));
42
+ // Search radius in samples
43
+ const searchRadius = Math.max(0, Math.floor((sampleRate * searchMs) / 1000));
44
+ // Window
45
+ const win = new Float32Array(frameSize);
46
+ for (let i = 0; i < frameSize; i++) {
47
+ const x = (Math.PI * 2 * i) / (frameSize - 1);
48
+ win[i] =
49
+ winKind === 'hann' ? 0.5 * (1 - Math.cos(x)) : 0.54 - 0.46 * Math.cos(x); // Hamming
50
+ }
51
+ // Estimate output length per channel and allocate with extra headroom
52
+ const estFrames = Math.max(1, Math.ceil(Math.max(0, samplesPerChannel - frameSize) / anaHop) + 1);
53
+ const estLen = Math.max(0, frameSize + synHop * (estFrames - 1));
54
+ const extraHead = frameSize * (headReinf + 1);
55
+ const extraTail = frameSize * (tailReinf + 2);
56
+ const outLenAlloc = estLen + searchRadius + extraHead + extraTail;
57
+ const out = Array.from({ length: channels }, () => new Float32Array(outLenAlloc));
58
+ const outWeight = new Float32Array(outLenAlloc);
59
+ // Temporary buffers
60
+ const chanFrames = Array.from({ length: channels }, () => new Float32Array(frameSize));
61
+ const guideFrame = new Float32Array(frameSize);
62
+ // Helpers
63
+ function readChannelFrame(chan, start, dst) {
64
+ let srcIndex = start * channels + chan;
65
+ for (let i = 0; i < frameSize; i++) {
66
+ const pos = start + i;
67
+ dst[i] = pos >= 0 && pos < samplesPerChannel ? input[srcIndex] : 0;
68
+ srcIndex += channels;
69
+ }
70
+ }
71
+ function readGuideFrame(start) {
72
+ for (let i = 0; i < frameSize; i++) {
73
+ const pos = start + i;
74
+ if (pos >= 0 && pos < samplesPerChannel) {
75
+ let sum = 0;
76
+ const base = pos * channels;
77
+ for (let c = 0; c < channels; c++)
78
+ sum += input[base + c];
79
+ guideFrame[i] = sum / channels;
80
+ }
81
+ else {
82
+ guideFrame[i] = 0;
83
+ }
84
+ }
85
+ }
86
+ // Find best local alignment around outPos using normalized cross-correlation
87
+ function bestAlignment(outPoss) {
88
+ let bestShift = 0;
89
+ let bestScore = -Infinity;
90
+ for (let shift = -searchRadius; shift <= searchRadius; shift++) {
91
+ const pos = outPoss + shift - overlap;
92
+ let score = 0;
93
+ let normA = 0;
94
+ let normB = 0;
95
+ for (let i = 0; i < overlap; i++) {
96
+ const idx = pos + i;
97
+ const outVal = idx >= 0 && idx < outLenAlloc ? out[0][idx] : 0; // channel 0 proxy
98
+ const frmVal = guideFrame[i];
99
+ score += outVal * frmVal;
100
+ normA += outVal * outVal;
101
+ normB += frmVal * frmVal;
102
+ }
103
+ const denom = Math.sqrt((normA || 1e-9) * (normB || 1e-9));
104
+ const corr = score / denom;
105
+ if (corr > bestScore) {
106
+ bestScore = corr;
107
+ bestShift = shift;
108
+ }
109
+ }
110
+ return bestShift;
111
+ }
112
+ // Overlap-add a frame for all channels at writeStart with windowing
113
+ function olaAllChannels(writeStart) {
114
+ for (let c = 0; c < channels; c++) {
115
+ for (let i = 0; i < frameSize; i++) {
116
+ const idx = writeStart + i;
117
+ if (idx >= 0 && idx < outLenAlloc) {
118
+ const w = win[i];
119
+ out[c][idx] += chanFrames[c][i] * w;
120
+ if (c === 0)
121
+ outWeight[idx] += w; // track weights once
122
+ }
123
+ }
124
+ }
125
+ }
126
+ // 1) Seed: place the first frame at t=0
127
+ readGuideFrame(0);
128
+ for (let c = 0; c < channels; c++)
129
+ readChannelFrame(c, 0, chanFrames[c]);
130
+ olaAllChannels(0);
131
+ // 2) Head reinforcement: place extra frames whose writeStart <= 0
132
+ for (let h = 0; h < headReinf; h++) {
133
+ // Option 1: reuse the first analysis position to strengthen early region
134
+ const headIn = Math.min(anaHop * h, Math.max(0, samplesPerChannel - frameSize));
135
+ readGuideFrame(headIn);
136
+ for (let c = 0; c < channels; c++)
137
+ readChannelFrame(c, headIn, chanFrames[c]);
138
+ // Align around outPos=0 so we bias writeStart near/before 0
139
+ const shift = bestAlignment(0);
140
+ const writeStart = shift - overlap; // likely negative; ok, we clamp on write
141
+ olaAllChannels(writeStart);
142
+ }
143
+ // 3) Main WSOLA loop
144
+ let inPos = anaHop; // next analysis position (we already seeded at 0)
145
+ let outPos = synHop; // next synthesis position
146
+ while (inPos < samplesPerChannel - 1) {
147
+ readGuideFrame(inPos);
148
+ for (let c = 0; c < channels; c++)
149
+ readChannelFrame(c, inPos, chanFrames[c]);
150
+ const shift = bestAlignment(outPos);
151
+ const writeStart = outPos + shift - overlap;
152
+ olaAllChannels(writeStart);
153
+ inPos += anaHop;
154
+ outPos += synHop;
155
+ // Safety: if we're very close to capacity, break to handle tail separately
156
+ if (outPos > outLenAlloc - (frameSize + searchRadius + 8))
157
+ break;
158
+ }
159
+ // 4) Tail reinforcement: ensure the end gets full coverage
160
+ // Place a few extra frames around the last outPos using the last available input frames.
161
+ for (let t = 0; t < tailReinf; t++) {
162
+ const tailIn = Math.max(0, Math.min(samplesPerChannel - frameSize, inPos - anaHop * t));
163
+ readGuideFrame(tailIn);
164
+ for (let c = 0; c < channels; c++)
165
+ readChannelFrame(c, tailIn, chanFrames[c]);
166
+ const shift = bestAlignment(outPos);
167
+ const writeStart = outPos + shift - overlap;
168
+ olaAllChannels(writeStart);
169
+ outPos += synHop;
170
+ }
171
+ // 5) Normalize by accumulated weights BEFORE trimming
172
+ for (let i = 0; i < outLenAlloc; i++) {
173
+ const w = outWeight[i];
174
+ if (w > 1e-9) {
175
+ const inv = 1 / w;
176
+ for (let c = 0; c < channels; c++)
177
+ out[c][i] *= inv;
178
+ }
179
+ else {
180
+ for (let c = 0; c < channels; c++)
181
+ out[c][i] = 0;
182
+ }
183
+ }
184
+ // 6) Produce final interleaved Int16Array with length ≈ round(n * f)
185
+ const targetPerChan = Math.max(1, Math.round(samplesPerChannel * f));
186
+ const targetTotal = targetPerChan * channels;
187
+ const result = new Int16Array(targetTotal);
188
+ // Interleave and clamp/round
189
+ for (let i = 0; i < targetPerChan; i++) {
190
+ for (let c = 0; c < channels; c++) {
191
+ const v = i < out[c].length ? out[c][i] : 0;
192
+ const y = clamp16(v);
193
+ result[i * channels + c] = y;
194
+ }
195
+ }
196
+ return result;
197
+ }