perl与mp3
程序员,Gold Software Systems
2004 年 2 月
每一位自我陶醉的计算机和音乐爱好者都需要能够操纵 MP3 —— 娱乐性数字音乐的事实标准。在本文中,Ted 介绍了几种使用 autotag.pl 应用程序管理和操纵(搜索、标记、重命名和注释,等等)MP3 的方法。Ted 向读者详细介绍了此应用程序,描述了 CPAN 模块如何启用该应用程序。
对于现在了解计算机的音乐爱好者而言,操纵 MP3 文件是一项必须具备的技能。虽然其他音乐文件格式已存在并在蓬勃发展着,但本文还是主要讨论 MP3 格式,因为众所周知,它是当今最流行的格式。但是,本文所讲述的一般方法也可用于处理其他允许使用标签(tag)的音乐文件格式。实际上,很多使用标签的文件格式都可以从类似本文中的 autotag.pl 程序中受益。欢迎您提出建议。
本文将一般性地讨论有关 Perl 的问题 ,特别关注 MP3 文件的操纵,并详细介绍了 autotag.pl 应用程序。
尽管已经有了 MP3::Info、MP3::ID3Lib、MusicBrainz::Client 和 AudioFile::Identify::MusicBrainz 模块,而且这些模块可能很有用,但我只使用 MP3::ID3Lib 的主要理由是因为它需要 id31ib 软件(请参阅 参考资料)。虽然 MP3::Info 是纯 Perl 语言编写的而且安装也很简单,但我发现 MP3::Tag 功能更强大。之所以没有使用 MusicBrainz::Client 和 AudioFile::Identify::MusicBrainz,是因为 MusicBrainz 似乎是比 FreeDB 更不全面的已发行 CD 的数据库。在本文的结尾,将向读者介绍 ID3 标签加注模块和曲目信息模块的选择。我经过试验和失败而艰难获得的经验表明, MP3::Tag 和 WebService::FreeDB 是最佳的模块。
虽然 CDDB (Gracenote) 磁盘库非常全面,但我还是没有选择使用它。Gracenote 是一家拥有 CD 曲目列表的专有数据库(只允许对数据库执行搜索,不能大量下载)的公司。在 Gracenote 只拥有 CDDB 的早期,志愿者贡献了这些数据库的相当一部分内容。而 FreeDB 是一个志愿者经过有组织的努力提供的免费、无限制的 CD 曲目数据库。FreeDB 数据库的整个内容都可以下载,无版权限制 —— 因此,如果您愿意,可以建立自己的 FreeDB 服务器。
我不使用的模块并不是因为这些模块一定不好,因此,如果您喜欢,您可以使用它们。基于个人经验和上述原因,我只是更喜欢 MP3::Tag 和 WebService::FreeDB。实际的读写标签在函数中进行了抽象,因此,如果使用不同的模块读写 MP3 标签,就不需要更改很多内容。
我还应提一下,在 Linux 内部的 xterm 和 Eterm 终端模拟器中,Term::ReadLine::Gnu 模块比默认模块 Term::ReadLine::Perl 能更好地工作。如果您注意到在提示输入期望的文本时出现一些奇怪的行为,那么可能要将其安装在 Term::ReadLine 之上。
|
MP3 标签的简单介绍 在硬件发展的同时,也产生了很多声音格式。.mid 适用于 MIDI 音调、.voc、.mod、.wav 等。专有的 MP3 格式(涉及到德国 Fraunhofer 学院拥有的很多专利)随着时间的推移流行开来 —— 它提供很好的压缩和性能。除 MP3 外还有许多格式,著名的有 Ogg Vorbis,但当今 MP3 似乎仍是音乐存储格式的最佳选择。 MP3 文件的一个优点是可以使用 ID3 标签来加注标签。文件内部是有关它的信息 —— 通常称为元数据。唱片集、艺术家、曲目名称、注释(使用 ID3 版本 1.1)甚至曲目数量都可以存储在 ID3 标签中,只要不超过特定字符数限制即可。 ID3 版本 1.1 的后续版本是 ID3 版本 2(简称为 ID3v2),除简单性外,后者几乎在所有方面都超过了前者。ID3v2 可以处理多种语言,在每个标签元素中存储任意长的数据,甚至将图片存储为标签的一部分。但不幸的是,使用 ID3v2 要了解到 TALB 是唱片集的名称,TIT2 是曲目数量。Ogg Vorbis 格式要花费很长时间才能识别,其中艺术家元素被称为...等等它吧...ARTIST!(公平地说,这仅仅是一个惯例 —— Ogg Vorbis 注释是无格式的)。不幸的是,现存的数十亿首 MP3 文件都不能在不损失质量的情况下转换为 Ogg Vorbis 格式或任何其他格式,因此,至少在接下来的 5 年里,您可能发现,我们不仅会使用下个“热门”格式,还要使用 MP3 文件。 我已非常努力地从实际的 ID3 标签中抽取标签作为内容。当时机来临时,修改 autotag.pl 会很容易,因此除 ID3 外,它还处理其他加注标签的格式。 |
基本的 autotag.pl 函数
我把 autotag.pl 几个功能放在了不同的函数中。首先,contains_word_char() 是一个判断某些文本中是否包含某个词(在 Perl 中是 \w in Perl)中的字符的函数。该函数也会正确地处理未定义的值,尽管在警告打开时,常规表达式在匹配未定义的值时会输出警告信息。该函数是极为有用的,因为它不显示警告信息;为了不使用函数而又达到这个目的,您必须检查是否每次都定义了字符串。
# {{{ contains_word_char: return 1 if the text contains a word character
sub contains_word_char
{
my $text = shift @_;
return $text && length $text && $text =~ m/\w/;
}
# }}}
|
接下来是输入例程。这些程序相当长,它们试图处理程序所需要的用户交互的大多数情况。
清单 2. get_tag() 函数
# {{{ get_tag: get a ID3 V2 tag, using V1 if necessary
sub get_tag
{
my $file = shift @_;
my $upgrade = shift @_;
my $mp3 = MP3::Tag->new($file);
return undef unless defined $mp3;
$mp3->get_tags();
my $tag = {};
if (exists $mp3->{ID3v2})
{
my $id3v2 = $mp3->{ID3v2};
my $frames = $id3v2->supported_frames();
while (my ($fname, $longname) = each %$frames)
{
# only grab the frames we know
next unless exists $supported_frames{$fname};
$tag->{$fname} = $id3v2->get_frame($fname);
delete $tag->{$fname} unless defined $tag->{$fname};
$tag->{$fname} = $tag->{$fname}->{Text} if $fname eq 'COMM';
$tag->{$fname} = $tag->{$fname}->{URL} if $fname eq 'WXXX';
$tag->{$fname} = '' unless defined $tag->{$fname};
}
}
elsif (exists $mp3->{ID3v1})
{
warn "No ID3 v2 TAG info in $file, using the v1 tag";
my $id3v1 = $mp3->{ID3v1};
$tag->{COMM} = $id3v1->comment();
$tag->{TIT2} = $id3v1->song();
$tag->{TPE1} = $id3v1->artist();
$tag->{TALB} = $id3v1->album();
$tag->{TYER} = $id3v1->year();
$tag->{TRCK} = $id3v1->track();
$tag->{TIT1} = $id3v1->genre();
if ($upgrade && read_yes_no("Upgrade ID3v1 tag to ID3v2 for $file?", 1))
{
set_tag($file, $tag);
}
}
else
{
warn "No ID3 TAG info in $file, creating it";
$tag = {
TIT2 => '',
TPE1 => '',
TALB => '',
TYER => 9999,
COMM => '',
};
}
print "Got tag ", Dumper $tag
if $config->DEBUG();
return $tag;
}
# }}}
|
Tags:perl,mp

