nodejs-audio-visualizer 5.1.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.
Files changed (51) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +81 -80
  3. package/dist/audio.d.ts +13 -13
  4. package/dist/audio.js +128 -128
  5. package/dist/beats.d.ts +39 -39
  6. package/dist/beats.js +220 -220
  7. package/dist/bpmEncoder.d.ts +14 -14
  8. package/dist/bpmEncoder.js +97 -97
  9. package/dist/config.d.ts +78 -77
  10. package/dist/config.js +377 -369
  11. package/dist/config.js.map +1 -1
  12. package/dist/dsp.d.ts +16 -16
  13. package/dist/dsp.js +76 -76
  14. package/dist/highlight.d.ts +66 -34
  15. package/dist/highlight.js +471 -334
  16. package/dist/highlight.js.map +1 -1
  17. package/dist/image.d.ts +97 -92
  18. package/dist/image.js +545 -538
  19. package/dist/image.js.map +1 -1
  20. package/dist/index.d.ts +87 -79
  21. package/dist/index.js +598 -566
  22. package/dist/index.js.map +1 -1
  23. package/dist/subtitleConvert.d.ts +3 -3
  24. package/dist/subtitleConvert.js +61 -61
  25. package/dist/video.d.ts +150 -120
  26. package/dist/video.js +677 -582
  27. package/dist/video.js.map +1 -1
  28. package/dist/waitForEventLoop.d.ts +1 -1
  29. package/dist/waitForEventLoop.js +5 -5
  30. package/package.json +62 -62
  31. package/src/audio.ts +129 -129
  32. package/src/beats.ts +279 -279
  33. package/src/bpmEncoder.ts +97 -97
  34. package/src/config.ts +487 -476
  35. package/src/dsp.ts +95 -95
  36. package/src/highlight.ts +451 -291
  37. package/src/image.ts +707 -700
  38. package/src/index.ts +813 -769
  39. package/src/subtitleConvert.ts +63 -63
  40. package/src/tests/audio.test.ts +102 -102
  41. package/src/tests/beats.test.ts +134 -134
  42. package/src/tests/config.test.ts +534 -496
  43. package/src/tests/dsp.test.ts +24 -24
  44. package/src/tests/highlight.test.ts +261 -178
  45. package/src/tests/image.test.ts +319 -308
  46. package/src/tests/index.test.ts +180 -180
  47. package/src/tests/subtitleConvert.test.ts +23 -23
  48. package/src/tests/video.test.ts +535 -447
  49. package/src/typings.d.ts +28 -28
  50. package/src/video.ts +856 -722
  51. package/src/waitForEventLoop.ts +2 -2
