Ubuntu: How to normalize sound in mp3 files



Question:

I am looking for a way to normalize the sound in MANY MP3 files I have. Some have low sound, while others are louder so I have to turn the volume up or down depending on the song. What ways are there to do this for all files. I specially would like to do it via the terminal but GUI ways are also accepted.


Solution:1

Audacity Install audacity

With Audacity we can easily batch process files to apply conversions or effects to many files in a list. To do so we first have to define a "Chain" containing the effects we want to apply.

This is done with "File --> Edit Chains...". In the now opening window press the Add button on the bottom left to insert a new chain (give it a sensible name):

enter image description here

Then choose the effect and it's parameters to insert to the chain (here shown for default values and the Normalize effect).

Important: we always need to also add the effect "Export MP3" (or any other export format) for saving the resulting conversion to disk.

When done leave this window with OK to open "File --> Apply Chain...". Select the Chain we have just created and load all files you need with "Apply to files...". Several files can be selected from the file chooser that opens.

enter image description here

Processed files will be saved in a new subdirectory "cleaned" in the original's path.


Sox Install sox

From version > 14.3 we can use the sox filter --norm for normalizing audio on the command line or for batch processing:

sox --norm infile outfile  

MP3-support is added to Sox with libsox-fmt-all Install libsox-fmt-all.


Solution:2

Take a look @ mp3gain which for me is even better than normalize-audio

mp3gain -r *.mp3  

another useful version could be the -c which prevent to ask if you want to do the changes for many files:

mp3gain -c -r *.mp3  

as said in the man page:

mp3gain does not just do peak normalization, as many normalizers do. Instead, it does some statistical analysis to determine how loud the file actually sounds to the human ear. Also, the changes mp3gain makes are completely lossless. There is no quality lost in the change because the program adjusts the mp3 file directly, without decoding and re-encoding.

Note: That package was removed on purpose on ubuntu 15.04. Debian proposes python-rgain as replacement. After installing it, run replaygain.

Alternatively, get the .deb file for 14.04 (the latest) from here. Install as usual. After that, you need to run sudo apt-get -f install to correct some dependencies issues.


Solution:3

I would use this project Normalize, it's a command-line tool for normalizing audio files. Looks to be exactly what you need. Can do batch processing and doesn't require resampling to intermediate formats.

It's in the package repos as normalize-audio, sudo apt-get install normalize-audio. This is a build maintained upstream by Debian so it should be in anything LTS or newer and is built with mp3 compatibility (tested). There is a good manpage man normalize-audio to explore the options but the commands defaults appear to work well. For batch processing (normalize volume across multiple files), normalize-audio -b *.mp3 or specify individual filenames instead of using wildcards.


Solution:4

For the sake of it, I'll throw my 2 cents in. I was looking for exactly the same thing (only for ogg files) and started a thread at Crunchbang Forum. You can view it here: Normalize-audio can't find mp3 decoder

Basically my solution was the script in post #8. It works for mp3, flac, and ogg input files, possibly others but definitely not wav.

Just create a file (name it whatever you want, I called mine db_adjust_mp3), chmod +x , and stick it in your ~/bin folder. It fills in any missing codec data as well. Example:

Original file: 16._This_Protector.mp3: Audio file with ID3 version 2.3.0, contains:

vs.

Normalized file: 16._This_Protector.mp3: Audio file with ID3 version 2.3.0, contains: MPEG ADTS, layer III, v1, 192 kbps, 44.1 kHz, JntStereo

I've modified the script to use normalize-mp3 here so you can use it if you want:

#!/bin/bash    find "$1" -iname "*.""$2" > $HOME/file_list    cat $HOME/file_list | while read line; do  #  echo "$line"    orig_gain="$(normalize-mp3 -n "$line" | cut -d 'd' -f1)"    larger=$(echo "$orig_gain"'>'-12 | bc)    if [[ larger ]]      then        gain_difference=$(echo "$orig_gain"*-1-12 | bc)      else        gain_difference=$(echo "$orig_gain"-12 | bc)    fi    echo "Gain Difference will be: $gain_difference""db"    normalize-ogg --mp3 --bitrate "$3" -g "$gain_difference""db" -v "$line"  done  

This script calculates the difference between the current db level and -12db, then applies a gain adjustment to put the gain at exactly -12db, which is what I've found works the best for me. It is recursive as well, which makes it great for doing entire music collections or files in many subfolders. If you wish to set a different db level, just change the both instances of the number "12" to whatever db level you would like to use. As I posted in my Crunchbang thread, usage is as follows:

normalize-mp3 <directory> <file extenstion(with no leading dot)> <bitrate>  

However, when I used to keep my music library in mp3 format, I used to use mp3gain as well, just as Philippe suggested. The dead simplicity of it is great and I really liked it. The problem with normalize-audio though is that it does decode an re-endcode the files, so there is some sound degradation. But unless you're an audiophile and your mp3's are encoded at a high bitrate you shouldn't notice much difference.

The thing I noticed with mp3gain though was that no matter what options I tried I couldn't get everything in my collection to be exactly the same db level, which is what I want so that I never have to adjust the volume from one track to the next. This script does exactly that. Sorry for being so long winded. Hope this helps.


Solution:5

replaygain

On Ubuntu 16.4 I had problems with other CLI alternatives. Then I found replaygain:

