@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.
- package/dist/audio/audio-for-preview.d.ts +30 -0
- package/dist/audio/audio-for-preview.js +213 -0
- package/dist/audio/audio-for-rendering.js +63 -12
- package/dist/audio/audio.js +8 -50
- package/dist/audio/props.d.ts +12 -3
- package/dist/audio-extraction/audio-cache.d.ts +1 -1
- package/dist/audio-extraction/audio-cache.js +5 -1
- package/dist/audio-extraction/audio-iterator.d.ts +7 -3
- package/dist/audio-extraction/audio-iterator.js +35 -12
- package/dist/audio-extraction/audio-manager.d.ts +10 -38
- package/dist/audio-extraction/audio-manager.js +40 -11
- package/dist/audio-extraction/extract-audio.d.ts +11 -3
- package/dist/audio-extraction/extract-audio.js +37 -17
- package/dist/caches.d.ts +11 -45
- package/dist/convert-audiodata/apply-tonefrequency.d.ts +2 -0
- package/dist/convert-audiodata/apply-tonefrequency.js +43 -0
- package/dist/convert-audiodata/combine-audiodata.js +2 -23
- package/dist/convert-audiodata/convert-audiodata.d.ts +1 -5
- package/dist/convert-audiodata/convert-audiodata.js +16 -24
- package/dist/convert-audiodata/wsola.d.ts +13 -0
- package/dist/convert-audiodata/wsola.js +197 -0
- package/dist/esm/index.mjs +2265 -589
- package/dist/extract-frame-and-audio.d.ts +7 -7
- package/dist/extract-frame-and-audio.js +69 -26
- package/dist/get-sink-weak.d.ts +3 -8
- package/dist/get-sink-weak.js +3 -11
- package/dist/get-sink.d.ts +13 -0
- package/dist/get-sink.js +15 -0
- package/dist/get-time-in-seconds.d.ts +10 -0
- package/dist/get-time-in-seconds.js +25 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.js +12 -2
- package/dist/is-network-error.d.ts +6 -0
- package/dist/is-network-error.js +17 -0
- package/dist/render-timestamp-range.d.ts +1 -0
- package/dist/render-timestamp-range.js +9 -0
- package/dist/video/media-player.d.ts +91 -0
- package/dist/video/media-player.js +484 -0
- package/dist/video/props.d.ts +37 -18
- package/dist/video/resolve-playback-time.d.ts +8 -0
- package/dist/video/resolve-playback-time.js +22 -0
- package/dist/video/timeout-utils.d.ts +2 -0
- package/dist/video/timeout-utils.js +18 -0
- package/dist/video/video-for-preview.d.ts +25 -0
- package/dist/video/video-for-preview.js +241 -0
- package/dist/video/video-for-rendering.d.ts +26 -2
- package/dist/video/video-for-rendering.js +95 -19
- package/dist/video/video.js +13 -18
- package/dist/video-extraction/extract-frame-via-broadcast-channel.d.ts +19 -6
- package/dist/video-extraction/extract-frame-via-broadcast-channel.js +67 -4
- package/dist/video-extraction/extract-frame.d.ts +21 -2
- package/dist/video-extraction/extract-frame.js +46 -9
- package/dist/video-extraction/get-frames-since-keyframe.d.ts +17 -10
- package/dist/video-extraction/get-frames-since-keyframe.js +77 -21
- package/dist/video-extraction/keyframe-bank.d.ts +3 -2
- package/dist/video-extraction/keyframe-bank.js +32 -12
- package/dist/video-extraction/keyframe-manager.d.ts +3 -8
- package/dist/video-extraction/keyframe-manager.js +25 -10
- 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
|
+
}
|