在GNU/Linux下将CD音乐转为mp3
以前我欣赏古典音乐都是听的CD,因而珍藏了不少光盘以及下载到电脑上的ape与flac格式的音乐文件。随着手机硬件性能(如电池续航能力、处理器速度、音质、存储容量等)和软件功能(音乐播放器对于曲目的管理)的提升,便需要考虑如何将这些资源转换成高质量的mp3文件放到手机上聆听。本文介绍如何基于GNU/Linux下的Audacity、k3b、easytag软件,以及自己写的Bash脚本程序来实现此功能。
从光盘抓取音乐并转为mp3
k3b是KDE环境下默认的光盘刻录与抓取软件。其界面如下图所示。

选择菜单Tools中的Rip Audio CD,我们可用它直接从CD光盘上抓取出wav文件。接下来,打开Audacity音乐编辑软件,将抓取的多个wav文件导入(而非打开)为多个音轨。再选择菜单Files中的Export Multiple,将导出格式选为mp3,导出选项中的采样频率设为320 kbps,然后点击导出即可完成转换。如下图所示。

最后,打开easytag软件,填写mp3文件的曲目信息(ID3 Tag)。注意,点击信息文本框旁边的小圆点,可以一次性地将设置应用到所有选中的文件。如下图所示。

将ape或flac文件转为mp3文件
一般下载的CD Rip文件是ape或flac格式的,具有无损音质。可若直接将其拷到手机上,一是某些软件可能不支持这两种格式,二是它们所占用的存储空间太大了,三是由于它们也不包含类似于mp3文件的ID3 tag信息,从而无法被音乐播放软件自动根据专辑名或作曲家名而自动分类管理。因此,有必要将ape和flac文件按曲目拆分并转换为mp3格式,填写曲目信息后再导入手机。
可以看出,这里首先需要解决的是ape与flac文件的曲目拆分问题。一般来说,与它们一同下载的还会有个扩展名为cue的文件。此文件保存了CD的曲目信息,包括音乐风格(GENRE)、制作年份(DATE)、表演者(PERFORMER)、专辑/CD名称(TITLE)、ape或flac文件的名称(FILE),以及每个音轨(TRACK)的标题(TITLE)、表演者(PERFORMER)和开始时间(INDEX 01)。如下所示:
REM GENRE Classical
REM DATE 1991
REM DISCID 9B0E701C
REM COMMENT "ExactAudioCopy v0.95b4"
PERFORMER "Wächter, Sutherland, Schwarzkopf, Taddei, Alva, Sciutti, Frick"
TITLE "Don Giovanni - Giulini 1/3"
FILE "CDImage.ape" WAVE
TRACK 01 AUDIO
TITLE "Sinfonia"
PERFORMER "Wächter, Sutherland, Schwarzkopf, Taddei, Alva, Sciutti, Frick"
INDEX 01 00:00:00
TRACK 02 AUDIO
TITLE "Notte e giorno faticar"
PERFORMER "Wächter, Sutherland, Schwarzkopf, Taddei, Alva, Sciutti, Frick"
INDEX 01 06:18:07
TRACK 03 AUDIO
TITLE "Non sperar, se non m'uccidi"
PERFORMER "Wächter, Sutherland, Schwarzkopf, Taddei, Alva, Sciutti, Frick"
INDEX 01 07:58:31
需要说明的是,某个音轨的信息中可能同时含有INDEX 00与INDEX 01,那么该曲目实际的开始时间是由INDEX 01来指定的。INDEX 01的值比INDEX 00要大一些,目的是为了跳过该曲目前端的空白部分。由INDEX 01指定的时间分为三部分:分钟:秒:1/75秒。
在搞清楚cue文件的格式后,我们再来看音乐编辑软件Audacity所拥有的一个功能:我们可以通过导入包含各音轨信息的标签(label)文件,再选择Export Multiple,则可以将整个的ape或flac文件作拆分并转换为mp3文件。该标签文件的格式如下:
0.000000 0.000000 Sinfonia
378.093333 378.093333 Notte e giorno faticar
478.413333 478.413333 Non sperar, se non m'uccidi
其中,每一行代表一个曲目。每一行中的第一列与第二列的内容相同,都是该音轨的开始时间,单位是秒。第三列则是该曲目的标题。
从cue到label文件的转换可以在这里在线完成,但毕竟不太方便。所以,我写了一个脚本程序cue2lbl.sh,来实现同样的功能。源代码如下:
#!/bin/bash script_name="cue2lbl.sh"
script_usage=$(cat <<EOF
$script_name [OPTIONS] cue_file
EOF
)
script_function=$(cat <<EOF
Convert a cue CD index file to Audacity label file.
EOF
)
script_doc=$(cat <<EOF
Script documentation.
-h Display this help.
-o Specify output lable file.
EOF
)
script_examples=$(cat <<EOF
$script_name -o music.txt music.cue
EOF
)
state_prefix="==="
warning_prefix="***"
error_prefix="!!!" function display_help() {
if [ -n "$script_usage" ]; then
echo -e "Usage: $script_usage"
fi if [ -n "$script_function" ]; then
echo -e "$script_function"
fi if [ -n "$script_doc" ] ; then
echo -e "\n$script_doc"
fi if [ -n "$script_examples" ]; then
echo -e "\nExamples"
echo -e "$script_examples"
fi
} # Output label file
lbl_file="" # Process command options
while getopts ":ho:" opt; do
case $opt in
h ) display_help
exit 0 ;;
o ) lbl_file=$OPTARG ;;
\? ) display_help
exit 1 ;;
esac
done
shift $(($OPTIND - 1)) # Start execute the command
if [ -z "$lbl_file" ]; then
lbl_file="${1%cue}txt"
fi # Label file first time writing
lbl_file_1st_write=1 # Searched state: 0 for start; 1 for track; 2 for title; 3 for index.
searched_state=0 declare -i track_time_minute=0 track_time_second=0 IFS=$'\n'
for line in `grep -i "\(INDEX\)\|\(TITLE\)\|\(TRACK\)" "$1"`; do
case $searched_state in
0 )
if [ -n "`echo "$line" | grep -i TRACK`" ]; then
searched_state=1
fi ;;
1 )
if [ -n "`echo "$line" | grep -i "TITLE"`" ]; then
# Remove blanks at the beginning and end of a line
line=`echo "$line" | gawk -f /usr/local/bin/scripts/rmblank.awk`
# Get title
track_title=`echo "$line" | gawk -f /usr/local/bin/scripts/cue2lbl_get_title.awk`
track_title=`echo "$track_title" | gawk -f /usr/local/bin/scripts/rmblank.awk | tr -d \"`
searched_state=2
fi ;;
2 )
if [ -n "`echo "$line" | grep -i "INDEX"`" ]; then
# Remove blanks at the beginning and end of a line
line=`echo "$line" | gawk -f /usr/local/bin/scripts/rmblank.awk`
# Get track index
line=`echo "$line" | gawk -f /usr/local/bin/scripts/cue2lbl_get_index.awk`
track_index=`echo "$line" | gawk -f /usr/local/bin/scripts/rmblank.awk | cut -f 1 -d " " | tr -d " "`
if [ "$track_index" = "01" ] || [ "$track_index" = "1" ]; then
# Get track time
track_time=`echo "$line" | gawk -f /usr/local/bin/scripts/rmblank.awk | cut -f 2 -d " " | tr -d " "`
track_time_minute=`echo "$track_time" | cut -f 1 -d ":" | gawk '{if (match($0, "^0+$") != 0) {print "0";} else {gsub("^0+", ""); print}}'`
track_time_second=`echo "$track_time" | cut -f 2 -d ":" | gawk '{if (match($0, "^0+$") != 0) {print "0";} else {gsub("^0+", ""); print}}'`
track_time_sub_second=`echo "$track_time" | cut -f 3 -d ":" | gawk '{if (match($0, "^0+$") != 0) {print "0";} else {gsub("^0+", ""); print}}'`
track_time_total_seconds=$(($track_time_minute * 60 + $track_time_second))
track_time_sub_second=`echo "scale=6; $track_time_sub_second / 75" | bc`
if [ "$track_time_sub_second" = "0" ]; then
track_time_sub_second=".000000"
fi
track_time_total_seconds=`echo "$track_time_total_seconds$track_time_sub_second"`
fi
fi if [ -n "`echo "$line" | grep -i "TRACK"`" ]; then
# Print collected track information
if [ "$lbl_file_1st_write" = "1" ]; then
echo -e "$track_time_total_seconds\t$track_time_total_seconds\t$track_title" > "$lbl_file"
lbl_file_1st_write=0
else
echo -e "$track_time_total_seconds\t$track_time_total_seconds\t$track_title" >> "$lbl_file"
fi searched_state=1
fi ;;
esac
done # Print the last collected track information
if [ "$lbl_file_1st_write" = "1" ]; then
echo -e "$track_time_total_seconds\t$track_time_total_seconds\t$track_title" > "$lbl_file"
else
echo -e "$track_time_total_seconds\t$track_time_total_seconds\t$track_title" >> "$lbl_file"
fi
为了完成字符串的匹配,该脚本程序中用到了几个gawk程序,分别如下:
1. 移除行首与行尾的空白字符:
{
gsub("(^[[:blank:]]+)|([[:blank:]]+$)", "");
print;
}
2. 删除INDEX:
/^(INDEX)|(index)/ {print gensub("^(INDEX)|(index)[[:blank:]]+", "", 1);}
3. 删除TITLE:
/^(TITLE)|(title)/ {print gensub("^(TITLE)|(title)[[:blank:]]+", "", 1);}
至此,有了label文件,便可用Audacity将ape和flac转换生成多个mp3文件了。
将mp3文件导入手机
目前我的手机上使用的是“酷我音乐”播放器,可以直接通过Wifi由电脑向手机传歌。如下图所示,打开“酷我音乐”后,点击页面底部的“电脑-手机传歌”:


