nodejs-audio-visualizer 5.2.0 → 5.3.0

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/README.md CHANGED
@@ -1,81 +1,81 @@
1
- # nodejs-audio-visualizer
2
- Audio visualizer generator for Node.js with simple configuration.
3
- Supports PNG, JPG for images, MP4/MOV/AVI/MKV for background videos, and MP3, WAV for audio.
4
-
5
- ## Example
6
- ```javascript
7
- const renderAudioVisualizer = require('nodejs-audio-visualizer').renderAudioVisualizer;
8
- const config = {
9
- image: { // Optional.
10
- path: 'media/background.png' // Supports PNG and JPG images. Use either 'image' or 'video', not both.
11
- },
12
- // OR use a video as background (optional):
13
- // video: {
14
- // path: 'media/background.mp4', // Supports MP4, MOV, AVI, MKV. Loops automatically if shorter than audio. Can also be an array of paths, e.g. ['media/bg1.mp4', 'media/bg2.mp4']: with autoEdit false the videos play one after another (looping the sequence as needed), and with autoHighlight producing several videos each one starts with a different video from the array; with autoEdit true, cuts switch (shuffle) between the given videos instead of auto-detecting scene changes. Videos in an array should share the same resolution and frame rate for best results, especially when outVideo.resolution is not set.
15
- // autoEdit: true, // Optional. Detects scene cuts and advances between them on the detected BPM beat grid about every 2–4 beats so the background edits with the music; omit or false for one continuous play-through from the start. When enabled, a brief camera shake starts 0.1s after each cut and decays over about one-third of a beat (if the video has no detected scene changes, and so no cuts, it shakes every 2 beats instead).
16
- // cameraShake: false, // Optional. With autoEdit: set to false to disable the camera shake applied on cuts (default true).
17
- // },
18
- audio: {
19
- path: 'media/audio.wav', // Supports MP3 and WAV audio
20
- autoHighlight: true,
21
- autoHighlightCount: 3, // Optional. With autoHighlight: how many non-overlapping 15s windows with the highest summed spectral energy to aim for (default 1; must be a whole number ≥ 1). You may get fewer videos if the track is too short or does not have that many valid windows. More than one window produces separate videos next to outVideo.path (e.g. out-1.mp4, out-2.mp4).
22
- },
23
- outVideo: {
24
- path: 'media/out.mp4',
25
- subtitles: { // Optional.
26
- path: 'media/subtitles.lrc', // Optional. .srt or .lrc format.
27
- rawContent: "1\n00:00:00,000 --> 99:59:59,999\nSome Artist - Some Song", // Only if path not specified.
28
- alignment: "middle", // Optional. Available values: 'top', 'middle', 'bottom'. Default: 'bottom'.
29
- },
30
- fps: 25, // Default value: 30
31
- resolution: { width: 1920, height: 1080 }, // Optional. Output frame size in pixels. Omit to keep the background image or video at its native resolution; when set, video frames are scaled to this size and images are resized (center-cropped first if landscape/portrait does not match the target aspect).
32
- spectrum: { // Audio spectrum configuration (linear bar visualizer). Optional. If neither 'spectrum' nor 'polar' is specified, no visualizer is drawn.
33
- width: '30%', // 30% of background image width. Default value: 33%. Also you can use absolute values. For example, value 300 for 300 pixels width.
34
- height: '15%', // 15% of background image height. Default value: 160. Also you can use absolute values. For example, value 300 for 300 pixels height.
35
- x: 'center', // Available values: 'left', 'center', right'. Also you can use absolute number values. For example, value 300 for 300 pixels x.
36
- y: 'bottom', // Available values: 'top', 'middle', bottom'. Also you can use absolute number values. For example, value 300 for 300 pixels y.
37
- rotation: 'mirror', // Available values: 'up', 'down', 'mirror'. Default value: 'mirror'.
38
- effect: 'volume', // Available values: 'volume', 'smooth', undefined. Default value: undefined.
39
- color: '#cccc99', // Default value: inverted color of background image
40
- opacity: '70%' // Default value: '80%'.
41
- },
42
- polar: { // Polar/circular audio spectrum configuration. Optional. Use either 'spectrum' or 'polar', not both.
43
- x: 'center', // Available values: 'left', 'center', 'right'. Also you can use absolute number values. Default value: 'center'.
44
- y: 'middle', // Available values: 'top', 'middle', 'bottom'. Also you can use absolute number values. Default value: 'middle'.
45
- innerRadius: 100, // Inner radius of the circular spectrum in pixels. Default value: 100.
46
- maxBarLength: 160, // Maximum bar length in pixels. Default value: 160.
47
- barWidth: 15, // Width of each bar in pixels. Default value: 15.
48
- effect: 'volume', // Available values: 'volume', 'smooth', undefined. Default value: undefined.
49
- color: '#cccc99', // Default value: inverted color of background image
50
- opacity: '70%' // Default value: '80%'.
51
- }
52
- },
53
- tweaks: { // Optional
54
- ffmpeg_cfr: '30', // Default value: 23
55
- ffmpeg_preset: 'ultrafast', // Default value: medium
56
- frame_processing_delay: 1000, // Delay between processing frames in milliseconds
57
- timeouts: { // Optional. FFmpeg I/O timeouts in milliseconds
58
- readVideoFrame: 30000, // Max wait for one background video frame from ffmpeg. Default: 30000
59
- waitDrain: 120000, // Max wait for ffmpeg stdin to accept more frames. Default: 120000
60
- waitForProcessExit: 480000 // Max wait for ffmpeg to finish after all frames are sent. Default: 480000
61
- }
62
- }
63
- };
64
-
65
- const onProgress = (progressPercent: number) => { // not necessary callback
66
- console.log(`progress: ${progressPercent} %`);
67
- };
68
-
69
- const shouldStop = () => { // not necessary callback
70
- return false;
71
- };
72
-
73
- renderAudioVisualizer(config, onProgress, shouldStop)
74
- .then(({ exitCode, outputVideoFiles }) => {
75
- console.log(`exited with code: ${exitCode}`);
76
- console.log(`written:`, outputVideoFiles);
77
- });
78
- ```
79
-
80
- ## Output preview
81
- ![frame of output video](example/media/out-sample.png)
1
+ # nodejs-audio-visualizer
2
+ Audio visualizer generator for Node.js with simple configuration.
3
+ Supports PNG, JPG for images, MP4/MOV/AVI/MKV for background videos, and MP3, WAV for audio.
4
+
5
+ ## Example
6
+ ```javascript
7
+ const renderAudioVisualizer = require('nodejs-audio-visualizer').renderAudioVisualizer;
8
+ const config = {
9
+ image: { // Optional.
10
+ path: 'media/background.png' // Supports PNG and JPG images. Use either 'image' or 'video', not both.
11
+ },
12
+ // OR use a video as background (optional):
13
+ // video: {
14
+ // path: 'media/background.mp4', // Supports MP4, MOV, AVI, MKV. Loops automatically if shorter than audio. Can also be an array of paths, e.g. ['media/bg1.mp4', 'media/bg2.mp4']: with autoEdit false the videos play one after another (looping the sequence as needed), and with autoHighlight producing several videos each one starts with a different video from the array; with autoEdit true, cuts switch (shuffle) between the given videos instead of auto-detecting scene changes. Videos in an array should share the same resolution and frame rate for best results, especially when outVideo.resolution is not set.
15
+ // autoEdit: true, // Optional. Detects scene cuts and advances between them on the detected BPM beat grid about every 2–4 beats so the background edits with the music; omit or false for one continuous play-through from the start. When enabled, a brief camera shake starts 0.1s after each cut and decays over about one-third of a beat (if the video has no detected scene changes, and so no cuts, it shakes every 2 beats instead).
16
+ // cameraShake: false, // Optional. With autoEdit: set to false to disable the camera shake applied on cuts (default true).
17
+ // },
18
+ audio: {
19
+ path: 'media/audio.wav', // Supports MP3 and WAV audio
20
+ autoHighlight: true, // Optional. Cuts the most energetic ~15s of the track. Start and end are moved onto beats (by up to 1.5s each), preferring a length of whole 4-beat bars, so the highlight may run slightly shorter or longer than 15s.
21
+ autoHighlightCount: 3, // Optional. With autoHighlight: how many non-overlapping ~15s windows with the highest summed spectral energy to aim for (default 1; must be a whole number ≥ 1). You may get fewer videos if the track is too short or does not have that many valid windows. More than one window produces separate videos next to outVideo.path (e.g. out-1.mp4, out-2.mp4).
22
+ },
23
+ outVideo: {
24
+ path: 'media/out.mp4',
25
+ subtitles: { // Optional.
26
+ path: 'media/subtitles.lrc', // Optional. .srt or .lrc format.
27
+ rawContent: "1\n00:00:00,000 --> 99:59:59,999\nSome Artist - Some Song", // Only if path not specified.
28
+ alignment: "middle", // Optional. Available values: 'top', 'middle', 'bottom'. Default: 'bottom'.
29
+ },
30
+ fps: 25, // Default value: 30
31
+ resolution: { width: 1920, height: 1080 }, // Optional. Output frame size in pixels. Omit to keep the background image or video at its native resolution; when set, video frames are scaled to this size and images are resized (center-cropped first if landscape/portrait does not match the target aspect).
32
+ spectrum: { // Audio spectrum configuration (linear bar visualizer). Optional. If neither 'spectrum' nor 'polar' is specified, no visualizer is drawn.
33
+ width: '30%', // 30% of background image width. Default value: 33%. Also you can use absolute values. For example, value 300 for 300 pixels width.
34
+ height: '15%', // 15% of background image height. Default value: 160. Also you can use absolute values. For example, value 300 for 300 pixels height.
35
+ x: 'center', // Available values: 'left', 'center', right'. Also you can use absolute number values. For example, value 300 for 300 pixels x.
36
+ y: 'bottom', // Available values: 'top', 'middle', bottom'. Also you can use absolute number values. For example, value 300 for 300 pixels y.
37
+ rotation: 'mirror', // Available values: 'up', 'down', 'mirror'. Default value: 'mirror'.
38
+ effect: 'volume', // Available values: 'volume', 'smooth', undefined. Default value: undefined.
39
+ color: '#cccc99', // Default value: inverted color of background image
40
+ opacity: '70%' // Default value: '80%'.
41
+ },
42
+ polar: { // Polar/circular audio spectrum configuration. Optional. Use either 'spectrum' or 'polar', not both.
43
+ x: 'center', // Available values: 'left', 'center', 'right'. Also you can use absolute number values. Default value: 'center'.
44
+ y: 'middle', // Available values: 'top', 'middle', 'bottom'. Also you can use absolute number values. Default value: 'middle'.
45
+ innerRadius: 100, // Inner radius of the circular spectrum in pixels. Default value: 100.
46
+ maxBarLength: 160, // Maximum bar length in pixels. Default value: 160.
47
+ barWidth: 15, // Width of each bar in pixels. Default value: 15.
48
+ effect: 'volume', // Available values: 'volume', 'smooth', undefined. Default value: undefined.
49
+ color: '#cccc99', // Default value: inverted color of background image
50
+ opacity: '70%' // Default value: '80%'.
51
+ }
52
+ },
53
+ tweaks: { // Optional
54
+ ffmpeg_cfr: '30', // Default value: 23
55
+ ffmpeg_preset: 'ultrafast', // Default value: medium
56
+ frame_processing_delay: 1000, // Delay between processing frames in milliseconds
57
+ timeouts: { // Optional. FFmpeg I/O timeouts in milliseconds
58
+ readVideoFrame: 30000, // Max wait for one background video frame from ffmpeg. Default: 30000
59
+ waitDrain: 120000, // Max wait for ffmpeg stdin to accept more frames. Default: 120000
60
+ waitForProcessExit: 480000 // Max wait for ffmpeg to finish after all frames are sent. Default: 480000
61
+ }
62
+ }
63
+ };
64
+
65
+ const onProgress = (progressPercent: number) => { // not necessary callback
66
+ console.log(`progress: ${progressPercent} %`);
67
+ };
68
+
69
+ const shouldStop = () => { // not necessary callback
70
+ return false;
71
+ };
72
+
73
+ renderAudioVisualizer(config, onProgress, shouldStop)
74
+ .then(({ exitCode, outputVideoFiles }) => {
75
+ console.log(`exited with code: ${exitCode}`);
76
+ console.log(`written:`, outputVideoFiles);
77
+ });
78
+ ```
79
+
80
+ ## Output preview
81
+ ![frame of output video](example/media/out-sample.png)
@@ -4,6 +4,18 @@ export interface BeatFrameEvent {
4
4
  frameIndex: number;
5
5
  intensity: number;
6
6
  }