This package provides a Python package to calculate the Replay Gain values of audio files and normalize the volume of those files according to the values. Two basic scripts exploiting these capabilities are shipped as well.

Replay Gain is a proposed standard designed to solve the very problem of varying volumes across audio files.

Install: sudo apt install python-rgain.

replaygain --force *.mp3  
  • -f, --force Recalculate Replay Gain even if the file already contains gain information.

Reference


Solution:6

I liked Neil's answer the most, because it doesn't introduce correlation between audio files: just pick one gain level and adjust everything to it.

However I had some problems parsing the output of normalize-ogg with some files I have. There is also one nasty issue with bc: it doesn't do real rounding, it only truncates.

So eventually I gave up on shell scripting and moved to python.

Note1: the exiftool part might be overkill but I wanted to be 100% sure that the original bitrate would be preserved.

Note2: this will overwrite the originals, if you want to preserve them, use --backup in the last call to normalize-ogg. But I found more practical to keep a copy in a separate, safer, directory.

Note3: this solution deals with ogg files, but it's trivial to adapt it to mp3, just replace the occurrences of "ogg" with "mp3".

Here's my take at the problem. The latest version can be found here: regain.py

#!/usr/bin/python3  """  Parallel normalize gains  """  '      This program is free software: you can redistribute it and/or modify      it under the terms of the GNU General Public License as published by      the Free Software Foundation, either version 3 of the License, or      (at your option) any later version.        This program is distributed in the hope that it will be useful,      but WITHOUT ANY WARRANTY; without even the implied warranty of      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      GNU General Public License for more details.        You should have received a copy of the GNU General Public License      along with this program.  If not, see <http://www.gnu.org/licenses/>.  '    # Absolute value, in dB for the desired gain of each file  TARGET_GAIN = -12    #   MAX_THREADS = 2    from subprocess import Popen, PIPE  from multiprocessing.dummy import Pool as ThreadPool  from os import listdir  import logging    def initlogger(logfile="log.log", mainlevel=logging.DEBUG,                 filelevel=logging.DEBUG, consolelevel=logging.DEBUG):      '''initlogger'''      # create logger       logger = logging.getLogger()      logger.setLevel(mainlevel)      # create file handler which logs even debug messages      fh = logging.FileHandler(logfile)      fh.setLevel(filelevel)      # create console handler also logging at DEBUG level      ch = logging.StreamHandler()      ch.setLevel(consolelevel)      # create formatter and add it to the handlers      formatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")      fh.setFormatter(formatter)      ch.setFormatter(formatter)      # add the handlers to the logger      logger.addHandler(fh)      logger.addHandler(ch)    def logcommand(command=[]):      '''logcommand'''      if not isinstance(command, list):          return "", "", -1      logging.info("Command:\n" + " ".join(command) + "\n")      proc = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)      output, err = proc.communicate()      output = output.decode("utf-8")      err = err.decode("utf-8")      logging.info("Output:\n" + output + "\n")      logging.info("Error:\n" + err + "\n")      logging.info("Return Code:\n" + str(proc.returncode) + "\n")      return output, err, proc.returncode    def regain(target):      '''regain'''      logging.info("============================ Start File  ============================")      logging.warning(target["name"])      logging.info("Extracting gain info.\n")      commandgetlevels = ['normalize-ogg', '-n', target["name"]]      output, err, retcode = logcommand(commandgetlevels)        level  = output.split()[0]      logging.debug("Level: " + level)      if "dBFS" in level:          level = level.split("dBFS")[0]      level = level.replace(',', '.')      level = int(round(float(level)))      delta = target["gain"] - level      logging.info("Required adjustment: " + str(delta) + "\n")      if delta is 0:          logging.warning(target["name"] + " is already at the correct level")          return 0        logging.info("Extracting average bitrate.\n")      commandgetinfo = ['exiftool', target["name"]]      output, err, retcode = logcommand(commandgetinfo)      bitrate = '0'      for line in output.split('\n'):          if 'Nominal Bitrate' in line:              bitrate = line.split(':')[1].split()[0]              break      logging.info("Average bitrate is: " + str(bitrate) + "\n")      if bitrate is '0':          logging.error("No valid bitrate found, aborting conversion.\n")          exit(-1)        logging.info("Re-normalizing.\n")      commandrenormalize = ['normalize-ogg', '--ogg', '--bitrate', bitrate,                            '-g', str(delta) + 'db', target["name"]]      output, err, retcode = logcommand(commandrenormalize)      if retcode is not 0:          log.error("Output:\n" + output)          log.error("err:\n" + err)          exit(retcode)        return retcode    # function to be mapped over  def parallelregain(gain=TARGET_GAIN, threads=MAX_THREADS):      '''parallelregain'''      logging.info("Creating thread pool with " + str(threads) + " elements.\n")      pool = ThreadPool(threads)      targets = []      files_list = listdir(".")      files_list.sort()      counter = 0      for filename in files_list:          if filename.endswith("ogg"):              target = {                  "name":filename,                  "gain":gain,              }              targets.append(target)              counter = counter + 1      pool.map(regain, targets)      pool.close()      pool.join()    if __name__ == "__main__":      initlogger(logfile="normalize.log", consolelevel=logging.WARNING)      parallelregain()  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »