如何规范mp3文件中的声音


39

我正在寻找一种标准化我拥有的许多MP3文件中声音的方法。有些声音较低,而另一些声音较大,所以我必须根据歌曲的大小调高或调低音量。有什么方法可以对所有文件执行此操作。我特别想通过终端执行此操作,但也接受GUI方式。


有关在演奏时进行规范化的信息,请访问:askubuntu.com/questions/95716/…。但是,这不会改变您的mp3文件内容-可能会有所帮助;)
Takkat 2013年

不在播放时,不想每次都设置它,或者不想在每次我想听歌曲时让播放器设置归一化。例如,假设我想将歌曲复制到ipod shuffle或笔式驱动器中,以在支持mp3的播放器中收听。
路易斯·阿尔瓦拉多

@Takkat BTW在另一个问题上做得很好。好信息。
Luis Alvarado

1
我的妻子刚刚测试了Audacity方法,并且效果很好!推荐的。请,当人们寻求建议时,是因为他们不是专家。因此,当他们可以通过易于理解的图形工具(例如Audacity)完成任务时,不要告诉他们使用命令行工具。告诉新的Linux用户打开终端并运行命令行工具只会吓them他们离开Ubuntu,感觉是Windows很简单,Linux很难。DOS死了,但Windows仍然存在,这不足为奇。

您的妻子能够找出图形的方式真是太好了,但是您是否错过了询问问题的人特别希望通过终端实现这一部分的部分?
理查德·P

Answers:


22

大胆

借助Audacity,我们可以轻松地批量处理文件,以将转换或效果应用于列表中的许多文件。为此,我们首先必须定义一个“链”,其中包含我们要应用的效果。

这可以通过“ File-> Edit Chains ...”完成。在现在打开的窗口中,按左下角的“ 添加”按钮以插入新链(给它取一个明智的名称):

在此处输入图片说明

然后选择效果及其参数以插入到链中(此处显示默认值和Normalize效果)。

重要说明:我们始终还需要添加效果“导出MP3”(或任何其他导出格式),以将转换结果保存到磁盘。

完成后,单击确定离开此窗口以打开“文件->应用链...”。选择我们刚刚创建的链,并通过“应用于文件...”加载所需的所有文件。可以从打开的文件选择器中选择几个文件。

在此处输入图片说明

处理后的文件将保存在原始路径中“清除”的新子目录中。


索克斯

从版本> 14.3开始,我们可以使用sox过滤器--norm在命令行上标准化音频或进行批处理:

sox --norm infile outfile

MP3支持通过libsox-fmt-all添加到Sox:

sudo apt install sox libsox-fmt-all

2
这些工具会解码并重新编码吗?
2014年

您不能在不重新编码的情况下进行归一化,至少要达到级别...
Takkat 2014年

对于使用LADSPA和看到的PulseAudio无损活正火askubuntu.com/questions/95716/...
Takkat

这会重新编码,因此会降低质量。如果要保留文件质量,请参阅我的答案。如果您的播放器支持音量标记,则无需重新编码。
威尔

1
可以批量使用soxfor f in *.mp3; do sox --norm "$f" /tmp/sox.mp3; mv -v /tmp/sox.mp3 "$f"; done
rubo77

30

看看@ mp3gain,对我而言,它甚至比normalize-audio更好

mp3gain -r *.mp3

另一个有用的版本可能是-c,它阻止询问您是否要对许多文件进行更改:

mp3gain -c -r *.mp3

如手册页中所述:

mp3gain 不仅像许多规范化器那样执行峰值规范化。取而代之的是,它进行一些统计分析,以确定文件实际向人耳发出的声音。而且,mp3gain所做的更改是完全无损的。更改不会造成质量损失,因为该程序无需解码和重新编码即可直接调整mp3文件。

注意:该软件包已在ubuntu 15.04上被有意删除

Debian建议使用该python-rgain软件包作为替代软件包(优点是'replaygain'支持多种文件格式,即Ogg Vorbis,Flac,WavPack和MP3。此外,它还允许您查看任何这些文件类型中的现有Replay Gain信息)。安装后,运行replaygain

要从终端安装python-rgain,请运行以下命令

sudo apt-get install python-rgain

或者,.deb此处获取14.04(最新)文件。照常安装。之后,您需要运行sudo apt-get -f install以更正一些依赖项问题。


1
另外,如果您不想使用该终端,则可以使用一个名为easymp3gain-gtk的GUI,这非常方便!
gilbertohasnofb 2014年

这是超级有用的。使用MP3Gain的Windows GUI的标准化质量给我留下了深刻的印象,因此当我需要Linux命令行解决方案时,我很高兴找到这个答案。肯定会推荐给别人。
亚历克斯·米勒

您能否添加一些有关如何安装的信息?默认情况下它不是随Ubuntu一起提供的,我找不到该软件包。
Błażej米哈利克

