前段時間,在區域網路裡面做一個小網站,其中有板塊是涉及音樂的線上播放。考慮到以後維護的方便,決定把mp3檔案都以專輯分不同的目錄存放。然後使用一個程式監控存放mp3的目錄,把每個mp3檔案的資料存入資料庫中,而用過ASP.NET頁面將mp3檔案的資訊呈現給使用者。其中使用.NET來讀取mp3 檔案的資訊雖然不難,但也需要不少技巧,故將流程整理與大家分享。
首先我們來看看mp3歌曲的資訊所存放的位置。 Mp3檔案包含一個叫做ID3的標籤。其實有兩個標籤,一個叫做ID3v1,另外一個叫做ID3v2。為了講述的簡單起見,我們這裡只介紹ID3v1。
ID3V1結構比較簡單,存放在MP3文件的結尾,大家可以用16進位的編輯器(例如:UltraEdit)開啟一個MP3文件,注意其末尾的128個字節,資料結構定義如下:
名稱 位置 長度 內容
Header 1-3 3 標籤頭
Title 4-33 30 標題
Artist 34-63 30 藝術家
Album 64-93 30 專輯
Year 94-97 4 出品年代
Comment 98-127 30 備註 1re 128Cenre 128Cenre
128Cenre12
注意:上述的標籤頭必須是”TAG”, 否則表示沒有標籤
ID3v1的各項信息是按順序依次存放的,每項信息之後並沒有任何的結束標誌,如果某項信息長度小於標準長度,使用” ”來補充。另外Genre是個例外,它用一個位元組表示歌曲流派,其對應表如下(由於該內容太多,只列出前50項):
0="Blues"
1="ClassicRock"
2="Country"
3="Dance"
4="Disco"
5="Funk"
6="Grunge"
7="Hip-Hop"
8="Jazz"
9=" Metal"
10="NewAge"
11="Oldies"
12="Other"
13="Pop"
14="R&B"
15="Rap"
16="Reggae"
17="Rock"
18="Techno"
19=" Industrial"
20="Alternative"
21="Ska"
22="DeathMetal"
23="Pranks"
24="Soundtrack"
25="Euro-Techno"
26="Ambient"
27="Trip-Hop"
28="Vocal "
29="Jazz+Funk"
30="Fusion"
31="Trance"
32="Classical"
33="Instrumental"
34="Acid"
35="House"
36="Game"
37="SoundClip"
38= "Gospel"
39="Noise"
40="AlternRock"
41="Bass"
42="Soul"
43="Punk"
44="Space"
45="Meditative"
46="InstrumentalPop"
47="InstrumentalRock"
48= "Ethnic"
49="Gothic"
50="Darkwave"
知道了MP3歌曲資訊存放的結構之後,我們就可以寫出對應的程式碼。
首先定一個MP3Info類別:
1 Public Class Mp3Info
2
3
4
5 Private Const TAGLEN As Integer = 128
6
7
8
9 Private _MP3Tag As String = String.Empty
10
11 Private _Artist As String = String.Empty
12
13 Private _Title As String = String.Empty
14
15 Private _Album As String = String.Empty
16
17 Private _Comment As String = String.Empty
18
19 Private _Year As String = String.Empty
20
21 Private _Genre As String = String.Empty
22
23 Private _GenreID As Byte
24
25
26
27 Private Genres() As String = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", _
28
29 "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", _
30
31 "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", _
32
33 "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", _
34
35 "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", _
36
37 "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", _
38
39 "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", _
40
41 "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave", _
42
43 "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", _
44
45 "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Bebob", "Latin", "Revival", _
46
47 "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", _
48
49 "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", _
50
51 "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", _
52
53 "Tango", "Samba", "Folklore"}
54
55
56
57 Public Property MP3Tag() As String
58
59 Get
60
61 Return _MP3Tag
62
63 End Get
64
65 Set(ByVal value As String)
66
67 _MP3Tag = value.Trim
68
69 End Set
70
71 End Property
72
73
74
75 Public Property Title() As String
76
77 Get
78
79 Return _Title
80
81 End Get
82
83 Set(ByVal value As String)
84
85 _Title = value.Trim
86
87 End Set
88
89 End Property
90
91
92
93 Public Property Artist() As String
94
95 Get
96
97 Return _Artist
98
99 End Get
100
101 Set(ByVal value As String)
102
103 _Artist = value.Trim
104
105 End Set
106
107 End Property
108
109
110
111 Public Property Album() As String
112
113 Get
114
115 Return _Album
116
117 End Get
118
119 Set(ByVal value As String)
120
121 _Album = value.Trim
122
123 End Set
124
125 End Property
126
127
128
129 Public Property Comment() As String
130
131 Get
132
133 Return _Comment
134
135 End Get
136
137 Set(ByVal value As String)
138
139 _Comment = value.Trim
140
141 End Set
142
143 End Property
144
145
146
147 Public Property Genre() As String
148
149 Get
150
151 Return _Genre
152
153 End Get
154
155 Set(ByVal value As String)
156
157 _Genre = value.Trim
158
159 End Set
160
161 End Property
162
163
164
165 Public Property GenreID() As Byte
166
167 Get
168
169 Return _GenreID
170
171 End Get
172
173 Set(ByVal value As Byte)
174
175 _GenreID = value
176
177 End Set
178
179 End Property
180
181
182
183 Public Property Year() As String
184
185 Get
186
187 Return _Year
188
189 End Get
190
191 Set(ByVal value As String)
192
193 _Year = value.Trim
194
195 End Set
196
197 End Property
198
199 End Class
200
201
202
203 上面的類別只包含了mp3歌曲資訊對應的資料結構,我們還要為它添加具體讀取mp3檔案資訊的過程:
204
205
206
207 Public Function GetMp3FileInfo(ByVal fname As String) As Boolean
208
209
210
211 'Open the filestream
212
213 Dim msfile As FileStream
214
215 Try
216
217 msfile = New FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
218
219 If Not (msfile.CanRead) Then
220
221 Throw New IO.IOException("無法讀取檔案:" + fname)
222
223 End If
224
225 Catch Ex As Exception
226
227 Throw New IO.IOException("讀取檔案發生錯誤!" + Ex.Message)
228
229 End Try
230
231
232
233 Dim ID3(TAGLEN - 1) As Byte
234
235 Dim BinReader As BinaryReader
236
237 Dim StrInfo As String
238
239
240
241 '使用BinaryReader來讀取訊息
242
243 BinReader = New BinaryReader(msfile)
244
245
246
247 msfile.Position = 0
248
249 msfile.Seek(-TAGLEN, SeekOrigin.End)
250
251
252
253 StrInfo = CBytesToString(BinReader.ReadBytes(3))
254
255
256
257 '判斷標籤頭是否為TAG
258
259 If StrInfo.ToUpper = "TAG" Then
260
261
262
263 '讀取標題信息
264
265 StrInfo = CBytesToString(BinReader.ReadBytes(30)).Replace(Chr(0), "")
266
267 _Title = StrInfo
268
269
270
271 '讀取藝術家信息
272
273 StrInfo = CBytesToString(BinReader.ReadBytes(30)).Replace(Chr(0), "")
274
275 _Artist = StrInfo
276
277
278
279 '讀取專輯信息
280
281 StrInfo = CBytesToString(BinReader.ReadBytes(30)).Replace(Chr(0), "")
282
283 _Album = StrInfo
284
285
286
287 '讀取出版年度信息
288
289 StrInfo = CBytesToString(BinReader.ReadBytes(4)).Replace(Chr(0), "")
290
291 _Year = StrInfo
292
293
294
295 '讀取備註信息
296
297 StrInfo = CBytesToString(BinReader.ReadBytes(30)).Replace(Chr(0), "")
298
299 _Comment = StrInfo
300
301
302
303 '讀取歌曲流派信息
304
305 _GenreID = BinReader.ReadByte
306
307
308
309 End If
310
311
312
313 BinReader.Close()
314
315 msfile.Close()
316
317
318
319 End Function
320
321
322
323 '用於轉換編碼, 防止中文亂碼
324
325 Private Function CBytesToString(ByVal Bytes() As Byte) As String
326
327 '注意這裡需要對編碼進行處理, 防止亂碼
328
329 Dim GbCode As Encoding = Encoding.GetEncoding("gb2312")
330
331 If Bytes.Length > 0 Then
332
333 Return GbCode.GetString(Bytes)
334
335 Else
336
337 Return String.Empty
338
339 End If
340
341 End Function
我們可以用一個簡單的Console程式來說明,如何使用Mp3Info類別。使用Visual Studio 2005 Express,建立一個Console程式:
1 Module Module1
2
3
4
5 Sub
6
7
8
9 Dim Mp3 As New Mp3Info("D:MusicTop 40 Singles39 Embrace - Natures Law.mp3")
10
11
12
13 Console.WriteLine("Title : " + Mp3.Title)
14
15 Console.WriteLine("Artist: " + Mp3.Artist)
16
17 Console.WriteLine("Album : " + Mp3.Album)
18
19 Console.Read()
20
21 End Sub
22
23
24 End Module
執行程式後輸出為:
Title : Nature's Law
Artist: Embrace
Album : DHZ.INC
Genre : Blues
本文只針對mp3的ID3v1進行了討論,而實際上許多mp3不僅包含ID3v1的信息,還包含ID3v2的信息。
但ID3v2要比ID3v1複雜,對於ID3v2的處理,要等下次有空的時候再寫了。