回 帖 发 新 帖 刷新版面

主题:[原创]MP3文件的数据结构以及为mp3内嵌歌词的代码

MP3文件的数据结构以及为mp3内嵌歌词的代码

  MP3文件是由帧构成,帧是 MP3文件的最小组成单位。根据帧性质的不同,文件大体分为四个部分:ID3v2标签帧、数据帧、APEV2标签帧、ID3v1标签帧,而只有数据帧才是必需的。
  数据帧包含了歌曲的压缩数据。标签帧提供了歌曲的演唱者、歌名、专辑、年份等信息。
  ID3v1 在文件结尾,以字符串“TAG”为标识,其长度是固定的 128 个字节。
  ID3v2 在文件头,以字符串“ID3”为标识,长度不固定,扩展了 ID3V1 的信息量。
  APEV2 是最新出现的一种标签,以字符串“APETAGEX”为标识,长度不固定,位置也不固定,可能在文件末尾也可能在文件头,比较常见的是位于文件尾部, 但在 ID3v1 之前。
  值得一提的是 Lyrics3v2,它是千千静听播放器发明的一种独立帧,位于 ID3v1 之前,APEV2 之后(如果有 APEV2 的话),它专用于内嵌 Lrc 类型的歌词文件。


一、ID3V1

表1:ID3V1结构
--------------------------------------------------------------------
名称 字节   说明
--------------------------------------------------------------------
Tag   3   ID3V1标识符“TAG”的Ascii码
Title  30  歌曲名
Artist  30  歌手名
Album  30  专辑名
Year   4   日期信息
Comment 28  注释信息,有时为30字节
Reserved 1   =0说明有音轨,下一字节就是音轨;≠0表示注释是30个字节
Track  1   音轨(字节型数值),歌曲在专辑里的序号 
Genre  1   歌曲风格(字节型数值)
--------------------------------------------------------------------
说明:
  ①如果MP3的注释=30字节,那么就要占用 Reserved 和 Track 两个字节,这要看 Reserved 是否=0,如果=0,那么注释有 28 个字节。如果不是,那么注释有 30 个字节。当注释=30 个字节的时候,那就没有 Track 了。
  ②如果 MP3 文件后面虽然有“TAG”三个字母,但字母后面全是0,那就不是一个合法的 ID3V1 信息,应该认为没有 ID3V1 信息。
  ③ID3V1 的各项信息都是顺序存放,没有任何标识将其分开,一般用 0补足规定的长度。比如歌曲名有 20 个字节,则在歌曲名后要补足 10 个 0,否则将造成信息错误。
  ④歌曲风格共 148 种,用编号表示,表2列出了前 30 种的风格与编号对照,详情可上网查询。

表2:30种歌曲风格与编号对照
---------------------------
编号 风格名称  中译义
---------------------------
00 Blues    布鲁斯
01 ClassicRock 古典摇滚
02 Country   乡村
03 Dance    舞曲
04 Disco    迪斯科
05 Funk     伤感爵士
06 Grunge    垃圾摇滚
07 Hip-Hop   饶舌
08 Jazz     爵士
09 Metal    金属
0A NewAge    前卫
0B Oldies    怀旧
0C Other    其他
0D Pop     流行
0E R&B     摇滚布鲁斯
0F Rap     说唱
10 Reggae    雷盖扭摆舞
11 Rock     摇滚
12 Techno    电子流行乐
13 Industrial  工业
14 Alternative 多变
15 Ska     斯卡
16 DeathMetal  重金属
17 Pranks    恶作剧
18 Soundtrack  电影配音
19 Euro-Techno 神游舞曲
1A Ambient   流行
1B Trip-Hop   迷幻舞曲
1C Vocal    非纯音乐
1D Jazz+Funk  爵士摇滚
1E Fusion    合成音乐
---------------------------


