@hyperframes/engine 0.6.56 → 0.6.57
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audioVolumeEnvelope.d.ts","sourceRoot":"","sources":["../../src/services/audioVolumeEnvelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"audioVolumeEnvelope.d.ts","sourceRoot":"","sources":["../../src/services/audioVolumeEnvelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAyDjE;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,mBAAmB,EAAE,EAChC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAkDT"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { readFileSync, renameSync, writeFileSync } from "fs";
|
|
18
18
|
import { randomBytes } from "crypto";
|
|
19
|
+
import { normaliseEnvelope } from "@hyperframes/core/media-volume-envelope";
|
|
19
20
|
const PCM_FORMAT = 1; // WAVE_FORMAT_PCM
|
|
20
21
|
const SUPPORTED_BITS = 16;
|
|
21
22
|
/**
|
|
@@ -64,34 +65,6 @@ function parseWavLayout(buffer) {
|
|
|
64
65
|
dataSize: data.size,
|
|
65
66
|
};
|
|
66
67
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Normalise keyframes to track-relative seconds, sorted and de-duplicated, with
|
|
69
|
-
* `baseVolume` filling any gap before the first keyframe. Returns the breakpoints
|
|
70
|
-
* the gain envelope is linearly interpolated between.
|
|
71
|
-
*/
|
|
72
|
-
function toRelativeEnvelope(keyframes, trackStart, baseVolume) {
|
|
73
|
-
const points = keyframes
|
|
74
|
-
.filter((k) => Number.isFinite(k.time) && Number.isFinite(k.volume))
|
|
75
|
-
.map((k) => ({
|
|
76
|
-
time: Math.max(0, k.time - trackStart),
|
|
77
|
-
volume: Math.max(0, Math.min(1, k.volume)),
|
|
78
|
-
}))
|
|
79
|
-
.sort((a, b) => a.time - b.time);
|
|
80
|
-
const deduped = [];
|
|
81
|
-
for (const point of points) {
|
|
82
|
-
const previous = deduped.at(-1);
|
|
83
|
-
if (previous && Math.abs(previous.time - point.time) < 1e-9)
|
|
84
|
-
previous.volume = point.volume;
|
|
85
|
-
else
|
|
86
|
-
deduped.push(point);
|
|
87
|
-
}
|
|
88
|
-
if (deduped.length === 0)
|
|
89
|
-
return deduped;
|
|
90
|
-
if (deduped[0].time > 0) {
|
|
91
|
-
deduped.unshift({ time: 0, volume: Math.max(0, Math.min(1, baseVolume)) });
|
|
92
|
-
}
|
|
93
|
-
return deduped;
|
|
94
|
-
}
|
|
95
68
|
/**
|
|
96
69
|
* Multiply a prepared WAV's samples by a time-varying gain envelope in place.
|
|
97
70
|
*
|
|
@@ -99,7 +72,7 @@ function toRelativeEnvelope(keyframes, trackStart, baseVolume) {
|
|
|
99
72
|
* expected 16-bit PCM (caller should fall back to the expression path).
|
|
100
73
|
*/
|
|
101
74
|
export function applyVolumeEnvelopeToWav(wavPath, keyframes, trackStart, baseVolume) {
|
|
102
|
-
const envelope =
|
|
75
|
+
const envelope = normaliseEnvelope(keyframes, trackStart, baseVolume);
|
|
103
76
|
if (envelope.length === 0)
|
|
104
77
|
return false;
|
|
105
78
|
try {
|
|
@@ -111,6 +84,10 @@ export function applyVolumeEnvelopeToWav(wavPath, keyframes, trackStart, baseVol
|
|
|
111
84
|
const bytesPerSample = SUPPORTED_BITS / 8;
|
|
112
85
|
const frameBytes = numChannels * bytesPerSample;
|
|
113
86
|
const frameCount = Math.floor(dataSize / frameBytes);
|
|
87
|
+
// Maintain an incremental segment cursor so the per-frame envelope lookup
|
|
88
|
+
// is O(N+M) overall, not O(N×M). interpolateVolumeGain restarts from 0 on
|
|
89
|
+
// each call — fine for the preview path (one call per RAF tick) but not for
|
|
90
|
+
// the PCM path (one call per sample, 48k×duration frames total).
|
|
114
91
|
let segment = 0;
|
|
115
92
|
for (let frame = 0; frame < frameCount; frame += 1) {
|
|
116
93
|
const time = frame / sampleRate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audioVolumeEnvelope.js","sourceRoot":"","sources":["../../src/services/audioVolumeEnvelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"audioVolumeEnvelope.js","sourceRoot":"","sources":["../../src/services/audioVolumeEnvelope.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/engine",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.57",
|
|
4
4
|
"description": "Seekable web page to video rendering engine (Puppeteer + FFmpeg)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"linkedom": "^0.18.12",
|
|
22
22
|
"puppeteer": "^24.0.0",
|
|
23
23
|
"puppeteer-core": "^24.39.1",
|
|
24
|
-
"@hyperframes/core": "^0.6.
|
|
24
|
+
"@hyperframes/core": "^0.6.57"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^25.0.10",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { readFileSync, renameSync, writeFileSync } from "fs";
|
|
19
19
|
import { randomBytes } from "crypto";
|
|
20
20
|
import type { AudioVolumeKeyframe } from "./audioMixer.types.js";
|
|
21
|
+
import { normaliseEnvelope } from "@hyperframes/core/media-volume-envelope";
|
|
21
22
|
|
|
22
23
|
const PCM_FORMAT = 1; // WAVE_FORMAT_PCM
|
|
23
24
|
const SUPPORTED_BITS = 16;
|
|
@@ -73,38 +74,6 @@ function parseWavLayout(buffer: Buffer): WavLayout | null {
|
|
|
73
74
|
};
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
/**
|
|
77
|
-
* Normalise keyframes to track-relative seconds, sorted and de-duplicated, with
|
|
78
|
-
* `baseVolume` filling any gap before the first keyframe. Returns the breakpoints
|
|
79
|
-
* the gain envelope is linearly interpolated between.
|
|
80
|
-
*/
|
|
81
|
-
function toRelativeEnvelope(
|
|
82
|
-
keyframes: AudioVolumeKeyframe[],
|
|
83
|
-
trackStart: number,
|
|
84
|
-
baseVolume: number,
|
|
85
|
-
): { time: number; volume: number }[] {
|
|
86
|
-
const points = keyframes
|
|
87
|
-
.filter((k) => Number.isFinite(k.time) && Number.isFinite(k.volume))
|
|
88
|
-
.map((k) => ({
|
|
89
|
-
time: Math.max(0, k.time - trackStart),
|
|
90
|
-
volume: Math.max(0, Math.min(1, k.volume)),
|
|
91
|
-
}))
|
|
92
|
-
.sort((a, b) => a.time - b.time);
|
|
93
|
-
|
|
94
|
-
const deduped: { time: number; volume: number }[] = [];
|
|
95
|
-
for (const point of points) {
|
|
96
|
-
const previous = deduped.at(-1);
|
|
97
|
-
if (previous && Math.abs(previous.time - point.time) < 1e-9) previous.volume = point.volume;
|
|
98
|
-
else deduped.push(point);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (deduped.length === 0) return deduped;
|
|
102
|
-
if (deduped[0]!.time > 0) {
|
|
103
|
-
deduped.unshift({ time: 0, volume: Math.max(0, Math.min(1, baseVolume)) });
|
|
104
|
-
}
|
|
105
|
-
return deduped;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
77
|
/**
|
|
109
78
|
* Multiply a prepared WAV's samples by a time-varying gain envelope in place.
|
|
110
79
|
*
|
|
@@ -117,7 +86,7 @@ export function applyVolumeEnvelopeToWav(
|
|
|
117
86
|
trackStart: number,
|
|
118
87
|
baseVolume: number,
|
|
119
88
|
): boolean {
|
|
120
|
-
const envelope =
|
|
89
|
+
const envelope = normaliseEnvelope(keyframes, trackStart, baseVolume);
|
|
121
90
|
if (envelope.length === 0) return false;
|
|
122
91
|
|
|
123
92
|
try {
|
|
@@ -130,6 +99,10 @@ export function applyVolumeEnvelopeToWav(
|
|
|
130
99
|
const frameBytes = numChannels * bytesPerSample;
|
|
131
100
|
const frameCount = Math.floor(dataSize / frameBytes);
|
|
132
101
|
|
|
102
|
+
// Maintain an incremental segment cursor so the per-frame envelope lookup
|
|
103
|
+
// is O(N+M) overall, not O(N×M). interpolateVolumeGain restarts from 0 on
|
|
104
|
+
// each call — fine for the preview path (one call per RAF tick) but not for
|
|
105
|
+
// the PCM path (one call per sample, 48k×duration frames total).
|
|
133
106
|
let segment = 0;
|
|
134
107
|
for (let frame = 0; frame < frameCount; frame += 1) {
|
|
135
108
|
const time = frame / sampleRate;
|