7
+ /**
8
+ * How far (seconds) a highlight boundary may move to land on a beat. The final length can
9
+ * therefore differ from `HIGHLIGHT_DURATION_SEC` by up to twice this value.
10
+ */
11
+ export declare const MAX_BEAT_SNAP_SEC = 1.5;
12
+ /** Tempo grid used to snap highlight cuts to beats (subset of `TempoEstimate`). */
13
+ export interface HighlightBeatGrid {
14
+ periodFrames: number;
15
+ phaseFrame: number;
16
+ /** Beat times in seconds from the start of the audio. */
17
+ beatsSec?: number[];
18
+ }
7
19
  export interface HighlightAudioSegment {
8
20
  seekSeconds: number;
9
21
  durationSeconds: number;
@@ -18,10 +30,30 @@ export interface HighlightRun {
18
30
  audioSegment: HighlightAudioSegment;
19
31
  }
20
32
  /**
21
- * Picks up to `segmentCount` non-overlapping 15s windows with highest summed spectral energy each,
22
- * sorts them chronologically, concatenates spectrums, and remaps beat indices.
33
+ * Beat frames (sorted, unique, within [0, totalFrames]) where a highlight may start or end.
34
+ * With a tempo grid: tracked beats from the analyzed region, then the regular grid beyond it
35
+ * (each grid beat nudged onto a nearby detected onset to follow slight tempo drift).
36
+ * Without one: the detected onset beats.
37
+ */
38
+ export declare function buildBeatCandidates(fps: number, totalFrames: number, beatEvents: BeatFrameEvent[], beatGrid?: HighlightBeatGrid | null): number[];
39
+ /**
40
+ * Moves a fixed-length window's start and end onto beats (each by at most `maxShiftFrames`),
41
+ * preferring lengths that span whole bars when the beat period is known.
42
+ * Boundaries without a nearby beat stay where they are.
43
+ */
44
+ export declare function snapSegmentToBeats(seg: {
45
+ startFrame: number;
46
+ highlightFrames: number;
47
+ }, totalFrames: number, beatFrames: number[], maxShiftFrames: number, periodFrames?: number): {
48
+ startFrame: number;
49
+ highlightFrames: number;
50
+ };
51
+ /**
52
+ * Picks up to `segmentCount` non-overlapping ~15s windows with highest summed spectral energy each,
53
+ * moves their boundaries onto beats (see `snapSegmentToBeats`), sorts them chronologically,
54
+ * concatenates spectrums, and remaps beat indices.
23
55
  */
24
- export declare function computeHighlightSlice(fps: number, totalFrames: number, spectrums: number[][], beatEvents: BeatFrameEvent[], segmentCount?: number): Promise<{
56
+ export declare function computeHighlightSlice(fps: number, totalFrames: number, spectrums: number[][], beatEvents: BeatFrameEvent[], segmentCount?: number, beatGrid?: HighlightBeatGrid | null): Promise<{
25
57
  startFrame: number;
26
58
  highlightFrames: number;
27
59
  spectrums: number[][];
package/dist/highlight.js CHANGED
@@ -39,6 +39,17 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  var waitForEventLoop_1 = require("./waitForEventLoop");
41
41
  exports.HIGHLIGHT_DURATION_SEC = 15;
42
+ /**
43
+ * How far (seconds) a highlight boundary may move to land on a beat. The final length can
44
+ * therefore differ from `HIGHLIGHT_DURATION_SEC` by up to twice this value.
45
+ */
46
+ exports.MAX_BEAT_SNAP_SEC = 1.5;
47
+ /** Beats per bar used when preferring highlight lengths made of whole bars. */
48
+ var BEATS_PER_BAR = 4;
49
+ /** Cost (in beats of boundary shift) for each beat the length is away from a whole bar. */
50
+ var OFF_BAR_PENALTY = 3;
51
+ /** Grid beats past the analyzed tempo region snap to a detected onset within this share of a beat. */
52
+ var GRID_ONSET_SNAP_SHARE = 0.2;
42
53
  function buildHighlightRun(fps, seg, spectrums, beatEvents) {
43
54
  var startFrame = seg.startFrame, highlightFrames = seg.highlightFrames;
44
55
  var spectrumsSlice = spectrums.slice(startFrame, startFrame + highlightFrames);
@@ -214,17 +225,136 @@ function findBestHighlightStart(energies, totalFrames, windowFrames, excludeRang
214
225
  });
215
226
  });
216
227
  }