二、ID3V2
  ID3V2 与 ID3V1 的作用差不多,也是记录 mp3 的有关信息,但 ID3V2 的结构比 ID3V1 要复杂得多,而且可以伸缩和扩展。ID3V2 到现在一共有 4 个版本,但流行的播放软件一般只支持第 3 版,既ID3V2.3。由于ID3V1记录在 MP3 文件的末尾,ID3V2 就只好记录在 MP3 文件的首部了。
  每个 ID3V2.3 的标签都一个标签头和若干个标签帧或一个扩展标签头组成。歌曲的信息如标题、作者等都存放在不同的标签帧中,扩展标签头和标签帧并不是必要的,但每个标签至少要有一个标签帧。对于 VB 爱好者来说,你可以把 ID3V2 看作是一个对象,而把标签帧看作是 ID3V2 的一个属性,那么,标签帧的标识符就可以看作是属性名了。

1.D3V2标签头
  一首MP3如果有ID3V2.3的话,那么ID3V2.3的标签头占用文件最前面的10个字节,其数据结构如下:

表3:ID3V2.3标签头结构
--------------------------------------------------------------------
名称  字节  说明
--------------------------------------------------------------------
Header  3    ID3V2.3标识符"ID3"的Ascii码,否则认为没有ID3V2.3
Ver    1  版本号,=03
Revision 1  副版本号,=00
flag   1  标志字节,一般没意义,=00
Size   4  标签内容长度,高位在前,不包括标签头的10个字节
---------------------------------------------------------------------
说明:
  ①Size 字段的计算公式如下(从左至右):
size =字节1的值×&H200000+字节2的值×&H4000+字节3的值×&H80+字节4的值
  ②如果所有标签帧的总长度<标签内容长度,则须用0填满。

2.D3V2标签帧 
  标签内容由若干个标签帧组成。每个标签帧都由一个10个字节的帧头和至少 1个字节的不固定长度的帧内容组成,它们顺序存放在文件中。
  每个帧都由帧头和帧内容组成,数据结构如下:

表4:标签帧的结构
----------------------------------------------------------
名称  字节  说明
----------------------------------------------------------
FrameID 4    帧标识符的Ascii码,常用标识符的意义见表5
Size   4    帧内容及编码方式的合计长度,高位在前
Flags  2    标志,只使用了6位,详见表6,一般均=0
encode  4    帧内容所用的编码方式。许多帧没有此项
帧内容      至少 1 个字节
----------------------------------------------------------
说明:
  ①Size的计算同上。
  ②标签帧之间没有特殊的分隔符,要得到一个完整的标签帧内容必须先从帧头中得到帧内容长度。
    ③encode 有 4 个可能值:
       0:表示帧内容字符用 ISO-8859-1 编码;
       1:表示帧内容字符用 UTF-16LE 编码;
       2:表示帧内容字符用 UTF-16BE 编码;
       3:表示帧内容字符用 UTF-8 编码(仅ID3V2.4才支持)
  但经常看到的是"eng"这样的字符形式,它表示帧内容所使用的自然语言为英语。也许 D3V2 标签帧进化到现在,encode 已经用“自然语言”取代了“编码方式”。
  ⑤帧内容均为字符串,常以 00 开头。

