Use FFmpeg (or sox) to reduce stereo - audio

The ffmpeg wiki has this method to mix stereo to stereo:
ffmpeg -i input.mp3 -af "pan=stereo|c0<c0+c1|c1<c0+c1" output.ogg
How could I do this but reduce the volume of the right part mixed into the left and the left part mixed into the right (diagonal arrows) by 60%, while leaving the volume of both channels as is (downward arrows)?
(If this could be done with sox, it be great too.)

ffmpeg -i input -af "pan=stereo|c0<c0+0.6*c1|c1<0.6*c0+c1" output
or
ffmpeg -i input -af "pan=stereo|FL<FL+0.6*FR|FR<0.6*FL+FR" output
Replace < with = if you don't want pan to normalize the combined gain to 1 for clipping avoidance.
See pan filter documentation.

Related

How to add outro background music to another audio file with FFMpeg?

I have two files: story.wav (180 seconds) and background-music.wav (90 seconds). I need a FFMpeg command that merges the two files and fades in background-music.wav (with esin) 30 seconds before the end of story.wav.
I have this in separate commands:
ffmpeg -i background-music.wav -filter_complex afade=t=in:curve=esin:ss=0:d=30 fadein.wav
ffmpeg -i fadein.wav -af "adelay=150000|150000" delayed.wav
ffmpeg -i delayed.wav -i story.wav -filter_complex amix=inputs=2:duration=longest final.wav
This is ugly - and it has the problem, that the volume of the first part is only 50% (the volume should be kept).
There must be an elegant way to achieve this in one command - but how?
Bonus question: how can I convert the result to mp3 (with parameters like bit rate set) in the same command?
Thanks for any help!
Sebastian
Use
ffmpeg -i background-music.wav -i story.wav
-filter_complex
"[0]afade=t=in:curve=esin:ss=0:d=30,adelay=150000|150000[bg];
[1]volume=2[fg];
[bg][fg]amix=inputs=2:duration=longest"
-b:a 128k final.mp3

Use FFMPEG to export audios with gaps filled

I have a MKV file with gaps in the audio. That is, there are gaps in the MKV audio track timestamps. According to "ffmpeg", the AC3 audio length is 802 seconds, but when exporting the audio to WAV, the resulting file length is 801'53 seconds. That is, the "exported" audio is shorter.
Triaging the issue with
ffmpeg -i INPUT.mkv -af ashowinfo -map 0:2 -y -frames:a XXXX -f alaw /dev/null
I can confirm that the length difference is consistent with gaps in the timestamps of the original audio frames. There are a handful of missing audio frames. I guess those are replaced by silence in the player.
The command I use to export the audio is:
ffmpeg -i INPUT.mkv -map 0:1 -ac 2 OUTPUT.wav
My question is: How can I instruct FFMPEG to preserve the gaps in the original audio, zero (silence) filled?. The WAV file duration should be the same than the original AC3 audio.
Given my current workflow, I would rather prefer to not keep the original timestamps in the output file but generate a WAV with (tiny) silences instead. I could consider keeping timestamps if there is no other choice, but this could be quite a pain in my workflow.
Advice? Help?
Thanks a lot in advance!
Use
ffmpeg -i INPUT.mkv -map 0:1 -af aresample=async=1 -ac 2 OUTPUT.wav
The aresample filter will insert silent samples within the gaps.

FFMPEG Amix filter volume is not constant [duplicate]

