( dir: string, inputPaths: string[], options: FfmpegOptions )
| 327 | } |
| 328 | |
| 329 | async function mixAudio( |
| 330 | dir: string, |
| 331 | inputPaths: string[], |
| 332 | options: FfmpegOptions |
| 333 | ): Promise<FfmpegResult> { |
| 334 | if (inputPaths.length < 2) throw new Error('mix_audio requires [voice, music]') |
| 335 | const outputPath = path.join(dir, 'out.mp3') |
| 336 | const voiceVol = options.volume ?? 1 |
| 337 | const musicVol = options.musicVolume ?? 0.3 |
| 338 | const command = ffmpeg() |
| 339 | .input(inputPaths[0]) |
| 340 | .input(inputPaths[1]) |
| 341 | .complexFilter([ |
| 342 | `[0:a]volume=${voiceVol}[v]`, |
| 343 | `[1:a]volume=${musicVol}[m]`, |
| 344 | `[v][m]amix=inputs=2:duration=longest:dropout_transition=0[a]`, |
| 345 | ]) |
| 346 | .outputOptions(['-map', '[a]']) |
| 347 | await runCommand(command, outputPath) |
| 348 | return readOut(outputPath, 'mp3') |
| 349 | } |
| 350 | |
| 351 | async function concat(dir: string, inputPaths: string[]): Promise<FfmpegResult> { |
| 352 | if (inputPaths.length < 2) throw new Error('concat requires at least 2 clips') |
no test coverage detected