228
+ function nearestOnset(sortedOnsets, frame) {
229
+ var lo = 0;
230
+ var hi = sortedOnsets.length;
231
+ while (lo < hi) {
232
+ var mid = (lo + hi) >> 1;
233
+ if (sortedOnsets[mid] < frame) {
234
+ lo = mid + 1;
235
+ }
236
+ else {
237
+ hi = mid;
238
+ }
239
+ }
240
+ var best = null;
241
+ for (var _i = 0, _a = [lo - 1, lo]; _i < _a.length; _i++) {
242
+ var i = _a[_i];
243
+ if (i >= 0 && i < sortedOnsets.length) {
244
+ var v = sortedOnsets[i];
245
+ if (best === null || Math.abs(v - frame) < Math.abs(best - frame)) {
246
+ best = v;
247
+ }
248
+ }
249
+ }
250
+ return best;
251
+ }
217
252
  /**
218
- * Picks up to `segmentCount` non-overlapping 15s windows with highest summed spectral energy each,
219
- * sorts them chronologically, concatenates spectrums, and remaps beat indices.
253
+ * Beat frames (sorted, unique, within [0, totalFrames]) where a highlight may start or end.
254
+ * With a tempo grid: tracked beats from the analyzed region, then the regular grid beyond it
255
+ * (each grid beat nudged onto a nearby detected onset to follow slight tempo drift).
256
+ * Without one: the detected onset beats.
220
257
  */
