• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • perl與mp3

    發表于:2007-07-04來源:作者:點擊數: 標簽:
    每一位自我陶醉的計算機和音樂愛好者都需要能夠操縱 MP3 —— 娛樂性數字音樂的事實標準。在本文中,Ted 介紹了幾種使用 autotag.pl 應用程序管理和操縱(搜索、標記、重命名和注釋,等等)MP3 的方法。Ted 向讀者詳細介紹了此應用程序,描述了 CPAN 模塊如


    每一位自我陶醉的計算機和音樂愛好者都需要能夠操縱 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 標簽的簡單介紹
    首先有音樂。然后出現計算機。計算機速度很慢且只能發出蜂鳴聲。即使使用諸如 PC 揚聲器這種很令人悲傷的工具(噢,我真希望成為 Apple 和 Amiga 用戶),我們也編寫程序生成音樂,在游戲和娛樂中使用。之后,聲卡越來越好,辦公室里到處發出環繞音響和 THX 認證的揚聲器所發出的震耳欲聾的聲音。

    在硬件發展的同時,也產生了很多聲音格式。.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)中的字符的函數。該函數也會正確地處理未定義的值,盡管在警告打開時,常規表達式在匹配未定義的值時會輸出警告信息。該函數是極為有用的,因為它不顯示警告信息;為了不使用函數而又達到這個目的,您必須檢查是否每次都定義了字符串。

    清單 1. contains_word_char() 函數
    # {{{ contains_word_char: return 1 if the text contains a word charactersub 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 necessarysub 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;}# }}}

    惟一一個稍微與眾不同的函數是 read_yes_no(),可以給它一個 Y 或 1 的默認參數來使默認值為真,任何其他的參數都會使默認值為假。這樣,當用戶按下回車鍵或者空格鍵時,我可以讓 read_yes_no() 函數接受不同的默認值。另外,Backspace 鍵或 Delete 鍵將使默認值反轉。這段代碼不華麗,但很實用。

    autotag.pl 的開頭部分
    應用程序 autotag.pl 以一些初始化例程開始。

    清單 3. 初始化
    use constant SEARCH_ALL => 'all';my %freedb_searches = ( artist => { keywords => [], abbrev => 'I', tagequiv => 'TPE1' }, title => { keywords => [], abbrev => 'T', tagequiv => 'TALB' }, track => { keywords => [], abbrev => 'K', tagequiv => 'TIT2' }, rest => { keywords => [], abbrev => 'R', tagequiv => 'COMM' }, );# maps ID3 v2 tag info to WebService::FreeDB infomy %info2freedb = ( TALB => 'cdname', TPE1 => 'artist', );my %supported_frames = ( TIT1 => 1, TIT2 => 1, TRCK => 1, TALB => 1, TPE1 => 1, COMM => 1, WXXX => 1, TYER => 1, );my @supported_frames = keys %supported_frames;my $term = new Term::ReadLine 'Input> '; # global input

    EARCH_ALL 是一個常數,當用戶想在任何地方搜尋一個詞的時候,比如曲目名、藝術家名等,就會使用它。為了防止有人想把它改為另外某個值,我把它設定為常數,但它也可能已經被硬編碼為“all”。

    %freedb_searches 散列將 FreeDB 字段映射到有關它們的信息上,包括 ID3v2 標簽元素。例如,它說明 FreeDB 怎樣稱呼那些在 MP3 標簽中被稱為“TPE1”的“artist”。在該散列條目中的“abbrev”字段被用來定義命令行開關,這樣,隨后我可以基于 %freedb_searches 信息定義一個 -artist 開關,它可以被簡寫為 -i 。

    %info2freedb 散列將光盤中的所有曲目的 FreeDB 字段都映射到 ID3v2 字段。它們不是 %freedb_searches 中的字段,這是一種不同的映射,它表明,對于一個光盤集的所有曲目而言,“cdname”和 “artists”(也分別被稱為“TALB”和“TPE1”)是相同的。

    我將用 %supported_frames 散列和 @supported_frames 列表來表示我支持哪些 ID3v2 標簽元素。我是從該列表生成了這個散列,而不是從該散列中獲得這個列表(解釋兩者之間的差別離題太遠,所以不再贅述)。大規模加注標簽時,以及在編寫 ID3v2 標簽時,都要用到已獲支持的框架(我只是修改已獲支持的框架而已)。

    最后,為了讓用戶在整個應用程序中輸入數據,我創建了一個 Term::ReadLine 對象。

    下面,我初始化 AppConfig 選項,這樣做雖然加重了我的負擔,但是有益的。

    清單 4. AppConfig 的初始化
    # {{{ set up AppConfig and process -helpmy $config = AppConfig->new();$config->define( DEBUG => { ARGCOUNT => ARGCOUNT_ONE, DEFAULT => 0, ALIAS => 'D' }, CONFIG_FILE => { ARGCOUNT => ARGCOUNT_ONE, DEFAULT => 0, ALIAS => 'F' }, HELP => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0, ALIAS => 'H' }, DUMP => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0 }, ACCEPT_ALL => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0, ALIAS => 'C' }, DRYRUN => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0, ALIAS => 'N' }, GUESS_TRACK_NUMBERS_ONLY => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0, ALIAS => 'G' }, STRIP_COMMENT_ONLY => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0, ALIAS => 'SC' }, MASS_TAG_ONLY => { ARGCOUNT => ARGCOUNT_HASH, ALIAS => 'M' }, RENAME_ONLY => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => 0, ALIAS => 'RO' }, RENAME_MAX_CHARS => { ARGCOUNT => ARGCOUNT_ONE, DEFAULT => 30}, RENAME_FORMAT => { ARGCOUNT => ARGCOUNT_ONE, DEFAULT => '%a-%t-%n-%c-%s.mp3'}, RENAME_BADCHARS => { ARGCOUNT => ARGCOUNT_LIST, ALIAS => 'RB' }, RENAME_REPLACECHARS => { ARGCOUNT => ARGCOUNT_LIST, ALIAS => 'RR' }, RENAME_REPLACEMENT => { ARGCOUNT => ARGCOUNT_ONE, DEFAULT => '_' }, FREEDB_HOST => { ARGCOUNT => ARGCOUNT_ONE, DEFAULT => 'http://www.freedb.org', }, OR => { ARGCOUNT => ARGCOUNT_NONE, DEFAULT => '0', }, SEARCH_ALL() => { ARGCOUNT => ARGCOUNT_LIST, ALIAS => 'A' }, );foreach my $search (keys %freedb_searches){ $config->define($search => { ARGCOUNT => ARGCOUNT_LIST, ALIAS => $freedb_searches{$search}->{abbrev}, });}$config->args();$config->file($config->CONFIG_FILE()) if $config->CONFIG_FILE();unless (scalar @{$config->RENAME_BADCHARS()}){ push @{$config->RENAME_BADCHARS()}, split(//, "\"`!'?&[]()/;\n\t");}unless (scalar @{$config->RENAME_REPLACECHARS()}){ push @{$config->RENAME_REPLACECHARS()}, split(//, " ");}if ($config->HELP()){ print <<EOHIPPUS;$0 [options] File1.mp3 File2.mp3 ...Options: -help (-h) : print this help -config_file (-f) N : use this config file, see AppConfig module docs for format -debug (-d) N : print debugging information (level N, 0 is lowest) -dump : just dump the list of albums and tracks within them -dryrun (-n) : do everything but modify the MP3 files -freedb_host H : set the FreeDB host, default "www.freedb.org" -or : search for keyword A or keyword B, not A and B as usual -aclearcase/" target="_blank" >ccept_all (c) : accept all search results for consideration for each file, also accept all renames without asking -rename_badchars (-rb) A -rb B : characters A and B to remove when renaming -rename_replacechars (-rr) A -rr B : characters A and B to replace when renaming -rename_maxchars N : use at most this many characters from a tag element when renaming, default: ${\$config->RENAME_MAX_CHARS()} -rename_replacement X : character to use when replacing, default: [${\$config->RENAME_REPLACEMENT()}] -rename_format (-f) F : format for renaming; default "${\$config->RENAME_FORMAT()}" %a -> Artist %t -> Track number %n -> Album name %c -> Comment %s -> Song title -guess_track_numbers_only (-g) : guess track numbers using the file name, then exit -rename_only (-ro) : rename tracks using the given format (see -rename_format), then exit -mass_tag_only (-m) A=X -m B=Y : mass-tag files (tag element A is X, B is Y), then exit (tag elements available: @supported_frames) -strip_comment_only (-sc) : strip comments and URLs, then exitRepeatable options (you can specify them more than once, K is the keyword): -all (-a) K : search everywhere -artist (-i) K : search for these artists -title (-t) K : search for these titles -track (-k) K : search for these tracks -rest (-r) K : search for these keywords everywhere elseNote that the repeatable options are cumulative, so artist A and titleB will produce matches for A and B, not A or B. In the same way,artist A and artist B will produce matches for A and B, not A or B.If you want to match A or B terms, use -or, for instance:$0 -or -artist "pink floyd" -artist "fred flintstone"EOHIPPUS exit;}# }}}

    是的,所有這些代碼都是初始化命令行選項的。通過使用 AppConfig,可以在整個程序中使用和修改這些選項。使用 AppConfig 還有很多好處,不過這些內容超出了本文的范圍(有關 AppConfig 的更多信息,請參閱參考資料)。

    另外,我還使用 %freedb_searches 散列中的條目來創建合適的配置選項,這樣可以使用戶和程序員更輕松一些。

    在加載配置文件以后,如果用戶指定了它,那么就用有意義的默認值來植入字符置換數組和不良字符數組。

    最后,處理 -help 開關。注意,通過變量插入不同選項的默認值是如何在幫助文本內打印出來大的。這樣就形成了可讀性非常強的幫助信息。我總是在增加新的特性之后(但有時候是在之前)立即更新幫助信息。我認為,幫助文本應該和程序的功能同步,否則人們將不理解程序,也不知道幫助文本說了些什么。autotag.pl 程序特別需要更多的文檔說明,POD 風格的文檔應該比較合適。在您閱讀本文時,這樣的文檔可能已經有了。POD 文檔是腳本的一部分,因此下載的 autotag.pl(請參閱參考資料)將包括 POD 文檔(如果我已經將它寫入的話)。

    與 ID3v2 標簽相關的函數
    get_tag() 函數是 autotag.pl 的基本函數。給出一個 MP3 文件名,它就會根據該文件構建一個散列標簽。如果標簽只是 ID3v1 標簽, get_tag() 函數將會免費把它升級為 ID3 標簽(多么好的交易?。?。如果沒有 ID3 標簽,get_tag() 函數將創建一個。而且,get_tag() 知道分別查看 COMM 和 WXXX 元素的 Text 和 URL 子元素。

    清單 5. get_tag() 函數
    # {{{ get_tag: get a ID3 V2 tag, using V1 if necessarysub 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;}# }}}

    set_tag() 函數是 get_tag() 函數的兄弟。它編寫 ID3v2 標簽,查看 COMM 和 WXXX 框架的子元素。它接受散列引用,比如 get_tag() 函數可能產生的那些散列引用。

    清單 6. set_tag() 函數
    # {{{ set_tag: set a ID3 V2 tag on a filesub set_tag{ my $file = shift @_; my $tag = shift @_; my $mp3 = MP3::Tag->new($file); print Dumper $tag; my $tags = $mp3->get_tags(); my $id3v2; if (ref $tags eq 'HASH' && exists $tags->{ID3v2}) { $id3v2 = $tags->{ID3v2}; } else { $id3v2 = $mp3->new_tag("ID3v2"); } my %old_frames = %{$id3v2->get_frame_ids()}; foreach my $fname (keys %$tag) { $id3v2->remove_frame($fname) if exists $old_frames{$fname}; if ($fname eq 'WXXX') { $id3v2->add_frame('WXXX', 'ENG', 'FreeDB URL', $tag->{WXXX}) ; } elsif ($fname eq 'COMM') { $id3v2->add_frame('COMM', 'ENG', 'Comment', $tag->{COMM}) ; } else { $id3v2->add_frame($fname, $tag->{$fname}); } } $id3v2->write_tag(); return 0;}# }}}

    print_tag_info() 函數簡單地打印輸出標簽的摘要。不像我在 autotag.pl 程序中的其他地方使用的 Data::Dumper 函數(必須指出,有時沒有必要使用),print_tag_info() 函數可以提供漂亮的、面向用戶的散列標簽元素的打印輸出。注意,該函數接受散列引用,而不是實際的文件名。

    給出文件名和某些可能的 ID3 標簽信息,guess_track_number() 函數和guess_artist_and_track() 函數會盡力工作。注意,guess_track_number() 函數知道曲目的數量很少大于 30。

    清單 7. print_tag_info()、 guess_track_number()、和 guess_artist_and_track() 函數
    # {{{ print_tag_info: print the tag infosub print_tag_info{ my $filename = shift @_; my $tag = shift @_; my $extra = shift @_ || 'Track info'; # argument checking return unless ref $tag eq 'HASH'; print "$extra for '$filename':\n"; foreach (keys %$tag) { printf "%10s : %s\n", $_, $tag->{$_}; }}# }}}# {{{ guess_track_number: guess track number from ID3 tag and file namesub guess_track_number{ my $filename = shift @_; my $tag = shift @_ || return undef; $filename = basename($filename); # directories can contain confusing data # first try to guess the track number from the old tag if (exists $tag->{TRCK} && contains_word_char($tag->{TRCK})) { my $n = $tag->{TRCK} + 0; # fix tracks like 1/10 return $n; } elsif ($filename =~ m/([012]?\d).*\.[^.]+$/) # now look for numbers in the filename (0 through 29) { print "Guessed track number $1 from filename '$filename'\n" if $config->DEBUG(); return $1; } return undef; # if all else fails, return undef}# }}}# {{{ guess_artist_and_track: guess artist and track from file namesub guess_artist_and_track{ my $filename = shift @_; my $artist; my $track; $filename = basename($filename); # directories can contain confusing data if ($filename =~ m/([^-_]{3,})\s*-\s*(.{3,})\s*\.[^.]+$/) { print "Guessed artist $1 from filename '$filename'\n" if $config->DEBUG(); $artist = $1; $track = $2; } return ($artist, $track);}# }}}

    我使用從 FreeDB 搜索中返回的數據來生成帶有適當元素的匿名散列。雖然 WebService::FreeDB 字段和 ID3v2 標簽元素之間的映射是試驗性的,但它工作得很好。

    清單 8. make_tag_from_freedb() 函數
    # {{{ make_tag_from_freedb: make the ID3 tag info from a FreeDB entrysub make_tag_from_freedb{ my $disc = shift @_; my $track = shift @_; # argument checking return undef unless $track =~ m/^\d+$/; # note that the user inputs track "1" but WebService::FreeDB gives us that # track at position 0, so we decrement $track $track--; return undef unless exists $disc->{trackinfo}; return undef unless exists $disc->{trackinfo}->[$track]; my $track_data = $disc->{trackinfo}->[$track]; return { TIT1 => $disc->{genre}, TIT2 => $track_data->[0], TRCK => $track+1, TPE1 => $disc->{artist}, TALB => $disc->{cdname}, TYER => $disc->{year}, WXXX => $disc->{url}, COMM => $disc->{rest}||'', };}# }}}

    大規模加注標簽、大規模重命名、剝離注釋和猜測曲目數量
    autotag.pl 的主要功能是識別 MP3 文件。但在這個過程中,往往需要對很多組文件進行小的調整。輸入 Four Autotagging Horsemen。

    剝離注釋是非常簡單的過程。我使用 get_tag() 獲得散列標簽,清空 COMM 和 WXXX 字段,以及使用 set_tag() 將該標簽寫回。實際上,注釋剝離可能已經通過大規模標簽加注完成了,但這個函數使用得非常頻繁,以至于使我感到有必要為它設置一個獨立的選項。

    猜測曲目數量也使相當簡單的。獲取散列標簽,在該文件和散列標簽上使用 guess_track_number() 函數,請求確認,然后將該標簽寫回到文件中。

    在一系列文件上對多個鍵(例如 TALB)進行大規模標簽加注操作。例如:

    autotag.pl -mt "TALB=Best" *.mp3

    于是,所有具有 mp3 擴展名的文件都在其 ID3v2 標簽中指定了 TALB 值。當您擁有某個藝術家的全部樂曲的目錄時,以及希望用該藝術家的名字標記所有這些樂曲時,采用大規模標簽加注的方式是非常合適的。只有受支持的標簽元素才可以大規模加注標簽。再一次進行這樣的過程:獲取散列標簽、進行修改,然后將它寫回。這樣做目的是使它的維護簡單便利。

    清單 9. 大規模加注標簽、注釋剝離和猜測曲目數量
    # {{{ handle the one-shot optionsif ($config->GUESS_TRACK_NUMBERS_ONLY() || $config->STRIP_COMMENT_ONLY() || scalar keys %{$config->MASS_TAG_ONLY()}){ foreach my $file (@ARGV) { my $tag = get_tag($file, 1); unless (defined $tag) { warn "No ID3 TAG info in '$file', skipping"; next; } next if $config->DRYRUN(); # delegate stripping comments to the mass tagging function if ($config->STRIP_COMMENT_ONLY()) { $config->MASS_TAG_ONLY()->{COMM} = ''; $config->MASS_TAG_ONLY()->{WXXX} = ''; } if (scalar keys %{$config->MASS_TAG_ONLY()}) { foreach (keys %{$config->MASS_TAG_ONLY()}) { unless (exists $supported_frames{$_}) { warn "Unsupported tag element $_ requested for mass tagging, skipping"; next; } $tag->{$_} = $config->MASS_TAG_ONLY()->{$_}; } set_tag($file, $tag); } else { my $track_number_guess = guess_track_number($file, $tag); next if $config->DRYRUN(); if (defined $track_number_guess && read_yes_no("Is track number $track_number_guess OK for '$file'?", 1)) { $tag->{TRCK} = $track_number_guess; set_tag ($file, $tag); } else { warn "Could not guess a track number for file $file, sorry"; } } } exit 0;}# }}}

    噢,該介紹大規模重命名選項了。我之所以將這個問題留在最后,是因為這個問題最復雜。對于每個重命名參數而言,我將標簽值中的每個“%”都表示為“{{{%}}}”,因為不這樣的話,當后面跟隨一個特殊的重命名參數時,“%”字符就可能被曲解。例如,用“100%true”作為曲目名,我們來看一看它如何變成“100%TRACKNAMErue”的,這里 TRACKNAME 是我從該散列標簽中獲取的曲目名。

    大規模重命名也可消除不良的字符,代之以某些帶有“_”的字符,以確保文件名合理。最后,除非通過命令行給出 -c(accept_all)選項,否則 autotag.pl 將詢問是否可以對文件重命名。

    清單 10. 大規模重命名
    # {{{ handle the -rename_only optionif ($config->RENAME_ONLY()){ foreach my $file (@ARGV) { my $tag = get_tag($file, 1); # the extra parameter will ask us about upgrading V1 to V2 unless (defined $tag) { warn "No ID3 TAG info in '$file', skipping"; next; } my %map = ( '%c' => 'COMM', '%s' => 'TIT2', '%a' => 'TPE1', '%t' => 'TALB', '%n' => 'TRCK', ); my $name = $config->RENAME_FORMAT(); foreach my $key (keys %map) { my $tagkey = $map{$key}; my $replacement = ''; if (exists $tag->{$tagkey}) { $replacement = substr $tag->{$tagkey}, 0, $config->RENAME_MAX_CHARS(); # limit to N characters if ($tagkey eq 'TRCK' && $replacement =~ m/^\d$/) { $replacement = "0$replacement"; } } $replacement =~ s/%/{{{%}}}/g; # this is how we preserve %a in the fields, for example $name =~ s/$key/$replacement/; } $name =~ s/{{{%}}}/%/g; # turn the {{{%}}} back into % in the fields print "The name after % expansion is $name\n" if $config->DEBUG(); foreach my $char (map { quotemeta } @{$config->RENAME_BADCHARS()}) { $name =~ s/$char//g; } print "The name after character removals is $name\n" if $config->DEBUG(); my $newchar = quotemeta $config->RENAME_REPLACEMENT(); foreach my $char (map { quotemeta } @{$config->RENAME_REPLACECHARS()}) { $name =~ s/$char/$newchar/eg; } print "The name after character replacements is $name\n" if $config->DEBUG(); if ($name eq $file) { # do nothing print "Renaming $file is unnecessary, it already answers to our high standards\n" if $config->DEBUG(); } elsif (-e $name) { warn "Could not use name $name, it's already taken by an existing file or directory $file"; } elsif ($config->ACCEPT_ALL() || read_yes_no("Is name $name OK for '$file'?", 1)) { next if $config->DRYRUN(); print "Renaming $file -> $name\n"; rename($file, $name); } else { # do nothing } } exit 0;}# }}}

    結束語
    本文的第 2 部分將討論 autotag.pl 的主循環,介紹該程序的一般用法。

    參考資料

    閱讀 Ted 在 developerWorks 上的“功能豐富的 Perl”系列中的所有 Perl 文章。

    下載 autotag application(為了運行該文件,請重命名為 autotag.pl)。

    The CPAN module archive 包含很多有用的 Perl 程序。

    Ted 在專有的 CDDB / Gracenote 上選擇免費的 FreeDB project 作為后端數據庫。

    可以在 Open Directory 中找到有關很多不同 音頻格式 (包括 MIDI、MP3 和 Ogg Vorbis)的資源。

    如果您在使用 Term:Readline:Perl 時曾經遇到過麻煩,請嘗試使用 Term:Readline:GNU。

    id3lib library 是用于讀、寫和操縱 ID3v1 和 ID3v2 標簽的。

    MP3::Tag CPAN module 是用于讀 MP3 音頻文件的標簽的。

    Webservice::FreeDB CPAN module 通過搜索關鍵字從 FreeDB 中獲取條目。

    MP3::ID3Lib CPAN module 使得您可以在 MP3 文件中編輯和添加 ID3 標簽 。

    CPAN bundle 安裝 MusicBrainz 客戶機和所要求的模塊。

    AudioFile-Identify-MusicBrainz 是 MusicBrainz 服務的另一種 CPAN 接口,是純 Perl 的 MusicBrainz 客戶機實現。

    IBM developerWorks 的文章“Thinking XML: Manage metadata with MusicBrainz”討論了 MusicBrainz 服務的元數據問題。

    AppConfig 是用于管理應用程序配置信息的 Perl5 模塊。

    在 Ted 的專欄“Application configuration with Perl”中可以了解更多有關 AppConfig 的信息。

    喜歡玩音響嗎?在 IBM developerWorks 的文章“Introducing XHTML + Voice -- IBM's proposal to the W3C on developing multimodal UIs”和“Multimodal applications”中,可以了解更多有關啟動聲音設備的內容。

    您可能希望閱讀 IBMalphaWorks 上的文章 Voice Toolkit Preview。

    噢,試一下Music Sketcher 吧,這是一個圖形化的作曲工具,它是由 IBM Research 的多媒體專家編寫的。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>