主题:[原创]制作 smi 字幕文件的方法
制作 smi 字幕文件的方法
微软的媒体播放器 wmplayer 使用 smi 字幕文件,可以使字幕与唱词同步。先来了解一下 smi 文件的基本结构:
<SAMI>
<head>
<style type="text/css"><!--
p {font-size:24pt;font-family:楷体_GB2312;}
.FRCC {lang: ZH-CN;}-->
</style>
</head>
<body>
<sync start=10><p class=EGCC>敖包相会(歌手:张振富、耿莲凤)
<sync start=25158><p class=EGCC>(男)十五的月亮升上了天空哎
……
</body>
</SAMI>
可以看出,smi 文件是用超文本语言写的。注意二点:
1.“start=****”时间参数,是以毫秒为单位的。
2.“{font-size:24pt;font-family:楷体_GB2312;}”这里只有2个参数,分别是字体大小和字体名称。还可以写成这样:
{ background-color: #000000; text-align: center; font-size: 24pt; font-family: 宋体; font-weight: bold; }
参数1:可选,字幕条的背景颜色为黑色,缺省为黑色。
参数2:可选,文本显示位置为窗口中央,缺省为左。
参数3:字体大小。
参数4:字体名称。
参数5:可选,字体重量为粗体。
参数的顺序没有严格要求,但必须以分号分隔。
下面介绍两种制作 smi 文件的方法。
一、使用 txt 歌词文件
如果我们用 MMControl 控件制作了一个播放器,利用该控件的 Position 属性,我们就可以实时制作 smi 字幕文件。当然,你还必须要有同名的 txt 歌词文件,这可以在网上下载,也可以自己编制。
MMControl 控件的 Position属性的作用是:根据指定的 TimeFormat 返回已打开的设备的位置,一般用四字节表示,只读。在使用 Position 属性之前,要先设置属性 TimeFormat=0,这样 Position属性返回的时间单位就是毫秒。
新建一个工程,在窗体上添加一个 MMControl 控件(将其名称改为MMC),一个 CommonDialog 控件、三个按纽、一个标签(标签的作用是显示当前的歌词),属性设置为:
MMControl 控件:在属性页中将所有的自带按纽均设置为无效和不可见。
三个按纽控件的名称与标题相同,分别为:openTXT、playMCI、txtTOsmi。
代码如下:
Option Explicit
Dim lrcST As String, smiST As String, txtST As String
Private Sub playMCI_Click()
CommonDialog1.Filter = "*.mp3;*.wma|*.mp3;*.wma"
With MMC
.FileName = openFile(1)
.Command = "Open"
.TimeFormat = 0 '时间格式为毫秒
.Notify = True '打开通知
.Command = "play"
End With
End Sub
Private Sub MMC_Done(NotifyCode As Integer)
If NotifyCode = 1 Then '如果播放完毕
MMC.Command = "stop"
MMC.Command = "close"
End If
End Sub
Private Sub openTXT_Click()
CommonDialog1.Filter = "txt 歌词文件(*.txt)|*.txt"
txtST = openFile(0)
End Sub
Private Sub txtTOsmi_Click()
Dim k1 As Long, t As Long
If Len(txtST) < 2 Then
saveFile
Exit Sub
End If
t = MMC.Position '取得播放时间位置
k1 = InStr(txtST, "~")
Label1 = Left$(txtST, k1 - 1)
txtST = Mid$(txtST, k1 + 1)
smiST = smiST & "<sync start=" & t & "><p class=EGCC>" & Label1.Caption & "~"
End Sub
Private Function openFile(bj As Boolean) As String
On Error GoTo 100
CommonDialog1.Flags = &H1808
CommonDialog1.DialogTitle = "打开文件"
CommonDialog1.ShowOpen
If Dir(CommonDialog1.FileName) = "" Then Exit Function
If bj Then openFile = CommonDialog1.FileName: Exit Function
Dim z As String, st As String
Open CommonDialog1.FileName For Input As #1
Do Until EOF(1)
Line Input #1, z
If Len(z) > 0 Then st = st & z & "~" '用这个不常用的字符"~"作为歌词句的分隔符
Loop
smiST = "": openFile = st
100
Close
End Function
Private Sub saveFile() '保存smi文件
On Error GoTo 100
CommonDialog1.DialogTitle = "保存"
CommonDialog1.Filter = "smi 文件(*.smi)|*.smi|"
CommonDialog1.Flags = &H200A
CommonDialog1.ShowSave
If CommonDialog1.FileName = "" Then Exit Sub
Dim st As String
smiST = "<SAMI><head>" & vbCrLf & "<style type=" & Chr(34) & "text/css" & Chr(34) & _
"><!--" & vbCrLf & "p {font-size:24pt;font-family:楷体_GB2312;}" & vbCrLf & _
".FRCC {lang: ZH-CN;}" & "--></style></head>" & vbCrLf & "<body>" & vbCrLf & _
smiST & "</body></SAMI>"
st = Replace(smiST, "~", vbCrLf)
Open CommonDialog1.FileName For Output As #1
Print #1, st
100
Close
End Sub
使用方法:首先点击【openTXT】,打开有关的 TXT 歌词文件,然后点击【playMCI】,这时候你就要认真听,当听到歌手将要唱到下一句时,就用鼠标点一下【txtTOsmi】,这样边听边点击地操作,一直到整首歌曲唱完,最后保存。如果不小心,某一句的时间误差太大,还可以用记事本打开 smi 文件修改。
二、利用 lrc 文件转换
这个就要简单多了,因为 lrc 文件已经包括了时间参数。还有个好处是可以批量操作。
在窗体上再添加二个按纽,名称与标题相同,分别为:openLRC、lrcTOsmi。
添加如下代码:
Private Sub openLRC_Click()
CommonDialog1.Filter = "Lrc 歌词文件(*.lrc)|*.lrc"
lrcST = openFile(0)
End Sub
Private Sub lrcTOsmi_Click()
Dim k1 As Long '歌词句在文件中的起始位置
Dim k2 As Long '歌词句的长度
Dim t As Long
Dim s As String, z As String
k1 = 1: k2 = InStr(k1, lrcST, "~")
Do While k2 > 0 '如果有"~"字符就继续循环
z = Mid$(lrcST, k1, k2 - k1) '从歌词句中取出含有方括号的字串
k1 = k2 + 1 '设置下一歌词句在文件中的起始位置
s = Mid$(z, 2, InStr(z, "]") - 2) '取出去掉了方括号的字串
If IsNumeric(Left$(s, 2)) Then '如果是时间字串
t = Val(s) * 60000 + Val(Mid$(s, 4)) * 1000 '将时间字串转换为毫秒
smiST = smiST & "<sync start=" & t & "><p class=EGCC>" & Mid$(z, InStr(z, "]") + 1) & "~"
End If
k2 = InStr(k1, lrcST, "~")
Loop
saveFile
End Sub
使用方法:首先点击【openLRC】,打开有关的 lrc 歌词文件,然后点击【lrcTOsmi】,几乎是眨
眼间,就已经转换完毕,最后保存。
参考:
smi 字幕可以在 wmplayer 播放器窗口显示二行,相当于预告下一句的内容。这两行的颜色可以不相同,例如:
……
<sync start=10><p class=EGCC><font color=#FFFFFF>十送红军(江西民歌)</font><br><font color=#6888E0>一送(里格)红军,(介支个)下了山,</font>
<sync start=17180><p class=EGCC><font color=#6888E0>秋风(里格)细雨,(介支个)缠绵绵。</font><br><font color=#FFFFFF>一送(里格)红军,(介支个)下了山,</font>
……
代码中超文本标记的意义:
<font color=#FFFFFF>:定义紧随其后的字体颜色,颜色可以是6位16进制数值(前面要加一个“#”字符),也可以是超文本语言的颜色常数(相当于 VB 的颜色常数),例如:black(黑色)、olive(橄榄色)、teal(鸭绿)等等,共 16 种颜色。
</font>:先前有关字体的定义到此为止,后面如果没有再次定义,将恢复默认定义。
<br>:相当于 VB 中的回车换行符。
大家如有兴趣,请自行研究制作方法,并不难。
附:在自制播放器中使用 smi 字幕文件的方法
在窗体上再添加一个计时器控件,Inteval = 20,Enabled = False。
歌词就使用刚制作好的 smi 文件(当然,你也可以再增加一个【openSMI】按纽,请自编代码)。
增加一个模块级变量:
Dim BJMode As Boolean 'True-显示歌词;False-制作歌词
Dim posit As Long 'smi文件中的时间参数位置
在 Sub saveFile() 过程后面增加一句:BJMode = True
在 Function openFile 函数后面增加一句:BJMode = False
在 Sub playMCI_Click 过程后面增加一句:If BJMode Then posit = 1: Timer1.Enabled = True
编写 Timer1_Timer 过程代码:
Private Sub Timer1_Timer()
Dim t As Long, k1 As Long, k2 As Long
If posit > Len(smiST) - 15 Then Timer1.Enabled = False: Exit Sub
k1 = InStr(posit, smiST, "start=") '查找时间字串
t = Val(Mid$(smiST, k1 + 6, 8)) '取出时间
If Abs(MMC.Position - t) < 200 Then '如果歌词与播放进度的时间差小于200毫秒
k1 = InStr(k1, smiST, "EGCC>") '查找歌词文本起点
k2 = InStr(k1, smiST, "~") '查找歌词文本终点
Label1 = Mid$(smiST, k1 + 5, k2 - k1 - 5) '取出歌词字串显示在标签上
posit = k2 + 1
End If
End Sub
使用方法:制作完成 smi 文件后,再点击【playMCI】按纽即可。
2011.6.27
微软的媒体播放器 wmplayer 使用 smi 字幕文件,可以使字幕与唱词同步。先来了解一下 smi 文件的基本结构:
<SAMI>
<head>
<style type="text/css"><!--
p {font-size:24pt;font-family:楷体_GB2312;}
.FRCC {lang: ZH-CN;}-->
</style>
</head>
<body>
<sync start=10><p class=EGCC>敖包相会(歌手:张振富、耿莲凤)
<sync start=25158><p class=EGCC>(男)十五的月亮升上了天空哎
……
</body>
</SAMI>
可以看出,smi 文件是用超文本语言写的。注意二点:
1.“start=****”时间参数,是以毫秒为单位的。
2.“{font-size:24pt;font-family:楷体_GB2312;}”这里只有2个参数,分别是字体大小和字体名称。还可以写成这样:
{ background-color: #000000; text-align: center; font-size: 24pt; font-family: 宋体; font-weight: bold; }
参数1:可选,字幕条的背景颜色为黑色,缺省为黑色。
参数2:可选,文本显示位置为窗口中央,缺省为左。
参数3:字体大小。
参数4:字体名称。
参数5:可选,字体重量为粗体。
参数的顺序没有严格要求,但必须以分号分隔。
下面介绍两种制作 smi 文件的方法。
一、使用 txt 歌词文件
如果我们用 MMControl 控件制作了一个播放器,利用该控件的 Position 属性,我们就可以实时制作 smi 字幕文件。当然,你还必须要有同名的 txt 歌词文件,这可以在网上下载,也可以自己编制。
MMControl 控件的 Position属性的作用是:根据指定的 TimeFormat 返回已打开的设备的位置,一般用四字节表示,只读。在使用 Position 属性之前,要先设置属性 TimeFormat=0,这样 Position属性返回的时间单位就是毫秒。
新建一个工程,在窗体上添加一个 MMControl 控件(将其名称改为MMC),一个 CommonDialog 控件、三个按纽、一个标签(标签的作用是显示当前的歌词),属性设置为:
MMControl 控件:在属性页中将所有的自带按纽均设置为无效和不可见。
三个按纽控件的名称与标题相同,分别为:openTXT、playMCI、txtTOsmi。
代码如下:
Option Explicit
Dim lrcST As String, smiST As String, txtST As String
Private Sub playMCI_Click()
CommonDialog1.Filter = "*.mp3;*.wma|*.mp3;*.wma"
With MMC
.FileName = openFile(1)
.Command = "Open"
.TimeFormat = 0 '时间格式为毫秒
.Notify = True '打开通知
.Command = "play"
End With
End Sub
Private Sub MMC_Done(NotifyCode As Integer)
If NotifyCode = 1 Then '如果播放完毕
MMC.Command = "stop"
MMC.Command = "close"
End If
End Sub
Private Sub openTXT_Click()
CommonDialog1.Filter = "txt 歌词文件(*.txt)|*.txt"
txtST = openFile(0)
End Sub
Private Sub txtTOsmi_Click()
Dim k1 As Long, t As Long
If Len(txtST) < 2 Then
saveFile
Exit Sub
End If
t = MMC.Position '取得播放时间位置
k1 = InStr(txtST, "~")
Label1 = Left$(txtST, k1 - 1)
txtST = Mid$(txtST, k1 + 1)
smiST = smiST & "<sync start=" & t & "><p class=EGCC>" & Label1.Caption & "~"
End Sub
Private Function openFile(bj As Boolean) As String
On Error GoTo 100
CommonDialog1.Flags = &H1808
CommonDialog1.DialogTitle = "打开文件"
CommonDialog1.ShowOpen
If Dir(CommonDialog1.FileName) = "" Then Exit Function
If bj Then openFile = CommonDialog1.FileName: Exit Function
Dim z As String, st As String
Open CommonDialog1.FileName For Input As #1
Do Until EOF(1)
Line Input #1, z
If Len(z) > 0 Then st = st & z & "~" '用这个不常用的字符"~"作为歌词句的分隔符
Loop
smiST = "": openFile = st
100
Close
End Function
Private Sub saveFile() '保存smi文件
On Error GoTo 100
CommonDialog1.DialogTitle = "保存"
CommonDialog1.Filter = "smi 文件(*.smi)|*.smi|"
CommonDialog1.Flags = &H200A
CommonDialog1.ShowSave
If CommonDialog1.FileName = "" Then Exit Sub
Dim st As String
smiST = "<SAMI><head>" & vbCrLf & "<style type=" & Chr(34) & "text/css" & Chr(34) & _
"><!--" & vbCrLf & "p {font-size:24pt;font-family:楷体_GB2312;}" & vbCrLf & _
".FRCC {lang: ZH-CN;}" & "--></style></head>" & vbCrLf & "<body>" & vbCrLf & _
smiST & "</body></SAMI>"
st = Replace(smiST, "~", vbCrLf)
Open CommonDialog1.FileName For Output As #1
Print #1, st
100
Close
End Sub
使用方法:首先点击【openTXT】,打开有关的 TXT 歌词文件,然后点击【playMCI】,这时候你就要认真听,当听到歌手将要唱到下一句时,就用鼠标点一下【txtTOsmi】,这样边听边点击地操作,一直到整首歌曲唱完,最后保存。如果不小心,某一句的时间误差太大,还可以用记事本打开 smi 文件修改。
二、利用 lrc 文件转换
这个就要简单多了,因为 lrc 文件已经包括了时间参数。还有个好处是可以批量操作。
在窗体上再添加二个按纽,名称与标题相同,分别为:openLRC、lrcTOsmi。
添加如下代码:
Private Sub openLRC_Click()
CommonDialog1.Filter = "Lrc 歌词文件(*.lrc)|*.lrc"
lrcST = openFile(0)
End Sub
Private Sub lrcTOsmi_Click()
Dim k1 As Long '歌词句在文件中的起始位置
Dim k2 As Long '歌词句的长度
Dim t As Long
Dim s As String, z As String
k1 = 1: k2 = InStr(k1, lrcST, "~")
Do While k2 > 0 '如果有"~"字符就继续循环
z = Mid$(lrcST, k1, k2 - k1) '从歌词句中取出含有方括号的字串
k1 = k2 + 1 '设置下一歌词句在文件中的起始位置
s = Mid$(z, 2, InStr(z, "]") - 2) '取出去掉了方括号的字串
If IsNumeric(Left$(s, 2)) Then '如果是时间字串
t = Val(s) * 60000 + Val(Mid$(s, 4)) * 1000 '将时间字串转换为毫秒
smiST = smiST & "<sync start=" & t & "><p class=EGCC>" & Mid$(z, InStr(z, "]") + 1) & "~"
End If
k2 = InStr(k1, lrcST, "~")
Loop
saveFile
End Sub
使用方法:首先点击【openLRC】,打开有关的 lrc 歌词文件,然后点击【lrcTOsmi】,几乎是眨
眼间,就已经转换完毕,最后保存。
参考:
smi 字幕可以在 wmplayer 播放器窗口显示二行,相当于预告下一句的内容。这两行的颜色可以不相同,例如:
……
<sync start=10><p class=EGCC><font color=#FFFFFF>十送红军(江西民歌)</font><br><font color=#6888E0>一送(里格)红军,(介支个)下了山,</font>
<sync start=17180><p class=EGCC><font color=#6888E0>秋风(里格)细雨,(介支个)缠绵绵。</font><br><font color=#FFFFFF>一送(里格)红军,(介支个)下了山,</font>
……
代码中超文本标记的意义:
<font color=#FFFFFF>:定义紧随其后的字体颜色,颜色可以是6位16进制数值(前面要加一个“#”字符),也可以是超文本语言的颜色常数(相当于 VB 的颜色常数),例如:black(黑色)、olive(橄榄色)、teal(鸭绿)等等,共 16 种颜色。
</font>:先前有关字体的定义到此为止,后面如果没有再次定义,将恢复默认定义。
<br>:相当于 VB 中的回车换行符。
大家如有兴趣,请自行研究制作方法,并不难。
附:在自制播放器中使用 smi 字幕文件的方法
在窗体上再添加一个计时器控件,Inteval = 20,Enabled = False。
歌词就使用刚制作好的 smi 文件(当然,你也可以再增加一个【openSMI】按纽,请自编代码)。
增加一个模块级变量:
Dim BJMode As Boolean 'True-显示歌词;False-制作歌词
Dim posit As Long 'smi文件中的时间参数位置
在 Sub saveFile() 过程后面增加一句:BJMode = True
在 Function openFile 函数后面增加一句:BJMode = False
在 Sub playMCI_Click 过程后面增加一句:If BJMode Then posit = 1: Timer1.Enabled = True
编写 Timer1_Timer 过程代码:
Private Sub Timer1_Timer()
Dim t As Long, k1 As Long, k2 As Long
If posit > Len(smiST) - 15 Then Timer1.Enabled = False: Exit Sub
k1 = InStr(posit, smiST, "start=") '查找时间字串
t = Val(Mid$(smiST, k1 + 6, 8)) '取出时间
If Abs(MMC.Position - t) < 200 Then '如果歌词与播放进度的时间差小于200毫秒
k1 = InStr(k1, smiST, "EGCC>") '查找歌词文本起点
k2 = InStr(k1, smiST, "~") '查找歌词文本终点
Label1 = Mid$(smiST, k1 + 5, k2 - k1 - 5) '取出歌词字串显示在标签上
posit = k2 + 1
End If
End Sub
使用方法:制作完成 smi 文件后,再点击【playMCI】按纽即可。
2011.6.27