表5:标签帧标识符的意义
---------------------------------------
名称  意义
---------------------------------------
AENC: 音频加密技术
APIC: 附加描述
COMM: 注释,相当于ID3v1的Comment
COMR: 广告
ENCR: 加密方法注册
ETC0: 事件时间编码
GEOB: 常规压缩对象
GRID: 组识别注册
IPLS: 复杂类别列表
MCDI: 音乐CD标识符
MLLT: MPEG位置查找表格
OWNE: 所有权
PRIV: 私有
PCNT: 播放计数
POPM: 普通仪表
POSS: 位置同步
RBUF: 推荐缓冲区大小
RVAD: 音量调节器
RVRB: 混响
SYLT: 同步歌词或文本
SYTC: 同步节拍编码
TALB: 专辑,相当于ID3v1的Album
TBPM: 每分钟节拍数 
TCOM: 作曲家 
TCON: 流派(风格),见表2
TCOP: 版权
TDAT: 日期
TDLY: 播放列表返录 
TENC: 编码 
TEXT: 歌词作者 
TFLT: 文件类型 
TIME: 时间
TIT1: 内容组描述 
TIT2: 标题,相当于ID3v1的Title 
TIT3: 副标题
TKEY: 最初关键字 
TLAN: 语言 
TLEN: 长度 
TMED: 媒体类型 
TOAL: 原唱片集 
TOFN: 原文件名 
TOLY: 原歌词作者
TOPE: 原艺术家
TORY: 最初发行年份 
TOWM: 文件所有者(许可证者) 
TPE1: 艺术家相当于ID3v1的Artist 
TPE2: 乐队
TPE3: 指挥者
TPE4: 翻译(记录员、修改员) 
TPOS: 作品集部分 
TPUB: 发行人 
TRCK: 音轨(曲号),相当于ID3v1的Track
TRDA: 录制日期 
TRSN: Intenet电台名称 
TRSO: Intenet电台所有者 
TSIZ: 大小  
TSRC: ISRC(国际的标准记录代码) 
TSSE: 编码使用的软件(硬件设置) 
TYER: 年代,相当于ID3v1的Year
TXXX: 年度
UFID: 唯一的文件标识符
USER: 使用条款
USLT: 歌词 
WCOM: 广告信息
WCOP: 版权信息
WOAF: 官方音频文件网页
WOAR: 官方艺术家网页
WOAS: 官方音频原始资料网页
WORS: 官方互联网无线配置首页
WPAY: 付款
WPUB: 出版商官方网页
WXXX: 用户定义的URL链接 
---------------------------------------
说明:
  ①帧内容是数字的,都用 Ascii 字符表示。
  ②有的 TCON(风格、流派)的帧内容是直接用字符串表示的,如“genre”,而有的则是用编号表示的,如“28 31 32 29”就是用字符串“(12)”表示 12 号风格,我们在解析的时候要注意。
  ③TRCK(音轨)的帧内容格式是:N/M。其中,分母表示专辑中共有 M 首歌曲,分子表示专辑中的第 N 首曲。

表6:标签帧中Flags标志的意义
----------------------------------------------------
位址 意义
----------------------------------------------------
0  标签保护标志,如设置表示此帧作废
1  文件保护标志,如设置表示此帧作废
2  只读标志,如设置表示此帧不能修改
3  压缩标志,如设置表示1个字节存放2个BCD码表示数字
4  加密标志
5  组标志,如设置表示此帧和其它的某帧是一组
----------------------------------------------------


三、APEV2
  APEV2 的特点是:字符串用 UTF-8 编码;允许给帧标识自由命名。

表7:APEv2标签结构
-------------
名称   字节
-------------
标签头  32
标签帧1  
标签帧2  
...    
标签尾  32  
-------------
说明:个别 APEV2 没有标签尾。

表8:APEV2标签头结构
------------------------------------------------------
名称   字节  说明
------------------------------------------------------
headerID 8   “APETAGEX”的Ascii码
version  4   APEV版本,现在常用APEV2(D0 07 00 00)
Size   4   所有标签帧和标签尾的总长度,低位在前
Count   4   标签帧个数,低位在前
flags   4   填充标记(00 00 00 A0)
reserved 8   保留,全为0
------------------------------------------------------

表9:APEV2标签尾结构
---------------------------------------------------------
名称   字节  说明
---------------------------------------------------------
headerID 8   “APETAGEX”的Ascii码
version  4   APEV版本,现在常用APEV2(D0 07 00 00)
Size   4   标签帧总长度(包括标签尾本身),低位在前
Count   4   标签帧个数,低位在前
flags   4   填充标记(00 00 00 80)
reserved 8   保留,全为0
---------------------------------------------------------

表10:APEV2标签帧结构
-------------------------------------------
名称   字节  说明
-------------------------------------------
Size   4    帧内容长度,低位在前
flags   4    填充标记
ID         帧标识,长度不固定
Pre    1    帧标识的结束字符,恒为0
Value       帧内容,长度由Size确定
-------------------------------------------
说明:APEV2 中,帧内容均为字符串,且均使用 UTF-8 编码。

