105

Searching Google on how to join/merge many mp3 files, it suggests that I should just cat them together.

That might "work", but clearly it is not the correct way to do it, as each header and set of IDv3 tags will also be concatenated.

Does a Linux program exist that can be scripted to join/merge many mp3?

Can mplayer/mencoder/ffmpeg do it?

Gareth
  • 18,809
Sandra
  • 2,643

10 Answers10

131

This will concatenate two mp3 files, and the resulting metadata will be that of the first file:

ffmpeg -i "concat:file1.mp3|file2.mp3" -acodec copy output.mp3

This is because, for ffmpeg, the whole "concat:" part is a single "input file", and its metadata will be of the first concatenated file. If you want to use metadata from the second file instead, you have to add it as a dummy input file and map its metadata to that of the output:

ffmpeg -i "concat:file1.mp3|file2.mp3" -i file2.mp3 -acodec copy test.mp3 -map_metadata 0:1

If you want to construct your metadata from the two metadatas, you'll have to do it by hand. You can dump a file's metadata with

ffmpeg -i file1.mp3 -f ffmetadata file1.metadata

After dumping both metadatas and constructing new metadata, you can add it to the output file with -metadata, and you can disable metadata copying by setting a -map_metadata mapping from a negative input file number. This sets a name value and no other metadata:

ffmpeg -i "concat:file1.mp3|file2.mp3" -acodec copy -metadata "title=Some Song" test.mp3 -map_metadata 0:-1
  • FYI this requires a certain version of ffmpeg. If it says file not found concat... try upgrading and running it again – Sameer Alibhai Sep 09 '12 at 23:14
  • Works fine in ffmpeg 0.10.4 in Gentoo. What are you using? Are you sure you haven't just mistyped the command? – Ambroz Bizjak Sep 10 '12 at 00:05
  • Ambroz I was saying that I had an old version and had to upgrade, then it worked. – Sameer Alibhai Sep 14 '12 at 20:58
  • Typing this in a DOS box in XP doesn't work: "'file2.mp3' is not recognized as an internal or external command, operable program or batch file". Is the command Linux-specific? – OverTheRainbow Oct 18 '12 at 16:54
  • @OverTheRainbow the argument is supposed to be "concat:file1.mp3|file2.mp3", without the backslash. The backslash is an escape character to prevent the unix shell from treating | as a pipe. I've changed it to use double quotes instead. – Ambroz Bizjak Oct 19 '12 at 21:19
  • It's worth noting the mp3s have to have the same formats - I had one mp3 at 16000hz and another at 44000hz - they merged without error, didnt play - it wasn't until I used mp3val to see the issues and I had to re-encode my source files - then they merged fine – Rob Oct 28 '13 at 13:37
  • https://trac.ffmpeg.org/wiki/Concatenate – DmitrySandalov Apr 08 '15 at 23:52
  • 7
    Just wanted to clarify a few things for others: -acodec means that audio codec will be used and copy mean that there will only be muxing and demuxing, but not encoding/transcoding (i.e. very fast and no quality loss) – The Onin Feb 04 '18 at 05:28
  • 3
    When several files have to be concatenated, as in the original question, the following snippet might come in handy to construct the string "file1.mp3|file2.mp3|file3.mp3"etc: s=""; for i in file*.mp3; do s="$s|$i"; done; echo ${s:1} – Immanuel Weihnachten Mar 03 '18 at 23:53
  • 1
    It would be great if there was a GUI program where I can drag and drop multiple files (e.g. sorted chronologically for recordings recorded sequentially, and perhaps some files edited) and it will then output one file. – James Ray Nov 15 '18 at 04:13
  • 2
    This is a good answer, however in almost every case, the resulting MP3 file has a short (sub-second) gap between where the files were joined. So if you're trying to merge MP3 tracks to create a seamless playback album / set / whatever, this doesn't work quite right. – The Lizard Dec 11 '18 at 17:59
  • I corroborate @Lizard's remark and get nasty artifacts at the join seam when played with mplayer. – Tom Russell Sep 14 '20 at 01:21
  • @JamesRay I'm making a web app front end for ffmpeg - add your email at lazypodcaster.com if you're interested in getting on the beta – niico Jan 24 '21 at 22:14
  • Does not work for me. I get the error: "Invalid audio stream. Exactly one MP3 audio stream is required." – Pedro Araujo Jorge Oct 27 '23 at 15:17
38

This will concatenate a folder full of MP3 into a single MP3 file:

1) Save a list of the MP3 files to concatenate, e.g.,

$ cat mylist.txt
file '/tmp/01.mp3'
file '/tmp/02.mp3'
file '/tmp/03.mp3'
file '/tmp/04.mp3'
file '/tmp/05.mp3'
file '/tmp/06.mp3'
file '/tmp/07.mp3'

2) Run the following command (-safe 0 is not required if mylist.txt uses relative paths instead):

$ ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp3
  • 3
    This works great if you have a long list of short mp3 files! Thank you. – Ray Hulha Apr 20 '20 at 04:14
  • in one command this can be used as: perl -E'say qq(file '\''$_'\'') for <*>' * > file.list && ffmpeg -f concat -safe 0 -i file.list -c copy myBigFile.mp3 (execute this in the folder with the single files. this will cause an error about "file.list" file but thats no problem, it still works – MacMartin Jan 18 '21 at 11:03
  • 1
    Just another one liner I used to join all mp3's starting with test: ls -1 test*.mp3 | awk '$0="file \""$0"\""' | sed "s/\"/'/g" | ffmpeg -f concat -protocol_whitelist file,pipe -safe 0 -i - -c copy concat_test.mp3 The awk and sed is used to get the files in each line surrounded with single quotes – John Doe Jul 26 '21 at 13:08
