nodejs-audio-visualizer 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-audio-visualizer",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/config.ts CHANGED
@@ -11,6 +11,11 @@ export const defaults = {
11
11
  spectrumRotation: 'mirror',
12
12
  spectrumBusMargin: 12,
13
13
  spectrumOpacity: '80%',
14
+ polarX: 'center',
15
+ polarY: 'middle',
16
+ polarInnerRadius: 100,
17
+ polarMaxBarLength: 160,
18
+ polarBarWidth: 15,
14
19
  };
15
20
 
16
21
  type RelativePositionValue = 0 | 0.5 | 1;
@@ -243,3 +248,105 @@ export const getFfmpeg_preset = (config: Config) =>
243
248
  export const getFrame_processing_delay = (config: Config) =>
244
249
  config.tweaks && config.tweaks.frame_processing_delay;
245
250
 
251
+ // Polar visualizer config getters
252
+ const getPolarX = (config: Config) =>
253
+ parseNumberIfPossible(
254
+ (config.outVideo.polar && config.outVideo.polar.x) ||
255
+ defaults.polarX
256
+ );
257
+
258
+ const getPolarY = (config: Config) =>
259
+ parseNumberIfPossible(
260
+ (config.outVideo.polar && config.outVideo.polar.y) ||
261
+ defaults.polarY
262
+ );
263
+
264
+ export const getPolarXAbsolute = (
265
+ config: Config,
266
+ backgroundImageWidth: number
267
+ ) => {
268
+ const polarX = getPolarX(config);
269
+ if (typeof polarX !== 'string') {
270
+ return polarX;
271
+ }
272
+ try {
273
+ const polarXParsed = parsePositionAlias(polarX);
274
+ if (polarXParsed.value === 0) {
275
+ const polarLength = getPolarMaxBarLength(config);
276
+ const polarRadius = getPolarInnerRadius(config);
277
+ return polarRadius + polarLength;
278
+ }
279
+ if (polarXParsed.value === 1) {
280
+ const polarLength = getPolarMaxBarLength(config);
281
+ const polarRadius = getPolarInnerRadius(config);
282
+ return backgroundImageWidth - polarRadius - polarLength;
283
+ }
284
+ return polarXParsed.value * backgroundImageWidth;
285
+ } catch {
286
+ throw new Error(`Invalid polar x value: ${polarX}. Valid values: ${getValidPositionAliasValues()}.`);
287
+ }
288
+ };
289
+
290
+ export const getPolarYAbsolute = (
291
+ config: Config,
292
+ backgroundImageHeight: number
293
+ ) => {
294
+ const polarY = getPolarY(config);
295
+ if (typeof polarY !== 'string') {
296
+ return polarY;
297
+ }
298
+ try {
299
+ const polarYParsed = parsePositionAlias(polarY);
300
+ if (polarYParsed.value === 0) {
301
+ const polarLength = getPolarMaxBarLength(config);
302
+ const polarRadius = getPolarInnerRadius(config);
303
+ return polarRadius + polarLength;
304
+ }
305
+ if (polarYParsed.value === 1) {
306
+ const polarLength = getPolarMaxBarLength(config);
307
+ const polarRadius = getPolarInnerRadius(config);
308
+ return backgroundImageHeight - polarRadius - polarLength;
309
+ }
310
+ return polarYParsed.value * backgroundImageHeight;
311
+ } catch {
312
+ throw new Error(`Invalid polar y value: ${polarY}. Valid values: ${getValidPositionAliasValues()}.`);
313
+ }
314
+ };
315
+
316
+ export const getPolarInnerRadius = (config: Config) =>
317
+ (config.outVideo.polar && config.outVideo.polar.innerRadius) ||
318
+ defaults.polarInnerRadius;
319
+
320
+ export const getPolarMaxBarLength = (config: Config) =>
321
+ (config.outVideo.polar && config.outVideo.polar.maxBarLength) ||
322
+ defaults.polarMaxBarLength;
323
+
324
+ export const getPolarBarWidth = (config: Config) =>
325
+ (config.outVideo.polar && config.outVideo.polar.barWidth) ||
326
+ defaults.polarBarWidth;
327
+
328
+ export const getPolarEffect = (config: Config) =>
329
+ config.outVideo.polar?.effect;
330
+
331
+ export const getPolarColor = (config: Config) =>
332
+ config.outVideo.polar && config.outVideo.polar.color;
333
+
334
+ export const getPolarOpacity = (config: Config) =>
335
+ (config.outVideo.polar && config.outVideo.polar.opacity) ||
336
+ defaults.spectrumOpacity;
337
+
338
+ export const getPolarOpacityParsed = (config: Config) => {
339
+ const polarOpacity = getPolarOpacity(config);
340
+ if (!checkIsPercentValue(polarOpacity)) {
341
+ throw new Error(`Invalid polar opacity value: '${polarOpacity}'. Use string percent value, for example '80%'.`);
342
+ }
343
+ const percentValue = parseInt(polarOpacity);
344
+ if (
345
+ (percentValue < 0) ||
346
+ (percentValue > 100)
347
+ ) {
348
+ throw new Error(`Invalid polar opacity value: '${polarOpacity}'. Percent values must be in range from '0%' to '100%'.`);
349
+ }
350
+ return percentValue / 100;
351
+ };
352
+
package/src/image.ts CHANGED
@@ -26,7 +26,7 @@ interface MixColorProps {
26
26
  backgroundColor: Color;
27
27
  }