表11:常用帧标识的意义
-----------------------------
名称     意义
-----------------------------
Album      专辑名
Artist      歌手名
Comment     注释
Composer     作曲家
Copyright    版权
Encoder     编码类型
Genre      风格
Lyric      歌词
Orchestra    乐队
Title      歌曲名
Track      音轨号
WM/AuthorWebpaga 作者网页
WM/BPM
WM/CodedBy    编码依据
WM/EncodedBy   英文编码依据
WM/FileWebpage  文件网页
WM/GenreID    风格编号
WM/OrigArtist  原创艺术家
WM/PromotionURL 推销URL
WM/URL
WM/Writer    作者
WMFSDKVersion  发行版本
WMFSDKNeeded   发行必需
Year       发行日期
-----------------------------
说明:Lyric 帧可以储存带时间参数的歌词,格式为:“[时:分:秒] 歌词 换行符”(类似于 Lrc歌词文件),时和分可以省略,秒可以用小数。

回复列表 (共3个回复)

沙发

四、Lyrics3v2
  MP3 允许把歌词内嵌到文件中,ID3V2 的 USLT 帧、APEV2 的 Lyric 帧都是保存歌词的。但千千静听播放器别出心裁地发明了把 lrc 格式的歌词内嵌到 mp3 文件中,这就是 Lyrics3v2。不过,也有一些 Lyrics3v2 并不含歌词,而是一个可以提供歌词的网址。
  Lyrics3v2 是单独的帧,不依附于任何标签,其位置在 APEv2 标签之后(如果有的话) ID3v1 标签之前,其数据结构见下表:

表12:Lyrics3v2结构
------------------------------------------------------
名称   字节  说明
------------------------------------------------------
开始标识 25  “LYRICSBEGININD00003110LYR”的Ascii码
歌词大小 5   歌词的长度,字符型
歌词   不定  lrc 格式的歌词或歌词网址
帧大小  6   前三项的长度,字符型
结束标识 9   “LYRICS200”的Ascii码
------------------------------------------------------
说明:
  1.Lyrics3v2 从开始标识到结束标识,全部是字符串。
  2.开始标识的前 11 个字节“LYRICSBEGIN”是“歌词开始”的意思,后 14 个字节也许是版本也许是别的什么东东,搞不懂,照写就是了。


  综上所述,大家可以看出,mp3 的各种标签帧并没有统一的标准和严格的规范,给读取信息的代码编写带来了麻烦。
  写到这里,我突发奇想:只要不破坏数据实体,我们可以在数据实体后面存放任何信息,这个信息的结构完全可以由我们自己来制定(让我们也来过一把标准制定者的瘾!),然后我们自编的播放器能解析这些信息。只要我们制定的这些信息标准足够新颖,受到广大 MP3 爱好者的追捧,那么那些大公司就只有降尊屈就地研究我们的标准了!


五、数据实体(MAIN_DATA)
  数据实体由数据帧构成。数据帧分为两种类型:CBR 和 VBR。

1.CBR数据帧的结构
  固定位率的 MP3 文件称作 CBR,大多数 MP3 文件都是 CBR 的。CBR 帧的大小是固定的(公式如上所述),只要知道文件总长度,和帧长即可由播放每帧需 26ms 计算得出播放总时间(注:有些时候,有的帧可能多一个或几个字节)。
  每个数据帧都由帧头和数据实体组成,有的帧在帧头后面还可能有校验值,结构如下:

表12:数据帧的结构
-----------------------------------
名称  字节  说明
-----------------------------------
帧头  4    帧头的结构见表5
校验  2    是否有校验要看帧头的有关位
数据       长度由帧头计算得出
-----------------------------------

  CBR数据帧头的结构:
  帧的数量由文件大小和帧长决定,每个帧的长度可能不固定,也可能固定,由位率决定,每个帧都分为帧头和数据实体两部分,帧头记录了 mp3的位率、采样率、版本等信息,每个帧之间相互独立。
  mp3 数据帧的帧头长 4 字节,对于 CBR 来说,所有帧的帧头格式都一样,把这 4 字节转换为 32 位二进制后,可用这样的符号来表示:AAAAAAAA AAABBCCD EEEEEFGH IIJJKLMM,解释见下表:

表13:数据帧头的结构
------------------------------------------------------------------------------------------
符号 占位 位址  说明
------------------------------------------------------------------------------------------
A   11  31-21  帧同步信息,所有位均=1,第1字节恒为FF
B   2   20-19  版本:11=mp3
C   2   18-17  层次:01=mp3
D   1   16    是否校验:0=是;1=否。如=0,则帧头后有16位校验
E   4   15-12  位率(又称比特率),其值的意义详见表6
F   2   11-10  采样频率,00=44100;01=48000;10=32000;11=保留
G   1   9    是否帧长调节(仅当采样频率=441000时才有效):0=否;1=是
H   1   8    保留
I   2   7-6   声道模式:00=立体声;01=强度立体声;10=双声道;11=单声道
J   2   5-4   扩充模式(仅强度立体声有),表示使用了哪一种joint stereo编码,详见表15
K   1   3    有无版权:0=无;1=有
L   1   2    是否原版:0=否;1=是
M   2   1-0    强调模式:00=无;01=50/15ms;10=保留;11=CCIT J.17
------------------------------------------------------------------------------------------
说明:
  ①无论帧长是多少,每帧的播放时间都是 26ms
  ②数据帧大小计算:数据帧大小=Int((144×位率)/采样频率))+帧长调节。例如:位率=128000,采样频率=44100, 帧长调节=1,那么,帧大小=(144×128000)/44100+1=418 bytes
  ③帧头后面是可变长度的附加信息,对于标准的MP3文件来说,其长度是32字节,紧接其后的是压缩的声音数据,当解码器读到此处时就进行解码了。
  ④歌曲时长=文件大小/位率×8
  ⑤强调模式用于声音经降噪压缩后再补偿的分类,目前还没有使用。

表14:mp3位率值意义
-----------------------------
位值 位率(单位:千比特/秒)
-----------------------------
0000 可变
0001 32
0010 40
0011 48
0100 56
0101 64
0110 80
0111 96
1000 112
1001 128
1010 160
1011 192
1100 224
1101 256
1110 320
1111 不允许出现此值
---------------------------------

表15:强度立体声扩充模式
-------------------------------
位值 Intensity立体声 MS立体声
-------------------------------
00  off        off
01  on        off
10  off        on
11  on        on
-------------------------------

2.VBR数据帧的结构
  可变位率的 MP3 文件称作 VBR(VBR 是 Variable BitRate 的简称),每个帧的长度都可能是变化的,它是 XING 公司推出的算法。
  VBR 以字符串"XING"为标记。标记存放在 MP3文件的第一个有效帧里,同时第一个帧里还存放了帧的总数,这就很容易获得播放总时间,同时还有 100 个字节存放了播放总时间的 100 个时间分段的帧的索引,假设 4 分钟的 MP3 歌曲,240秒,分成 100 段,每两个相邻索引的时间差就是 2.4秒,所以通过这个索引,只要前后处理少数的帧,就能快速找出我们需要快进的帧头。

表16:VBR文件第一数据帧结构
--------------------------------------------------------------------------------------
名称   字节    说明
--------------------------------------------------------------------------------------
帧头    1-4   与CBR相同的标准帧头
标识    5-40   VBR文件标识“Xing”的Ascii码(58 69 6E 67),标识的前后字节均为0
Flags   41-44  标志,说明是否存储了帧数、数据帧长度、帧索引和VBR规模信息
Frames   45-48  帧数(包括第一帧),高位在前
Bytes   49-52  数据帧总长度(不包括所有标签帧的长度),高位在前
Toc    53-152  帧索引,用来按时间进行字节定位,从0开始计数
VBR Scale 153-156 VBR规模,用于位率变动
--------------------------------------------------------------------------------------
说明:
  ①“Xing”标识具体位置视采用的 MPEG 标准和声道模式而定:位于 37-40字节,表示 mp3 立体声;位于 22-25 字节,表示 mp3 单声道。
  ②第 41-44 字节的标志实际上只用了第 44 字节的低 4 位,1=存储了帧数;2=存储了数据帧长度;4=存储了帧索引;8=存储了VBR规模信息,可以相加,如果都存储了,这个值=&HF
  ③有的 VBR 第一个数据帧的帧头后面的 32 个字节都=0,这是为什么呢?原来这个第一帧并不是真正的数据帧,而是 Zone LAME 编码的标志帧。 从 157 字节起的 20 个字节,是 Zone LAME 信息,表示该文件使用了 LAME 编码技术,可以看到字符串“LAME3.93”,(版本号为3.93),在所有数据帧的最后面还会出现一次“LAME3.93”
  ④笔者还看到过用字符串“INFO”为标识的,它的位置的含义与“Xing”一样,在帧头后面也是32个字节的 0,并且帧结构与③完全相同,也有 20 个字节的 LAME 标志帧,字符串是“LAME3.96”。弄不懂这是 CBR 还是 VBR。

