以前我欣赏古典音乐都是听的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的更多相关文章

  1. 我在GNU/Linux下使用的桌面环境工具组合

    为了使GNU/Linux桌面环境下加载的程序较少以节省内存资源和提高启动时间,我目前并不使用重量级的桌面环境KDE和Gnome,甚至连登录窗界面gdm或xdm都不用,而是直接启动到控制台,登录后调用s ...

  2. GNU/Linux下Freeplane的界面渲染问题

    如下图所示,思维导图软件Freeplane在GNU/Linux下默认的界面渲染效果是很差的,即便将Preferences → Appearance → Antialias设置为Antialias al ...

  3. 在GNU/Linux下制作Windows 10安装U盘

    今年春节回家期间,我需要将家里的一台安装了Debian Stretch的ZaReason笔记本电脑更换为Windows 10系统,好让爸妈从老台式机上的XP系统升级到新的平台上来.回家前,小仙女已在微 ...

  4. Gnu Linux下文件的字符编码及转换工具

    /*********************************************************************  * Author  : Samson  * Date   ...

  5. 在GNU/Linux下使用Lilypond排版简谱

    尽管GNU/Linux并非无所不能,但确实能在很多时候提供免费.开放的解决方案.这两天我想做一个简谱,在网上搜索乐谱排版软件,发现了基于GPL协议的Lilypond软件.只不过Lilypond是用来做 ...

  6. Linux下一个CD翻录 创CUE 压缩flac攻略

    于Windows我们通常使用较低EAC翻录压缩发生器CUE找工作的步骤,但在Linux在稍微有点麻烦.每一步,我们需要自己做.经过我的反复尝试寻找和总结了相当不错的方法,使用软件和步骤如下面的. 使用 ...

  7. arch linux下网易云音乐运行没反应,只能使用root用户运行

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/netease_music_can_not_open 最近打开网易 ...

  8. GNU/Linux下LVM配置管理以及快照卷、物理卷、卷组、逻辑卷的创建和删除

    LVM是Linux环境中对磁盘分区进行管理的一种机制,是建立在硬盘和分区之上.文件系统之下的一个逻辑层,可提高磁盘分区管理的灵活性.最大的优点是在不损伤数据的前提下调整存储空间的大小. 本篇主要讲述L ...

  9. 在GNU/Linux下设置与定时更换桌面壁纸

    1 简介 在电脑桌面设置一组可以定时更换的壁纸已经不是什么新奇的功能了.比如,Windows 7.KDE桌面环境都可以实现这样的效果.可是,自己目前使用的Debian系统并未安装KDE.GNOME这样 ...

随机推荐

  1. Eclipse plugin web site 发布和版本更新

    Eclipse plugin web site 发布和版本更新 在eclipse插件开发过程中免不了要发布1.0, 1.1, 1.2…….等等,随着版本的递增,假如每次都发布一个插件zip包,那使用者 ...

  2. 什么是Numpy的ndarray

    什么是Numpy的ndarray 首先,Numpy的核心是ndarray. 然后,ndarray本质是数组,其不同于一般的数组,或者Python 的list的地方在于它可以有N 维(dimention ...

  3. 使用Emacs:生存篇

    使用Emacs:生存篇 vim和Emacs都是很强大的编辑器.所以,入门有一定难度.这里不谈vim,谈Emacs下的生存--第一次使用Emacs时的使用. 1.emacs的安装: 在Fedora下: ...

  4. 解析JSON、扩展Fiddler

    解析JSON.扩展Fiddler 按文章结构,这部分应该给出WCFRest项目示例,我想WinForm示例足够详尽了,况且WCFRest还不需要使用插件AppDomain那一套,于是把最近写的Fidd ...

  5. [Android笔记1]Activity+Layout+Button

    线性布局(LinearLayout)是指view对象在父view中可按水平或垂直方向线性排列. 相对布局(RelativeLayout)是指view对象的排列依赖于各对象之间的相对位置. 下面是展示两 ...

  6. [置顶] 安卓UI组件之ListView详解

    ListView是很常见的一个UI组件,在许多App中都很常用,其意思就是可滚动的列表,使用ListView必须使用Adapter(适配器),常用的适配器友谊ArrayAdapter,SimpleAd ...

  7. jvm内存JVM学习笔记-引用(Reference)机制

    在写这篇文章之前,xxx已经写过了几篇关于改jvm内存主题的文章,想要了解的朋友可以去翻一下之前的文章 如果你还不了解JVM的基本概念和内存划分,请阅读JVM学习笔记-基础知识和JVM学习笔记-内存处 ...

  8. 命令版本git 分支篇-----不断更新中

    最近应用开发的过程中出现了一个小问题,顺便记录一下原因和方法--命令版本 开发中想看看过去某个版本的代码,我们先查看log git log commit f224a720b8192165a4e70f2 ...

  9. VS 使用技巧

    1.按下alt键,可以做到竖向选择 2.

  10. Xpath学习笔记

    最近复习自己上一年的课本,想起来刚学那个时候想做一个写日记的软件. 想不如做,用控制台瞎写了一个,一做就成了,没什么bug,期间使用Xpath来读数据,所以就稍微学了一下. 学习过程就这样做一点笔记, ...