221
- function computeHighlightSlice(fps, totalFrames, spectrums, beatEvents, segmentCount) {
222
- if (segmentCount === void 0) { segmentCount = 1; }
258
+ function buildBeatCandidates(fps, totalFrames, beatEvents, beatGrid) {
223
259
  var _a, _b, _c;
260
+ var onsets = Array.from(new Set(beatEvents.map(function (b) { return b.frameIndex; })))
261
+ .filter(function (f) { return f >= 0 && f <= totalFrames; })
262
+ .sort(function (a, b) { return a - b; });
263
+ var period = (_b = (_a = beatGrid) === null || _a === void 0 ? void 0 : _a.periodFrames, (_b !== null && _b !== void 0 ? _b : 0));
264
+ if (!beatGrid || !(period > 0) || !isFinite(period)) {
265
+ return onsets;
266
+ }
267
+ var frames = new Set();
268
+ var lastTracked = -Infinity;
269
+ for (var _i = 0, _d = (_c = beatGrid.beatsSec, (_c !== null && _c !== void 0 ? _c : [])); _i < _d.length; _i++) {
270
+ var t = _d[_i];
271
+ var f = Math.round(t * fps);
272
+ if (f >= 0 && f <= totalFrames) {
273
+ frames.add(f);
274
+ lastTracked = Math.max(lastTracked, f);
275
+ }
276
+ }
277
+ var maxOnsetShift = period * GRID_ONSET_SNAP_SHARE;
278
+ var firstN = Math.ceil(-beatGrid.phaseFrame / period);
279
+ for (var n = firstN;; n++) {
280
+ var gridFrame = beatGrid.phaseFrame + n * period;
281
+ if (gridFrame > totalFrames) {
282
+ break;
283
+ }
284
+ if (gridFrame <= lastTracked + period / 2) {
285
+ continue;
286
+ }
287
+ var onset = nearestOnset(onsets, gridFrame);
288
+ var f = onset !== null && Math.abs(onset - gridFrame) <= maxOnsetShift
289
+ ? onset
290
+ : Math.round(gridFrame);
291
+ if (f >= 0 && f <= totalFrames) {
292
+ frames.add(f);
293
+ }
294
+ }
295
+ return Array.from(frames).sort(function (a, b) { return a - b; });
296
+ }
297
+ exports.buildBeatCandidates = buildBeatCandidates;
298
+ /**
299
+ * Moves a fixed-length window's start and end onto beats (each by at most `maxShiftFrames`),
300
+ * preferring lengths that span whole bars when the beat period is known.
301
+ * Boundaries without a nearby beat stay where they are.
302
+ */
303
+ function snapSegmentToBeats(seg, totalFrames, beatFrames, maxShiftFrames, periodFrames) {
304
+ var rawStart = seg.startFrame;
305
+ var rawEnd = seg.startFrame + seg.highlightFrames;
306
+ var near = function (target, max) {
307
+ return beatFrames.filter(function (f) { return Math.abs(f - target) <= maxShiftFrames && f >= 0 && f <= max; });
308
+ };
309
+ var startCands = near(rawStart, totalFrames - 1);
310
+ var endCands = near(rawEnd, totalFrames);
311
+ if (startCands.length === 0) {
312
+ startCands.push(rawStart);
313
+ }
314
+ if (endCands.length === 0) {
315
+ endCands.push(Math.min(rawEnd, totalFrames));
316
+ }
317
+ var period = periodFrames && periodFrames > 0 && isFinite(periodFrames) ? periodFrames : 0;
318
+ var shiftUnit = period > 0 ? period : Math.max(1, maxShiftFrames);
319
+ var best = null;
320
+ var bestCost = Infinity;
321
+ for (var _i = 0, startCands_1 = startCands; _i < startCands_1.length; _i++) {
322
+ var s = startCands_1[_i];
323
+ for (var _a = 0, endCands_1 = endCands; _a < endCands_1.length; _a++) {
324
+ var e = endCands_1[_a];
325
+ if (e - s < seg.highlightFrames / 2) {
326
+ continue;
327
+ }
328
+ var cost = (Math.abs(s - rawStart) + Math.abs(e - rawEnd)) / shiftUnit;
329
+ if (period > 0) {
330
+ var beats = Math.round((e - s) / period);
331
+ var offBar = Math.abs(beats - BEATS_PER_BAR * Math.round(beats / BEATS_PER_BAR));
332
+ cost += offBar * OFF_BAR_PENALTY;
333
+ }
334
+ if (cost < bestCost) {
335
+ bestCost = cost;
336
+ best = { startFrame: s, endFrame: e };
337
+ }
338
+ }
339
+ }
340
+ if (!best) {
341
+ return seg;
342
+ }
343
+ return { startFrame: best.startFrame, highlightFrames: best.endFrame - best.startFrame };
344
+ }
345
+ exports.snapSegmentToBeats = snapSegmentToBeats;
346
+ /**
347
+ * Picks up to `segmentCount` non-overlapping ~15s windows with highest summed spectral energy each,
348
+ * moves their boundaries onto beats (see `snapSegmentToBeats`), sorts them chronologically,
349
+ * concatenates spectrums, and remaps beat indices.
350
+ */
351
+ function computeHighlightSlice(fps, totalFrames, spectrums, beatEvents, segmentCount, beatGrid) {
352
+ if (segmentCount === void 0) { segmentCount = 1; }
353
+ var _a, _b, _c, _d;
224
354
  return __awaiter(this, void 0, void 0, function () {
225
- var highlightFramesTarget, audioSegments_1, fullSeg, fullRun, highlightFrames, energies, excludeRanges, rawSegments, n, k, startFrame, runs, slicedSpectrums, beatFrameIndices, beatIntensities, outOffset, _loop_1, _i, rawSegments_1, seg, totalHighlightFrames, audioSegments, first;
226
- return __generator(this, function (_d) {
227
- switch (_d.label) {
355
+ var highlightFramesTarget, audioSegments_1, fullSeg, fullRun, highlightFrames, energies, excludeRanges, rawSegments, beatFrames, maxShiftFrames, n, k, startFrame, snapped, runs, slicedSpectrums, beatFrameIndices, beatIntensities, outOffset, _loop_1, _i, rawSegments_1, seg, totalHighlightFrames, audioSegments, first;
356
+ return __generator(this, function (_e) {
357
+ switch (_e.label) {
228
358
  case 0:
229
359
  highlightFramesTarget = Math.ceil(exports.HIGHLIGHT_DURATION_SEC * fps);
230
360
  if (totalFrames <= 0) {
@@ -264,23 +394,30 @@ function computeHighlightSlice(fps, totalFrames, spectrums, beatEvents, segmentC
264
394
  highlightFrames = highlightFramesTarget;
265
395
  return [4 /*yield*/, buildFrameEnergies(spectrums, totalFrames)];
266
396
  case 1:
267
- energies = _d.sent();
397
+ energies = _e.sent();
268
398
  excludeRanges = [];
269
399
  rawSegments = [];
400
+ beatFrames = buildBeatCandidates(fps, totalFrames, beatEvents, beatGrid);
401
+ maxShiftFrames = Math.round(exports.MAX_BEAT_SNAP_SEC * fps);
270
402
  n = Math.max(1, Math.floor(segmentCount));
271
403
  k = 0;
272
- _d.label = 2;
404
+ _e.label = 2;
273
405
  case 2:
274
406
  if (!(k < n)) return [3 /*break*/, 5];
275
407
  return [4 /*yield*/, findBestHighlightStart(energies, totalFrames, highlightFrames, excludeRanges)];
276
408
  case 3:
277
- startFrame = _d.sent();
409
+ startFrame = _e.sent();
278
410
  if (startFrame === null) {
279
411
  return [3 /*break*/, 5];
280
412
  }
281
- rawSegments.push({ startFrame: startFrame, highlightFrames: highlightFrames });
282
- excludeRanges.push({ start: startFrame, endExclusive: startFrame + highlightFrames });
283
- _d.label = 4;
413
+ snapped = snapSegmentToBeats({ startFrame: startFrame, highlightFrames: highlightFrames }, totalFrames, beatFrames, maxShiftFrames, (_a = beatGrid) === null || _a === void 0 ? void 0 : _a.periodFrames);
414
+ rawSegments.push(snapped);
415
+ // Padded so the next raw window, once snapped, cannot reach back into this one.
416
+ excludeRanges.push({
417
+ start: snapped.startFrame - maxShiftFrames,
418
+ endExclusive: snapped.startFrame + snapped.highlightFrames + maxShiftFrames,
419
+ });
420
+ _e.label = 4;
284
421
  case 4:
285
422
  k++;
286
423
  return [3 /*break*/, 2];
@@ -315,9 +452,9 @@ function computeHighlightSlice(fps, totalFrames, spectrums, beatEvents, segmentC
315
452
  seekSeconds: seg.startFrame / fps,
316
453
  durationSeconds: seg.highlightFrames / fps,
317
454
  }); });
318
- first = (_a = audioSegments[0], (_a !== null && _a !== void 0 ? _a : { seekSeconds: 0, durationSeconds: 0 }));
455
+ first = (_b = audioSegments[0], (_b !== null && _b !== void 0 ? _b : { seekSeconds: 0, durationSeconds: 0 }));
319
456
  return [2 /*return*/, {
320
- startFrame: (_c = (_b = rawSegments[0]) === null || _b === void 0 ? void 0 : _b.startFrame, (_c !== null && _c !== void 0 ? _c : 0)),
457
+ startFrame: (_d = (_c = rawSegments[0]) === null || _c === void 0 ? void 0 : _c.startFrame, (_d !== null && _d !== void 0 ? _d : 0)),
321
458
  highlightFrames: totalHighlightFrames,
322
459
  spectrums: slicedSpectrums,
323
460
  beatFrameIndices: beatFrameIndices,
@@ -1 +1 @@
1
- {"version":3,"file":"highlight.js","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"highlight.js","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { rotationAliasValues, SpectrumEffect } from './config';
3
3
  import { Color } from './image';
4
4
  export { BeatInfo, BeatDetectorOptions, TempoEstimate, estimateTempo, beatGridFrameIndices, shiftTempoPhase, tempoForWindow } from './beats';
5
- export { computeHighlightSlice, HIGHLIGHT_DURATION_SEC, BeatFrameEvent, HighlightAudioSegment, HighlightRun } from './highlight';
5
+ export { computeHighlightSlice, HIGHLIGHT_DURATION_SEC, MAX_BEAT_SNAP_SEC, BeatFrameEvent, HighlightAudioSegment, HighlightRun, HighlightBeatGrid } from './highlight';
6
6
  export declare const PCM_FORMAT: {
7
7
  bit: number;
8
8
  sign: string;
@@ -12,7 +12,7 @@ export interface Config {
12
12
  audio: {
13
13
  path: string;
14
14
  autoHighlight?: boolean;
15
- /** When `autoHighlight` is true, number of non-overlapping 15s windows to stitch (default 1). */
15
+ /** When `autoHighlight` is true, number of non-overlapping ~15s beat-aligned windows to stitch (default 1). */
16
16
  autoHighlightCount?: number;
17
17
  };
18
18
  image?: {
package/dist/index.js CHANGED
@@ -69,6 +69,7 @@ var waitForEventLoop_1 = require("./waitForEventLoop");
69
69
  var highlight_2 = require("./highlight");
70
70
  exports.computeHighlightSlice = highlight_2.computeHighlightSlice;
71
71
  exports.HIGHLIGHT_DURATION_SEC = highlight_2.HIGHLIGHT_DURATION_SEC;
72
+ exports.MAX_BEAT_SNAP_SEC = highlight_2.MAX_BEAT_SNAP_SEC;
72
73
  exports.PCM_FORMAT = {
73
74
  bit: 8,
74
75
  sign: 'u',
@@ -285,7 +286,7 @@ function resolveBackgroundFrameBuffer(params) {
285
286
  }
286
287
  exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
287
288
  return new Promise(function (resolve) { return __awaiter(void 0, void 0, void 0, function () {
288
- var audioFilePath, outVideoPath, subtitleSpec, subtitleFilePath, subtitleFileIsTemporary, subtitleAlignmentAss, absPath, ext, raw, backgroundVideoPaths, backgroundImagePath, useVideoBackground, audioReader, audioBuffer, sampleRate, spectrumBusMargin, FPS, ffmpeg_cfr, ffmpeg_preset, frame_processing_delay, videoTimeouts, audioDuration, framesCount, outputResolution, maxProgressReported, reportProgress, preprocessed, autoHighlight, spectrumsForRender, beatIndicesForRender, beatIntensitiesForRender, framesCountForRender, highlightSlice, autoEditVideo, cameraShakeEnabled, shakeDelayFrames, trackTempo, sampleRateNum, maxSamples, tempoBuffer, separateHighlightFiles, passes, totalPassFrames, totalRenderMilestones, renderMilestonesCompleted, reportRenderProgress, lastExitCode, exitReason, outputVideoFiles, _loop_1, passIndex, state_1;
289
+ var audioFilePath, outVideoPath, subtitleSpec, subtitleFilePath, subtitleFileIsTemporary, subtitleAlignmentAss, absPath, ext, raw, backgroundVideoPaths, backgroundImagePath, useVideoBackground, audioReader, audioBuffer, sampleRate, spectrumBusMargin, FPS, ffmpeg_cfr, ffmpeg_preset, frame_processing_delay, videoTimeouts, audioDuration, framesCount, outputResolution, maxProgressReported, reportProgress, preprocessed, autoHighlight, autoEditVideo, trackTempo, sampleRateNum, maxSamples, tempoBuffer, spectrumsForRender, beatIndicesForRender, beatIntensitiesForRender, framesCountForRender, highlightSlice, cameraShakeEnabled, shakeDelayFrames, separateHighlightFiles, passes, totalPassFrames, totalRenderMilestones, renderMilestonesCompleted, reportRenderProgress, lastExitCode, exitReason, outputVideoFiles, _loop_1, passIndex, state_1;
289
290
  var _a, _b;
290
291
  return __generator(this, function (_c) {
291
292
  switch (_c.label) {
@@ -363,13 +364,23 @@ exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
363
364
  preprocessed = _c.sent();
364
365
  reportProgress(PRE_PROCESS_PROGRESS_SHARE);
365
366
  autoHighlight = config_1.getAudioAutoHighlight(config);
367
+ autoEditVideo = config_1.getAutoEditVideo(config);
368
+ trackTempo = null;
369
+ if (autoEditVideo || autoHighlight) {
370
+ sampleRateNum = Number(sampleRate);
371
+ maxSamples = Math.floor(sampleRateNum * beats_1.MAX_TEMPO_ANALYSIS_SECONDS);
372
+ tempoBuffer = audioBuffer.length > maxSamples
373
+ ? audioBuffer.slice(0, maxSamples)
374
+ : audioBuffer;
375
+ trackTempo = beats_1.estimateTempo(audio_1.pcmU8ToFloatSamples(tempoBuffer), sampleRateNum, FPS);
376
+ }
366
377
  spectrumsForRender = preprocessed.spectrums;
367
378
  beatIndicesForRender = preprocessed.beatFrameIndices;
368
379
  beatIntensitiesForRender = preprocessed.beatEvents.map(function (event) { return event.intensity; });
369
380
  framesCountForRender = framesCount;
370
381
  if (!autoHighlight) return [3 /*break*/, 4];
371
382
  reportProgress(PRE_PROCESS_PROGRESS_SHARE + 1);
372
- return [4 /*yield*/, highlight_1.computeHighlightSlice(FPS, framesCount, preprocessed.spectrums, preprocessed.beatEvents, config_1.getAudioAutoHighlightCount(config))];
383
+ return [4 /*yield*/, highlight_1.computeHighlightSlice(FPS, framesCount, preprocessed.spectrums, preprocessed.beatEvents, config_1.getAudioAutoHighlightCount(config), trackTempo)];
373
384
  case 3:
374
385
  highlightSlice = _c.sent();
375
386
  spectrumsForRender = highlightSlice.spectrums;
@@ -382,18 +393,8 @@ exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
382
393
  reportProgress(PRE_PROCESS_PROGRESS_SHARE + POST_AUDIO_PROGRESS_SHARE);
383
394
  _c.label = 5;
384
395
  case 5:
385
- autoEditVideo = config_1.getAutoEditVideo(config);
386
396
  cameraShakeEnabled = config_1.getCameraShakeEnabled(config);
387
397
  shakeDelayFrames = Math.round(FPS * image_1.CAMERA_SHAKE_DELAY_SECONDS);
388
- trackTempo = null;
389
- if (autoEditVideo) {
390
- sampleRateNum = Number(sampleRate);
391
- maxSamples = Math.floor(sampleRateNum * beats_1.MAX_TEMPO_ANALYSIS_SECONDS);
392
- tempoBuffer = audioBuffer.length > maxSamples
393
- ? audioBuffer.slice(0, maxSamples)
394
- : audioBuffer;
395
- trackTempo = beats_1.estimateTempo(audio_1.pcmU8ToFloatSamples(tempoBuffer), sampleRateNum, FPS);
396
- }
397
398
  separateHighlightFiles = autoHighlight &&
398
399
  highlightSlice &&
399
400
  highlightSlice.runs.length > 1;
@@ -449,7 +450,7 @@ exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
449
450
  switch (_d.label) {
450
451
  case 0:
451
452
  pass = passes[passIndex];
452
- tempo = trackTempo
453
+ tempo = autoEditVideo && trackTempo
453
454
  ? beats_1.tempoForWindow(trackTempo, pass.startFrame, FPS, pass.frameCount, pass.beatIndices)
454
455
  : null;
455
456
  shakeAmplitudes = tempo