I am trying to split a track into multiple fixed-sized (30-second) clips, each with a (5-second) fade-in / fade-out at the beginning and end, respectively. I'm using node-fluent-ffmpeg
to interface with ffmpeg
and saving each of the ffmpeg
commands in an array of ES6 Promises that I later execute using Promise.all()
.
I am able to clip the tracks and add the fade-in filter successfully, but for some reason the fade-out filter is only applied to the first clip of the track. I have looked around for answers both in the ffmpeg
and node-fluent-ffmpeg
documentation (here and here), but there is no mention of issues arising from applying fade-out filters to a track that is being clipped multiple times.
My code is very similar to the snippet below, with the audio filters being applied in sequence using the audioFilters
method. Note that I have tried leaving only the fade-out filter, but the problem persists. Any pointers would be greatly appreciated.
var promises = [];
const duration = track.duration;
const interval = 30;
const fade = 5;
const bitrate = 128;
for (var i = 0; i <= Math.floor(duration) - interval; ++i) {
const start = i; // Start second.
const end = start + interval;
const mp3 = `${new ObjectId().toHexString()}.mp3`;
var command = new Promise((resolve, reject) => {
ffmpeg(path).setStartTime(start)
.audioBitrate(bitrate)
.audioFilters([
{
filter: 'afade',
options: `t=in:ss=${start}:d=${fade}`
},
{
filter: 'afade',
options: `t=out:st=${end - fade}:d=${fade}`
}
])
.duration(interval)
.on('error', (err) => {
reject("An error occurred while clipping.");
})
.on('end', () => {
resolve(`Finished processing ${output}.`);
})
.save(mp3);
});
promises.push(command);
}
And here is my ffmpeg
version information:
ffmpeg version 2.8.6 Copyright (c) 2000-2016 the FFmpeg developers
built with Apple LLVM version 7.0.2 (clang-700.1.81)
configuration: --prefix=/usr/local/Cellar/ffmpeg/2.8.6 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-opencl --enable-libx264 --enable-libmp3lame --enable-libvo-aacenc --enable-libxvid --enable-vda
libavutil 54. 31.100 / 54. 31.100
libavcodec 56. 60.100 / 56. 60.100
libavformat 56. 40.101 / 56. 40.101
libavdevice 56. 4.100 / 56. 4.100
libavfilter 5. 40.101 / 5. 40.101
libavresample 2. 1. 0 / 2. 1. 0
libswscale 3. 1.101 / 3. 1.101
libswresample 1. 2.101 / 1. 2.101
libpostproc 53. 3.100 / 53. 3.100
After a while of tinkering around, clipping different tracks with the code above, I figured out the issue.
The problem was with how I kept track of the start
and end
times for the fades. It turns out that the times for the fade were being measured with respect to the 30-second clips, not the original track itself. I, on the other hand, kept increasing the start
and end
times using the loop below, thinking the fade was applied at the time step in relation to the original track.
for (var i = 0; i <= Math.floor(duration) - interval; ++i) {
const start = i; // Start second.
const end = start + interval;
...
So by updating the start
and end
values with the loop, I was going beyond the end of the 30-second clip when I applied the audio filters.
.audioFilters([
{
filter: 'afade',
options: `t=in:ss=${start}:d=${fade}`
},
{
filter: 'afade',
options: `t=out:st=${end - fade}:d=${fade}`
}
])
That is why I could only hear the fade out for the first clips. The fade-in was not working either, but it was harder to notice, because the first few clips would have a fade in that sounded natural (even though it was also moving up the track and eventually not being applied).
Turns out it was super simple. I just needed to replace the values in the options
key so that the start
for the fade in was always 0
and the start
for the fade out was always the interval length (30) minus the fade duration (3).
.audioFilters([
{
filter: 'afade',
options: `t=in:ss=0:d=${fade}`
},
{
filter: 'afade',
options: `t=out:st=${interval - fade}:d=${fade}`
}
])
It was a simple issue in the end. Nevertheless, it's good to point out that if you're clipping and applying a fade at the same time, you need to make sure your times are with regards to the clipped track, not the original one.