28
28
 
29
- export const mixValues =(value1: number, value1Opacity: number, value2: number) =>
29
+ export const mixValues = (value1: number, value1Opacity: number, value2: number) =>
30
30
  Math.round(value2 * (1 - value1Opacity) + value1 * value1Opacity);
31
31
 
32
32
  export const mixColors = ({
@@ -101,6 +101,126 @@ export const drawRect = ({
101
101
  }
102
102
  };
103
103
 
104
+ interface Edge {
105
+ yMin: number;
106
+ yMax: number;
107
+ x: number;
108
+ dx: number;
109
+ }
110
+
111
+ interface FillRectProps {
112
+ imageDstBuffer: EncodedBmp;
113
+ points: [Position, Position, Position, Position];
114
+ color: Color;
115
+ opacity: number;
116
+ }
117
+
118
+ const buildQuadEdgeTable = (points: [Position, Position, Position, Position]): Edge[] => {
119
+ const edges: Edge[] = [];
120
+
121
+ for (let i = 0; i < points.length; i++) {
122
+ const p1 = points[i];
123
+ const p2 = points[(i + 1) % points.length];
124
+
125
+ if (p1.y === p2.y) continue; // Skip horizontal edges
126
+
127
+ const yMin = Math.min(p1.y, p2.y);
128
+ const yMax = Math.max(p1.y, p2.y);
129
+ const x = p1.y < p2.y ? p1.x : p2.x;
130
+ const dx = (p2.x - p1.x) / (p2.y - p1.y);
131
+
132
+ edges.push({ yMin, yMax, x, dx });
133
+ }
134
+
135
+ return edges.sort((a, b) => a.yMin - b.yMin);
136
+ };
137
+
138
+ /**
139
+ * Fills a quadrilateral (4-sided polygon) using scan-line algorithm
140
+ * Only the outer edges are anti-aliased
141
+ */
142
+ export const fillRect = ({
143
+ imageDstBuffer,
144
+ points,
145
+ color,
146
+ opacity,
147
+ }: FillRectProps) => {
148
+ // Build edge table from all 4 vertices
149
+ const edgeTable = buildQuadEdgeTable(points);
150
+ if (edgeTable.length === 0) return;
151
+
152
+ // Find the bounding box
153
+ const yMin = Math.min(...points.map(p => p.y));
154
+ const yMax = Math.max(...points.map(p => p.y));
155
+
156
+ // Active Edge Table for scan line algorithm
157
+ const activeEdges: Edge[] = [];
158
+
159
+ // Scan line algorithm: process each horizontal line
160
+ for (let y = Math.floor(yMin); y <= Math.ceil(yMax); y++) {
161
+ // Add edges that start at this scanline to AET
162
+ for (const edge of edgeTable) {
163
+ if (Math.floor(edge.yMin) === y) {
164
+ activeEdges.push({ ...edge });
165
+ }
166
+ }
167
+
168
+ // Remove edges that end at this scanline from AET
169
+ for (let i = activeEdges.length - 1; i >= 0; i--) {
170
+ if (Math.ceil(activeEdges[i].yMax) <= y) {
171
+ activeEdges.splice(i, 1);
172
+ }
173
+ }
174
+
175
+ // Sort active edges by x coordinate
176
+ activeEdges.sort((a, b) => a.x - b.x);
177
+
178
+ // Fill pixels between pairs of intersections
179
+ for (let i = 0; i < activeEdges.length; i += 2) {
180
+ if (i + 1 < activeEdges.length) {
181
+ const xStart = activeEdges[i].x;
182
+ const xEnd = activeEdges[i + 1].x;
183
+
184
+ // Anti-aliased rendering with sub-pixel precision
185
+ const xStartFloor = Math.floor(xStart);
186
+ const xEndCeil = Math.ceil(xEnd);
187
+
188
+ for (let x = xStartFloor; x < xEndCeil; x++) {
189
+ const pixelIndex = imageDstBuffer.shiftPos + y * imageDstBuffer.rowBytes + x * 3;
190
+
191
+ // Calculate coverage for anti-aliasing
192
+ let coverage = 1.0;
193
+ if (x === xStartFloor) {
194
+ // Left edge pixel - calculate fractional coverage
195
+ coverage = Math.min(1.0, 1.0 - (xStart - xStartFloor));
196
+ } else if (x === xEndCeil - 1) {
197
+ // Right edge pixel - calculate fractional coverage
198
+ coverage = Math.min(1.0, xEnd - Math.floor(xEnd));
199
+ }
200
+
201
+ // Apply coverage to opacity for smooth edges
202
+ const effectiveOpacity = opacity * coverage;
203
+
204
+ const pixelColor = getRectPixelColor({
205
+ imageDstBuffer,
206
+ pixelIndex,
207
+ color,
208
+ opacity: effectiveOpacity,
209
+ });
210
+ imageDstBuffer.data[pixelIndex] = pixelColor.blue;
211
+ imageDstBuffer.data[pixelIndex + 1] = pixelColor.green;
212
+ imageDstBuffer.data[pixelIndex + 2] = pixelColor.red;
213
+ }
214
+ }
215
+ }
216
+
217
+ // Update x coordinates for next scanline (x' = x + dx)
218
+ for (const edge of activeEdges) {
219
+ edge.x += edge.dx;
220
+ }
221
+ }
222
+ };
223
+
104
224
  interface DrawSpectrumProps {
105
225
  imageDstBuffer: EncodedBmp;
106
226
  spectrum: number[];
@@ -167,9 +287,79 @@ const drawSpectrum = ({
167
287
  }
168
288
  };
169
289
 
170
- interface CreateVisualizerFrameProps {
290
+ const calcCirclePoint = (angleRadians: number, radius: number): Position => {
291
+ const circleX = radius * Math.cos(angleRadians);
292
+ const circleY = radius * Math.sin(angleRadians);
293
+ return { x: circleX, y: circleY };
294
+ };
295
+
296
+ const lerp = (start: number, end: number, t: number) =>
297
+ start + (end - start) * t;
298
+
299
+ interface DrawPolarSpectrumProps {
300
+ imageDstBuffer: EncodedBmp;
301
+ spectrum: number[];
302
+ centerX: number;
303
+ centerY: number;
304
+ innerRadius: number;
305
+ maxBarLength: number;
306
+ barWidth: number;
307
+ color: Color;
308
+ opacity: number;
309
+ }
310
+
311
+ const drawPolarSpectrum = ({
312
+ imageDstBuffer,
313
+ spectrum,
314
+ centerX,
315
+ centerY,
316
+ innerRadius,
317
+ maxBarLength,
318
+ barWidth,
319
+ color,
320
+ opacity,
321
+ }: DrawPolarSpectrumProps) => {
322
+ const angleStep = (2 * Math.PI) / spectrum.length;
323
+ const innerLength = innerRadius * 2 * Math.PI;
324
+ const radiansPerPixel = 2 * Math.PI / innerLength;
325
+ const barWidthInRadians = radiansPerPixel * barWidth;
326
+ const spectrumAverage = spectrum.reduce((a, b) => a + b, 0) / spectrum.length;
327
+ const scaleFactor = lerp(0.75, 1, spectrumAverage);
328
+ const scaledMaxOuterRadius = (innerRadius + maxBarLength) * scaleFactor;
329
+ const scaledInnerRadius = innerRadius * scaleFactor;
330
+ for (let i = 0; i < spectrum.length; i++) {
331
+ const currentSpectrumValue = spectrum[i] || 0;
332
+ const busRadius = lerp(scaledInnerRadius, scaledMaxOuterRadius, currentSpectrumValue);
333
+ const angle = i * angleStep;
334
+ const angleRadiansStart = angle;
335
+ const angleRadiansEnd = angle + barWidthInRadians;
336
+
337
+ const point1 = calcCirclePoint(angleRadiansStart, scaledInnerRadius);
338
+ const point2 = calcCirclePoint(angleRadiansStart, busRadius);
339
+
340
+ const point3 = calcCirclePoint(angleRadiansEnd, scaledInnerRadius);
341
+ const point4 = calcCirclePoint(angleRadiansEnd, busRadius);
342
+
343
+ fillRect({
344
+ imageDstBuffer,
345
+ points: [
346
+ { x: centerX + Math.round(point1.x), y: centerY + Math.round(point1.y) },
347
+ { x: centerX + Math.round(point2.x), y: centerY + Math.round(point2.y) },
348
+ { x: centerX + Math.round(point4.x), y: centerY + Math.round(point4.y) },
349
+ { x: centerX + Math.round(point3.x), y: centerY + Math.round(point3.y) },
350
+ ],
351
+ color,
352
+ opacity,
353
+ });
354
+ }
355
+ };
356
+
357
+ export interface CommonVisualizerFrameProps {
171
358
  backgroundImageBuffer: EncodedBmp;
172
359
  spectrum: number[];
360
+ }
361
+
362
+ export interface CreateVisualizerFrameProps {
173
363
  size: Size;
174
364
  position: Position;
175
365
  rotation: RotationAliasName;
@@ -179,7 +369,18 @@ interface CreateVisualizerFrameProps {
179
369
  spectrumEffect?: SpectrumEffect;
180
370
  }
181
371
 
182
- export const createVisualizerFrameGenerator = () => {
372
+ export interface CreatePolarVisualizerFrameProps {
373
+ centerX: number;
374
+ centerY: number;
375
+ innerRadius: number;
376
+ maxBarLength: number;
377
+ barWidth: number;
378
+ color: Color | string;
379
+ opacity: number;
380
+ spectrumEffect?: SpectrumEffect;
381
+ }
382
+
383
+ export const createSpectrumVisualizerFrameGenerator = () => {
183
384
  let prevSpectrum: number[] | null = null;
184
385
 
185
386
  return ({
@@ -192,35 +393,34 @@ export const createVisualizerFrameGenerator = () => {
192
393
  color,
193
394
  opacity,
194
395
  spectrumEffect,
195
- }: CreateVisualizerFrameProps) => {
396
+ }: CommonVisualizerFrameProps & CreateVisualizerFrameProps) => {
196
397
  const imageDstBuffer = Object.assign({}, backgroundImageBuffer);
197
398
  imageDstBuffer.data = Buffer.from(backgroundImageBuffer.data);
198
-
199
-
399
+
200
400
  const rgbSpectrumColor = (typeof color === 'string') ? hexToRgb(color) : color;
201
401
  if (spectrumEffect === 'volume') {
202
402
  drawSpectrum({
203
- imageDstBuffer,
204
- spectrum,
205
- size,
206
- position: { x: position.x + 2, y: position.y + 2 },
207
- rotation,
208
- margin,
209
- color: rgbSpectrumColor,
210
- opacity: opacity * 0.5,
211
- });
403
+ imageDstBuffer,
404
+ spectrum,
405
+ size,
406
+ position: { x: position.x + 2, y: position.y + 2 },
407
+ rotation,
408
+ margin,
409
+ color: rgbSpectrumColor,
410
+ opacity: opacity * 0.5,
411
+ });
212
412
  }
213
413
  if (spectrumEffect === 'smooth' && prevSpectrum) {
214
414
  drawSpectrum({
215
- imageDstBuffer,
216
- spectrum: prevSpectrum,
217
- size,
218
- position,
219
- rotation,
220
- margin,
221
- color: rgbSpectrumColor,
222
- opacity: opacity * 0.3,
223
- });
415
+ imageDstBuffer,
416
+ spectrum: prevSpectrum,
417
+ size,
418
+ position,
419
+ rotation,
420
+ margin,
421
+ color: rgbSpectrumColor,
422
+ opacity: opacity * 0.3,
423
+ });
224
424
  }
225
425
  drawSpectrum({
226
426
  imageDstBuffer,
@@ -232,9 +432,78 @@ export const createVisualizerFrameGenerator = () => {
232
432
  color: rgbSpectrumColor,
233
433
  opacity,
234
434
  });
235
-
435
+
236
436
  prevSpectrum = spectrum;
237
-
437
+
438
+ return imageDstBuffer;
439
+ };
440
+ };
441
+
442
+ export const createPolarVisualizerFrameGenerator = () => {
443
+ let prevSpectrum: number[] | null = null;
444
+
445
+ return ({
446
+ backgroundImageBuffer,
447
+ spectrum,
448
+ centerX,
449
+ centerY,
450
+ innerRadius,
451
+ maxBarLength,
452
+ barWidth,
453
+ color,
454
+ opacity,
455
+ spectrumEffect,
456
+ }: CommonVisualizerFrameProps & CreatePolarVisualizerFrameProps) => {
457
+ const imageDstBuffer = Object.assign({}, backgroundImageBuffer);
458
+ imageDstBuffer.data = Buffer.from(backgroundImageBuffer.data);
459
+
460
+ const rgbSpectrumColor = (typeof color === 'string') ? hexToRgb(color) : color;
461
+
462
+ // Draw shadow/volume effect
463
+ if (spectrumEffect === 'volume') {
464
+ drawPolarSpectrum({
465
+ imageDstBuffer,
466
+ spectrum,
467
+ centerX: centerX + 2,
468
+ centerY: centerY + 2,
469
+ innerRadius,
470
+ maxBarLength,
471
+ barWidth,
472
+ color: rgbSpectrumColor,
473
+ opacity: opacity * 0.5,
474
+ });
475
+ }
476
+
477
+ // Draw smooth/trail effect with previous frame
478
+ if (spectrumEffect === 'smooth' && prevSpectrum) {
479
+ drawPolarSpectrum({
480
+ imageDstBuffer,
481
+ spectrum: prevSpectrum,
482
+ centerX,
483
+ centerY,
484
+ innerRadius,
485
+ maxBarLength,
486
+ barWidth,
487
+ color: rgbSpectrumColor,
488
+ opacity: opacity * 0.3,
489
+ });
490
+ }
491
+
492
+ // Draw main spectrum
493
+ drawPolarSpectrum({
494
+ imageDstBuffer,
495
+ spectrum,
496
+ centerX,
497
+ centerY,
498
+ innerRadius,
499
+ maxBarLength,
500
+ barWidth,
501
+ color: rgbSpectrumColor,
502
+ opacity,
503
+ });
504
+
505
+ prevSpectrum = spectrum;
506
+
238
507
  return imageDstBuffer;
239
508
  };
240
509
  };
package/src/index.ts CHANGED
@@ -17,11 +17,20 @@ import {
17
17
  getSpectrumRotation,
18
18
  getSpectrumEffect,
19
19
  SpectrumEffect,
20
+ getPolarXAbsolute,
21
+ getPolarYAbsolute,
22
+ getPolarInnerRadius,
23
+ getPolarMaxBarLength,
24
+ getPolarBarWidth,
25
+ getPolarEffect,
26
+ getPolarColor,
27
+ getPolarOpacityParsed,
20
28
  } from './config';
21
29
  import { createAudioBuffer, bufferToUInt8, createSpectrumsProcessor } from './audio';
22
- import { parseImage, getImageColor, invertColor, Color, convertToBmp, createVisualizerFrameGenerator } from './image';
30
+ import { parseImage, getImageColor, invertColor, Color, convertToBmp, createSpectrumVisualizerFrameGenerator, createPolarVisualizerFrameGenerator, CreatePolarVisualizerFrameProps, CreateVisualizerFrameProps, CommonVisualizerFrameProps } from './image';
23
31
  import { spawnFfmpegVideoWriter, getProgress, calculateProgress, waitDrain } from './video';
24
- import { createBpmEncoder } from './bpmEncoder';
32
+ import { createBpmEncoder, EncodedBmp } from './bpmEncoder';
33
+ import { BmpDecoder } from 'bmp-js';
25
34
 
26
35
  export const PCM_FORMAT = {
27
36
  bit: 8,
@@ -50,6 +59,16 @@ export interface Config {
50
59
  effect?: SpectrumEffect;
51
60
  color?: Color | string;
52
61
  opacity?: string;
62
+ };
63
+ polar?: {
64
+ x?: number | PositionAliasName;
65
+ y?: number | PositionAliasName;
66
+ innerRadius?: number;
67
+ maxBarLength?: number;
68
+ barWidth?: number;
69
+ effect?: SpectrumEffect;
70
+ color?: Color | string;
71
+ opacity?: string;
53
72
  }
54
73
  };
55
74
  tweaks?: {
@@ -74,8 +93,67 @@ export type RotationAliasName = typeof rotationAliasValues[number];
74
93
  const sleep = (timeout: number) =>
75
94
  new Promise(resolve => setTimeout(resolve, timeout));
76
95
 
96
+ const createVisualizerFrameGenerator = (
97
+ config: Config,
98
+ backgroundImage: BmpDecoder,
99
+ spectrumBusMargin: number
100
+ ): (params: CommonVisualizerFrameProps) => EncodedBmp => {
101
+ if (!config.outVideo.spectrum) {
102
+ const createPolarVisualizerFrame = createPolarVisualizerFrameGenerator();
103
+ const polarX = getPolarXAbsolute(config, backgroundImage.width);
104
+ const polarY = getPolarYAbsolute(config, backgroundImage.height);
105
+ const polarInnerRadius = getPolarInnerRadius(config);
106
+ const polarMaxBarLength = getPolarMaxBarLength(config);
107
+ const polarBarWidth = getPolarBarWidth(config);
108
+ const polarColor = getPolarColor(config) || invertColor(getImageColor(backgroundImage));
109
+ const polarEffect = getPolarEffect(config);
110
+ const polarOpacity = getPolarOpacityParsed(config);
111
+
112
+ return (params: CommonVisualizerFrameProps) => {
113
+ return createPolarVisualizerFrame({
114
+ ...params,
115
+ centerX: polarX,
116
+ centerY: polarY,
117
+ innerRadius: polarInnerRadius,
118
+ maxBarLength: polarMaxBarLength,
119
+ barWidth: polarBarWidth,
120
+ color: polarColor,
121
+ opacity: polarOpacity,
122
+ spectrumEffect: polarEffect,
123
+ });
124
+ };
125
+ }
126
+ const createPolarVisualizerFrame = createSpectrumVisualizerFrameGenerator();
127
+ const spectrumWidth = getSpectrumWidthAbsolute(config, backgroundImage.width);
128
+ const spectrumHeight = getSpectrumHeightAbsolute(config, backgroundImage.height);
129
+ const spectrumX = getSpectrumXAbsolute(config, spectrumWidth, backgroundImage.width);
130
+ const spectrumY = getSpectrumYAbsolute(config, spectrumHeight, backgroundImage.height);
131
+ const spectrumRotation = getSpectrumRotation(config);
132
+ const spectrumColor = getSpectrumColor(config) || invertColor(getImageColor(backgroundImage));
133
+ const spectrumEffect = getSpectrumEffect(config);
134
+ const spectrumOpacity = getSpectrumOpacityParsed(config);
135
+
136
+ return (params: CommonVisualizerFrameProps) => {
137
+ return createPolarVisualizerFrame({
138
+ ...params,
139
+ size: { width: spectrumWidth, height: spectrumHeight },
140
+ position: { x: spectrumX, y: spectrumY },
141
+ rotation: spectrumRotation,
142
+ margin: spectrumBusMargin,
143
+ color: spectrumColor,
144
+ opacity: spectrumOpacity,
145
+ spectrumEffect,
146
+ });
147
+ };
148
+ };
149
+
77
150
  export const renderAudioVisualizer = (config: Config, onProgress?: (progress: number) => any, shouldStop?: () => boolean) =>
78
151
  new Promise<number>(async (resolve) => {
152
+ // Validate that only one visualizer type is specified
153
+ if (config.outVideo.spectrum && config.outVideo.polar) {
154
+ throw new Error('Cannot use both "spectrum" and "polar" options. Please specify only one visualizer type.');
155
+ }
156
+
79
157
  const audioFilePath = getAudioFilePath(config);
80
158
  const backgroundImagePath = getBackgroundImagePath(config);
81
159
  const outVideoPath = getOutVideoPath(config);
@@ -91,25 +169,12 @@ export const renderAudioVisualizer = (config: Config, onProgress?: (progress: nu
91
169
 
92
170
  const spectrumBusMargin = getSpectrumBusMargin();
93
171
  const FPS = getFPS(config);
94
- const spectrumWidth =
95
- getSpectrumWidthAbsolute(config, backgroundImage.width);
96
- const spectrumHeight =
97
- getSpectrumHeightAbsolute(config, backgroundImage.height);
98
- const spectrumX =
99
- getSpectrumXAbsolute(config, spectrumWidth, backgroundImage.width);
100
- const spectrumY =
101
- getSpectrumYAbsolute(config, spectrumHeight, backgroundImage.height);
102
- const spectrumRotation =
103
- getSpectrumRotation(config);
104
- const spectrumColor =
105
- getSpectrumColor(config) ||
106
- invertColor(getImageColor(backgroundImage));
107
- const spectrumEffect = getSpectrumEffect(config);
108
- const spectrumOpacity = getSpectrumOpacityParsed(config);
109
172
  const ffmpeg_cfr = getFfmpeg_cfr(config);
110
173
  const ffmpeg_preset = getFfmpeg_preset(config);
111
174
  const frame_processing_delay = getFrame_processing_delay(config);
112
175
 
176
+ const createVisualizerFrame = createVisualizerFrameGenerator(config, backgroundImage, spectrumBusMargin);
177
+
113
178
  const audioDuration = audioBuffer.length / sampleRate;
114
179
  const framesCount = Math.trunc(audioDuration * FPS);
115
180
  const audioDataStep = Math.trunc(audioBuffer.length / framesCount);
@@ -129,7 +194,7 @@ export const renderAudioVisualizer = (config: Config, onProgress?: (progress: nu
129
194
  const backgroundImageBuffer = bpmEncoder(backgroundImage.data);
130
195
  const skipFramesCount = FPS < 45 ? 1 : 2;
131
196
  const processSpectrum = createSpectrumsProcessor(sampleRate, skipFramesCount);
132
- const createVisualizerFrame = createVisualizerFrameGenerator();
197
+
133
198
  for (let i = 0; i < framesCount; i++) {
134
199
  const currentFrameData = PCM_FORMAT.parseFunction(audioBuffer, i * audioDataStep, i * audioDataStep + audioDataStep);
135
200
  processingBuffer.copyWithin(0, currentFrameData.length);
@@ -137,17 +202,11 @@ export const renderAudioVisualizer = (config: Config, onProgress?: (progress: nu
137
202
 
138
203
  const audioDataParser = () => Array.from(processingBuffer);
139
204
  const spectrum = processSpectrum(audioDataParser);
140
- const frameImage = createVisualizerFrame({
205
+ const commonVisualizerFrameProps: CommonVisualizerFrameProps = {
141
206
  backgroundImageBuffer,
142
207
  spectrum,
143
- size: { width: spectrumWidth, height: spectrumHeight },
144
- position: { x: spectrumX, y: spectrumY },
145
- rotation: spectrumRotation,
146
- margin: spectrumBusMargin,
147
- color: spectrumColor,
148
- opacity: spectrumOpacity,
149
- spectrumEffect,
150
- });
208
+ };
209
+ const frameImage = createVisualizerFrame(commonVisualizerFrameProps);
151
210
  const isFrameProcessed = ffmpegVideoWriter.stdin.write(frameImage.data);
152
211
  if (!isFrameProcessed) {
153
212
  await waitDrain(ffmpegVideoWriter.stdin);