nodejs-audio-visualizer 4.2.3 → 4.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,467 +1,471 @@
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 config_1 = require("./config");
55
- var audio_1 = require("./audio");
56
- var image_1 = require("./image");
57
- var video_1 = require("./video");
58
- var bpmEncoder_1 = require("./bpmEncoder");
59
- var beats_1 = require("./beats");
60
- var highlight_1 = require("./highlight");
61
- var waitForEventLoop_1 = require("./waitForEventLoop");
62
- var highlight_2 = require("./highlight");
63
- exports.computeHighlightSlice = highlight_2.computeHighlightSlice;
64
- exports.HIGHLIGHT_DURATION_SEC = highlight_2.HIGHLIGHT_DURATION_SEC;
65
- exports.PCM_FORMAT = {
66
- bit: 8,
67
- sign: 'u',
68
- parseFunction: audio_1.bufferToUInt8
69
- };
70
- var FFMPEG_FORMAT = "" + exports.PCM_FORMAT.sign + exports.PCM_FORMAT.bit;
71
- var PROCESSING_BUFFER_SIZE = Math.pow(2, 12);
72
- var sleep = function (timeout) {
73
- return new Promise(function (resolve) { return setTimeout(resolve, timeout); });
74
- };
75
- var createVisualizerFrameGenerator = function (config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin) {
76
- if (!config.outVideo.spectrum) {
77
- var createPolarVisualizerFrame_1 = image_1.createPolarVisualizerFrameGenerator();
78
- var polarX_1 = config_1.getPolarXAbsolute(config, backgroundWidth);
79
- var polarY_1 = config_1.getPolarYAbsolute(config, backgroundHeight);
80
- var polarInnerRadius_1 = config_1.getPolarInnerRadius(config);
81
- var polarMaxBarLength_1 = config_1.getPolarMaxBarLength(config);
82
- var polarBarWidth_1 = config_1.getPolarBarWidth(config);
83
- var polarColor_1 = config_1.getPolarColor(config) || image_1.invertColor(defaultColor);
84
- var polarEffect_1 = config_1.getPolarEffect(config);
85
- var polarOpacity_1 = config_1.getPolarOpacityParsed(config);
86
- return function (params) {
87
- 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 }));
88
- };
89
- }
90
- var createSpectrumVisualizerFrame = image_1.createSpectrumVisualizerFrameGenerator();
91
- var spectrumWidth = config_1.getSpectrumWidthAbsolute(config, backgroundWidth);
92
- var spectrumHeight = config_1.getSpectrumHeightAbsolute(config, backgroundHeight);
93
- var spectrumX = config_1.getSpectrumXAbsolute(config, spectrumWidth, backgroundWidth);
94
- var spectrumY = config_1.getSpectrumYAbsolute(config, spectrumHeight, backgroundHeight);
95
- var spectrumRotation = config_1.getSpectrumRotation(config);
96
- var spectrumColor = config_1.getSpectrumColor(config) || image_1.invertColor(defaultColor);
97
- var spectrumEffect = config_1.getSpectrumEffect(config);
98
- var spectrumOpacity = config_1.getSpectrumOpacityParsed(config);
99
- return function (params) {
100
- return createSpectrumVisualizerFrame(__assign(__assign({}, params), { size: { width: spectrumWidth, height: spectrumHeight }, position: { x: spectrumX, y: spectrumY }, rotation: spectrumRotation, margin: spectrumBusMargin, color: spectrumColor, opacity: spectrumOpacity, spectrumEffect: spectrumEffect }));
101
- };
102
- };
103
- var PRE_PROCESS_PROGRESS_SHARE = 10;
104
- var preProcessAudio = function (audioBuffer, sampleRate, fps, framesCount, onPreProcessProgress) { return __awaiter(void 0, void 0, void 0, function () {
105
- var t, audioDataStep, processingBuffer, skipFramesCount, processSpectrum, detectBeat, spectrums, beatFrameIndices, beatEvents, nextPreProcessMilestone, i, currentFrameData, audioDataParser, spectrum, beat, p;
106
- var _a, _b;
107
- return __generator(this, function (_c) {
108
- switch (_c.label) {
109
- case 0:
110
- if (framesCount === 0) {
111
- for (t = 1; t <= PRE_PROCESS_PROGRESS_SHARE; t += 1) {
112
- (_a = onPreProcessProgress) === null || _a === void 0 ? void 0 : _a(t);
113
- }
114
- return [2 /*return*/, { spectrums: [], beatFrameIndices: [], beatEvents: [] }];
115
- }
116
- audioDataStep = Math.trunc(audioBuffer.length / framesCount);
117
- processingBuffer = new Float32Array(PROCESSING_BUFFER_SIZE).fill(0);
118
- skipFramesCount = fps < 45 ? 1 : 2;
119
- processSpectrum = audio_1.createSpectrumsProcessor(sampleRate, skipFramesCount);
120
- detectBeat = beats_1.createBeatDetector(fps);
121
- spectrums = [];
122
- beatFrameIndices = [];
123
- beatEvents = [];
124
- nextPreProcessMilestone = 1;
125
- i = 0;
126
- _c.label = 1;
127
- case 1:
128
- if (!(i < framesCount)) return [3 /*break*/, 4];
129
- currentFrameData = exports.PCM_FORMAT.parseFunction(audioBuffer, i * audioDataStep, i * audioDataStep + audioDataStep);
130
- processingBuffer.copyWithin(0, currentFrameData.length);
131
- processingBuffer.set(currentFrameData, PROCESSING_BUFFER_SIZE - currentFrameData.length);
132
- audioDataParser = function () { return Array.from(processingBuffer); };
133
- spectrum = processSpectrum(audioDataParser);
134
- beat = detectBeat(spectrum);
135
- spectrums.push(spectrum);
136
- if (beat.isBeat) {
137
- beatFrameIndices.push(i);
138
- beatEvents.push({ frameIndex: i, intensity: beat.intensity });
139
- }
140
- p = PRE_PROCESS_PROGRESS_SHARE * (i + 1) / framesCount;
141
- while (nextPreProcessMilestone <= PRE_PROCESS_PROGRESS_SHARE
142
- && p >= nextPreProcessMilestone) {
143
- (_b = onPreProcessProgress) === null || _b === void 0 ? void 0 : _b(nextPreProcessMilestone);
144
- nextPreProcessMilestone += 1;
145
- }
146
- return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
147
- case 2:
148
- _c.sent();
149
- _c.label = 3;
150
- case 3:
151
- i++;
152
- return [3 /*break*/, 1];
153
- case 4: return [2 /*return*/, { spectrums: spectrums, beatFrameIndices: beatFrameIndices, beatEvents: beatEvents }];
154
- }
155
- });
156
- }); };
157
- function prepareBackgroundForRender(params) {
158
- var _a, _b, _c, _d, _e, _f;
159
- return __awaiter(this, void 0, void 0, function () {
160
- var useVideoBackground, backgroundVideoPath, backgroundImagePath, beatFrameIndices, framesCount, outputResolution, fps, autoEditVideo, videoInfo, sceneChanges, _g, backgroundWidth_1, backgroundHeight_1, videoFrameSize, encodeVideoFrame, segments, concatFilePath, videoFrameReader, firstFrame, defaultColor_1, staticBackgroundBuffer_1, backgroundImageBmpBuffer, backgroundImage, backgroundWidth, backgroundHeight, defaultColor, bpmEncoder, staticBackgroundBuffer;
161
- return __generator(this, function (_h) {
162
- switch (_h.label) {
163
- case 0:
164
- useVideoBackground = params.useVideoBackground, backgroundVideoPath = params.backgroundVideoPath, backgroundImagePath = params.backgroundImagePath, beatFrameIndices = params.beatFrameIndices, framesCount = params.framesCount, outputResolution = params.outputResolution, fps = params.fps, autoEditVideo = params.autoEditVideo;
165
- if (!(useVideoBackground && backgroundVideoPath)) return [3 /*break*/, 6];
166
- return [4 /*yield*/, video_1.getVideoInfo(backgroundVideoPath)];
167
- case 1:
168
- videoInfo = _h.sent();
169
- if (!autoEditVideo) return [3 /*break*/, 3];
170
- return [4 /*yield*/, video_1.detectSceneChanges(backgroundVideoPath)];
171
- case 2:
172
- _g = _h.sent();
173
- return [3 /*break*/, 4];
174
- case 3:
175
- _g = [];
176
- _h.label = 4;
177
- case 4:
178
- sceneChanges = _g;
179
- backgroundWidth_1 = (_b = (_a = outputResolution) === null || _a === void 0 ? void 0 : _a.width, (_b !== null && _b !== void 0 ? _b : videoInfo.width));
180
- backgroundHeight_1 = (_d = (_c = outputResolution) === null || _c === void 0 ? void 0 : _c.height, (_d !== null && _d !== void 0 ? _d : videoInfo.height));
181
- videoFrameSize = backgroundWidth_1 * backgroundHeight_1 * 3;
182
- encodeVideoFrame = bpmEncoder_1.createBgrFrameEncoder({ width: backgroundWidth_1, height: backgroundHeight_1 });
183
- segments = video_1.buildBeatSyncedSegments(beatFrameIndices, framesCount, sceneChanges, videoInfo.duration);
184
- concatFilePath = video_1.writeConcatFile(segments, backgroundVideoPath, videoInfo.duration, fps);
185
- videoFrameReader = video_1.spawnConcatVideoFrameReader(__assign({ concatFilePath: concatFilePath,
186
- fps: fps, totalFrames: framesCount }, (outputResolution && {
187
- width: backgroundWidth_1,
188
- height: backgroundHeight_1,
189
- sourceWidth: videoInfo.width,
190
- sourceHeight: videoInfo.height,
191
- })));
192
- return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize)];
193
- case 5:
194
- firstFrame = _h.sent();
195
- if (!firstFrame) {
196
- throw new Error("Could not read frames from video: " + backgroundVideoPath);
197
- }
198
- defaultColor_1 = image_1.getVideoFrameColor(firstFrame, backgroundWidth_1, backgroundHeight_1);
199
- staticBackgroundBuffer_1 = encodeVideoFrame(firstFrame);
200
- return [2 /*return*/, {
201
- backgroundWidth: backgroundWidth_1,
202
- backgroundHeight: backgroundHeight_1,
203
- defaultColor: defaultColor_1,
204
- staticBackgroundBuffer: staticBackgroundBuffer_1,
205
- videoFrameReader: videoFrameReader,
206
- videoFrameSize: videoFrameSize,
207
- encodeVideoFrame: encodeVideoFrame,
208
- concatFilePath: concatFilePath,
209
- }];
210
- case 6:
211
- if (!backgroundImagePath) {
212
- throw new Error('Background image path is required when not using video background.');
213
- }
214
- 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)];
215
- case 7:
216
- backgroundImageBmpBuffer = _h.sent();
217
- backgroundImage = image_1.parseImage(backgroundImageBmpBuffer);
218
- backgroundWidth = backgroundImage.width;
219
- backgroundHeight = backgroundImage.height;
220
- defaultColor = image_1.getImageColor(backgroundImage);
221
- bpmEncoder = bpmEncoder_1.createBpmEncoder({ width: backgroundWidth, height: backgroundHeight });
222
- staticBackgroundBuffer = bpmEncoder(backgroundImage.data);
223
- return [2 /*return*/, {
224
- backgroundWidth: backgroundWidth,
225
- backgroundHeight: backgroundHeight,
226
- defaultColor: defaultColor,
227
- staticBackgroundBuffer: staticBackgroundBuffer,
228
- videoFrameSize: 0,
229
- }];
230
- }
231
- });
232
- });
233
- }
234
- function resolveBackgroundFrameBuffer(params) {
235
- return __awaiter(this, void 0, void 0, function () {
236
- var frameIndex, useVideoBackground, videoFrameReader, videoFrameSize, encodeVideoFrame, staticBackgroundBuffer, videoFrame;
237
- return __generator(this, function (_a) {
238
- switch (_a.label) {
239
- case 0:
240
- frameIndex = params.frameIndex, useVideoBackground = params.useVideoBackground, videoFrameReader = params.videoFrameReader, videoFrameSize = params.videoFrameSize, encodeVideoFrame = params.encodeVideoFrame, staticBackgroundBuffer = params.staticBackgroundBuffer;
241
- if (!(useVideoBackground && videoFrameReader && encodeVideoFrame)) return [3 /*break*/, 2];
242
- if (frameIndex === 0) {
243
- return [2 /*return*/, staticBackgroundBuffer];
244
- }
245
- return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize)];
246
- case 1:
247
- videoFrame = _a.sent();
248
- return [2 /*return*/, videoFrame
249
- ? encodeVideoFrame(videoFrame)
250
- : staticBackgroundBuffer];
251
- case 2: return [2 /*return*/, staticBackgroundBuffer];
252
- }
253
- });
254
- });
255
- }
256
- exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
257
- return new Promise(function (resolve) { return __awaiter(void 0, void 0, void 0, function () {
258
- var audioFilePath, outVideoPath, backgroundVideoPath, backgroundImagePath, useVideoBackground, audioReader, audioBuffer, sampleRate, spectrumBusMargin, FPS, ffmpeg_cfr, ffmpeg_preset, frame_processing_delay, audioDuration, framesCount, outputResolution, preprocessed, autoHighlight, spectrumsForRender, beatIndicesForRender, framesCountForRender, highlightSlice, separateHighlightFiles, passes, progressDenominator, progressFrameBase, lastExitCode, outputVideoFiles, _loop_1, _i, passes_1, pass, state_1;
259
- return __generator(this, function (_a) {
260
- switch (_a.label) {
261
- case 0:
262
- if (config.outVideo.spectrum && config.outVideo.polar) {
263
- throw new Error('Cannot use both "spectrum" and "polar" options. Please specify only one visualizer type.');
264
- }
265
- if (!config.image && !config.video) {
266
- throw new Error('Either "image" or "video" must be specified as the background source.');
267
- }
268
- if (config.image && config.video) {
269
- throw new Error('Cannot use both "image" and "video" options. Please specify only one background source.');
270
- }
271
- audioFilePath = config_1.getAudioFilePath(config);
272
- outVideoPath = config_1.getOutVideoPath(config);
273
- backgroundVideoPath = config_1.getBackgroundVideoPath(config);
274
- backgroundImagePath = config_1.getBackgroundImagePath(config);
275
- useVideoBackground = !!backgroundVideoPath;
276
- return [4 /*yield*/, audio_1.createAudioBuffer(audioFilePath, FFMPEG_FORMAT)];
277
- case 1:
278
- audioReader = _a.sent();
279
- audioBuffer = audioReader.audioBuffer;
280
- sampleRate = audioReader.sampleRate;
281
- if (!sampleRate) {
282
- throw new Error('ffmpeg didn\'t show audio sample rate');
283
- }
284
- spectrumBusMargin = config_1.getSpectrumBusMargin();
285
- FPS = config_1.getFPS(config);
286
- ffmpeg_cfr = config_1.getFfmpeg_cfr(config);
287
- ffmpeg_preset = config_1.getFfmpeg_preset(config);
288
- frame_processing_delay = config_1.getFrame_processing_delay(config);
289
- audioDuration = audioBuffer.length / sampleRate;
290
- framesCount = Math.trunc(audioDuration * FPS);
291
- outputResolution = config_1.getOutputResolution(config);
292
- if (onProgress) {
293
- onProgress(0);
294
- }
295
- return [4 /*yield*/, preProcessAudio(audioBuffer, sampleRate, FPS, framesCount, onProgress)];
296
- case 2:
297
- preprocessed = _a.sent();
298
- autoHighlight = config_1.getAudioAutoHighlight(config);
299
- spectrumsForRender = preprocessed.spectrums;
300
- beatIndicesForRender = preprocessed.beatFrameIndices;
301
- framesCountForRender = framesCount;
302
- if (!autoHighlight) return [3 /*break*/, 4];
303
- return [4 /*yield*/, highlight_1.computeHighlightSlice(FPS, framesCount, preprocessed.spectrums, preprocessed.beatEvents, config_1.getAudioAutoHighlightCount(config))];
304
- case 3:
305
- highlightSlice = _a.sent();
306
- spectrumsForRender = highlightSlice.spectrums;
307
- beatIndicesForRender = highlightSlice.beatFrameIndices;
308
- framesCountForRender = highlightSlice.highlightFrames;
309
- _a.label = 4;
310
- case 4:
311
- separateHighlightFiles = autoHighlight &&
312
- highlightSlice &&
313
- highlightSlice.runs.length > 1;
314
- passes = separateHighlightFiles && highlightSlice
315
- ? highlightSlice.runs.map(function (run, i) {
316
- var dir = path_1.default.dirname(outVideoPath);
317
- var ext = path_1.default.extname(outVideoPath);
318
- var base = path_1.default.basename(outVideoPath, ext);
319
- var numberedPath = path_1.default.resolve(dir, base + "-" + (i + 1) + ext);
320
- return {
321
- outPath: numberedPath,
322
- spectrums: run.spectrums,
323
- beatIndices: run.beatFrameIndices,
324
- frameCount: run.highlightFrames,
325
- audioSegment: run.audioSegment,
326
- };
327
- })
328
- : [
329
- {
330
- outPath: outVideoPath,
331
- spectrums: spectrumsForRender,
332
- beatIndices: beatIndicesForRender,
333
- frameCount: framesCountForRender,
334
- audioSegment: autoHighlight &&
335
- highlightSlice &&
336
- highlightSlice.audioSegments.length > 0
337
- ? highlightSlice.audioSegments[0]
338
- : undefined,
339
- },
340
- ];
341
- progressDenominator = passes.reduce(function (s, p) { return s + p.frameCount; }, 0) + passes.length;
342
- progressFrameBase = 0;
343
- lastExitCode = 0;
344
- outputVideoFiles = [];
345
- _loop_1 = function (pass) {
346
- var _a, backgroundWidth, backgroundHeight, defaultColor, staticBackgroundBuffer, videoFrameReader, videoFrameSize, encodeVideoFrame, concatFilePath, createVisualizerFrame, ffmpegVideoWriter, exitPromise, stoppedEarly, i, spectrum, backgroundImageBuffer, commonVisualizerFrameProps, frameImage, isFrameProcessed;
347
- return __generator(this, function (_b) {
348
- switch (_b.label) {
349
- case 0: return [4 /*yield*/, prepareBackgroundForRender({
350
- useVideoBackground: useVideoBackground,
351
- backgroundVideoPath: backgroundVideoPath,
352
- backgroundImagePath: backgroundImagePath,
353
- beatFrameIndices: pass.beatIndices,
354
- framesCount: pass.frameCount,
355
- outputResolution: outputResolution,
356
- fps: FPS,
357
- autoEditVideo: config_1.getAutoEditVideo(config),
358
- })];
359
- case 1:
360
- _a = _b.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;
361
- createVisualizerFrame = createVisualizerFrameGenerator(config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin);
362
- ffmpegVideoWriter = video_1.spawnFfmpegVideoWriter(__assign(__assign(__assign(__assign({ audioFilename: audioFilePath, videoFileName: pass.outPath, fps: FPS }, (pass.audioSegment && { audioSegment: pass.audioSegment })), (!!onProgress && {
363
- onStderr: video_1.getProgress(function (currentFrame) {
364
- var g = progressFrameBase + currentFrame;
365
- onProgress(+(Math.min(100, PRE_PROCESS_PROGRESS_SHARE
366
- + (90 * g) / progressDenominator)).toFixed(2));
367
- }),
368
- })), (ffmpeg_cfr && { crf: ffmpeg_cfr })), (ffmpeg_preset && { preset: ffmpeg_preset })));
369
- exitPromise = new Promise(function (res) {
370
- var settled = false;
371
- ffmpegVideoWriter.on('exit', function (code) {
372
- if (settled) {
373
- return;
374
- }
375
- settled = true;
376
- res((code !== null && code !== void 0 ? code : 0));
377
- });
378
- });
379
- stoppedEarly = false;
380
- i = 0;
381
- _b.label = 2;
382
- case 2:
383
- if (!(i < pass.frameCount)) return [3 /*break*/, 10];
384
- spectrum = pass.spectrums[i];
385
- return [4 /*yield*/, resolveBackgroundFrameBuffer({
386
- frameIndex: i,
387
- useVideoBackground: useVideoBackground,
388
- videoFrameReader: videoFrameReader,
389
- videoFrameSize: videoFrameSize,
390
- encodeVideoFrame: encodeVideoFrame,
391
- staticBackgroundBuffer: staticBackgroundBuffer,
392
- })];
393
- case 3:
394
- backgroundImageBuffer = _b.sent();
395
- commonVisualizerFrameProps = {
396
- backgroundImageBuffer: backgroundImageBuffer,
397
- spectrum: spectrum,
398
- };
399
- frameImage = createVisualizerFrame(commonVisualizerFrameProps);
400
- isFrameProcessed = ffmpegVideoWriter.stdin.write(frameImage.data);
401
- if (!!isFrameProcessed) return [3 /*break*/, 5];
402
- return [4 /*yield*/, video_1.waitDrain(ffmpegVideoWriter.stdin)];
403
- case 4:
404
- _b.sent();
405
- _b.label = 5;
406
- case 5:
407
- if (shouldStop && shouldStop()) {
408
- stoppedEarly = true;
409
- return [3 /*break*/, 10];
410
- }
411
- if (!frame_processing_delay) return [3 /*break*/, 7];
412
- return [4 /*yield*/, sleep(frame_processing_delay)];
413
- case 6:
414
- _b.sent();
415
- _b.label = 7;
416
- case 7: return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
417
- case 8:
418
- _b.sent();
419
- _b.label = 9;
420
- case 9:
421
- i++;
422
- return [3 /*break*/, 2];
423
- case 10:
424
- if (videoFrameReader) {
425
- videoFrameReader.kill();
426
- }
427
- if (concatFilePath) {
428
- video_1.cleanupConcatFile(concatFilePath);
429
- }
430
- ffmpegVideoWriter.stdin.end();
431
- return [4 /*yield*/, exitPromise];
432
- case 11:
433
- lastExitCode = _b.sent();
434
- progressFrameBase += pass.frameCount + 1;
435
- if (lastExitCode === 0 && !stoppedEarly) {
436
- outputVideoFiles.push(pass.outPath);
437
- }
438
- if (stoppedEarly || lastExitCode !== 0) {
439
- return [2 /*return*/, "break-passLoop"];
440
- }
441
- return [2 /*return*/];
442
- }
443
- });
444
- };
445
- _i = 0, passes_1 = passes;
446
- _a.label = 5;
447
- case 5:
448
- if (!(_i < passes_1.length)) return [3 /*break*/, 8];
449
- pass = passes_1[_i];
450
- return [5 /*yield**/, _loop_1(pass)];
451
- case 6:
452
- state_1 = _a.sent();
453
- switch (state_1) {
454
- case "break-passLoop": return [3 /*break*/, 8];
455
- }
456
- _a.label = 7;
457
- case 7:
458
- _i++;
459
- return [3 /*break*/, 5];
460
- case 8:
461
- resolve({ exitCode: lastExitCode, outputVideoFiles: outputVideoFiles });
462
- return [2 /*return*/];
463
- }
464
- });
465
- }); });
466
- };
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 config_1 = require("./config");
55
+ var audio_1 = require("./audio");
56
+ var image_1 = require("./image");
57
+ var video_1 = require("./video");
58
+ var bpmEncoder_1 = require("./bpmEncoder");
59
+ var beats_1 = require("./beats");
60
+ var highlight_1 = require("./highlight");
61
+ var waitForEventLoop_1 = require("./waitForEventLoop");
62
+ var highlight_2 = require("./highlight");
63
+ exports.computeHighlightSlice = highlight_2.computeHighlightSlice;
64
+ exports.HIGHLIGHT_DURATION_SEC = highlight_2.HIGHLIGHT_DURATION_SEC;
65
+ exports.PCM_FORMAT = {
66
+ bit: 8,
67
+ sign: 'u',
68
+ parseFunction: audio_1.bufferToUInt8
69
+ };
70
+ var FFMPEG_FORMAT = "" + exports.PCM_FORMAT.sign + exports.PCM_FORMAT.bit;
71
+ var PROCESSING_BUFFER_SIZE = Math.pow(2, 12);
72
+ var sleep = function (timeout) {
73
+ return new Promise(function (resolve) { return setTimeout(resolve, timeout); });
74
+ };
75
+ var createVisualizerFrameGenerator = function (config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin) {
76
+ if (!config.outVideo.spectrum) {
77
+ var createPolarVisualizerFrame_1 = image_1.createPolarVisualizerFrameGenerator();
78
+ var polarX_1 = config_1.getPolarXAbsolute(config, backgroundWidth);
79
+ var polarY_1 = config_1.getPolarYAbsolute(config, backgroundHeight);
80
+ var polarInnerRadius_1 = config_1.getPolarInnerRadius(config);
81
+ var polarMaxBarLength_1 = config_1.getPolarMaxBarLength(config);
82
+ var polarBarWidth_1 = config_1.getPolarBarWidth(config);
83
+ var polarColor_1 = config_1.getPolarColor(config) || image_1.invertColor(defaultColor);
84
+ var polarEffect_1 = config_1.getPolarEffect(config);
85
+ var polarOpacity_1 = config_1.getPolarOpacityParsed(config);
86
+ return function (params) {
87
+ 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 }));
88
+ };
89
+ }
90
+ var createSpectrumVisualizerFrame = image_1.createSpectrumVisualizerFrameGenerator();
91
+ var spectrumWidth = config_1.getSpectrumWidthAbsolute(config, backgroundWidth);
92
+ var spectrumHeight = config_1.getSpectrumHeightAbsolute(config, backgroundHeight);
93
+ var spectrumX = config_1.getSpectrumXAbsolute(config, spectrumWidth, backgroundWidth);
94
+ var spectrumY = config_1.getSpectrumYAbsolute(config, spectrumHeight, backgroundHeight);
95
+ var spectrumRotation = config_1.getSpectrumRotation(config);
96
+ var spectrumColor = config_1.getSpectrumColor(config) || image_1.invertColor(defaultColor);
97
+ var spectrumEffect = config_1.getSpectrumEffect(config);
98
+ var spectrumOpacity = config_1.getSpectrumOpacityParsed(config);
99
+ return function (params) {
100
+ return createSpectrumVisualizerFrame(__assign(__assign({}, params), { size: { width: spectrumWidth, height: spectrumHeight }, position: { x: spectrumX, y: spectrumY }, rotation: spectrumRotation, margin: spectrumBusMargin, color: spectrumColor, opacity: spectrumOpacity, spectrumEffect: spectrumEffect }));
101
+ };
102
+ };
103
+ var PRE_PROCESS_PROGRESS_SHARE = 60;
104
+ var preProcessAudio = function (audioBuffer, sampleRate, fps, framesCount, onPreProcessProgress) { return __awaiter(void 0, void 0, void 0, function () {
105
+ var t, audioDataStep, processingBuffer, skipFramesCount, processSpectrum, detectBeat, spectrums, beatFrameIndices, beatEvents, nextPreProcessMilestone, i, currentFrameData, audioDataParser, spectrum, beat, p;
106
+ var _a, _b;
107
+ return __generator(this, function (_c) {
108
+ switch (_c.label) {
109
+ case 0:
110
+ if (framesCount === 0) {
111
+ for (t = 1; t <= PRE_PROCESS_PROGRESS_SHARE; t += 1) {
112
+ (_a = onPreProcessProgress) === null || _a === void 0 ? void 0 : _a(t);
113
+ }
114
+ return [2 /*return*/, { spectrums: [], beatFrameIndices: [], beatEvents: [] }];
115
+ }
116
+ audioDataStep = Math.trunc(audioBuffer.length / framesCount);
117
+ processingBuffer = new Float32Array(PROCESSING_BUFFER_SIZE).fill(0);
118
+ skipFramesCount = fps < 45 ? 1 : 2;
119
+ processSpectrum = audio_1.createSpectrumsProcessor(sampleRate, skipFramesCount);
120
+ detectBeat = beats_1.createBeatDetector(fps);
121
+ spectrums = [];
122
+ beatFrameIndices = [];
123
+ beatEvents = [];
124
+ nextPreProcessMilestone = 1;
125
+ i = 0;
126
+ _c.label = 1;
127
+ case 1:
128
+ if (!(i < framesCount)) return [3 /*break*/, 4];
129
+ currentFrameData = exports.PCM_FORMAT.parseFunction(audioBuffer, i * audioDataStep, i * audioDataStep + audioDataStep);
130
+ processingBuffer.copyWithin(0, currentFrameData.length);
131
+ processingBuffer.set(currentFrameData, PROCESSING_BUFFER_SIZE - currentFrameData.length);
132
+ audioDataParser = function () { return Array.from(processingBuffer); };
133
+ spectrum = processSpectrum(audioDataParser);
134
+ beat = detectBeat(spectrum);
135
+ spectrums.push(spectrum);
136
+ if (beat.isBeat) {
137
+ beatFrameIndices.push(i);
138
+ beatEvents.push({ frameIndex: i, intensity: beat.intensity });
139
+ }
140
+ p = PRE_PROCESS_PROGRESS_SHARE * (i + 1) / framesCount;
141
+ while (nextPreProcessMilestone <= PRE_PROCESS_PROGRESS_SHARE
142
+ && p >= nextPreProcessMilestone) {
143
+ (_b = onPreProcessProgress) === null || _b === void 0 ? void 0 : _b(nextPreProcessMilestone);
144
+ nextPreProcessMilestone += 1;
145
+ }
146
+ return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
147
+ case 2:
148
+ _c.sent();
149
+ _c.label = 3;
150
+ case 3:
151
+ i++;
152
+ return [3 /*break*/, 1];
153
+ case 4: return [2 /*return*/, { spectrums: spectrums, beatFrameIndices: beatFrameIndices, beatEvents: beatEvents }];
154
+ }
155
+ });
156
+ }); };
157
+ function prepareBackgroundForRender(params) {
158
+ var _a, _b, _c, _d, _e, _f;
159
+ return __awaiter(this, void 0, void 0, function () {
160
+ var useVideoBackground, backgroundVideoPath, backgroundImagePath, beatFrameIndices, framesCount, outputResolution, fps, autoEditVideo, videoInfo, sceneChanges, _g, backgroundWidth_1, backgroundHeight_1, videoFrameSize, encodeVideoFrame, segments, concatFilePath, videoFrameReader, firstFrame, defaultColor_1, staticBackgroundBuffer_1, backgroundImageBmpBuffer, backgroundImage, backgroundWidth, backgroundHeight, defaultColor, bpmEncoder, staticBackgroundBuffer;
161
+ return __generator(this, function (_h) {
162
+ switch (_h.label) {
163
+ case 0:
164
+ useVideoBackground = params.useVideoBackground, backgroundVideoPath = params.backgroundVideoPath, backgroundImagePath = params.backgroundImagePath, beatFrameIndices = params.beatFrameIndices, framesCount = params.framesCount, outputResolution = params.outputResolution, fps = params.fps, autoEditVideo = params.autoEditVideo;
165
+ if (!(useVideoBackground && backgroundVideoPath)) return [3 /*break*/, 6];
166
+ return [4 /*yield*/, video_1.getVideoInfo(backgroundVideoPath)];
167
+ case 1:
168
+ videoInfo = _h.sent();
169
+ if (!autoEditVideo) return [3 /*break*/, 3];
170
+ return [4 /*yield*/, video_1.detectSceneChanges(backgroundVideoPath)];
171
+ case 2:
172
+ _g = _h.sent();
173
+ return [3 /*break*/, 4];
174
+ case 3:
175
+ _g = [];
176
+ _h.label = 4;
177
+ case 4:
178
+ sceneChanges = _g;
179
+ backgroundWidth_1 = (_b = (_a = outputResolution) === null || _a === void 0 ? void 0 : _a.width, (_b !== null && _b !== void 0 ? _b : videoInfo.width));
180
+ backgroundHeight_1 = (_d = (_c = outputResolution) === null || _c === void 0 ? void 0 : _c.height, (_d !== null && _d !== void 0 ? _d : videoInfo.height));
181
+ videoFrameSize = backgroundWidth_1 * backgroundHeight_1 * 3;
182
+ encodeVideoFrame = bpmEncoder_1.createBgrFrameEncoder({ width: backgroundWidth_1, height: backgroundHeight_1 });
183
+ segments = video_1.buildBeatSyncedSegments(beatFrameIndices, framesCount, sceneChanges, videoInfo.duration);
184
+ concatFilePath = video_1.writeConcatFile(segments, backgroundVideoPath, videoInfo.duration, fps);
185
+ videoFrameReader = video_1.spawnConcatVideoFrameReader(__assign({ concatFilePath: concatFilePath,
186
+ fps: fps, totalFrames: framesCount }, (outputResolution && {
187
+ width: backgroundWidth_1,
188
+ height: backgroundHeight_1,
189
+ sourceWidth: videoInfo.width,
190
+ sourceHeight: videoInfo.height,
191
+ })));
192
+ return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize)];
193
+ case 5:
194
+ firstFrame = _h.sent();
195
+ if (!firstFrame) {
196
+ throw new Error("Could not read frames from video: " + backgroundVideoPath);
197
+ }
198
+ defaultColor_1 = image_1.getVideoFrameColor(firstFrame, backgroundWidth_1, backgroundHeight_1);
199
+ staticBackgroundBuffer_1 = encodeVideoFrame(firstFrame);
200
+ return [2 /*return*/, {
201
+ backgroundWidth: backgroundWidth_1,
202
+ backgroundHeight: backgroundHeight_1,
203
+ defaultColor: defaultColor_1,
204
+ staticBackgroundBuffer: staticBackgroundBuffer_1,
205
+ videoFrameReader: videoFrameReader,
206
+ videoFrameSize: videoFrameSize,
207
+ encodeVideoFrame: encodeVideoFrame,
208
+ concatFilePath: concatFilePath,
209
+ }];
210
+ case 6:
211
+ if (!backgroundImagePath) {
212
+ throw new Error('Background image path is required when not using video background.');
213
+ }
214
+ 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)];
215
+ case 7:
216
+ backgroundImageBmpBuffer = _h.sent();
217
+ backgroundImage = image_1.parseImage(backgroundImageBmpBuffer);
218
+ backgroundWidth = backgroundImage.width;
219
+ backgroundHeight = backgroundImage.height;
220
+ defaultColor = image_1.getImageColor(backgroundImage);
221
+ bpmEncoder = bpmEncoder_1.createBpmEncoder({ width: backgroundWidth, height: backgroundHeight });
222
+ staticBackgroundBuffer = bpmEncoder(backgroundImage.data);
223
+ return [2 /*return*/, {
224
+ backgroundWidth: backgroundWidth,
225
+ backgroundHeight: backgroundHeight,
226
+ defaultColor: defaultColor,
227
+ staticBackgroundBuffer: staticBackgroundBuffer,
228
+ videoFrameSize: 0,
229
+ }];
230
+ }
231
+ });
232
+ });
233
+ }
234
+ function resolveBackgroundFrameBuffer(params) {
235
+ return __awaiter(this, void 0, void 0, function () {
236
+ var frameIndex, useVideoBackground, videoFrameReader, videoFrameSize, encodeVideoFrame, staticBackgroundBuffer, videoFrame;
237
+ return __generator(this, function (_a) {
238
+ switch (_a.label) {
239
+ case 0:
240
+ frameIndex = params.frameIndex, useVideoBackground = params.useVideoBackground, videoFrameReader = params.videoFrameReader, videoFrameSize = params.videoFrameSize, encodeVideoFrame = params.encodeVideoFrame, staticBackgroundBuffer = params.staticBackgroundBuffer;
241
+ if (!(useVideoBackground && videoFrameReader && encodeVideoFrame)) return [3 /*break*/, 2];
242
+ if (frameIndex === 0) {
243
+ return [2 /*return*/, staticBackgroundBuffer];
244
+ }
245
+ return [4 /*yield*/, video_1.readVideoFrame(videoFrameReader.stdout, videoFrameSize)];
246
+ case 1:
247
+ videoFrame = _a.sent();
248
+ return [2 /*return*/, videoFrame
249
+ ? encodeVideoFrame(videoFrame)
250
+ : staticBackgroundBuffer];
251
+ case 2: return [2 /*return*/, staticBackgroundBuffer];
252
+ }
253
+ });
254
+ });
255
+ }
256
+ exports.renderAudioVisualizer = function (config, onProgress, shouldStop) {
257
+ return new Promise(function (resolve) { return __awaiter(void 0, void 0, void 0, function () {
258
+ var audioFilePath, outVideoPath, backgroundVideoPath, backgroundImagePath, useVideoBackground, audioReader, audioBuffer, sampleRate, spectrumBusMargin, FPS, ffmpeg_cfr, ffmpeg_preset, frame_processing_delay, audioDuration, framesCount, outputResolution, preprocessed, autoHighlight, spectrumsForRender, beatIndicesForRender, framesCountForRender, highlightSlice, separateHighlightFiles, passes, progressDenominator, progressFrameBase, lastExitCode, outputVideoFiles, _loop_1, _i, passes_1, pass, state_1;
259
+ return __generator(this, function (_a) {
260
+ switch (_a.label) {
261
+ case 0:
262
+ if (config.outVideo.spectrum && config.outVideo.polar) {
263
+ throw new Error('Cannot use both "spectrum" and "polar" options. Please specify only one visualizer type.');
264
+ }
265
+ if (!config.image && !config.video) {
266
+ throw new Error('Either "image" or "video" must be specified as the background source.');
267
+ }
268
+ if (config.image && config.video) {
269
+ throw new Error('Cannot use both "image" and "video" options. Please specify only one background source.');
270
+ }
271
+ audioFilePath = config_1.getAudioFilePath(config);
272
+ outVideoPath = config_1.getOutVideoPath(config);
273
+ backgroundVideoPath = config_1.getBackgroundVideoPath(config);
274
+ backgroundImagePath = config_1.getBackgroundImagePath(config);
275
+ useVideoBackground = !!backgroundVideoPath;
276
+ return [4 /*yield*/, audio_1.createAudioBuffer(audioFilePath, FFMPEG_FORMAT)];
277
+ case 1:
278
+ audioReader = _a.sent();
279
+ audioBuffer = audioReader.audioBuffer;
280
+ sampleRate = audioReader.sampleRate;
281
+ if (!sampleRate) {
282
+ throw new Error('ffmpeg didn\'t show audio sample rate');
283
+ }
284
+ spectrumBusMargin = config_1.getSpectrumBusMargin();
285
+ FPS = config_1.getFPS(config);
286
+ ffmpeg_cfr = config_1.getFfmpeg_cfr(config);
287
+ ffmpeg_preset = config_1.getFfmpeg_preset(config);
288
+ frame_processing_delay = config_1.getFrame_processing_delay(config);
289
+ audioDuration = audioBuffer.length / sampleRate;
290
+ framesCount = Math.trunc(audioDuration * FPS);
291
+ outputResolution = config_1.getOutputResolution(config);
292
+ if (onProgress) {
293
+ onProgress(0);
294
+ }
295
+ return [4 /*yield*/, preProcessAudio(audioBuffer, sampleRate, FPS, framesCount, onProgress)];
296
+ case 2:
297
+ preprocessed = _a.sent();
298
+ autoHighlight = config_1.getAudioAutoHighlight(config);
299
+ spectrumsForRender = preprocessed.spectrums;
300
+ beatIndicesForRender = preprocessed.beatFrameIndices;
301
+ framesCountForRender = framesCount;
302
+ if (!autoHighlight) return [3 /*break*/, 4];
303
+ return [4 /*yield*/, highlight_1.computeHighlightSlice(FPS, framesCount, preprocessed.spectrums, preprocessed.beatEvents, config_1.getAudioAutoHighlightCount(config))];
304
+ case 3:
305
+ highlightSlice = _a.sent();
306
+ spectrumsForRender = highlightSlice.spectrums;
307
+ beatIndicesForRender = highlightSlice.beatFrameIndices;
308
+ framesCountForRender = highlightSlice.highlightFrames;
309
+ _a.label = 4;
310
+ case 4:
311
+ separateHighlightFiles = autoHighlight &&
312
+ highlightSlice &&
313
+ highlightSlice.runs.length > 1;
314
+ passes = separateHighlightFiles && highlightSlice
315
+ ? highlightSlice.runs.map(function (run, i) {
316
+ var dir = path_1.default.dirname(outVideoPath);
317
+ var ext = path_1.default.extname(outVideoPath);
318
+ var base = path_1.default.basename(outVideoPath, ext);
319
+ var numberedPath = path_1.default.resolve(dir, base + "-" + (i + 1) + ext);
320
+ return {
321
+ outPath: numberedPath,
322
+ spectrums: run.spectrums,
323
+ beatIndices: run.beatFrameIndices,
324
+ frameCount: run.highlightFrames,
325
+ audioSegment: run.audioSegment,
326
+ };
327
+ })
328
+ : [
329
+ {
330
+ outPath: outVideoPath,
331
+ spectrums: spectrumsForRender,
332
+ beatIndices: beatIndicesForRender,
333
+ frameCount: framesCountForRender,
334
+ audioSegment: autoHighlight &&
335
+ highlightSlice &&
336
+ highlightSlice.audioSegments.length > 0
337
+ ? highlightSlice.audioSegments[0]
338
+ : undefined,
339
+ },
340
+ ];
341
+ progressDenominator = passes.reduce(function (s, p) { return s + p.frameCount; }, 0) + passes.length;
342
+ progressFrameBase = 0;
343
+ lastExitCode = 0;
344
+ outputVideoFiles = [];
345
+ _loop_1 = function (pass) {
346
+ var _a, backgroundWidth, backgroundHeight, defaultColor, staticBackgroundBuffer, videoFrameReader, videoFrameSize, encodeVideoFrame, concatFilePath, createVisualizerFrame, ffmpegVideoWriter, exitPromise, stoppedEarly, i, spectrum, backgroundImageBuffer, commonVisualizerFrameProps, frameImage, isFrameProcessed, isDrained;
347
+ return __generator(this, function (_b) {
348
+ switch (_b.label) {
349
+ case 0: return [4 /*yield*/, prepareBackgroundForRender({
350
+ useVideoBackground: useVideoBackground,
351
+ backgroundVideoPath: backgroundVideoPath,
352
+ backgroundImagePath: backgroundImagePath,
353
+ beatFrameIndices: pass.beatIndices,
354
+ framesCount: pass.frameCount,
355
+ outputResolution: outputResolution,
356
+ fps: FPS,
357
+ autoEditVideo: config_1.getAutoEditVideo(config),
358
+ })];
359
+ case 1:
360
+ _a = _b.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;
361
+ createVisualizerFrame = createVisualizerFrameGenerator(config, backgroundWidth, backgroundHeight, defaultColor, spectrumBusMargin);
362
+ ffmpegVideoWriter = video_1.spawnFfmpegVideoWriter(__assign(__assign(__assign(__assign({ audioFilename: audioFilePath, videoFileName: pass.outPath, fps: FPS }, (pass.audioSegment && { audioSegment: pass.audioSegment })), (!!onProgress && {
363
+ onStderr: video_1.getProgress(function (currentFrame) {
364
+ var g = progressFrameBase + currentFrame;
365
+ onProgress(+(Math.min(100, PRE_PROCESS_PROGRESS_SHARE
366
+ + (90 * g) / progressDenominator)).toFixed(2));
367
+ }),
368
+ })), (ffmpeg_cfr && { crf: ffmpeg_cfr })), (ffmpeg_preset && { preset: ffmpeg_preset })));
369
+ exitPromise = new Promise(function (res) {
370
+ var settled = false;
371
+ ffmpegVideoWriter.on('exit', function (code) {
372
+ if (settled) {
373
+ return;
374
+ }
375
+ settled = true;
376
+ res((code !== null && code !== void 0 ? code : 0));
377
+ });
378
+ });
379
+ stoppedEarly = false;
380
+ i = 0;
381
+ _b.label = 2;
382
+ case 2:
383
+ if (!(i < pass.frameCount)) return [3 /*break*/, 10];
384
+ spectrum = pass.spectrums[i];
385
+ return [4 /*yield*/, resolveBackgroundFrameBuffer({
386
+ frameIndex: i,
387
+ useVideoBackground: useVideoBackground,
388
+ videoFrameReader: videoFrameReader,
389
+ videoFrameSize: videoFrameSize,
390
+ encodeVideoFrame: encodeVideoFrame,
391
+ staticBackgroundBuffer: staticBackgroundBuffer,
392
+ })];
393
+ case 3:
394
+ backgroundImageBuffer = _b.sent();
395
+ commonVisualizerFrameProps = {
396
+ backgroundImageBuffer: backgroundImageBuffer,
397
+ spectrum: spectrum,
398
+ };
399
+ frameImage = createVisualizerFrame(commonVisualizerFrameProps);
400
+ isFrameProcessed = ffmpegVideoWriter.stdin.write(frameImage.data);
401
+ if (!!isFrameProcessed) return [3 /*break*/, 5];
402
+ return [4 /*yield*/, video_1.waitDrain(ffmpegVideoWriter.stdin, ffmpegVideoWriter)];
403
+ case 4:
404
+ isDrained = _b.sent();
405
+ if (!isDrained) {
406
+ stoppedEarly = true;
407
+ return [3 /*break*/, 10];
408
+ }
409
+ _b.label = 5;
410
+ case 5:
411
+ if (shouldStop && shouldStop()) {
412
+ stoppedEarly = true;
413
+ return [3 /*break*/, 10];
414
+ }
415
+ if (!frame_processing_delay) return [3 /*break*/, 7];
416
+ return [4 /*yield*/, sleep(frame_processing_delay)];
417
+ case 6:
418
+ _b.sent();
419
+ _b.label = 7;
420
+ case 7: return [4 /*yield*/, waitForEventLoop_1.waitForEventLoop()];
421
+ case 8:
422
+ _b.sent();
423
+ _b.label = 9;
424
+ case 9:
425
+ i++;
426
+ return [3 /*break*/, 2];
427
+ case 10:
428
+ if (videoFrameReader) {
429
+ videoFrameReader.kill();
430
+ }
431
+ if (concatFilePath) {
432
+ video_1.cleanupConcatFile(concatFilePath);
433
+ }
434
+ ffmpegVideoWriter.stdin.end();
435
+ return [4 /*yield*/, exitPromise];
436
+ case 11:
437
+ lastExitCode = _b.sent();
438
+ progressFrameBase += pass.frameCount + 1;
439
+ if (lastExitCode === 0 && !stoppedEarly) {
440
+ outputVideoFiles.push(pass.outPath);
441
+ }
442
+ if (stoppedEarly || lastExitCode !== 0) {
443
+ return [2 /*return*/, "break-passLoop"];
444
+ }
445
+ return [2 /*return*/];
446
+ }
447
+ });
448
+ };
449
+ _i = 0, passes_1 = passes;
450
+ _a.label = 5;
451
+ case 5:
452
+ if (!(_i < passes_1.length)) return [3 /*break*/, 8];
453
+ pass = passes_1[_i];
454
+ return [5 /*yield**/, _loop_1(pass)];
455
+ case 6:
456
+ state_1 = _a.sent();
457
+ switch (state_1) {
458
+ case "break-passLoop": return [3 /*break*/, 8];
459
+ }
460
+ _a.label = 7;
461
+ case 7:
462
+ _i++;
463
+ return [3 /*break*/, 5];
464
+ case 8:
465
+ resolve({ exitCode: lastExitCode, outputVideoFiles: outputVideoFiles });
466
+ return [2 /*return*/];
467
+ }
468
+ });
469
+ }); });
470
+ };
467
471
  //# sourceMappingURL=index.js.map