I tried three different methods in order to concatenate songs
Audacity: Works, but it adds a "click" sound between the first and second song
cat command: I tried cat *.wma > result.wma and cat second.wma >> first.wma. Both have the same problem, the resulting file is just the first one.
ffmpeg: ffmpeg -i "concat:uno.wma|dos.wma" -acodec copy result.wma, same problem as cat command, the file result.wma is a copy of uno.wma
Any help?
You should use ">>" operator instead of ">", because ">" overrides the result of first operation. But, I'm not sure about the correctness of this operation on audio files.
Example:
$ echo "1" > output
$ echo "2" > output
$ cat output
2
$ echo "1" >> output2
$ echo "2" >> output2
$ cat output2
1
2
If you write: cat *.wma > result.wma, actually you do:
cat 1.wma > result.wma
cat 2.wma > result.wma
So, you'll get 2.wma in result.wma, without 1.wma in it.
The ffmpeg concat protocol you're using (the "concat:" pattern) does not work for concatenating some media files like WMA and WAV.
https://trac.ffmpeg.org/wiki/Concatenate
Likely because they have some headers at the beginning of their files. At least, WAV files have a 46 byte file header if made with ffmpeg. These headers are likely also tripping up the playback of files concatenated with the cat command.
So try this for generic concatenation instead:
ffmpeg -i "first.wma" -i "second.wma" -filter_complex '[0:0][1:0]concat=n=2:v=0:a=1[out]' -map '[out]' result.wma
See related question and answer (for WAV files):
https://superuser.com/q/587511/192525
Try this:
cat song1.wma song2.wma > bothsongs.wma
Related
this is a beginner's question but i can't figure out the answer after looking into it for several days:
I want ffmpeg to extract the audio portion of a video and save it in an .ogg container. If i run the following command in terminal it works as expected:
ffmpeg -i example.webm -vn -acodec copy example.ogg
For convenience, i want to do this in a script. However, if i pass a variable to ffmpeg it apparently just considers the first word and produces the error "No such file or directory".
I noticed that my terminal escapes spaces by a \ so i included this in my script. This doesn't solve the problem though.
Can someone please explain to me, why ffmpeg doesn't consider the whole variable that is passed to it in a script while working correctly when getting passed the same content in the terminal?
This is my script that passes the filename with spaces escaped by \ to ffmpeg:
#!/bin/bash
titelschr=$(echo $# | sed "s/ /\\\ /g")
titelohne=$(echo $titelschr | cut -d. -f 1)
titelogg=$(echo -e ${titelohne}.ogg)
ffmpeg -i $titelschr -vn -acodec copy $titelogg
Thank you very much in advance!
You need to quote variable expansions, try this :
#!/usr/bin/env bash
titelschr=$1
titelogg="${titelschr%.*}.ogg"
ffmpeg -i "$titelschr" -vn -acodec copy "$titelogg"
call with :
bash test.sh "Some video file.mp4"
This way, you don't need to escape spaces.
I am trying to pad a series of wav files with silence at the beginning and end using ffmpeg.
the line of code for this i gleaned from elsewhere on this amazing site:
ffmpeg -f concat -i input.txt -codec copy output.wav
where input.txt is simply a list of 3 filenames:
silence.wav
0.wav
silence.wav
indicating what is to be concatenated
I can do this for an individual file and then update line 2 manually, but there are 1000+ files. They are named 0.wav 1.wav 2.wav.
I figure this is trivial in a loop:
COUNTER=1
for FILE in *.wav
do
ffmpeg -f concat -i input.txt -codec copy $FILE
echo $FILE
echo $COUNTER
sed -i "2s/.*/file \'${COUNTER}.wav\'/" input.txt
((COUNTER=COUNTER+1))
done
However the loop doesn't iterate sequentially 0.wav 1.wav 2.wav - rather more erratically (0.wav, 10.wav, 11.wav) - so my counter is out of sync. and my saved filenames are not aligned with their original filenames.
Is there a work around that strips the name from the file itself rather than relying on a counter?
If the counter is already contained in the file name, why not just reuse the file name? That would avoid the issue with string sorting (in which "11" < "9") versus numerical sorting (in which 11 > 9) and it would also work fine if the file names (numbers) were sparse. Also, the output file should not be the same file as one of the inputs. (It might be the case that ffmpeg can handle it gracefully using temporary files, bu I wouldn’t bet on that.)
for file in *.wav; do
sed -i "2s/.*/file \'${file}\'/" input.txt
ffmpeg -f concat -i input.txt -codec copy "output-${file}"
mv "output-${file}" "$file" # replaces original file!
done
The main problem with your setup is that you read your files in alphabetical order. So after 1.wav comes 10.wav.
Your code then becomes:
ffmpeg -f concat -i input.txt -codec copy 10.wav
sed -i "2s/.*/file \'2.wav\'/" input.txt
So FFmpeg works with 10.wav, while you replace something about 2.wav in input.txt. Maybe you could do something like this to loop over your files:
COUNTER=1
while [ $COUNTER -le 1000 ]
do
echo "Filename: ${COUNTER}.wav"
((COUNTER=COUNTER+1))
done
I don't know if FFmpeg starts a new process, but the loop might start FFmpeg, but not wait till it is finished. This way you could end up with 1000 FFmpeg processes running at the same time.
You should try replacing
for FILE in *.wav
with
for FILE in $(ls *.wav | sort -t '.' -k 1 -n)
Let me know if it worked.
I've looked everywhere to try to combine a bunch of FLAC files with differing sample rates into 1 file. What I've tried so far is:
ffmpeg concat with a wildcard:
ffmpeg -f concat -i <( for f in *.flac; do echo "file '$(pwd)/$f'"; done ) -safe 0 output.flac
I get for every filename, (even if I change pwd to './' for relative):
ffmpeg unsafe filename
Regardless of the file's filename.
I've tried sox:
sox *.flac output.flac
Which leads to:
sox FAIL sox: Input files must have the same sample-rate
I've even tried combining the two:
#!/usr/bin/env bash
set -eu
for i in *.flac *.ogg *.mp3
do
ffmpeg -i "$i" "$i.wav"
done
sox *.wav combined.wav
Same error as above.
Anyone have any tips? I'm sure that in some Windows program you can drag in 5 differing sound files and combine them with ease. Is there not a simple way to do this on linux cmdline?
safe 0 is a private option for the concat demuxer, so it has to appear before the input i.e. -f concat -safe 0 -i ...
I'm trying to get the size of an input video using ffmpeg, below is the code that I use, what I'm trying to do is to first store the result into a txt file and then do some parsing to get the size of the video:
$ ffmpeg -i TheNorth.mp4
The terminal says "At least one output file must be specified"
Then I tried this:
$ ffmpeg -i TheNorth.mp4 result.txt
The terminal says "Unable to find a suitable output format for 'size.txt'"
So how could I get the result and save it to the specified file?
You can store the output ffmpeg generates with piping:
ffmpeg -i TheNorth.mp4 2> result.txt
You need to use 2> here, as ffmpeg writes to StdErr (and not StdOut).
ffprobe
If you just want to get the size of the video then you can get that, and other info, directly with ffprobe. This will avoid redirection, temporary output files, and the additional parsing.
$ ffprobe -v error -select_streams v:0 -show_entries stream=height,width -of csv=p=0:s=x input.mkv
1280x720
See FFmpeg Wiki: FFprobe Tips for more examples.
tee
For users who want to encode and capture the resulting console output, I recommend using tee. The problem with pure redirection is that important messages such as error messages, failures, and prompts can be missed.
You can avoid this by including tee to show the output in the console and to save it to a file:
ffmpeg -i input … output |& tee console.txt
ffmpeg outputs to stderr instead of the more typical stdout, so the & is added to the | pipe to deal with that. This is only for Bash 4+. If you're using something else then change |& to 2>&1 which redirects stderr to stdout before it is sent to the pipe.
Somewhat better idea is to use ffprobe
ffprobe -show_format -print_format json TheNorth.mp4
that will output JSON formated info about video. Guess it is easier to parse than raw output. To redirect output to file use just ordinary pipe > result.txt similar to accepted answer but without two.
i want to analyze multiple mp3 files and get the bpm of the files. Therefore i'm using soundstretch. At first i'm converting the mp3 files using sox
sox -t mp3 -r 44100 -c 2 file.mp3 -t wav file3.wav
after this i want to analyze the track with soundstretch
soundstretch file.wav -bpm
this also gives me the result in the console. But i'm not able to redirect the printed response to a file. i already tried stuff like
soundstretch file.wav -bpm > file.mp3.bpm
soundstretch file.wav -bpm 2>&1 > file.mp3.bpm
the only result is, that the messages are displayed in the console and there is a empty file
Switch it around if you want one file
soundstretch file.wav -bpm > file.mp3.bpm 2>&1
or use two file two files:
soundstretch file.wav -bpm 2> file.mp3.err > file.mp3.bpm
I think you should use the soundstretch as
soundstretch inputFile outputFile options
ex. : soundstretch Sample.waw out.txt -bpm