package/dist/index.js CHANGED
@@ -1,567 +1,599 @@
1
- "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
- function verb(n) { return function (v) { return step([n, v]); }; }
26
- function step(op) {
27
- if (f) throw new TypeError("Generator is already executing.");
28
- while (_) try {
29
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
- if (y = 0, t) op = [op[0] & 2, t.value];
31
- switch (op[0]) {
32
- case 0: case 1: t = op; break;
33
- case 4: _.label++; return { value: op[1], done: false };
34
- case 5: _.label++; y = op[1]; op = [0]; continue;
35
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
- default:
37
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
- if (t[2]) _.ops.pop();
42
- _.trys.pop(); continue;
43
- }
44
- op = body.call(thisArg, _);
45
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
- }
48
- };
49
- var __importDefault = (this && this.__importDefault) || function (mod) {
50
- return (mod && mod.__esModule) ? mod : { "default": mod };
51
- };
52
- Object.defineProperty(exports, "__esModule", { value: true });
53
- var path_1 = __importDefault(require("path"));
54
- var fs_1 = require("fs");
55
- var config_1 = require("./config");
56
- var audio_1 = require("./audio");
57
- var image_1 = require("./image");
58
- var subtitleConvert_1 = require("./subtitleConvert");
59
- var video_1 = require("./video");
60
- var bpmEncoder_1 = require("./bpmEncoder");
61
- var beats_1 = require("./beats");
62
- var beats_2 = require("./beats");
63
- exports.estimateTempo = beats_2.estimateTempo;
64
- exports.beatGridFrameIndices = beats_2.beatGridFrameIndices;
65
- exports.shiftTempoPhase = beats_2.shiftTempoPhase;
66
- exports.tempoForWindow = beats_2.tempoForWindow;
67
- var highlight_1 = require("./highlight");
68
- var waitForEventLoop_1 = require("./waitForEventLoop");
69
- var highlight_2 = require("./highlight");
70
- exports.computeHighlightSlice = highlight_2.computeHighlightSlice;
71
- exports.HIGHLIGHT_DURATION_SEC = highlight_2.HIGHLIGHT_DURATION_SEC;
72
- exports.PCM_FORMAT = {
73
- bit: 8,
74
- sign: 'u',
75
- parseFunction: audio_1.bufferToUInt8
76
- };
77
- var FFMPEG_FORMAT = "" + exports.PCM_FORMAT.sign + exports.PCM_FORMAT.bit;
78
- var PROCESSING_BUFFER_SIZE = Math.pow(2, 12);
79
- var sleep = function (timeout) {
80
- return new Promise(function (resolve) { return setTimeout(resolve, timeout); });
81
- };
82
- var createVisualizerFrameGenerator = function (config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin) {
83
- if (config.outVideo.spectrum) {
84
- var createSpectrumVisualizerFrame_1 = image_1.createSpectrumVisualizerFrameGenerator();
85
- var spectrumWidth_1 = config_1.getSpectrumWidthAbsolute(config, backgroundWidth);
86
- var spectrumHeight_1 = config_1.getSpectrumHeightAbsolute(config, backgroundHeight);
87
- var spectrumX_1 = config_1.getSpectrumXAbsolute(config, spectrumWidth_1, backgroundWidth);
88
- var spectrumY_1 = config_1.getSpectrumYAbsolute(config, spectrumHeight_1, backgroundHeight);
89
- var spectrumRotation_1 = config_1.getSpectrumRotation(config);
90
- var spectrumColor_1 = config_1.getSpectrumColor(config) || image_1.invertColor(defaultColor);
91
- var spectrumEffect_1 = config_1.getSpectrumEffect(config);
92
- var spectrumOpacity_1 = config_1.getSpectrumOpacityParsed(config);
93
- return function (params) {
94
- return createSpectrumVisualizerFrame_1(__assign(__assign({}, params), { size: { width: spectrumWidth_1, height: spectrumHeight_1 }, position: { x: spectrumX_1, y: spectrumY_1 }, rotation: spectrumRotation_1, margin: spectrumBusMargin, color: spectrumColor_1, opacity: spectrumOpacity_1, spectrumEffect: spectrumEffect_1 }));
95
- };
96
- }
97
- if (config.outVideo.polar) {
98
- var createPolarVisualizerFrame_1 = image_1.createPolarVisualizerFrameGenerator();
99
- var polarX_1 = config_1.getPolarXAbsolute(config, backgroundWidth);
100
- var polarY_1 = config_1.getPolarYAbsolute(config, backgroundHeight);
101
- var polarInnerRadius_1 = config_1.getPolarInnerRadius(config);
102
- var polarMaxBarLength_1 = config_1.getPolarMaxBarLength(config);
103
- var polarBarWidth_1 = config_1.getPolarBarWidth(config);
104
- var polarColor_1 = config_1.getPolarColor(config) || image_1.invertColor(defaultColor);
105
- var polarEffect_1 = config_1.getPolarEffect(config);
106
- var polarOpacity_1 = config_1.getPolarOpacityParsed(config);
107
- return function (params) {
108
- return createPolarVisualizerFrame_1(__assign(__assign({}, params), { centerX: polarX_1, centerY: polarY_1, innerRadius: polarInnerRadius_1, maxBarLength: polarMaxBarLength_1, barWidth: polarBarWidth_1, color: polarColor_1, opacity: polarOpacity_1, spectrumEffect: polarEffect_1 }));
109
- };
110
- }
111
- return function (params) { return params.backgroundImageBuffer; };
112
- };
113
- var PRE_PROCESS_PROGRESS_SHARE = 60;
114
- var POST_AUDIO_PROGRESS_SHARE = 10;
115
- var RENDER_PROGRESS_SHARE = 30;
116
- var preProcessAudio = function (audioBuffer, sampleRate, fps, framesCount, onPreProcessProgress) { return __awaiter(void 0, void 0, void 0, function () {
117
- var t, audioDataStep, processingBuffer, skipFramesCount, processSpectrum, detectBeat, spectrums, beatFrameIndices, beatEvents, nextPreProcessMilestone, i, currentFrameData, frameDataLength, frameDataTailStart, frameDataToProcess, audioDataParser, spectrum, beat, p;
118
- var _a, _b;
119
- return __generator(this, function (_c) {
120
- switch (_c.label) {
121
- case 0:
122
- if (framesCount === 0) {
123
- for (t = 1; t <= PRE_PROCESS_PROGRESS_SHARE; t += 1) {
124
- (_a = onPreProcessProgress) === null || _a === void 0 ? void 0 : _a(t);
125
- }
126
- return [2 /*return*/, { spectrums: [], beatFrameIndices: [], beatEvents: [] }];
127
- }
128
- audioDataStep = Math.trunc(audioBuffer.length / framesCount);
129
- processingBuffer = new Float32Array(PROCESSING_BUFFER_SIZE).fill(0);
130
- skipFramesCount = fps < 45 ? 1 : 2;
131
- processSpectrum = audio_1.createSpectrumsProcessor(sampleRate, skipFramesCount);
132
- detectBeat = beats_1.createBeatDetector(fps);
133
- spectrums = [];
134
- beatFrameIndices = [];
135
- beatEvents = [];
136
- nextPreProcessMilestone = 1;
137
- i = 0;
138
- _c.label = 1;
139
- case 1:
140
- if (!(i < framesCount)) return [3 /*break*/, 4];
141
- currentFrameData = exports.PCM_FORMAT.parseFunction(audioBuffer, i * audioDataStep, i * audioDataStep + audioDataStep);
142
- frameDataLength = Math.min(currentFrameData.length, PROCESSING_BUFFER_SIZE);
143
- frameDataTailStart = currentFrameData.length - frameDataLength;
144
- frameDataToProcess = currentFrameData.slice(frameDataTailStart);
145
- processingBuffer.copyWithin(0, frameDataLength);
146
- processingBuffer.set(frameDataToProcess, PROCESSING_BUFFER_SIZE - frameDataLength);
147
- audioDataParser = function () { return Array.from(processingBuffer); };
148
- spectrum = processSpectrum(audioDataParser);
149
- beat = detectBeat(spectrum);
150
- spectrums.push(spectrum);
151
- if (beat.isBeat) {
152
- beatFrameIndices.push(i);
153
- beatEvents.push({ frameIndex: i, intensity: beat.intensity });
154
- }
155
- p = PRE_PROCESS_PROGRESS_SHARE * (i + 1) / framesCount;
156
- while (nextPreProcessMilestone <= PRE_PROCESS_PROGRESS_SHARE
157
- && p >= nextPreProcessMilestone) {
158
- (_b = onPreProcessProgress) === null || _b === void 0 ? void 0 : _b(nextPreProcessMilestone);
159
- nextPreProcessMilestone += 1;
160
- }
161
- return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
162
- case 2:
163
- _c.sent();
164
- _c.label = 3;
165
- case 3:
166
- i++;
167
- return [3 /*break*/, 1];
168
- case 4: return [2 /*return*/, { spectrums: spectrums, beatFrameIndices: beatFrameIndices, beatEvents: beatEvents }];
169
- }
170
- });
171
- }); };
172
- function prepareBackgroundForRender(params) {
173
- var _a, _b, _c, _d, _e, _f;
174
- return __awaiter(this, void 0, void 0, function () {
175
- var useVideoBackground, backgroundVideoPath, backgroundImagePath, beatFrameIndices, beatIntensities, framesCount, outputResolution, fps, autoEditVideo, readVideoFrameTimeout, tempo, videoInfo, sceneChanges, _g, backgroundWidth_1, backgroundHeight_1, videoFrameSize, encodeVideoFrame, segments, concatFilePath, cutFrameIndices, videoFrameReader, firstFrame, defaultColor_1, staticBackgroundBuffer_1, backgroundImageBmpBuffer, backgroundImage, backgroundWidth, backgroundHeight, defaultColor, bpmEncoder, staticBackgroundBuffer;
176
- return __generator(this, function (_h) {
177
- switch (_h.label) {
178
- case 0:
179
- useVideoBackground = params.useVideoBackground, backgroundVideoPath = params.backgroundVideoPath, backgroundImagePath = params.backgroundImagePath, beatFrameIndices = params.beatFrameIndices, beatIntensities = params.beatIntensities, framesCount = params.framesCount, outputResolution = params.outputResolution, fps = params.fps, autoEditVideo = params.autoEditVideo, readVideoFrameTimeout = params.readVideoFrameTimeout, tempo = params.tempo;
180
- if (!(useVideoBackground && backgroundVideoPath)) return [3 /*break*/, 6];
181
- return [4 /*yield*/, video_1.getVideoInfo(backgroundVideoPath)];
182
- case 1:
183
- videoInfo = _h.sent();
184
- if (!autoEditVideo) return [3 /*break*/, 3];
185
- return [4 /*yield*/, video_1.detectSceneChanges(backgroundVideoPath)];
186
- case 2:
187
- _g = _h.sent();
188
- return [3 /*break*/, 4];
189
- case 3:
190
- _g = [];
191
- _h.label = 4;
192
- case 4:
193
- sceneChanges = _g;
194
- backgroundWidth_1 = (_b = (_a = outputResolution) === null || _a === void 0 ? void 0 : _a.width, (_b !== null && _b !== void 0 ? _b : videoInfo.width));
195
- backgroundHeight_1 = (_d = (_c = outputResolution) === null || _c === void 0 ? void 0 : _c.height, (_d !== null && _d !== void 0 ? _d : videoInfo.height));
196
- videoFrameSize = backgroundWidth_1 * backgroundHeight_1 * 3;
197
- encodeVideoFrame = bpmEncoder_1.createBgrFrameEncoder({ width: backgroundWidth_1, height: backgroundHeight_1 });
198
- segments = video_1.buildBeatSyncedSegments(beatFrameIndices, framesCount, sceneChanges, videoInfo.duration, fps, __assign({ beatIntensities: beatIntensities }, (autoEditVideo && tempo ? { tempo: tempo } : {})));
199
- concatFilePath = video_1.writeConcatFile(segments, backgroundVideoPath, videoInfo.duration, fps);
200
- cutFrameIndices = autoEditVideo ? video_1.getCutFrameIndices(segments) : [];
201
- videoFrameReader = video_1.spawnConcatVideoFrameReader(__assign({ concatFilePath: concatFilePath,
202
- fps: fps, totalFrames: framesCount }, (outputResolution && {
203
- width: backgroundWidth_1,
204
- height: backgroundHeight_1,
205
- sourceWidth: videoInfo.width,
206
- sourceHeight: videoInfo.height,
207
- })));
208
- return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize, readVideoFrameTimeout)];
209
- case 5:
210
- firstFrame = _h.sent();
211
- if (!firstFrame) {
212
- throw new Error("Could not read frames from video: " + backgroundVideoPath);
213
- }
214
- defaultColor_1 = image_1.getVideoFrameColor(firstFrame, backgroundWidth_1, backgroundHeight_1);
215
- staticBackgroundBuffer_1 = encodeVideoFrame(firstFrame);
216
- return [2 /*return*/, {
217
- backgroundWidth: backgroundWidth_1,
218
- backgroundHeight: backgroundHeight_1,
219
- defaultColor: defaultColor_1,
220
- staticBackgroundBuffer: staticBackgroundBuffer_1,
221
- videoFrameReader: videoFrameReader,
222
- videoFrameSize: videoFrameSize,
223
- encodeVideoFrame: encodeVideoFrame,
224
- concatFilePath: concatFilePath,
225
- cutFrameIndices: cutFrameIndices,
226
- }];
227
- case 6:
228
- if (!backgroundImagePath) {
229
- throw new Error('Background image path is required when not using video background.');
230
- }
231
- return [4 /*yield*/, image_1.convertToBmp(backgroundImagePath, (_e = outputResolution) === null || _e === void 0 ? void 0 : _e.width, (_f = outputResolution) === null || _f === void 0 ? void 0 : _f.height)];
232
- case 7:
233
- backgroundImageBmpBuffer = _h.sent();
234
- backgroundImage = image_1.parseImage(backgroundImageBmpBuffer);
235
- backgroundWidth = backgroundImage.width;
236
- backgroundHeight = backgroundImage.height;
237
- defaultColor = image_1.getImageColor(backgroundImage);
238
- bpmEncoder = bpmEncoder_1.createBpmEncoder({ width: backgroundWidth, height: backgroundHeight });
239
- staticBackgroundBuffer = bpmEncoder(backgroundImage.data);
240
- return [2 /*return*/, {
241
- backgroundWidth: backgroundWidth,
242
- backgroundHeight: backgroundHeight,
243
- defaultColor: defaultColor,
244
- staticBackgroundBuffer: staticBackgroundBuffer,
245
- videoFrameSize: 0,
246
- cutFrameIndices: [],
247
- }];
248
- }
249
- });
250
- });
251
- }
252
- function resolveBackgroundFrameBuffer(params) {
253
- return __awaiter(this, void 0, void 0, function () {
254
- var frameIndex, useVideoBackground, videoFrameReader, videoFrameSize, encodeVideoFrame, staticBackgroundBuffer, readVideoFrameTimeout, videoFrame;
255
- return __generator(this, function (_a) {
256
- switch (_a.label) {
257
- case 0:
258
- frameIndex = params.frameIndex, useVideoBackground = params.useVideoBackground, videoFrameReader = params.videoFrameReader, videoFrameSize = params.videoFrameSize, encodeVideoFrame = params.encodeVideoFrame, staticBackgroundBuffer = params.staticBackgroundBuffer, readVideoFrameTimeout = params.readVideoFrameTimeout;
259
- if (!(useVideoBackground && videoFrameReader && encodeVideoFrame)) return [3 /*break*/, 2];
260
- if (frameIndex === 0) {
261
- return [2 /*return*/, { frameBuffer: staticBackgroundBuffer, frameReadFailed: false }];
262
- }
263
- return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize, readVideoFrameTimeout)];
264
- case 1:
265
- videoFrame = _a.sent();
266
- if (videoFrame) {
267
- return [2 /*return*/, { frameBuffer: encodeVideoFrame(videoFrame), frameReadFailed: false }];
268
- }
269
- return [2 /*return*/, { frameBuffer: staticBackgroundBuffer, frameReadFailed: false }];
270
- case 2: return [2 /*return*/, { frameBuffer: staticBackgroundBuffer, frameReadFailed: false }];
271
- }
272
- });
273
- });
274
- }
275
- exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
276
- return new Promise(function (resolve) { return __awaiter(void 0, void 0, void 0, function () {
277
- var audioFilePath, outVideoPath, subtitleSpec, subtitleFilePath, subtitleFileIsTemporary, subtitleAlignmentAss, absPath, ext, raw, backgroundVideoPath, 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, trackTempo, sampleRateNum, maxSamples, tempoBuffer, separateHighlightFiles, passes, totalPassFrames, totalRenderMilestones, renderMilestonesCompleted, reportRenderProgress, lastExitCode, exitReason, outputVideoFiles, _i, passes_1, pass, tempo, shakeAmplitudes, _a, backgroundWidth, backgroundHeight, defaultColor, staticBackgroundBuffer, videoFrameReader, videoFrameSize, encodeVideoFrame, concatFilePath, shakeFrames, createVisualizerFrame, ffmpegVideoWriter, exitPromise, stoppedEarly, i, spectrum, _b, backgroundImageBuffer, frameReadFailed, commonVisualizerFrameProps, frameImage, shakeOffset, isFrameProcessed, isDrained, _c, exitCode, ffmpegExitReason;
278
- var _d, _e;
279
- return __generator(this, function (_f) {
280
- switch (_f.label) {
281
- case 0:
282
- if (config.outVideo.spectrum && config.outVideo.polar) {
283
- throw new Error('Cannot use both "spectrum" and "polar" options. Please specify only one visualizer type.');
284
- }
285
- if (!config.image && !config.video) {
286
- throw new Error('Either "image" or "video" must be specified as the background source.');
287
- }
288
- if (config.image && config.video) {
289
- throw new Error('Cannot use both "image" and "video" options. Please specify only one background source.');
290
- }
291
- audioFilePath = config_1.getAudioFilePath(config);
292
- outVideoPath = config_1.getOutVideoPath(config);
293
- subtitleSpec = config_1.getSubtitleRenderSpec(config);
294
- subtitleFileIsTemporary = false;
295
- subtitleAlignmentAss = 2;
296
- if (subtitleSpec) {
297
- subtitleAlignmentAss = config_1.subtitleAlignmentToAss(subtitleSpec.alignment);
298
- if (subtitleSpec.source.kind === 'file') {
299
- absPath = subtitleSpec.source.path;
300
- ext = path_1.default.extname(absPath).toLowerCase();
301
- if (ext === '.lrc') {
302
- raw = fs_1.readFileSync(absPath, 'utf-8');
303
- subtitleFilePath = video_1.writeSubtitlesFile(subtitleConvert_1.lrcToSrt(raw));
304
- subtitleFileIsTemporary = true;
305
- }
306
- else {
307
- subtitleFilePath = absPath;
308
- }
309
- }
310
- else {
311
- subtitleFilePath = video_1.writeSubtitlesFile(subtitleConvert_1.normalizeInlineSubtitlesToSrt(subtitleSpec.source.text));
312
- subtitleFileIsTemporary = true;
313
- }
314
- }
315
- backgroundVideoPath = config_1.getBackgroundVideoPath(config);
316
- backgroundImagePath = config_1.getBackgroundImagePath(config);
317
- useVideoBackground = !!backgroundVideoPath;
318
- return [4 /*yield*/, audio_1.createAudioBuffer(audioFilePath, FFMPEG_FORMAT)];
319
- case 1:
320
- audioReader = _f.sent();
321
- audioBuffer = audioReader.audioBuffer;
322
- sampleRate = audioReader.sampleRate;
323
- if (!sampleRate) {
324
- throw new Error('ffmpeg didn\'t show audio sample rate');
325
- }
326
- spectrumBusMargin = config_1.getSpectrumBusMargin();
327
- FPS = config_1.getFPS(config);
328
- ffmpeg_cfr = config_1.getFfmpeg_cfr(config);
329
- ffmpeg_preset = config_1.getFfmpeg_preset(config);
330
- frame_processing_delay = config_1.getFrame_processing_delay(config);
331
- videoTimeouts = config_1.getVideoTimeouts(config);
332
- audioDuration = audioBuffer.length / sampleRate;
333
- framesCount = Math.trunc(audioDuration * FPS);
334
- outputResolution = config_1.getOutputResolution(config);
335
- maxProgressReported = -1;
336
- reportProgress = function (progress) {
337
- if (!onProgress) {
338
- return;
339
- }
340
- var normalized = +Math.min(100, Math.max(0, progress)).toFixed(2);
341
- if (normalized <= maxProgressReported) {
342
- return;
343
- }
344
- maxProgressReported = normalized;
345
- onProgress(normalized);
346
- };
347
- reportProgress(0);
348
- return [4 /*yield*/, preProcessAudio(audioBuffer, sampleRate, FPS, framesCount, function (progress) {
349
- reportProgress(progress);
350
- })];
351
- case 2:
352
- preprocessed = _f.sent();
353
- reportProgress(PRE_PROCESS_PROGRESS_SHARE);
354
- autoHighlight = config_1.getAudioAutoHighlight(config);
355
- spectrumsForRender = preprocessed.spectrums;
356
- beatIndicesForRender = preprocessed.beatFrameIndices;
357
- beatIntensitiesForRender = preprocessed.beatEvents.map(function (event) { return event.intensity; });
358
- framesCountForRender = framesCount;
359
- if (!autoHighlight) return [3 /*break*/, 4];
360
- reportProgress(PRE_PROCESS_PROGRESS_SHARE + 1);
361
- return [4 /*yield*/, highlight_1.computeHighlightSlice(FPS, framesCount, preprocessed.spectrums, preprocessed.beatEvents, config_1.getAudioAutoHighlightCount(config))];
362
- case 3:
363
- highlightSlice = _f.sent();
364
- spectrumsForRender = highlightSlice.spectrums;
365
- beatIndicesForRender = highlightSlice.beatFrameIndices;
366
- beatIntensitiesForRender = highlightSlice.beatIntensities;
367
- framesCountForRender = highlightSlice.highlightFrames;
368
- reportProgress(PRE_PROCESS_PROGRESS_SHARE + POST_AUDIO_PROGRESS_SHARE);
369
- return [3 /*break*/, 5];
370
- case 4:
371
- reportProgress(PRE_PROCESS_PROGRESS_SHARE + POST_AUDIO_PROGRESS_SHARE);
372
- _f.label = 5;
373
- case 5:
374
- autoEditVideo = config_1.getAutoEditVideo(config);
375
- trackTempo = null;
376
- if (autoEditVideo) {
377
- sampleRateNum = Number(sampleRate);
378
- maxSamples = Math.floor(sampleRateNum * beats_1.MAX_TEMPO_ANALYSIS_SECONDS);
379
- tempoBuffer = audioBuffer.length > maxSamples
380
- ? audioBuffer.slice(0, maxSamples)
381
- : audioBuffer;
382
- trackTempo = beats_1.estimateTempo(audio_1.pcmU8ToFloatSamples(tempoBuffer), sampleRateNum, FPS);
383
- }
384
- separateHighlightFiles = autoHighlight &&
385
- highlightSlice &&
386
- highlightSlice.runs.length > 1;
387
- passes = separateHighlightFiles && highlightSlice
388
- ? highlightSlice.runs.map(function (run, i) {
389
- var dir = path_1.default.dirname(outVideoPath);
390
- var ext = path_1.default.extname(outVideoPath);
391
- var base = path_1.default.basename(outVideoPath, ext);
392
- var numberedPath = path_1.default.resolve(dir, base + "-" + (i + 1) + ext);
393
- return {
394
- outPath: numberedPath,
395
- spectrums: run.spectrums,
396
- beatIndices: run.beatFrameIndices,
397
- beatIntensities: run.beatIntensities,
398
- frameCount: run.highlightFrames,
399
- startFrame: run.startFrame,
400
- audioSegment: run.audioSegment,
401
- };
402
- })
403
- : [
404
- {
405
- outPath: outVideoPath,
406
- spectrums: spectrumsForRender,
407
- beatIndices: beatIndicesForRender,
408
- beatIntensities: beatIntensitiesForRender,
409
- frameCount: framesCountForRender,
410
- startFrame: (_e = (_d = highlightSlice) === null || _d === void 0 ? void 0 : _d.startFrame, (_e !== null && _e !== void 0 ? _e : 0)),
411
- audioSegment: autoHighlight &&
412
- highlightSlice &&
413
- highlightSlice.audioSegments.length > 0
414
- ? highlightSlice.audioSegments[0]
415
- : undefined,
416
- },
417
- ];
418
- totalPassFrames = passes.reduce(function (sum, pass) { return sum + pass.frameCount; }, 0);
419
- totalRenderMilestones = totalPassFrames + (passes.length * 2);
420
- renderMilestonesCompleted = 0;
421
- reportRenderProgress = function (milestoneIncrement) {
422
- if (milestoneIncrement === void 0) { milestoneIncrement = 1; }
423
- renderMilestonesCompleted += milestoneIncrement;
424
- reportProgress(PRE_PROCESS_PROGRESS_SHARE
425
- + POST_AUDIO_PROGRESS_SHARE
426
- + (RENDER_PROGRESS_SHARE * renderMilestonesCompleted / Math.max(1, totalRenderMilestones)));
427
- };
428
- lastExitCode = 0;
429
- outputVideoFiles = [];
430
- _f.label = 6;
431
- case 6:
432
- _f.trys.push([6, , 21, 22]);
433
- _i = 0, passes_1 = passes;
434
- _f.label = 7;
435
- case 7:
436
- if (!(_i < passes_1.length)) return [3 /*break*/, 20];
437
- pass = passes_1[_i];
438
- tempo = trackTempo
439
- ? beats_1.tempoForWindow(trackTempo, pass.startFrame, FPS, pass.frameCount, pass.beatIndices)
440
- : null;
441
- shakeAmplitudes = tempo
442
- ? image_1.buildCutShakeAmplitudes(tempo.periodFrames)
443
- : undefined;
444
- return [4 /*yield*/, prepareBackgroundForRender(__assign({ useVideoBackground: useVideoBackground,
445
- backgroundVideoPath: backgroundVideoPath,
446
- backgroundImagePath: backgroundImagePath, beatFrameIndices: pass.beatIndices, beatIntensities: pass.beatIntensities, framesCount: pass.frameCount, outputResolution: outputResolution, fps: FPS, autoEditVideo: autoEditVideo, readVideoFrameTimeout: videoTimeouts.readVideoFrame }, (tempo ? { tempo: tempo } : {})))];
447
- case 8:
448
- _a = _f.sent(), backgroundWidth = _a.backgroundWidth, backgroundHeight = _a.backgroundHeight, defaultColor = _a.defaultColor, staticBackgroundBuffer = _a.staticBackgroundBuffer, videoFrameReader = _a.videoFrameReader, videoFrameSize = _a.videoFrameSize, encodeVideoFrame = _a.encodeVideoFrame, concatFilePath = _a.concatFilePath;
449
- reportRenderProgress();
450
- shakeFrames = new Set(autoEditVideo
451
- ? (tempo
452
- ? beats_1.beatGridFrameIndices(tempo, pass.frameCount, image_1.CAMERA_SHAKE_EVERY_BEATS)
453
- : pass.beatIndices.filter(function (frameIndex) { return frameIndex > 0; }).filter(function (_, i) { return i % image_1.CAMERA_SHAKE_EVERY_BEATS === 0; }))
454
- : []);
455
- createVisualizerFrame = createVisualizerFrameGenerator(config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin);
456
- ffmpegVideoWriter = video_1.spawnFfmpegVideoWriter(__assign(__assign(__assign(__assign(__assign({ audioFilename: audioFilePath, videoFileName: pass.outPath }, (subtitleFilePath && {
457
- subtitleFilename: subtitleFilePath,
458
- subtitleAlignmentAss: subtitleAlignmentAss,
459
- })), { fps: FPS }), (pass.audioSegment && { audioSegment: pass.audioSegment })), (ffmpeg_cfr && { crf: ffmpeg_cfr })), (ffmpeg_preset && { preset: ffmpeg_preset })));
460
- exitPromise = video_1.waitForProcessExit(ffmpegVideoWriter, videoTimeouts.waitForProcessExit);
461
- stoppedEarly = false;
462
- i = 0;
463
- _f.label = 9;
464
- case 9:
465
- if (!(i < pass.frameCount)) return [3 /*break*/, 17];
466
- spectrum = pass.spectrums[i];
467
- return [4 /*yield*/, resolveBackgroundFrameBuffer({
468
- frameIndex: i,
469
- useVideoBackground: useVideoBackground,
470
- videoFrameReader: videoFrameReader,
471
- videoFrameSize: videoFrameSize,
472
- encodeVideoFrame: encodeVideoFrame,
473
- staticBackgroundBuffer: staticBackgroundBuffer,
474
- readVideoFrameTimeout: videoTimeouts.readVideoFrame,
475
- })];
476
- case 10:
477
- _b = _f.sent(), backgroundImageBuffer = _b.frameBuffer, frameReadFailed = _b.frameReadFailed;
478
- commonVisualizerFrameProps = {
479
- backgroundImageBuffer: backgroundImageBuffer,
480
- spectrum: spectrum,
481
- };
482
- frameImage = createVisualizerFrame(commonVisualizerFrameProps);
483
- shakeOffset = image_1.getCutShakeOffset(i, shakeFrames, shakeAmplitudes);
484
- if (shakeOffset.x !== 0 || shakeOffset.y !== 0) {
485
- image_1.applyCameraShake(frameImage, backgroundWidth, backgroundHeight, shakeOffset.x, shakeOffset.y);
486
- }
487
- isFrameProcessed = ffmpegVideoWriter.stdin.write(frameImage.data);
488
- if (!!isFrameProcessed) return [3 /*break*/, 12];
489
- return [4 /*yield*/, video_1.waitDrain(ffmpegVideoWriter.stdin, ffmpegVideoWriter, videoTimeouts.waitDrain)];
490
- case 11:
491
- isDrained = _f.sent();
492
- if (!isDrained) {
493
- stoppedEarly = true;
494
- exitReason = 'ffmpeg stdin drain failed';
495
- return [3 /*break*/, 17];
496
- }
497
- _f.label = 12;
498
- case 12:
499
- if (shouldStop && shouldStop()) {
500
- stoppedEarly = true;
501
- exitReason = 'render stopped by shouldStop callback';
502
- return [3 /*break*/, 17];
503
- }
504
- if (!frame_processing_delay) return [3 /*break*/, 14];
505
- return [4 /*yield*/, sleep(frame_processing_delay)];
506
- case 13:
507
- _f.sent();
508
- _f.label = 14;
509
- case 14: return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
510
- case 15:
511
- _f.sent();
512
- reportRenderProgress();
513
- _f.label = 16;
514
- case 16:
515
- i++;
516
- return [3 /*break*/, 9];
517
- case 17:
518
- if (videoFrameReader) {
519
- videoFrameReader.kill();
520
- }
521
- if (concatFilePath) {
522
- video_1.cleanupConcatFile(concatFilePath);
523
- }
524
- ffmpegVideoWriter.stdin.end();
525
- return [4 /*yield*/, exitPromise];
526
- case 18:
527
- _c = _f.sent(), exitCode = _c.exitCode, ffmpegExitReason = _c.reason;
528
- lastExitCode = exitCode;
529
- if (!exitReason && ffmpegExitReason) {
530
- exitReason = ffmpegExitReason;
531
- }
532
- if (lastExitCode === 0 && !stoppedEarly) {
533
- reportRenderProgress();
534
- }
535
- if (lastExitCode === 0 && !stoppedEarly) {
536
- outputVideoFiles.push(pass.outPath);
537
- }
538
- if (stoppedEarly || lastExitCode !== 0) {
539
- if (exitReason && lastExitCode === 0) {
540
- lastExitCode = 1;
541
- }
542
- return [3 /*break*/, 20];
543
- }
544
- _f.label = 19;
545
- case 19:
546
- _i++;
547
- return [3 /*break*/, 7];
548
- case 20:
549
- if (lastExitCode === 0 && outputVideoFiles.length === passes.length) {
550
- reportProgress(100);
551
- }
552
- if (exitReason) {
553
- console.error(exitReason);
554
- }
555
- resolve({ exitCode: lastExitCode, reason: exitReason, outputVideoFiles: outputVideoFiles });
556
- return [3 /*break*/, 22];
557
- case 21:
558
- if (subtitleFilePath && subtitleFileIsTemporary) {
559
- video_1.cleanupTempFile(subtitleFilePath);
560
- }
561
- return [7 /*endfinally*/];
562
- case 22: return [2 /*return*/];
563
- }
564
- });
565
- }); });
566
- };
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (_) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ var path_1 = __importDefault(require("path"));
54
+ var fs_1 = require("fs");
55
+ var config_1 = require("./config");
56
+ var audio_1 = require("./audio");
57
+ var image_1 = require("./image");
58
+ var subtitleConvert_1 = require("./subtitleConvert");
59
+ var video_1 = require("./video");
60
+ var bpmEncoder_1 = require("./bpmEncoder");
61
+ var beats_1 = require("./beats");
62
+ var beats_2 = require("./beats");
63
+ exports.estimateTempo = beats_2.estimateTempo;
64
+ exports.beatGridFrameIndices = beats_2.beatGridFrameIndices;
65
+ exports.shiftTempoPhase = beats_2.shiftTempoPhase;
66
+ exports.tempoForWindow = beats_2.tempoForWindow;
67
+ var highlight_1 = require("./highlight");
68
+ var waitForEventLoop_1 = require("./waitForEventLoop");
69
+ var highlight_2 = require("./highlight");
70
+ exports.computeHighlightSlice = highlight_2.computeHighlightSlice;
71
+ exports.HIGHLIGHT_DURATION_SEC = highlight_2.HIGHLIGHT_DURATION_SEC;
72
+ exports.MAX_BEAT_SNAP_SEC = highlight_2.MAX_BEAT_SNAP_SEC;
73
+ exports.PCM_FORMAT = {
74
+ bit: 8,
75
+ sign: 'u',
76
+ parseFunction: audio_1.bufferToUInt8
77
+ };
78
+ var FFMPEG_FORMAT = "" + exports.PCM_FORMAT.sign + exports.PCM_FORMAT.bit;
79
+ var PROCESSING_BUFFER_SIZE = Math.pow(2, 12);
80
+ var sleep = function (timeout) {
81
+ return new Promise(function (resolve) { return setTimeout(resolve, timeout); });
82
+ };
83
+ var createVisualizerFrameGenerator = function (config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin) {
84
+ if (config.outVideo.spectrum) {
85
+ var createSpectrumVisualizerFrame_1 = image_1.createSpectrumVisualizerFrameGenerator();
86
+ var spectrumWidth_1 = config_1.getSpectrumWidthAbsolute(config, backgroundWidth);
87
+ var spectrumHeight_1 = config_1.getSpectrumHeightAbsolute(config, backgroundHeight);
88
+ var spectrumX_1 = config_1.getSpectrumXAbsolute(config, spectrumWidth_1, backgroundWidth);
89
+ var spectrumY_1 = config_1.getSpectrumYAbsolute(config, spectrumHeight_1, backgroundHeight);
90
+ var spectrumRotation_1 = config_1.getSpectrumRotation(config);
91
+ var spectrumColor_1 = config_1.getSpectrumColor(config) || image_1.invertColor(defaultColor);
92
+ var spectrumEffect_1 = config_1.getSpectrumEffect(config);
93
+ var spectrumOpacity_1 = config_1.getSpectrumOpacityParsed(config);
94
+ return function (params) {
95
+ return createSpectrumVisualizerFrame_1(__assign(__assign({}, params), { size: { width: spectrumWidth_1, height: spectrumHeight_1 }, position: { x: spectrumX_1, y: spectrumY_1 }, rotation: spectrumRotation_1, margin: spectrumBusMargin, color: spectrumColor_1, opacity: spectrumOpacity_1, spectrumEffect: spectrumEffect_1 }));
96
+ };
97
+ }
98
+ if (config.outVideo.polar) {
99
+ var createPolarVisualizerFrame_1 = image_1.createPolarVisualizerFrameGenerator();
100
+ var polarX_1 = config_1.getPolarXAbsolute(config, backgroundWidth);
101
+ var polarY_1 = config_1.getPolarYAbsolute(config, backgroundHeight);
102
+ var polarInnerRadius_1 = config_1.getPolarInnerRadius(config);
103
+ var polarMaxBarLength_1 = config_1.getPolarMaxBarLength(config);
104
+ var polarBarWidth_1 = config_1.getPolarBarWidth(config);
105
+ var polarColor_1 = config_1.getPolarColor(config) || image_1.invertColor(defaultColor);
106
+ var polarEffect_1 = config_1.getPolarEffect(config);
107
+ var polarOpacity_1 = config_1.getPolarOpacityParsed(config);
108
+ return function (params) {
109
+ return createPolarVisualizerFrame_1(__assign(__assign({}, params), { centerX: polarX_1, centerY: polarY_1, innerRadius: polarInnerRadius_1, maxBarLength: polarMaxBarLength_1, barWidth: polarBarWidth_1, color: polarColor_1, opacity: polarOpacity_1, spectrumEffect: polarEffect_1 }));
110
+ };
111
+ }
112
+ return function (params) { return params.backgroundImageBuffer; };
113
+ };
114
+ var PRE_PROCESS_PROGRESS_SHARE = 60;
115
+ var POST_AUDIO_PROGRESS_SHARE = 10;
116
+ var RENDER_PROGRESS_SHARE = 30;
117
+ var preProcessAudio = function (audioBuffer, sampleRate, fps, framesCount, onPreProcessProgress) { return __awaiter(void 0, void 0, void 0, function () {
118
+ var t, audioDataStep, processingBuffer, skipFramesCount, processSpectrum, detectBeat, spectrums, beatFrameIndices, beatEvents, nextPreProcessMilestone, i, currentFrameData, frameDataLength, frameDataTailStart, frameDataToProcess, audioDataParser, spectrum, beat, p;
119
+ var _a, _b;
120
+ return __generator(this, function (_c) {
121
+ switch (_c.label) {
122
+ case 0:
123
+ if (framesCount === 0) {
124
+ for (t = 1; t <= PRE_PROCESS_PROGRESS_SHARE; t += 1) {
125
+ (_a = onPreProcessProgress) === null || _a === void 0 ? void 0 : _a(t);
126
+ }
127
+ return [2 /*return*/, { spectrums: [], beatFrameIndices: [], beatEvents: [] }];
128
+ }
129
+ audioDataStep = Math.trunc(audioBuffer.length / framesCount);
130
+ processingBuffer = new Float32Array(PROCESSING_BUFFER_SIZE).fill(0);
131
+ skipFramesCount = fps < 45 ? 1 : 2;
132
+ processSpectrum = audio_1.createSpectrumsProcessor(sampleRate, skipFramesCount);
133
+ detectBeat = beats_1.createBeatDetector(fps);
134
+ spectrums = [];
135
+ beatFrameIndices = [];
136
+ beatEvents = [];
137
+ nextPreProcessMilestone = 1;
138
+ i = 0;
139
+ _c.label = 1;
140
+ case 1:
141
+ if (!(i < framesCount)) return [3 /*break*/, 4];
142
+ currentFrameData = exports.PCM_FORMAT.parseFunction(audioBuffer, i * audioDataStep, i * audioDataStep + audioDataStep);
143
+ frameDataLength = Math.min(currentFrameData.length, PROCESSING_BUFFER_SIZE);
144
+ frameDataTailStart = currentFrameData.length - frameDataLength;
145
+ frameDataToProcess = currentFrameData.slice(frameDataTailStart);
146
+ processingBuffer.copyWithin(0, frameDataLength);
147
+ processingBuffer.set(frameDataToProcess, PROCESSING_BUFFER_SIZE - frameDataLength);
148
+ audioDataParser = function () { return Array.from(processingBuffer); };
149
+ spectrum = processSpectrum(audioDataParser);
150
+ beat = detectBeat(spectrum);
151
+ spectrums.push(spectrum);
152
+ if (beat.isBeat) {
153
+ beatFrameIndices.push(i);
154
+ beatEvents.push({ frameIndex: i, intensity: beat.intensity });
155
+ }
156
+ p = PRE_PROCESS_PROGRESS_SHARE * (i + 1) / framesCount;
157
+ while (nextPreProcessMilestone <= PRE_PROCESS_PROGRESS_SHARE
158
+ && p >= nextPreProcessMilestone) {
159
+ (_b = onPreProcessProgress) === null || _b === void 0 ? void 0 : _b(nextPreProcessMilestone);
160
+ nextPreProcessMilestone += 1;
161
+ }
162
+ return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
163
+ case 2:
164
+ _c.sent();
165
+ _c.label = 3;
166
+ case 3:
167
+ i++;
168
+ return [3 /*break*/, 1];
169
+ case 4: return [2 /*return*/, { spectrums: spectrums, beatFrameIndices: beatFrameIndices, beatEvents: beatEvents }];
170
+ }
171
+ });
172
+ }); };
173
+ function prepareBackgroundForRender(params) {
174
+ var _a, _b, _c, _d, _e, _f;
175
+ return __awaiter(this, void 0, void 0, function () {
176
+ var useVideoBackground, backgroundVideoPaths, backgroundImagePath, beatFrameIndices, beatIntensities, framesCount, outputResolution, fps, autoEditVideo, readVideoFrameTimeout, tempo, _g, startVideoIndex, videoInfos, primaryVideoInfo, backgroundWidth_1, backgroundHeight_1, videoFrameSize, encodeVideoFrame, segments, sceneChanges, _h, videoSources, concatFilePath, cutFrameIndices, videoFrameReader, firstFrame, defaultColor_1, staticBackgroundBuffer_1, backgroundImageBmpBuffer, backgroundImage, backgroundWidth, backgroundHeight, defaultColor, bpmEncoder, staticBackgroundBuffer;
177
+ return __generator(this, function (_j) {
178
+ switch (_j.label) {
179
+ case 0:
180
+ useVideoBackground = params.useVideoBackground, backgroundVideoPaths = params.backgroundVideoPaths, backgroundImagePath = params.backgroundImagePath, beatFrameIndices = params.beatFrameIndices, beatIntensities = params.beatIntensities, framesCount = params.framesCount, outputResolution = params.outputResolution, fps = params.fps, autoEditVideo = params.autoEditVideo, readVideoFrameTimeout = params.readVideoFrameTimeout, tempo = params.tempo, _g = params.startVideoIndex, startVideoIndex = _g === void 0 ? 0 : _g;
181
+ if (!(useVideoBackground && backgroundVideoPaths && backgroundVideoPaths.length > 0)) return [3 /*break*/, 8];
182
+ return [4 /*yield*/, Promise.all(backgroundVideoPaths.map(function (videoPath) { return video_1.getVideoInfo(videoPath); }))];
183
+ case 1:
184
+ videoInfos = _j.sent();
185
+ primaryVideoInfo = videoInfos[0];
186
+ backgroundWidth_1 = (_b = (_a = outputResolution) === null || _a === void 0 ? void 0 : _a.width, (_b !== null && _b !== void 0 ? _b : primaryVideoInfo.width));
187
+ backgroundHeight_1 = (_d = (_c = outputResolution) === null || _c === void 0 ? void 0 : _c.height, (_d !== null && _d !== void 0 ? _d : primaryVideoInfo.height));
188
+ videoFrameSize = backgroundWidth_1 * backgroundHeight_1 * 3;
189
+ encodeVideoFrame = bpmEncoder_1.createBgrFrameEncoder({ width: backgroundWidth_1, height: backgroundHeight_1 });
190
+ segments = void 0;
191
+ if (!(backgroundVideoPaths.length > 1)) return [3 /*break*/, 2];
192
+ segments = autoEditVideo
193
+ ? video_1.buildShuffledVideoSegments(beatFrameIndices, framesCount, backgroundVideoPaths.length, fps, __assign({ beatIntensities: beatIntensities }, (tempo ? { tempo: tempo } : {})))
194
+ : video_1.buildSequentialVideoSegments(framesCount, videoInfos.map(function (info) { return info.duration; }), fps, startVideoIndex % backgroundVideoPaths.length);
195
+ return [3 /*break*/, 6];
196
+ case 2:
197
+ if (!autoEditVideo) return [3 /*break*/, 4];
198
+ return [4 /*yield*/, video_1.detectSceneChanges(backgroundVideoPaths[0])];
199
+ case 3:
200
+ _h = _j.sent();
201
+ return [3 /*break*/, 5];
202
+ case 4:
203
+ _h = [];
204
+ _j.label = 5;
205
+ case 5:
206
+ sceneChanges = _h;
207
+ segments = video_1.buildBeatSyncedSegments(beatFrameIndices, framesCount, sceneChanges, primaryVideoInfo.duration, fps, __assign({ beatIntensities: beatIntensities }, (autoEditVideo && tempo ? { tempo: tempo } : {})));
208
+ _j.label = 6;
209
+ case 6:
210
+ videoSources = videoInfos.map(function (info, i) { return ({ path: backgroundVideoPaths[i], duration: info.duration }); });
211
+ concatFilePath = video_1.writeConcatFile(segments, videoSources, fps);
212
+ cutFrameIndices = autoEditVideo ? video_1.getCutFrameIndices(segments) : [];
213
+ videoFrameReader = video_1.spawnConcatVideoFrameReader(__assign({ concatFilePath: concatFilePath,
214
+ fps: fps, totalFrames: framesCount }, (outputResolution && {
215
+ width: backgroundWidth_1,
216
+ height: backgroundHeight_1,
217
+ sourceWidth: primaryVideoInfo.width,
218
+ sourceHeight: primaryVideoInfo.height,
219
+ })));
220
+ return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize, readVideoFrameTimeout)];
221
+ case 7:
222
+ firstFrame = _j.sent();
223
+ if (!firstFrame) {
224
+ throw new Error("Could not read frames from video: " + backgroundVideoPaths.join(', '));
225
+ }
226
+ defaultColor_1 = image_1.getVideoFrameColor(firstFrame, backgroundWidth_1, backgroundHeight_1);
227
+ staticBackgroundBuffer_1 = encodeVideoFrame(firstFrame);
228
+ return [2 /*return*/, {
229
+ backgroundWidth: backgroundWidth_1,
230
+ backgroundHeight: backgroundHeight_1,
231
+ defaultColor: defaultColor_1,
232
+ staticBackgroundBuffer: staticBackgroundBuffer_1,
233
+ videoFrameReader: videoFrameReader,
234
+ videoFrameSize: videoFrameSize,
235
+ encodeVideoFrame: encodeVideoFrame,
236
+ concatFilePath: concatFilePath,
237
+ cutFrameIndices: cutFrameIndices,
238
+ }];
239
+ case 8:
240
+ if (!backgroundImagePath) {
241
+ throw new Error('Background image path is required when not using video background.');
242
+ }
243
+ return [4 /*yield*/, image_1.convertToBmp(backgroundImagePath, (_e = outputResolution) === null || _e === void 0 ? void 0 : _e.width, (_f = outputResolution) === null || _f === void 0 ? void 0 : _f.height)];
244
+ case 9:
245
+ backgroundImageBmpBuffer = _j.sent();
246
+ backgroundImage = image_1.parseImage(backgroundImageBmpBuffer);
247
+ backgroundWidth = backgroundImage.width;
248
+ backgroundHeight = backgroundImage.height;
249
+ defaultColor = image_1.getImageColor(backgroundImage);
250
+ bpmEncoder = bpmEncoder_1.createBpmEncoder({ width: backgroundWidth, height: backgroundHeight });
251
+ staticBackgroundBuffer = bpmEncoder(backgroundImage.data);
252
+ return [2 /*return*/, {
253
+ backgroundWidth: backgroundWidth,
254
+ backgroundHeight: backgroundHeight,
255
+ defaultColor: defaultColor,
256
+ staticBackgroundBuffer: staticBackgroundBuffer,
257
+ videoFrameSize: 0,
258
+ cutFrameIndices: [],
259
+ }];
260
+ }
261
+ });
262
+ });
263
+ }
264
+ function resolveBackgroundFrameBuffer(params) {
265
+ return __awaiter(this, void 0, void 0, function () {
266
+ var frameIndex, useVideoBackground, videoFrameReader, videoFrameSize, encodeVideoFrame, staticBackgroundBuffer, readVideoFrameTimeout, videoFrame;
267
+ return __generator(this, function (_a) {
268
+ switch (_a.label) {
269
+ case 0:
270
+ frameIndex = params.frameIndex, useVideoBackground = params.useVideoBackground, videoFrameReader = params.videoFrameReader, videoFrameSize = params.videoFrameSize, encodeVideoFrame = params.encodeVideoFrame, staticBackgroundBuffer = params.staticBackgroundBuffer, readVideoFrameTimeout = params.readVideoFrameTimeout;
271
+ if (!(useVideoBackground && videoFrameReader && encodeVideoFrame)) return [3 /*break*/, 2];
272
+ if (frameIndex === 0) {
273
+ return [2 /*return*/, { frameBuffer: staticBackgroundBuffer, frameReadFailed: false }];
274
+ }
275
+ return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize, readVideoFrameTimeout)];
276
+ case 1:
277
+ videoFrame = _a.sent();
278
+ if (videoFrame) {
279
+ return [2 /*return*/, { frameBuffer: encodeVideoFrame(videoFrame), frameReadFailed: false }];
280
+ }
281
+ return [2 /*return*/, { frameBuffer: staticBackgroundBuffer, frameReadFailed: false }];
282
+ case 2: return [2 /*return*/, { frameBuffer: staticBackgroundBuffer, frameReadFailed: false }];
283
+ }
284
+ });
285
+ });
286
+ }
287
+ exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
288
+ return new Promise(function (resolve) { return __awaiter(void 0, void 0, void 0, function () {
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;
290
+ var _a, _b;
291
+ return __generator(this, function (_c) {
292
+ switch (_c.label) {
293
+ case 0:
294
+ if (config.outVideo.spectrum && config.outVideo.polar) {
295
+ throw new Error('Cannot use both "spectrum" and "polar" options. Please specify only one visualizer type.');
296
+ }
297
+ if (!config.image && !config.video) {
298
+ throw new Error('Either "image" or "video" must be specified as the background source.');
299
+ }
300
+ if (config.image && config.video) {
301
+ throw new Error('Cannot use both "image" and "video" options. Please specify only one background source.');
302
+ }
303
+ audioFilePath = config_1.getAudioFilePath(config);
304
+ outVideoPath = config_1.getOutVideoPath(config);
305
+ subtitleSpec = config_1.getSubtitleRenderSpec(config);
306
+ subtitleFileIsTemporary = false;
307
+ subtitleAlignmentAss = 2;
308
+ if (subtitleSpec) {
309
+ subtitleAlignmentAss = config_1.subtitleAlignmentToAss(subtitleSpec.alignment);
310
+ if (subtitleSpec.source.kind === 'file') {
311
+ absPath = subtitleSpec.source.path;
312
+ ext = path_1.default.extname(absPath).toLowerCase();
313
+ if (ext === '.lrc') {
314
+ raw = fs_1.readFileSync(absPath, 'utf-8');
315
+ subtitleFilePath = video_1.writeSubtitlesFile(subtitleConvert_1.lrcToSrt(raw));
316
+ subtitleFileIsTemporary = true;
317
+ }
318
+ else {
319
+ subtitleFilePath = absPath;
320
+ }
321
+ }
322
+ else {
323
+ subtitleFilePath = video_1.writeSubtitlesFile(subtitleConvert_1.normalizeInlineSubtitlesToSrt(subtitleSpec.source.text));
324
+ subtitleFileIsTemporary = true;
325
+ }
326
+ }
327
+ backgroundVideoPaths = config_1.getBackgroundVideoPaths(config);
328
+ backgroundImagePath = config_1.getBackgroundImagePath(config);
329
+ useVideoBackground = !!backgroundVideoPaths && backgroundVideoPaths.length > 0;
330
+ return [4 /*yield*/, audio_1.createAudioBuffer(audioFilePath, FFMPEG_FORMAT)];
331
+ case 1:
332
+ audioReader = _c.sent();
333
+ audioBuffer = audioReader.audioBuffer;
334
+ sampleRate = audioReader.sampleRate;
335
+ if (!sampleRate) {
336
+ throw new Error('ffmpeg didn\'t show audio sample rate');
337
+ }
338
+ spectrumBusMargin = config_1.getSpectrumBusMargin();
339
+ FPS = config_1.getFPS(config);
340
+ ffmpeg_cfr = config_1.getFfmpeg_cfr(config);
341
+ ffmpeg_preset = config_1.getFfmpeg_preset(config);
342
+ frame_processing_delay = config_1.getFrame_processing_delay(config);
343
+ videoTimeouts = config_1.getVideoTimeouts(config);
344
+ audioDuration = audioBuffer.length / sampleRate;
345
+ framesCount = Math.trunc(audioDuration * FPS);
346
+ outputResolution = config_1.getOutputResolution(config);
347
+ maxProgressReported = -1;
348
+ reportProgress = function (progress) {
349
+ if (!onProgress) {
350
+ return;
351
+ }
352
+ var normalized = +Math.min(100, Math.max(0, progress)).toFixed(2);
353
+ if (normalized <= maxProgressReported) {
354
+ return;
355
+ }
356
+ maxProgressReported = normalized;
357
+ onProgress(normalized);
358
+ };
359
+ reportProgress(0);
360
+ return [4 /*yield*/, preProcessAudio(audioBuffer, sampleRate, FPS, framesCount, function (progress) {
361
+ reportProgress(progress);
362
+ })];
363
+ case 2:
364
+ preprocessed = _c.sent();
365
+ reportProgress(PRE_PROCESS_PROGRESS_SHARE);
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
+ }
377
+ spectrumsForRender = preprocessed.spectrums;
378
+ beatIndicesForRender = preprocessed.beatFrameIndices;
379
+ beatIntensitiesForRender = preprocessed.beatEvents.map(function (event) { return event.intensity; });
380
+ framesCountForRender = framesCount;
381
+ if (!autoHighlight) return [3 /*break*/, 4];
382
+ reportProgress(PRE_PROCESS_PROGRESS_SHARE + 1);
383
+ return [4 /*yield*/, highlight_1.computeHighlightSlice(FPS, framesCount, preprocessed.spectrums, preprocessed.beatEvents, config_1.getAudioAutoHighlightCount(config), trackTempo)];
384
+ case 3:
385
+ highlightSlice = _c.sent();
386
+ spectrumsForRender = highlightSlice.spectrums;
387
+ beatIndicesForRender = highlightSlice.beatFrameIndices;
388
+ beatIntensitiesForRender = highlightSlice.beatIntensities;
389
+ framesCountForRender = highlightSlice.highlightFrames;
390
+ reportProgress(PRE_PROCESS_PROGRESS_SHARE + POST_AUDIO_PROGRESS_SHARE);
391
+ return [3 /*break*/, 5];
392
+ case 4:
393
+ reportProgress(PRE_PROCESS_PROGRESS_SHARE + POST_AUDIO_PROGRESS_SHARE);
394
+ _c.label = 5;
395
+ case 5:
396
+ cameraShakeEnabled = config_1.getCameraShakeEnabled(config);
397
+ shakeDelayFrames = Math.round(FPS * image_1.CAMERA_SHAKE_DELAY_SECONDS);
398
+ separateHighlightFiles = autoHighlight &&
399
+ highlightSlice &&
400
+ highlightSlice.runs.length > 1;
401
+ passes = separateHighlightFiles && highlightSlice
402
+ ? highlightSlice.runs.map(function (run, i) {
403
+ var dir = path_1.default.dirname(outVideoPath);
404
+ var ext = path_1.default.extname(outVideoPath);
405
+ var base = path_1.default.basename(outVideoPath, ext);
406
+ var numberedPath = path_1.default.resolve(dir, base + "-" + (i + 1) + ext);
407
+ return {
408
+ outPath: numberedPath,
409
+ spectrums: run.spectrums,
410
+ beatIndices: run.beatFrameIndices,
411
+ beatIntensities: run.beatIntensities,
412
+ frameCount: run.highlightFrames,
413
+ startFrame: run.startFrame,
414
+ audioSegment: run.audioSegment,
415
+ };
416
+ })
417
+ : [
418
+ {
419
+ outPath: outVideoPath,
420
+ spectrums: spectrumsForRender,
421
+ beatIndices: beatIndicesForRender,
422
+ beatIntensities: beatIntensitiesForRender,
423
+ frameCount: framesCountForRender,
424
+ startFrame: (_b = (_a = highlightSlice) === null || _a === void 0 ? void 0 : _a.startFrame, (_b !== null && _b !== void 0 ? _b : 0)),
425
+ audioSegment: autoHighlight &&
426
+ highlightSlice &&
427
+ highlightSlice.audioSegments.length > 0
428
+ ? highlightSlice.audioSegments[0]
429
+ : undefined,
430
+ },
431
+ ];
432
+ totalPassFrames = passes.reduce(function (sum, pass) { return sum + pass.frameCount; }, 0);
433
+ totalRenderMilestones = totalPassFrames + (passes.length * 2);
434
+ renderMilestonesCompleted = 0;
435
+ reportRenderProgress = function (milestoneIncrement) {
436
+ if (milestoneIncrement === void 0) { milestoneIncrement = 1; }
437
+ renderMilestonesCompleted += milestoneIncrement;
438
+ reportProgress(PRE_PROCESS_PROGRESS_SHARE
439
+ + POST_AUDIO_PROGRESS_SHARE
440
+ + (RENDER_PROGRESS_SHARE * renderMilestonesCompleted / Math.max(1, totalRenderMilestones)));
441
+ };
442
+ lastExitCode = 0;
443
+ outputVideoFiles = [];
444
+ _c.label = 6;
445
+ case 6:
446
+ _c.trys.push([6, , 11, 12]);
447
+ _loop_1 = function (passIndex) {
448
+ var pass, tempo, shakeAmplitudes, _a, backgroundWidth, backgroundHeight, defaultColor, staticBackgroundBuffer, videoFrameReader, videoFrameSize, encodeVideoFrame, concatFilePath, cutFrameIndices, beatShakeFrames, shakeFrames, createVisualizerFrame, ffmpegVideoWriter, exitPromise, stoppedEarly, i, spectrum, _b, backgroundImageBuffer, frameReadFailed, commonVisualizerFrameProps, frameImage, shakeOffset, isFrameProcessed, isDrained, _c, exitCode, ffmpegExitReason;
449
+ return __generator(this, function (_d) {
450
+ switch (_d.label) {
451
+ case 0:
452
+ pass = passes[passIndex];
453
+ tempo = autoEditVideo && trackTempo
454
+ ? beats_1.tempoForWindow(trackTempo, pass.startFrame, FPS, pass.frameCount, pass.beatIndices)
455
+ : null;
456
+ shakeAmplitudes = tempo
457
+ ? image_1.buildCutShakeAmplitudes(tempo.periodFrames)
458
+ : undefined;
459
+ return [4 /*yield*/, prepareBackgroundForRender(__assign(__assign({ useVideoBackground: useVideoBackground,
460
+ backgroundVideoPaths: backgroundVideoPaths,
461
+ backgroundImagePath: backgroundImagePath, beatFrameIndices: pass.beatIndices, beatIntensities: pass.beatIntensities, framesCount: pass.frameCount, outputResolution: outputResolution, fps: FPS, autoEditVideo: autoEditVideo, readVideoFrameTimeout: videoTimeouts.readVideoFrame }, (tempo ? { tempo: tempo } : {})), {
462
+ // Each separate highlight output opens with a different video from the array.
463
+ startVideoIndex: passIndex }))];
464
+ case 1:
465
+ _a = _d.sent(), backgroundWidth = _a.backgroundWidth, backgroundHeight = _a.backgroundHeight, defaultColor = _a.defaultColor, staticBackgroundBuffer = _a.staticBackgroundBuffer, videoFrameReader = _a.videoFrameReader, videoFrameSize = _a.videoFrameSize, encodeVideoFrame = _a.encodeVideoFrame, concatFilePath = _a.concatFilePath, cutFrameIndices = _a.cutFrameIndices;
466
+ reportRenderProgress();
467
+ beatShakeFrames = function () { return (tempo
468
+ ? beats_1.beatGridFrameIndices(tempo, pass.frameCount, image_1.CAMERA_SHAKE_EVERY_BEATS)
469
+ : pass.beatIndices.filter(function (frameIndex) { return frameIndex > 0; }).filter(function (_, i) { return i % image_1.CAMERA_SHAKE_EVERY_BEATS === 0; })); };
470
+ shakeFrames = new Set(autoEditVideo && cameraShakeEnabled
471
+ ? (cutFrameIndices.length > 0 ? cutFrameIndices : beatShakeFrames())
472
+ : []);
473
+ createVisualizerFrame = createVisualizerFrameGenerator(config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin);
474
+ ffmpegVideoWriter = video_1.spawnFfmpegVideoWriter(__assign(__assign(__assign(__assign(__assign({ audioFilename: audioFilePath, videoFileName: pass.outPath }, (subtitleFilePath && {
475
+ subtitleFilename: subtitleFilePath,
476
+ subtitleAlignmentAss: subtitleAlignmentAss,
477
+ })), { fps: FPS }), (pass.audioSegment && { audioSegment: pass.audioSegment })), (ffmpeg_cfr && { crf: ffmpeg_cfr })), (ffmpeg_preset && { preset: ffmpeg_preset })));
478
+ exitPromise = video_1.waitForProcessExit(ffmpegVideoWriter, videoTimeouts.waitForProcessExit);
479
+ stoppedEarly = false;
480
+ i = 0;
481
+ _d.label = 2;
482
+ case 2:
483
+ if (!(i < pass.frameCount)) return [3 /*break*/, 10];
484
+ spectrum = pass.spectrums[i];
485
+ return [4 /*yield*/, resolveBackgroundFrameBuffer({
486
+ frameIndex: i,
487
+ useVideoBackground: useVideoBackground,
488
+ videoFrameReader: videoFrameReader,
489
+ videoFrameSize: videoFrameSize,
490
+ encodeVideoFrame: encodeVideoFrame,
491
+ staticBackgroundBuffer: staticBackgroundBuffer,
492
+ readVideoFrameTimeout: videoTimeouts.readVideoFrame,
493
+ })];
494
+ case 3:
495
+ _b = _d.sent(), backgroundImageBuffer = _b.frameBuffer, frameReadFailed = _b.frameReadFailed;
496
+ commonVisualizerFrameProps = {
497
+ backgroundImageBuffer: backgroundImageBuffer,
498
+ spectrum: spectrum,
499
+ };
500
+ frameImage = createVisualizerFrame(commonVisualizerFrameProps);
501
+ shakeOffset = image_1.getCutShakeOffset(i, shakeFrames, shakeAmplitudes, shakeDelayFrames);
502
+ if (shakeOffset.x !== 0 || shakeOffset.y !== 0) {
503
+ image_1.applyCameraShake(frameImage, backgroundWidth, backgroundHeight, shakeOffset.x, shakeOffset.y);
504
+ }
505
+ isFrameProcessed = ffmpegVideoWriter.stdin.write(frameImage.data);
506
+ if (!!isFrameProcessed) return [3 /*break*/, 5];
507
+ return [4 /*yield*/, video_1.waitDrain(ffmpegVideoWriter.stdin, ffmpegVideoWriter, videoTimeouts.waitDrain)];
508
+ case 4:
509
+ isDrained = _d.sent();
510
+ if (!isDrained) {
511
+ stoppedEarly = true;
512
+ exitReason = 'ffmpeg stdin drain failed';
513
+ return [3 /*break*/, 10];
514
+ }
515
+ _d.label = 5;
516
+ case 5:
517
+ if (shouldStop && shouldStop()) {
518
+ stoppedEarly = true;
519
+ exitReason = 'render stopped by shouldStop callback';
520
+ return [3 /*break*/, 10];
521
+ }
522
+ if (!frame_processing_delay) return [3 /*break*/, 7];
523
+ return [4 /*yield*/, sleep(frame_processing_delay)];
524
+ case 6:
525
+ _d.sent();
526
+ _d.label = 7;
527
+ case 7: return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
528
+ case 8:
529
+ _d.sent();
530
+ reportRenderProgress();
531
+ _d.label = 9;
532
+ case 9:
533
+ i++;
534
+ return [3 /*break*/, 2];
535
+ case 10:
536
+ if (videoFrameReader) {
537
+ videoFrameReader.kill();
538
+ }
539
+ if (concatFilePath) {
540
+ video_1.cleanupConcatFile(concatFilePath);
541
+ }
542
+ ffmpegVideoWriter.stdin.end();
543
+ return [4 /*yield*/, exitPromise];
544
+ case 11:
545
+ _c = _d.sent(), exitCode = _c.exitCode, ffmpegExitReason = _c.reason;
546
+ lastExitCode = exitCode;
547
+ if (!exitReason && ffmpegExitReason) {
548
+ exitReason = ffmpegExitReason;
549
+ }
550
+ if (lastExitCode === 0 && !stoppedEarly) {
551
+ reportRenderProgress();
552
+ }
553
+ if (lastExitCode === 0 && !stoppedEarly) {
554
+ outputVideoFiles.push(pass.outPath);
555
+ }
556
+ if (stoppedEarly || lastExitCode !== 0) {
557
+ if (exitReason && lastExitCode === 0) {
558
+ lastExitCode = 1;
559
+ }
560
+ return [2 /*return*/, "break-passLoop"];
561
+ }
562
+ return [2 /*return*/];
563
+ }
564
+ });
565
+ };
566
+ passIndex = 0;
567
+ _c.label = 7;
568
+ case 7:
569
+ if (!(passIndex < passes.length)) return [3 /*break*/, 10];
570
+ return [5 /*yield**/, _loop_1(passIndex)];
571
+ case 8:
572
+ state_1 = _c.sent();
573
+ switch (state_1) {
574
+ case "break-passLoop": return [3 /*break*/, 10];
575
+ }
576
+ _c.label = 9;
577
+ case 9:
578
+ passIndex++;
579
+ return [3 /*break*/, 7];
580
+ case 10:
581
+ if (lastExitCode === 0 && outputVideoFiles.length === passes.length) {
582
+ reportProgress(100);
583
+ }
584
+ if (exitReason) {
585
+ console.error(exitReason);
586
+ }
587
+ resolve({ exitCode: lastExitCode, reason: exitReason, outputVideoFiles: outputVideoFiles });
588
+ return [3 /*break*/, 12];
589
+ case 11:
590
+ if (subtitleFilePath && subtitleFileIsTemporary) {
591
+ video_1.cleanupTempFile(subtitleFilePath);
592
+ }
593
+ return [7 /*endfinally*/];
594
+ case 12: return [2 /*return*/];
595
+ }
596
+ });
597
+ }); });
598
+ };
567
599
  //# sourceMappingURL=index.js.map