板凳

六、读取 ID3V1 信息的代码:
  新建一个工程,在窗体上添加一个文本框(属性MultiLine=Ture),一个组合框,一个按纽。代码如下:

Option Explicit 
 
Dim FileName As String 

Private Sub Form1_Load()
FileName = "D:\100.mp3" 'MP3的全路径文件名
Combo1.AddItem "布鲁斯"
Combo1.AddItem "古典摇滚"
Combo1.AddItem "乡村"
Combo1.AddItem "舞曲"
Combo1.AddItem "迪斯科"
Combo1.AddItem "伤感爵士"
Combo1.AddItem "垃圾摇滚"
Combo1.AddItem "饶舌"
Combo1.AddItem "爵士"
Combo1.AddItem "金属"
'....
'自己添加吧
End Sub

Private Sub Command1_Click()
Dim Tag As String * 3
Dim Title(29) As Byte
Dim artist(29) As Byte
Dim album(29) As Byte
Dim year(3) As Byte
Dim comment() As Byte
Dim genre As Byte
Dim st As String
ReDim comment(29)

Open FileName For Binary As #1
Get #1, LOF(1) - 127, Tag
If Not Tag = "TAG" Then Close #1: Exit Sub
Get #1, , Title
Get #1, , artist
Get #1, , album
Get #1, , year
Get #1, , comment
Get #1, , genre
Close #1

st = "歌曲名:" & StrConv(Title, vbUnicode) & vbCrLf
st = st & "歌手名:" & StrConv(artist, vbUnicode) & vbCrLf
st = st & "专辑名:" & StrConv(album, vbUnicode) & vbCrLf
st = st & "年代:" & StrConv(year, vbUnicode) & vbCrLf
If comment(28) = 0 Then '如果该字节=0,说明注释长度为28字节
  st = st & "音轨:" & Val(comment(29)) & vbCrLf
  ReDim Preserve comment(27)
End If
st = st & "注释:" & StrConv(comment, vbUnicode)
st = Replace(st, Chr(0), "")

Text1 = st
If genre < 148 Then Combo1.ListIndex = genre
End Sub


七、为 mp3 内嵌歌词的代码
  本代码内嵌的歌词,可以被千千静听解析并显示,当然,也应该能被我们自己编写的播放器解析并显示。
  歌词必须是 lrc 格式的(其实也可以是 smi 格式或者其它什么格式,不过那样一来,就只有自编的播放器能够解析了)。

Private Sub Command1_Click()
On Error GoTo 100
Dim mp3Name As String, lrcName As String, mp3_lrc_Name As String
Dim f1 As String, f2 As String, Lyric As String
Dim tem(127) As Byte, dat() As Byte, Lyrics3v2() As Byte, i As Long, L As Long

mp3Name = "E:\100.mp3" '全路径mp3文件名
lrcName = "D:\100.lrc" '全路径lrc文件名
mp3_lrc_Name = "E:\100A.mp3" '内嵌了歌词的全路径mp3文件名

Open lrcName For Input As #1 '读入lrc文件
Do Until EOF(1)
  Line Input #1, f1
  If Len(f1) > 0 Then Lyric = Lyric & f1 & vbCrLf
Loop
Close #1

Open mp3Name For Binary As #2 '读入mp3文件
L = LOF(2)
ReDim dat(L - 1)
Get #2, , dat
Close #2

If dat(L - 128) = 84 And dat(L - 127) = 65 And dat(L - 126) = 71 Then
  For i = 0 To 127: tem(127 - i) = dat(L - i - 1): Next '剥离ID3v1
  ReDim Preserve dat(L - 128)