谢谢...在Ubuntu 16.04上安装python-rgain时没有任何依赖项错误。
巴拉特·马拉马普

使用mkdir mp3gain; cd mp3gain; wget https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/mp3gain/1.5.2-r2-6/mp3gain_1.5.2-r2.orig.tar.gz; tar -xvzf mp3gain_1.5.2-r2.orig.tar.gz; make; sudo make install
rubo77

14

我将使用此项目Normalize,这是用于规范音频文件的命令行工具。看起来正是您所需要的。可以进行批处理,不需要重新采样为中间格式。

这是在包回购的规范化音频,sudo apt-get install normalize-audio。这是Debian在上游维护的构建,因此它应为LTS或更高版本,并具有mp3兼容性(经过测试)。有一个不错的联机帮助页man normalize-audio,供您探索这些选项,但命令默认值似乎可以正常工作。对于批处理(跨多个文件规范化卷),normalize-audio -b *.mp3或指定单个文件名而不使用通配符。


OP要求执行此操作的指令。你能提供那些吗?
赛斯

@iSeth我最初对仅源注释不正确,因为在apt-cache搜索中找不到它。我已经更新了有关deb软件包的详细信息。
sean_m 2013年

这似乎是一个很好的选择,但是找不到正确的编码器,并且摆脱了“没有可用的编码器”的问题。尝试过libsox-fmt-mp3libavcodec-extra-b *.mp3仅使用一个(随机?)文件执行某些操作。
Pablo A

4

重播

更快,更容易replaygain

该软件包提供了一个Python软件包来计算音频文件的Replay Gain值,并根据这些值标准化这些文件的音量。同时提供了两个利用这些功能的基本脚本。

重播增益是一项提议的标准,旨在解决整个音频文件中音量变化的问题。

安装:sudo apt install python-rgain

replaygain --force *.mp3
  • -f, --force 即使文件已经包含增益信息,也要重新计算Replay Gain。

由于仅计算/更改重放增益值,因此速度也更快:对于普通PC(Intel i7-6500U,8GB RAM),速率约为20个文件/分钟。

参考


3

为此,我将投入2美分。我一直在寻找完全相同的东西(仅用于ogg文件),并在Crunchbang论坛上开始了一个话题。您可以在此处查看:Normalize-audio找不到mp3解码器

基本上,我的解决方案是发布#8中的脚本。它适用于mp3,flac和ogg输入文件,可能还有其他文件,但绝对不是wav。

只需创建一个文件(随便命名,我叫db_adjust_mp3),chmod + x,然后将其粘贴到您的〜/ bin文件夹中即可。它还会填写任何缺少的编解码器数据。例:

原始文件: 16._This_Protector.mp3: Audio file with ID3 version 2.3.0, contains:

规范化文件: 16._This_Protector.mp3: Audio file with ID3 version 2.3.0, contains: MPEG ADTS, layer III, v1, 192 kbps, 44.1 kHz, JntStereo

我已将脚本修改为在此处使用normalize-mp3,因此可以根据需要使用它:

#!/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

该脚本计算当前数据库级别和-12db之间的差异,然后应用增益调整将增益精确地设置为-12db,这是我发现最适合我的。它也是递归的,因此非常适合在许多子文件夹中进行整个音乐收藏或文件制作。如果希望设置不同的数据库级别,只需将数字“ 12”的两个实例都更改为您要使用的任何数据库级别。正如我在Crunchbang主题中发布的那样,用法如下:

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

但是,当我以前将音乐库保持为mp3格式时,就像Philippe所建议的那样,我也曾经使用mp3gain。它的简单性很棒,我真的很喜欢它。但是normalize-audio的问题在于它确实解码了文件的重新结束编码,因此声音会有所下降。但是,除非您是发烧友并且您的mp3是以高比特率编码的,否则您不会注意到太大的区别。

我通过mp3gain注意到的事情是,无论我尝试了什么选项,我都无法将收藏集中的所有内容都设为完全相同的db级别,这就是我想要的,这样我就不必将音量从一个音轨调整为下一个。该脚本正是这样做的。很抱歉这么长时间。希望这可以帮助。


0

我最喜欢Neil的答案,因为它不会在音频文件之间引入相关性:只需选择一个增益水平并将其调整为所有增益水平即可。

但是我在解析normalize-ogg某些文件的输出时遇到了一些问题。还有一个令人讨厌的问题bc:它不进行真正的舍入,它只会截断。

所以最终我放弃了shell脚本,转而使用python。

注意1: exiftool部分可能过大,但我想100%确保保留原始比特率。

注意2:这将覆盖原始文件,如果要保留原始文件,请在最后一次调用normalize-ogg时使用--backup。但是我发现将副本保存在单独的,更安全的目录中更为实用。

注意3:此解决方案处理ogg文件,但是将其适应mp3并不容易,只需将出现的“ ogg”替换为“ mp3”即可。

这是我对这个问题的看法。最新版本可以在这里找到: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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.