I noticed that ffmpeg amix filter doesn't output good result in specific situation. It works fine if input files have equal duration. In that case volume is dropped in constant value and could be fixed with ",volume=2".
In my case I'm using files with different duration. Resulted volume is not good. First mixed stream resulted in lowest volume, and last one is highest. You can see on image that volume is increased linearly withing a time.
My command:
ffmpeg -i temp_0.mp4 -i user_2123_10.mp4 -i user_2123_3.mp4 -i user_2123_4.mp4
-i user_2123_7.mp4 -i user_2123_5.mp4 -i user_2123_1.mp4 -i user_2123_8.mp4
-i user_2123_0.mp4 -i user_2123_6.mp4 -i user_2123_9.mp4 -i user_2123_2.mp4
-i user_2123_11.mp4 -filter_complex "[1:a]adelay=34741.0[aud1];
[2:a]adelay=18241.0[aud2];[3:a]adelay=20602.0[aud3];
[4:a]adelay=27852.0[aud4];[5:a]adelay=22941.0[aud5];
[6:a]adelay=13142.0[aud6];[7:a]adelay=29810.0[aud7];
[8:a]adelay=12.0[aud8];[9:a]adelay=25692.0[aud9];
[10:a]adelay=32143.002[aud10];[11:a]adelay=16101.0[aud11];
[12:a]adelay=40848.0[aud12];
[0:a][aud1][aud2][aud3][aud4][aud5][aud6][aud7]
[aud8][aud9][aud10][aud11]
[aud12]amix=inputs=13:duration=first:dropout_transition=0"
-vcodec copy -y temp_1.mp4
That could be fixed by applying silence at the beginning and end of each clip, then they will have same duration and volume will be at the same level.
Please suggest how I can use amix to mix many inputs and ensure constant volume level.
amix scales each input's volume by 1/n where n = no. of active inputs. This is evaluated for each audio frame. So when an input drops out, the volume of the remaining inputs is scaled by a smaller amount, hence their volumes increase.
Changing the dropout_transition for all earlier inputs, as suggested in other answers, is one approach, but I think it will result in coarse volume modulations. Better method is to normalize the audio after the amix.
At present, you have two options, the loudnorm or the dynaudnorm filter. The latter is much faster
Syntax is to add it after the amix, so
[aud11][aud12]amix=inputs=13:duration=first:dropout_transition=0,dynaudnorm"
Read the documentation, if you wish to tweak parameters for maximum volume or RMS mode normalization..etc
The latest version of FFMPEG includes the normalize parameter for the amix filter, which you can use to turn off the constantly changing normalization. Here's the documentation for it.
Your amix filter string can be changed to:
[aud12]amix=inputs=13:normalize=0
The solution I've found is to specify the volume for each track in a "descendant" order and use no normalization filter afterwards.
I use this example, where I concat the same audio file in different positions:
ffmpeg -vn -i test.mp3 -i test.mp3 -i test.mp3 -filter_complex "[0]adelay=0|0,volume=3[a];[1]adelay=2000|2000,volume=2[b];[2]adelay=4000|4000,volume=1[c];[a][b][c]amix=inputs=3:dropout_transition=0" -q:a 1 -acodec libmp3lame -y amix-volume.mp3
More details, see this image. The first track is the normal mixing, the second is the one with volumes specified; the third is the original track. As we can see the 2nd track looks to have a normal volume.
ffmpeg -vn -i test.mp3 -i test.mp3 -i test.mp3 -filter_complex "[0]adelay=0|0[a];[1]adelay=2000|2000[b];[2]adelay=4000|4000[c];[a][b][c]amix=inputs=3:dropout_transition=0" -q:a 1 -acodec libmp3lame -y amix-no-volume.mp3
ffmpeg -vn -i test.mp3 -i test.mp3 -i test.mp3 -filter_complex "[0]adelay=0|0,volume=3[a];[1]adelay=2000|2000,volume=2[b];[2]adelay=4000|4000,volume=1[c];[a][b][c]amix=inputs=3:dropout_transition=0" -q:a 1 -acodec libmp3lame -y amix-volume.mp3
I can't really understand why amix changes the volume; anyway; I was digging around since a while for a good solution.
The solution seems to be a combination of "pre-amp", or multiplication, as Maxim puts it, AND you have to set dropout_transition >= max delay + max input length (or a very high number):
amix=inputs=13:dropout_transition=1000,volume=13
Notes:
amix has to resample float anyway, so there is no downside with adding the volume filter (which by default resamples to float, too).
And since we're using floats, there's no clipping and (almost) no loss of precision.
H't to #Mulvya for the analysis but their solution is frustratingly non-mathematical
I was originally trying to do this with sox, which was too slow. Sox's remix filter has the -m switch which disables the 1/n adjustment.
While faster, ffmpeg seems to be using way more memory for the same task. YMMV - I didn't test this thoroughly, because I finally settled on a small python script which uses pydub's overlay function, and only keeps the final output file and one segment in memory (whereas ffmpeg and sox seem to keep all of the segments in memory).
I got the same problem but found a solution!
First the Problem: i had to mix a background music file with 3 different TTS voice pieces that start with different delay. At the end the background sound was extremely loud.
I tried the suggested answer but it did not work for me, the end volume was still much higher. So my thoughts were: "All inputs must have the same length so everytime the same amount of audio is active in the mix"
apad on all TTS inputs with whole_len set and -shortest option in combination did the work for me.
Example call:
ffmpeg -y
-nostats
-hide_banner
-v quiet
-hwaccel auto
-f image2pipe
-i pipe:0
-i bgAudio.aac
-i TTS1.mp3
-i TTS2.mp3
-i TTS3.mp3
-filter_complex [1:a]loudnorm=I=-16:TP=-1.5:LRA=11:linear=false[a0];[2:a]loudnorm=I=-16:TP=-1.5:LRA=11:linear=false:dual_mono=true,adelay=7680|7680,apad=whole_len=2346240[a1];[3:a]loudnorm=I=-16:TP=-1.5:LRA=11:linear=false:dual_mono=true,adelay=14640|14640,apad=whole_len=2346240[a2];[4:a]loudnorm=I=-16:TP=-1.5:LRA=11:linear=false:dual_mono=true,adelay=3240|3240,apad=whole_len=2346240[a3];[a0][a1][a2][a3]amix=inputs=4:dropout_transition=0,asplit=6[audio0][audio1][audio2][audio3][audio4][audio5];[0:v]format=yuv420p,split=6[1080p][720p][480p][360p][240p][144p]
-map [audio0] -map [1080p] -s 1920x1080 -shortest out1080p.mp4
-map [audio1] -map [720p] -s 1280x720 -shortest out720p.mp4
-map [audio2] -map [480p] -s 858x480 -shortest out480p.mp4
-map [audio3] -map [360p] -s 640x360 -shortest out360p.mp4
-map [audio4] -map [240p] -s 426x240 -shortest out240p.mp4
-map [audio5] -map [144p] -s 256x144 -shortest out144p.mp4
Hope someone helps this!
Try to use multiplication:
"amix=inputs="+ chunks.length + ":duration=first:dropout_transition=3,volume=" + chunks.length
Sorry, for not sending ffmpeg output.
After all we ended up by writing small util in C++ for mixing audio. But first we converted mp4 to raw(pcm) format. That worked just fine for us, even requires addition HDD space for raw intermediate files.
Code looks like this:
short addSounds(short a, short b) {
double da = a;
da /= 65536.0;
da += 0.5;
double db = b;
db /= 65536.0;
db += 0.5;
double z = 0;
if (da < 0.5 && db < 0.5) {
z = 2 * da*db;
}
else {
z = 2 * ( da + db ) - 2 * da* db - 1;
}
z -= 0.5;
z *= 65536.0;
return (short)z;
}
I will show you my code.
"amix="+inputs.size()+",volume="+(inputs.size()+1)/2+"[mixout]\""
I don't use the code dropout_transition=0 because it will cause the problem you meet.
but I also find the problem that volume will be lower as the size of inputs increases.
so I make the volume louder.
try to change dropout transition to the duration of the first input:
duration=first:dropout_transition=_duration_of_the_first_input_in_seconds_
here is my ffmpeg command:
ffmpeg -y -i long.wav -i short.wav -filter_complex "[1:a]adelay=6000|6000[a1];[1:a]adelay=10000|10000[a2];[1:a]adelay=14000|14000[a3];[1:a]adelay=18000|18000[a4];[1:a]adelay=21000|21000[a5];[1:a]adelay=25500|25500[a6];[0:a][a1][a2][a3][a4][a5][a6]amix=inputs=7:duration=first:dropout_transition=32[aout]" -map "[aout]" -ac 2 -b:a 192k -ar 44100 output.mp3
see two dropout transitions as screenshot