End If

L = LenB(StrConv(Lyric, vbFromUnicode))
f1 = "LYRICSBEGININD00003110LYR" & Right("0000" & L, 5)
f2 = Right("00000" & (L + 30), 6) & "LYRICS200"
Lyrics3v2 = StrConv(f1 & Lyric & f2, vbFromUnicode)

Open mp3_lrc_Name For Binary As #3
Put #3, , dat
Put #3, , Lyrics3v2
If tem(0) = 84 Then Put #3, , tem
MsgBox "歌词内嵌成功!"
100
Close
End Sub


八、从 mp3 中取出内嵌歌词的函数代码

Private Function resolving(mp3Name As String) As String
Dim Lyrics3v2(9999) As Byte, Mem() As Byte, i As Long, k As Long, j As Long, L As Long, n As Long, BJ As Boolean

Open mp3Name For Binary As #1 '读入mp3文件
L = LOF(1) - 10000
Get #1, , Lyrics3v2
Close #1

Mem = StrConv("LYRICSBEGININD00003110LYR", vbFromUnicode) '定义Lyrics3v2开始标识

For k = 0 To 9955 '查找Lyrics3v2开始标识
  i = 0
  If Lyrics3v2(k) = Mem(i) Then
    n = 1
    For j = k + 1 To k + 24
      i = i + 1: n = n + 1: If Lyrics3v2(j) <> Mem(i) Then Exit For
    Next
    If n = 25 Then BJ = True: Exit For
  End If
Next

If BJ Then '如果有Lyrics3v2
  ReDim Mem(4)
  k = 0
  For i = j To j + 4: Mem(k) = Lyrics3v2(i): k = k + 1: Next '取出歌词长度字符串
  L = Val(StrConv(Mem, vbUnicode)) - 1 '计算歌词长度
  ReDim Mem(L)
  k = 0
  For i = j + 5 To j + 5 + L: Mem(k) = Lyrics3v2(i): k = k + 1: Next '取出歌词
  Dim z As String
  z = StrConv(Mem, vbUnicode)
  If InStr(z, "[") > 0 And InStr(z, "]") > 0 Then resolving = z '转换成字符
End If

End Function

3 楼

[quote]六、读取 ID3V1 信息的代码:
  新建一个工程,在窗体上添加一个文本框(属性MultiLine=Ture),一个组合框,一个按纽。代码如下:

Option Explicit 
 
Dim FileName As String 

Private Sub Form1_Load()
FileName = "D:\100.mp3" 'MP3的全路径文件名
Combo1.AddItem "布鲁斯"
Combo1.AddItem "古典摇滚"
Combo1.AddItem "乡村"
Combo1.AddItem "舞曲"
Combo1.AddItem "迪斯科"
Combo1.AddItem "伤感爵士"
Combo1.AddItem "垃圾摇滚"
Combo1.AddItem "饶舌"
Combo1.AddItem "爵士"
Combo1.AddItem "金属"
'....
'自己添加吧
End Sub

Private Sub Command1_Click()
Dim Tag As String * 3
Dim Title(29) As Byte
Dim artist(29) As Byte
Dim album(29) As Byte
Dim year(3) As Byte
Dim comment() As Byte
Dim genre As Byte
Dim st As String
ReDim comment(29)

Open FileName For Binary As #1
Get #1, LOF(1) - 127, Tag
If Not Tag = "TAG" Then Close #1: Exit Sub
Get #1, , Title
Get #1, , artist
Get #1, , album
Get #1, , year
Get #1, , comment
Get #1, , genre
Close #1

st = "歌曲名:" & StrConv(Title, vbUnicode) & vbCrLf
st = st & "歌手名:" & StrConv(artist, vbUnicode) & vbCrLf
st = st & "专辑名:" & StrConv(album, vbUnicode) & vbCrLf
st = st & "年代:" & StrConv(year, vbUnicode) & vbCrLf
If comment(28) = 0 Then '如果该字节=0,说明注释长度为28字节
  st = st & "音轨:" & Val(comment(29)) & vbCrLf
  ReDim Preserve comment(27)