15

Mp3Wrap - Command-line utility that wraps multiple MP3 files into a single, playable MP3, without losing filenames or ID3 information, and without reencoding. Also supports archiving non-audio data such as playlists, info files, and cover images inside the MP3. These files can be unpacked later (using mp3splt, e.g.); ordinary MP3 decoders can play the entire audio stream as one long track.

lig
  • 286
  • 1
    Thanks for this recommendation.. much lighter/simpler solution then ffmpeg, since I was combining 100+ mp3's and wanted the option of splitting back to originals. – joshbaptiste May 17 '14 at 02:29
  • This no longer works property - try concatenating a few files and inspect the output file in mp3val - it will report sync errors. This means that it will not play after the first chunk in Chrome 64+ (see https://bugs.chromium.org/p/chromium/issues/detail?id=794782 and https://bugs.chromium.org/p/chromium/issues/detail?id=806601#c10) – The Onin Feb 04 '18 at 06:24
  • Doesn't seem to work on Windows. No metadata preserved. – Gruber Jun 04 '19 at 06:31
13

zsh:

audio-join() ffmpeg -i "concat:${(j:|:)@[2,-1]}" -acodec copy $1

audio-join output.mp3 *.mp3
HappyFace
  • 1,221
  • 1
    We expect answers to include explanations.  (Not all of the answers on this page are good examples.) – Scott - Слава Україні Aug 10 '19 at 21:55
  • The first line appears to create bash function audio-join consisting of the remaining text on the line. The 2nd line invokes audio-join to join all MP3 files in the current working directory into one having the filename 'output.mp3'. BTW, ffmpeg generates output with nasty artifacts on my system. – Tom Russell Sep 14 '20 at 01:14
  • 1
    For some audiobooks I had to join mp3 files in 100+ subdirectories so every audiobook only consisted of one audio file. Using the above answer, and a for loop, zsh combined them all using audio-join() ffmpeg -i "concat:${(j:|:)@[2,-1]}" -acodec copy $1 and then for d in ./*/ ; do (cd "$d" && audio-join output.mp3 *.mp3); done

    Very nice!

    – MisterMike Mar 20 '21 at 11:55
6

Based on Miles Wolbe's answer, here is a one-liner that worked for me:

ls *.mp3 | \
    sed -e "s/\(.*\)/file '\1'/" | \
    ffmpeg -protocol_whitelist 'file,pipe' -f concat -i - -c copy output.mp3
  • 2
    add -safe 0 if filenames contain Spaces. Error: Unsafe file name '100 Vortrag.mp3' pipe:: Operation not permitted – phiphi Apr 23 '20 at 20:21
4

One liner based on Miles Wolbe's answer to join all .mp3 sorted by name in current directory:

ffmpeg \
-f concat \
-safe 0 \
-i <(find "$(pwd)" -iname '*.mp3' -printf "file '%p'\n" | sort) \
-c copy \
merged.mp3

The find command finds any *.mp3 and prints it with file prepended to the path. $(pwd) makes find print the absolute path. Piping to sort sorts the files by name. <() is process substitution which allows output of find to appear as contents of a file.

aksh1618
  • 442
  • Note that this requires find version later than whatever macOS has (for a reason surprisingly difficult to glean, but which seems somehow related to -printf). – ijoseph Jun 08 '23 at 20:19
3

If you want to concat all mp3 files of the current directory:

function join_by { local IFS="$1"; shift; echo "$*"; }
files=(*.mp3)
ffmpeg -i "concat:`join_by "|" $files`" -acodec copy output.mp3
  • I used ffmpeg -i "concat:`ls -1 *.mp3 | tr "\n" "|" | sed 's/.$//'`" -acodec copy output.mp3 is an alternative and worked well for me in zsh on macOS. – wteuber Jan 14 '24 at 09:33
1

If you need scripting, you're probably better off using the ffmpeg solution. However, if you ever just need an application to do stuff like that, you could try out Audacity. It's open source and cross platform. I haven't used it to join mp3s, but I've used it to crop sections out of an mp3 and fade them out at the end. I'm be willing to bet you can join mp3s and cross-fade them into each other with it as well.

Brandon
  • 664
  • 4
    Audacity, as far as I know, works on the raw sound data, and concatenating mp3's with it will result in a degradation due to transcoding. – Ambroz Bizjak Jul 23 '11 at 22:28
0

couple windows scripts I created to do this (using ffmpeg)

direnhanced.bat

@echo off
setlocal enabledelayedexpansion
for /f "tokens=*" %%f in ('dir /b *.mp3') do (
  echo file '%%f'
  )
endlocal

mergemp3s.bat

call direnhanced.bat > fileList.txt
set /p FILENAME=Output file name then hit ENTER to continue...
ffmpeg -f concat -safe 0 -i fileList.txt -c copy "%FILENAME%.mp3"
0

To create a list of your MP3 files in a format that meets the requirement, such as:

file '01.mp3'
file '02.mp3'
file '03.mp3'

You can do so from the windows command prompt: (Given the current directory is in the mp3 files folder)

c:>(for %i in (*.mp3) do @echo file '%i') > mylist.txt

Harry
  • 154