然后在电脑上打开浏览器,输入提示的地址,添加文件即可。
在GNU/Linux下将CD音乐转为mp3的更多相关文章
- 我在GNU/Linux下使用的桌面环境工具组合
为了使GNU/Linux桌面环境下加载的程序较少以节省内存资源和提高启动时间,我目前并不使用重量级的桌面环境KDE和Gnome,甚至连登录窗界面gdm或xdm都不用,而是直接启动到控制台,登录后调用s ...
- GNU/Linux下Freeplane的界面渲染问题
如下图所示,思维导图软件Freeplane在GNU/Linux下默认的界面渲染效果是很差的,即便将Preferences → Appearance → Antialias设置为Antialias al ...
- 在GNU/Linux下制作Windows 10安装U盘
今年春节回家期间,我需要将家里的一台安装了Debian Stretch的ZaReason笔记本电脑更换为Windows 10系统,好让爸妈从老台式机上的XP系统升级到新的平台上来.回家前,小仙女已在微 ...
- Gnu Linux下文件的字符编码及转换工具
/********************************************************************* * Author : Samson * Date ...
- 在GNU/Linux下使用Lilypond排版简谱
尽管GNU/Linux并非无所不能,但确实能在很多时候提供免费.开放的解决方案.这两天我想做一个简谱,在网上搜索乐谱排版软件,发现了基于GPL协议的Lilypond软件.只不过Lilypond是用来做 ...
- Linux下一个CD翻录 创CUE 压缩flac攻略
于Windows我们通常使用较低EAC翻录压缩发生器CUE找工作的步骤,但在Linux在稍微有点麻烦.每一步,我们需要自己做.经过我的反复尝试寻找和总结了相当不错的方法,使用软件和步骤如下面的. 使用 ...
- arch linux下网易云音乐运行没反应,只能使用root用户运行
本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/netease_music_can_not_open 最近打开网易 ...
- GNU/Linux下LVM配置管理以及快照卷、物理卷、卷组、逻辑卷的创建和删除
LVM是Linux环境中对磁盘分区进行管理的一种机制,是建立在硬盘和分区之上.文件系统之下的一个逻辑层,可提高磁盘分区管理的灵活性.最大的优点是在不损伤数据的前提下调整存储空间的大小. 本篇主要讲述L ...
- 在GNU/Linux下设置与定时更换桌面壁纸
1 简介 在电脑桌面设置一组可以定时更换的壁纸已经不是什么新奇的功能了.比如,Windows 7.KDE桌面环境都可以实现这样的效果.可是,自己目前使用的Debian系统并未安装KDE.GNOME这样 ...
随机推荐
- WPF/Silverlight中的RichTextBox总结
WPF/Silverlight中的RichTextBox总结 在WPF或者是在Silverlight中有个非常强大的可以编辑的容器控件RichTextBox,有的时间会采取该控件来作为编辑控件.鉴 ...
- Morn简介及使用教程
[Morn UI系列教程]Morn简介及使用教程 网页游戏开发的一大部分工作是在和UI制作上,一个好的工具及框架能使开发事半功倍,Adobe自带flash IDE和Flex各有不足. Morn UI学 ...
- 完整显示当前日期和时间的JS代码(2007年2月25日星期日正午12:42:48)
代码演示效果为“2007年2月25日星期日正午12:42:48”. 使用方法:将下面的JS代码放到你想要显示的页面中(支持HTML页面),然后在你想要显示时间的位置插入下面的代码即可 <div ...
- .net下简单快捷的数值高低位切换
.net下简单快捷的数值高低位切换 做网络通讯中数值传输是很普遍的事情,但数值的存储在不平台和硬件上存储方式都不一样,主要有两大类分别是高位和低位存储:而.net平台下是低位存储,通过.net提供的函 ...
- easyUI datagrid 动态绑定列名称
easyUI 基于Jquery ,所以需要引用Jquery文件 easyUI自带了很多样式文件,可以根据需要,引用相应的css文件. 其中datagrid是一个根据json数据,js前端生成前端显示的 ...
- Linux登录ssh携带密码
最近在使用ssh,但是每次都需要输入密码,想简单一步搞定,Google了一下,发现了一个比较笨的但实用的方法 1.安装 sshpass sudo apt-get install sshpass 2.携 ...
- mybatis里面的 #{}和${}
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111&qu ...
- jquery ajax请求成功,数据返回成功,seccess不执行的问题
1.状态码返回200--表明服务器正常响应了客户端的请求: 2.通过firebug和IE的httpWatcher可以看出服务器端返回了正常的数据,并且是符合业务逻辑的数据. ...
- UIView的生命周期和layout方法总结
生命周期 1. loadView 什么时候调用? 每次访问UIViewController的view时候并且view == nil时候调用. 如何实现? 1> 如果在初始化UIViewContr ...
- Maven3在Eclipse上安装插件
eclipse 安装插件的方式最常见的有两种: 1. 一种是在线安装,这貌似是用的最多的,就是:Help --> Install New Software,然后输入 HTTP 地址来安装,但有 ...