End If
st = st & "注释:" & StrConv(comment, vbUnicode)
st = Replace(st, Chr(0), "")

Text1 = st
If genre < 148 Then Combo1.ListIndex = genre
End Sub


七、为 mp3 内嵌歌词的代码
  本代码内嵌的歌词,可以被千千静听解析并显示,当然,也应该能被我们自己编写的播放器解析并显示。
  歌词必须是 lrc 格式的(其实也可以是 smi 格式或者其它什么格式,不过那样一来,就只有自编的播放器能够解析了)。

Private Sub Command1_Click()
On Error GoTo 100
Dim mp3Name As String, lrcName As String, mp3_lrc_Name As String
Dim f1 As String, f2 As String, Lyric As String
Dim tem(127) As Byte, dat() As Byte, Lyrics3v2() As Byte, i As Long, L As Long

mp3Name = "E:\100.mp3" '全路径mp3文件名
lrcName = "D:\100.lrc" '全路径lrc文件名
mp3_lrc_Name = "E:\100A.mp3" '内嵌了歌词的全路径mp3文件名

Open lrcName For Input As #1 '读入lrc文件
Do Until EOF(1)
  Line Input #1, f1
  If Len(f1) > 0 Then Lyric = Lyric & f1 & vbCrLf
Loop
Close #1

Open mp3Name For Binary As #2 '读入mp3文件
L = LOF(2)
ReDim dat(L - 1)
Get #2, , dat
Close #2

If dat(L - 128) = 84 And dat(L - 127) = 65 And dat(L - 126) = 71 Then
  For i = 0 To 127: tem(127 - i) = dat(L - i - 1): Next '剥离ID3v1
  ReDim Preserve dat(L - 128)
End If

L = LenB(StrConv(Lyric, vbFromUnicode))
f1 = "LYRICSBEGININD00003110LYR" & Right("0000" & L, 5)
f2 = Right("00000" & (L + 30), 6) & "LYRICS200"
Lyrics3v2 = StrConv(f1 & Lyric & f2, vbFromUnicode)

Open mp3_lrc_Name For Binary As #3
Put #3, , dat
Put #3, , Lyrics3v2
If tem(0) = 84 Then Put #3, , tem
MsgBox "歌词内嵌成功!"
100
Close
End Sub


八、从 mp3 中取出内嵌歌词的函数代码

Private Function resolving(mp3Name As String) As String
Dim Lyrics3v2(9999) As Byte, Mem() As Byte, i As Long, k As Long, j As Long, L As Long, n As Long, BJ As Boolean

Open mp3Name For Binary As #1 '读入mp3文件
L = LOF(1) - 10000
ReDim Lyrics3v2(L)
Get #1, L, Lyrics3v2
Close #1

Mem = StrConv("LYRICSBEGININD00003110LYR", vbFromUnicode) '定义Lyrics3v2开始标识

For k = 0 To L - 45 '查找Lyrics3v2开始标识
  i = 0
  If Lyrics3v2(k) = Mem(i) Then
    n = 1
    If n < 25 Then For j = k + 1 To k + 24: i = i + 1: n = n + Abs(Lyrics3v2(j) = Mem(i)): Next
    If n = 25 Then BJ = True: Exit For
  End If
Next

If BJ Then '如果有Lyrics3v2
  ReDim Mem(4)
  k = 0
  For i = j To j + 4: Mem(k) = Lyrics3v2(i): k = k + 1: Next '取出歌词长度字符串
  L = Val(StrConv(Mem, vbUnicode)) - 1 '计算歌词长度
  ReDim Mem(L)
  k = 0
  For i = j + 5 To j + 5 + L: Mem(k) = Lyrics3v2(i): k = k + 1: Next '取出歌词
  resolving = StrConv(Mem, vbUnicode) '转换成字符
End If
End Function
[/quote]
一江秋水老师好像对文件格式特别有研究!很好嘛!我想能不能给我们讲一下exe文件的基本结构,比如程序图标的偏移,文件大小的说明,文件头信息等等,谢谢了!

我来回复

您尚未登录,请登录后再回复。点此登录或注册