问题由来:有一批客服提供的配音文件,好几千个,需要用作我写的程序合成,发现其尺寸差异较大,遂检查了一遍,发现果然里面10%的文件格式有问题,和其他不一致:
Option Explicit
Public Type RIFF
ID As String * 4 '0x00 4Byte 大端 'RIFF' (0x52494646)
Size As Long '0x04 4Byte 小端 fileSize - 8
Type As String * 4 '0x08 4Byte 大端 'WAVE'(0x57415645)
End Type
Public Type FORMAT
ID As String * 4 ' 0x00 4Byte 大端 'fmt ' (0x666D7420)
Size As Long ' 0x04 4Byte 小端 16
AudioFormat As Integer ' 0x08 2Byte 小端 音频格式
NumChannels As Integer ' 0x0A 2Byte 小端 声道数
SampleRate As Long ' 0x0C 4Byte 小端 采样率
ByteRate As Long ' 0x10 4Byte 小端 每秒数据字节数
BlockAlign As Integer ' 0x14 2Byte 小端 数据块对齐
BitsPerSample As Integer ' 0x16 2Byte 小端 采样位数
End Type
Public Type data
ID As String * 4 ' 0x00 4Byte 大端 'data' (0x64617461)
Size As Long ' 0x04 4Byte 小端 N
dataBlock() As Integer
End Type
Public Type HP1
data As String * 14 '0x00 4Byte 大端 Lavf58.29.100
End Type
Public Type HP
ID As String * 8 '0x00 4Byte 大端 INFOISFT
Size As Long '0x04 4Byte 小端
data As HP1
End Type
Public Type LIST '-------------ffmpeg 转换出来的 WAV 文件,文件头会多出 LIST 块,所以单独定义个判断下,以免忘记了。
ID As String * 4 '0x00 4Byte 大端 LIST
Size As Long '0x04 4Byte 小端
data As HP
End Type
Public Function apppath()
apppath = ActiveWorkbook.Path & "\"
End Function
Public Sub chkWavFormat()
Dim P1 As RIFF, P2 As FORMAT, P3 As data, P2x As LIST
Dim P0 As RIFF, AR As Long, dataBlock() As Integer
Dim i As Integer, fn As String, fpath As String, fp As Integer, col As Integer
Dim Headsize As Long
fpath = apppath & "基本语音\wav\"
fn = Dir(fpath & "*.wav")
Do
'-----------读取文件格式
fp = FreeFile
Open fpath & fn For Binary As #fp
Get #fp, , P1
Get #fp, , P2
Get #fp, , P0
AR = Seek(fp) - 12
Seek #fp, AR
If P0.ID <> "data" Then
Get #fp, , P2x
Headsize = 12 + 8 + P2.Size + 8 + P2x.Size + 8
Else
Headsize = 12 + 8 + P2.Size + 8
End If
' Get #fp, , P3.ID
' Get #fp, , P3.Size
If P2.BlockAlign = 1 Then
'ReDim dataBlock(1 To P3.Size) As Byte
ElseIf P2.BlockAlign = 2 Then
'ReDim dataBlock(1 To P3.Size / 2) As Integer
Else
' Close #fp
' MsgBox "不处理32位音频!"
' Exit Sub
End If
Close #fp
'------------------
i = i + 1
col = 1
Worksheets("Sheet3").Cells(10 + i, col).Value = i: col = col + 1
Worksheets("Sheet3").Cells(10 + i, col).Value = fn: col = col + 1
With P2
Worksheets("Sheet3").Cells(10 + i, col).Value = .AudioFormat: col = col + 1
Worksheets("Sheet3").Cells(10 + i, col).Value = .NumChannels: col = col + 1
Worksheets("Sheet3").Cells(10 + i, col).Value = .SampleRate: col = col + 1
Worksheets("Sheet3").Cells(10 + i, col).Value = .ByteRate: col = col + 1
Worksheets("Sheet3").Cells(10 + i, col).Value = .BlockAlign: col = col + 1
Worksheets("Sheet3").Cells(10 + i, col).Value = .BitsPerSample: col = col + 1
End With
Worksheets("Sheet3").Cells(10 + i, col).Value = Headsize: col = col + 1
'——----------
DoEvents
fn = Dir
Loop Until Len(fn) < 4
MsgBox i & "个文件处理完毕"
End Sub
而且发现所有文件采样率和我程序要求的都不一样。
所以想将其格式全部转换为我设定的一致,用 ffpmeg 试了一下,发现直接 wav 转 wav 转出来得到是 PCM 格式文件,并不能得到 wav 格式文件:
ffmpeg -y -i 12.wav -f s16le -ac 1 -ar 16000 -acodec pcm_s16le 12.ok.wav
图中可将,wav 文件头没了,将扩展名改为 PCM 用 goldwave 打开,填入之前转换的参数,播放正确:
说明格式采样率转换已经正确完成,只是 ffpmeg 只输出了数据部分,没带 wav 文件头,那么接下来就简单了,从 pcm 转为 wav 加上文件头,就可以得到完整的 wav 文件了:
ffmpeg -y -f s16le -ac 1 -ar 16000 -acodec pcm_s16le -i 12.ok.pcm test.wav
至此,转换方案可以确定,即,将各种不同格式的 wav 文件先转为 16位16K单声 pcm 格式,然后,在按这个格式转换为 wav 格式即可,加上批处理批量转换两次就完成了:
rem 不同格式的 wav 文件批量转换为 16 位 16K 单声道的 pcm 格式
e:
cd E:\Studio\web\xfttsWeb\DOC\基本语音
for %%a in (".\all\*.wav") do "ffmpeg.exe" -y -i "%%a" -f s16le -ac 1 -ar 16000 -acodec pcm_s16le ".\pcm\%%~na.pcm"
rem pcm 文件批量转换为 16 位 16K 单声道的 wav 格式
e:
cd E:\Studio\web\xfttsWeb\DOC\基本语音
for %%a in (".\pcm\*.pcm") do "ffmpeg.exe" -y -f s16le -ac 1 -ar 16000 -acodec pcm_s16le -i "%%a" ".\wav\%%~na.wav"
这样,几分钟就把一堆不同采样率的文件一起转换好了。
转换后的文件再次检测格式,都已经全部为制定格式:
此记!