ffmpeg merge silent video with another video+audio

I want to create, in a single command, a video from 3 sources:
a silent background video;
a smaller video to be overlayed (same length of 1), KEEPING its AUDIO;
a PNG logo to be overlayed
I can create the video but cannot get the audio track. I don't understand if -vf is supposed to work in this case. This is what I've tried to do :
ffmpeg.exe -y -i MASTER_SILENT_VIDEO.mp4 -vf "movie=SMALLER_VIDEO_WITH_AUDIO.flv, scale=320:-1[inner];movie=MY_LOGO.png[inner2]; [in][inner] overlay=800:480,amerge [step1]; [step1][inner2] overlay=30:30 [out]" completed.mp4
The "amerge" filter should do the audio merging job, but of course it doesn't work. I've found similar questions involving -map or filtergraph but they refer to mixing a video source and an audio source; I tried several filtergraph examples without success. Any idea?
overlay one video over other using audio from one input
Use -filter_complex, eliminate the movie source filters, and explicitly define output streams with -map:
ffmpeg -y -i main.mp4 -i overlay_with_audio.flv -i logo.png -filter_complex
"[1:v]scale=320:-1[scaled];
[0:v][scaled]overlay=800:480[bg];
[bg][2:v]overlay=30:30,format=yuv420p[video]"
-map "[video]" -map 1:a -movflags +faststart
output.mp4
You may have to provide additional options to the overlay filters depending on the length of the inputs and how you want overlay to react, but because you did not provide the complete console output from your command I had to make a generic, less efficient, and possibly incorrect example.
overlay one video over other merging audio from both inputs
ffmpeg -y -i main.mp4 -i overlay_with_audio.flv -i logo.png -filter_complex
"[1:v]scale=320:-1[scaled];
[0:v][scaled]overlay=800:480[bg];
[bg][2:v]overlay=30:30,format=yuv420p[video];
[0:a][1:a]amerge=inputs=2[audio]"
-map "[video]" -map "[audio]" -ac 2 -movflags +faststart
output.mp4
I'm assuming both inputs are stereo and that you want a stereo output. Also see FFmpeg Wiki: Audio channel Manipulation - 2 × stereo → stereo.

Increase volume of one channel in 8channel .wav file ffmpeg

I have 8-channel .wav file with sine wave in there. I would like to increase the volume of only 4th channel in this file. I don't know how to do it though.
ffmpeg -i input.wav -af "volume=1.5" output.wav
This will increase volume for all 8 channels. How can i apply it only to 1 channel (4th one) but still maintain the 8-channel .wav file?
Something like this should work: ffmpeg -i input.wav -af "pan=8c|c0=c0|c1=c1|c2=c2|c3=1.5*c3|c4=c4|c5=c5|c6=c6|c7=c7" output.wav

Resources