本帖最后由 Zleepwalking 于 2015/3/22 18:29 编辑
2015.3
本贴所包含信息时间过于久远,已废弃。出于保留项目历史原因在此搁置。 内容概述:
CBV文件结构定义,发音记号系统,音源库开发流程,音源库制作软件TDPSMStudio使用方法和原理。
从《关于CybervoiceEngine和TDPSM》里,你应该知道Rocaloid的CBV是一种记载了分拆后语音帧的音源库文件。CBV这个格式是Rocaloid唯一的从初代保留到二代的数据文件后缀。CBV的格式倒是经过了三次变化。Rocaloid Renaissance 1.6核心版采用了两种版本的CBV:v0.5和v0.6。我本来像把CBV 0.5, 0.6的后缀改成CVDB,但在CVE 1.5时期为了兼容老版本CBV所以后缀没变,但较原来的CBV,CVDB多了一个文件头。
CVDB 0.5
这是Rocaloid音源库中用于保存音源数据的文件格式。
记录的内容:数据特性、语音数据、语音帧分界线的位置。
先说CVDB 0.5吧。Rocaloid保存的音源库规格为: PCM signed 16bit little endian 96000HZ 1536kbps mono。如果你装了Goldwave一类的波形编辑软件,按这个规格直接打开CVDB 0.5的文件,应该会看到:
其实CVDB 0.5是在音源库数据中穿插FE 7F(32766)和FF 7F(32767)来分割语音信号周期。其中FF 7F表示最后一个周期结束。
用winhex打开CVDB 0.5的话,你会在开头看到:
CVDB 0.5的文件头定义如下: - CVDB Information
- 0-3 CVDB Header 'CVDB'
- 4-5 Version UInt16
- 6 Consonant FF(255)-True FE(254)-False
- 7-10 StartPoint Int32
- 11-14 Average Period Int32
- 15 Fill FF(255)
- 16-255 Information String
- CVDB Data
- FE 7F Frame/Period
- FF 7F CVDB End
复制代码 (Rocaloid_HatsuneMiku 1.5.1 -RENAISSANCE-字样其实只是装帅。。。。。。。。。)
CVDB 0.6
这是Rocaloid音源库中用于保存音源数据的文件格式。
记录的内容:数据特性、语音数据、语音帧分界线的位置。
比CVDB 0.5更先进。
CVDB 0.6和0.5的差别主要是,0.6里不再用FE 7F和FF 7F代表语音帧之间的界线,而是在文件头里塞下了一个帧长度表。Winhex打开如下:
在帧长度表结束后就是一个去掉文件头的wav。所以你可以很容易地从CVDB 0.6中还原出wav,以后数据压缩也会很容易。
而Goldwave打开的CVDB 0.6看上去跟wav几乎没区别,你甚至可以直接播放它。注意文件头会在起始处形成一个爆音。
这是CVDB 0.6文件定义:- 0-3 CVDB Header "CVDB"
- 4-5 Version UInt16 = 0x0002
- 6 Consonant FF(255)-True FE(254)-False
- 7-10 StartPosition Int32
- 11-14 PeriodStartPosition Int32
- 15 Fill FF(255)
- 16-17 Chunk number UInt16
- 18-? Frame Chunks
- Period Length UInt16
- ?+1 Wave Data
- Data Chunks Int16
复制代码 Rocaloid Renaissance发音记号系统
这一段介绍Rocaloid Renaissance使用的发音记号和对应的发音,开发音源库或者高级调教需要看:
最后给出了一张对照表,你懒得看介绍的话可以直接去看表。
从初代。开始(打dai kai会被和谐掉。。。)Rocaloid就使用一套与众不同的发音记号系统。不用罗马音,国际音标,X-SAMPA等记号系统的原因:
- 这些记号系统可能无法准确地描述音源库文件的发音。
- 这些记号系统有太多发音,在Rocaloid的音源库中没有对应。
- 使用复杂的发音记号不利于开发和调试。
关于初代的发音记号就不详述了。初代只有1000多个CBV文件,而且每个辅音只有一组对应的CBV,比如b只有ba对应,c只有ci,k对应ke,x对应xi,p对应po……
Roca Rena的发音记号系统相比一代丰富了5倍,每个辅音,例如b,对应了3-5种辅音-元音的diphone,如ba, bo, be, bi, bu(汉语拼音)。
辅音-元音diphone在Roca Rena记号系统中表示为:第一个字符是汉语拼音,第二个字符是@ [ 3 # ~中的一个。
- @ 对应 a
- [ 对应 o
- 3 对应 e
- # 对应 i
- ~ 对应 u
特殊情况是当辅音的汉语拼音占两个字符时,要用符号替换:
把发音记号限制成两个字符以内是为了开发方便,看起来也舒服(我觉得舒服吧。。。)。
元音如此对应:
- a 对应 a
- o 对应 ao
- e 对应 ai
- e- 对应 e
- i 对应 i
- u 对应 u
- v 对应 yu (也就是v)
对于鼻音,也规划在元音之内:
NG偏后鼻音,前面两个看情况使用,我很难用语言表述出它们的区别。@http404求说明。。。
还有几个特殊的发音记号
- - 对应 ri后面的"i"的发音
- -# 对应 zi后面的"i"的发音,或者zhi、chi、shi中"i"的发音
- v- 对应 yu,和v的区别是v仅是yu后"u"的发音(用作元音),v-是整个yu(用作辅音)
这里给出一张表格,是目前音源库中使用所有Rocaloid发音记号:
No. | Field | Rocaloid Symbol | Pronounciation | 1 | Vowel | a | a | 2 | o | ao | 3 | e | ai | 4 | e- | e | 5 | i | yi | 6 | u | u | 7 | v | yu | 8 | b | b@ | ba | 9 | b3 | be | 10 | b[ | buo | 11 | b# | bi | 12 | b~ | bu | 13 | p | p@ | pa | 14 | p3 | pe | 15 | p[ | puo | 16 | p# | pi | 17 | p~ | pu | 18 | m | m@ | ma | 19 | m3 | me | 20 | m[ | muo | 21 | m# | mi | 22 | m~ | mu | 23 | f | f@ | fa | 24 | f3 | fe | 25 | f[ | fuo | 26 | d | d@ | da | 27 | d3 | de | 28 | d[ | duo | 29 | d# | di | 30 | d~ | du | 31 | t | t@ | ta | 32 | t3 | te | 33 | t[ | tuo | 34 | t# | ti | 35 | t~ | tu | 36 | n | n@ | na | 37 | n3 | ne | 38 | n[ | nuo | 39 | n# | ni | 40 | n~ | nu | 41 | l | l@ | la | 42 | l3 | le | 43 | l[ | luo | 44 | l# | li | 45 | l~ | lu | 46 | j | j# | ji | 47 | q | q# | qi | 48 | x | x# | xi | 49 | g | g@ | ga | 50 | g3 | ge | 51 | g[ | guo | 52 | g~ | gu | 53 | k | k@ | ka | 54 | k3 | ke | 55 | k[ | kuo | 56 | k~ | ku | 57 | h | h@ | ha | 58 | h3 | he | 59 | h[ | huo | 60 | h~ | hu | 61 | z | z@ | za | 62 | z3 | ze | 63 | z[ | zuo | 64 | z# | zi | 65 | c | c@ | ca | 66 | c3 | ce | 67 | c[ | cuo | 68 | c# | ci | 69 | s | s@ | sa | 70 | s3 | se | 71 | s[ | suo | 72 | s# | si | 73 | zh | %@ | zha | 74 | %3 | zhe | 75 | %[ | zhuo | 76 | %# | zhi | 77 | %~ | zhu | 78 | ch | ^@ | cha | 79 | ^3 | che | 80 | ^[ | chuo | 81 | sh | &@ | sha | 82 | &3 | she | 83 | &[ | shuo | 84 | &~ | shu | 85 | w | w@ | wa | 86 | w3 | we | 87 | w[ | wuo | 88 | r | -# | zi | 89 | - | ri | 90 | n | N | n | 91 | NG | n | 92 | NN | n | 93 | v | v- | yu |
若要包含所有发音符号在所有音高下的发音,工作量太大了,所以我仅制作了C2-C5,属于比较常用的音域。
93个发音符号 × 37个音高(C2 - C5) = 3441,也就是1.6核心版音源库中的CBV文件个数。
CBV的文件名命名规则
统一的命名规则:发音记号+下划线+音高.cbv
如:b@_C3.cbv即C3下ba的发音。
注意音高半音均使用#,例如C#3, D#3, F#3, G#3, A#3, C#4, D#4……但没有Eb3, Bb3这种表示。
音源库开发流程
介绍了音源库开发的四个步骤:
| 步骤 | 使用工具 | 1 | 导出原始波形数据 | Vocaloid、按键精灵 | 2 | 纠正错误的或突兀的发音 | TDPSMStudio(Wave Editor模式) | 3 | 拆帧 | TDPSMStudio(Wave Analyzer模式) | 4 | 检查,标注VOT | TDPSMStudio(CVDB Quality Control模式) | 最后附带了一个能自动调教Vocaloid的按键精灵脚本。
如果你要加入开发音源库,看这段:
这是使用CVMaker+CVQC+VoiceWaver方案的流程图
因为TDPSMStudio的完成,如我在【序章】提到,这个软件涵盖了CVMaker+CVQC+VoiceWaver的功能,上面的方案已经被简化:把三个工具名字用TDPSMStudio替换掉,把用CVQC优化CBV的一步改成“检查和标注VOT”即可。
音源库的3441个文件都是从Vocaloid里导出后经由上述操作制成的。即是说初音唱了3441次……实际上的次数远大于这个数字,因为音源库来回刷了好几遍才能做出最好的。现在的音源库(1.6.1也不是最终的版本)。
DBManager是一个音源库管理工具,用批处理写的。起初我们使用Hamachi组建虚拟局域网,用windows自带的局域网文件共享传文件。这个批处理就放在共享文件夹里。后来Hamachi速度实在跟不上,我们就用百度网盘共享文件了,同样,批处理丢进同步文件夹就好了。
起初音源库操作经历上述三个步骤,中间会产生大量的文件。难处是这些文件即使不用了还得留着,说不定那天还会用得上。我在开发初代的时候受了个教训:总是记得以前有个音源库版本发音比当前的版本还好,回去找却发现文件已经被删掉了。 DBManager所做的事情就是把这些中间产生的文件自动归类和取出。首先相同发音的文件放在同一个文件夹里:
在这些文件夹里,不同步骤产生的文件又被放进数个子文件夹里归类。
文件夹 | 存储内容 | Raw | 从Vocaloid里直接导出的文件 | Raw | 经过波形调整的wav文件 | Gen | 经过拆帧产生的cbv文件 | Edit | 经过检查和调整的cbv文件 | 因为一个发音会被重新制作n次,所以在Raw\Gen\Edit后面加上数字以表明版本,如Raw1, Gen2, Edit1这样……这些都是DBManager做的事情。
因为TDPSMStudio的出现,Gen被合并到Edit里去了。
最后的音源库版本号,如1.6.1\71-236,1.6.1是音源库总版本号;71是所有Edit版的数量,236是所有Raw+Gen+Edit版的数量。
1.6.1\71-236,也是发此贴时的音源库版本,共包含三万五千个半手工半自动处理的文件。好在有了TDPSMStudio这种工具后音源库开发的自动化程度大大提高。
不过开源后这种共享方式不能继续了,DBManager也得退役了。因为我不能保证不会有人修改百度网盘的密码。Rgwan提议通过打7z包互传音源库部分文件的方式共享资料。
从Vocaloid导出文件也是批量导出的,我用按键精灵写了个脚本,输入一个发音记号就可以全自动从C2合成输出到C5:
- PID = Plugin.Window.Foreground()
- PitchList = Array("C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4","C5")
- Notes = Array("mo", "mi", "me", "mu")
- NoteNames= Array("m[","m#","m3","m~")
- NoteNo=0
- NoteName = InputBox("Input the synthesis symbol:")
- PitchNum = 0
- Call Plugin.Window.Show(PID)
- Rem Restart
- 'NoteName=NoteNames(NoteNo)
- For i = 0 To 36
- Delay 100
- 'Select All
- KeyDown 18, 1
- KeyPress 69, 1
- KeyUp 18, 1
- Delay 50
- KeyPress "E", 1
- Delay 100
- 'Goto Skip
- FileName = NoteName & "_" & PitchList(i)
- 'CTRL+ALT+SHIFT+S
- KeyDown 17, 1
- KeyDown 18, 1
- KeyDown 16, 1
- KeyPress 83, 1
- KeyUp 16, 1
- KeyUp 18, 1
- KeyUp 17, 1
- KeyPress "Enter", 1
- Delay 50
- 'Input FileName
- SayString FileName
- Delay 100
- KeyPress "Enter", 1
- Delay 100
- 'Wait For Synthesis
- Call WaitForColorChange(673,329)
- Rem Skip
- 'Find Note
- FindColor 115,93,800,520,"F4E90B",intX,intY
- NoteX = intX + 30
- NoteY = intY + 5
- 'Move
- MoveTo NoteX, NoteY
- Delay 100
- LeftDown 1
- Delay 100
- MoveR 0, -5
- Delay 10
- MoveR 0, -4
- Delay 10
- MoveR 0, -3
- Delay 100
- LeftUp 1
- Delay 100
- LeftClick 1
- Delay 100
- 'Scroll
- If NoteY < 200 Then
- MouseWheel 4
- End If
- Delay 100
- Next
- Call Restore
- NoteNo = NoteNo + 1
- FindColor 115,93,800,520,"F4E90B",intX,intY
- NoteX = intX + 30
- NoteY = intY + 5
- If NoteNo = 4 Then
- Goto EndS
- End If
- 'Delay 20
- 'MoveTo NoteX, NoteY
- 'Delay 20
- 'LeftDoubleClick 1
- 'Delay 20
- 'SayString Notes(NoteNo)
- 'Delay 20
- 'KeyPress "Enter", 1
- 'Delay 50
- 'Goto Restart
- Rem EndS
- Function WaitForColorChange(x, y)
- Rem F_WFCC
- Delay 10
- If GetPixelColor(x, y) = "C8D0D4" Then
- Goto F_WFCC
- End If
- End Function
- Function Restore()
- For i = 0 To 36
- Delay 20
- KeyDown 17, 1
- KeyPress 90, 1
- KeyUp 17, 1
- Delay 10
- FindColor 115,93,800,520,"F4E90B",intX,intY
- NoteX = intX + 30
- NoteY = intY + 5
- If NoteY > 455 Then
- MouseWheel -1
- Delay 20
- MouseWheel -1
- End If
- Next
- End Function
复制代码
这是适用于V3的版本,简单改一下就可以适用于V2。你可以看到代码里隐藏了一个可以合成整个辅音-元音系列的功能,像这样按顺序合成:ma mi me mo。(人类已经不能阻止我开发Rocaloid了。。。)
关于TDPSMStudio
TDPSMStudio是Rocaloid Renaissance中最新的用于开发音源库的软件,打破了以往用一批零散的工具开发音源库的局面。接下来的几段介绍TDPSMStudio的使用方法。
既然它替代了以往一堆软件的功能,它有多个工作模式:
要加入音源库开发请读这几段:
TDPSMStudio 1.0.5.27281下载地址(484KB): http://pan.baidu.com/share/link?shareid=543662&uk=3423845838 这个压缩包里包括了TDPSMStudio本体和一个测试用的o_C2.wav文件。(其实o_C2.wav保存的是%[_C2的数据。音源库里用%[代替o的发音。) TDPSMStudio有三种模式,分别对应原本VoiceWaver, CVMaker 和 CVQC的功能(波形编辑,拆帧,检查)。
Wave Analyzer模式
这是用于拆帧的模式,打开TDPSMStudio后的默认模式。 在Symbol后输入发音记号,在Pitch里输入音高(遵循文件名的音高命名方式),然后点击Open即可打开一个wav文件。
波形下面的框是三种模式通用的。Amplitdue滑块控制显示面板上波形的竖向缩放比例;如果打开的是一个辅音-元音Diphone,就把Consonant勾上;Data Length是拆帧拆出来的数据长度,一般Diphone用0.5秒,元音用2秒;Balance Wave是自动平衡波形,一般情况下勾上。不过Balance多了理论上会对波形质量造成影响,如果这个波形之前被Balance过,就不用选了。前面说了,o_C2这个文件其实是zho的发音,所以把Consonant勾上就可以当成Diphone分析,不勾上就可以当元音分析。
红色的线代表音量大小,黑色的线是用来反映音量变化速率的,一般用不着。
载入一个wav后,会先出来连根粉红色的线,这是TDPSMStudio识别出的一个周期。拆帧时就会以这个地方为起始点拆帧。
波形视图的缩放方法跟Goldwave一样,鼠标滚轮控制缩放和移动,缩放的中心点即鼠标所在位置,很容易上手。
菜单栏下面的一排按钮里,有个Analyze Frame。点一下就可以自动拆帧。如果成功了会变成这样:
辅音部分因为没有周期性,会自动用音高对应的周期代替。
如果你在和TDPSMStudio同一目录下放了一个发音记号从C2到C5的所有发音的wav文件,就可以按Analyze Frame To All,一次按下对所有wav自动拆帧。TDPSMStudio理论上支持任意CPU核心数量的电脑,并且可以100%利用电脑的性能。在批量操作的时候会变得非常卡,鼠标甚至都会被卡住。。。好在处理37个文件速度很快,在i5-3320M上不到10秒就可以完成37个文件的批量处理。
在Settings->Analyzer里可以对分析器(拆帧器)进行设定:
Silence Threshold | 判断为静音的音量阀值 | Allowing Error | 范围是0-1,当识别出的相邻两个周期长度区别超过这个倍数时,就停止分析(判断为VOT) | Self Correlation | 使用自相关算法 | Self Difference | 使用自差分算法 | Search Window | 搜寻窗口大小,即寻找周期长度的范围 |
Wave Editor 模式
从Mode -> Wave Editor可以进入这个波形编辑器模式。在Wave Analyzer模式的基础上,可以用鼠标左右键单击波形窗口选中一段波形。
此外你会看到一条红线,这是TDPSMStudio自动识别的VOT位置。
此模式下左边一排工具栏处于可用状态,从上向下功能依次为:
- 播放选定区域
- 停止播放
- 复制选定区域
- 切除选定区域
- 将复制的部分混音在选定区域的左边界线
- 改变选定区域的音量
- 平滑(模糊)选定区域
- 标准化选定区域内的音量
- 缩短选定区域(相当于CVE中的Shrink,须选中VOT之前的部分,不然会崩)
- 使选定区域静音
- 淡入选定区域
- 按二次函数,减弱选定区域中心
- 自适应性标准化+平衡(其实是标准化使音量全部在0.1以内)
在Fade In或者Weaken按钮上按右键,右键菜单中有一列数字可以选择,这是一些参数。Fade In弹出的参数是淡入前的起始音量(比例)。Weaken弹出的参数是最低音量比例。
与Wave Analyzer模式类似,如果你已经在TDPSMStudio所在目录放置了从C2到C5的同一个发音记号的37个wav文件,打开发音记号_C2后按Adjust To All可以批量对所有wav文件进行处理。
Automatic Adjust | 字面意思是自动调整,其实是标准化+平衡,找不到合适的名字了……后面跟的数字是音量大小限制 | Smoothen At VOT | 在VOT处平滑音量变化。Vocaloid在音高较高的时候,某些辅音的音量会突然上升,导致听上去不自然。此功能可以把VOT处的音量变化抑制在Limit以内 | Shrink Consonant | 缩短辅音 | Limit Consonants | 某些辅音的音量过大,Limit Consonant其实是个针对于辅音的Automatic Adjust | Consonant Fading In | 淡入辅音,同样是针对辅音音量过大的问题 | Until | 从当前音高一直批量处理到指定音高 |
若要保存调整后的wav,按快捷键Ctrl + C。
CVDB Quality Control 模式
这个模式直接对应CVQC的功能,即对批量CBV文件的检测。如果你已经生成了一个CBV文件,或者已经把CBV文件丢到TDPSMStudio同一目录下,输入发音记号和音高即可打开CBV。
波形视图上呈现的就是拆帧后的CBV,红线代表准许CVE识别为周期性信号的位置。为了保持稳定,红线的位置被刻意放在VOT之后一小段时间。在此之前的信号被当作辅音的部分,CVE不对其进行处理或参与过渡。因为红线位置过于靠后会导致合成时产生爆音。一般此位置需要手动稍微向前调整。
调整周期其实位置只需在调整后的位置点击。若要保存起始位置调整后的CBV,按快捷键Ctrl + C。
适用于任何模式的功能
快捷键:
这种特殊的,和Windows常用快捷键不同的快捷键排布方式是为了能用左手操纵键盘,同时右手操纵鼠标,以提高操作效率。- Ctrl + A 上一个音高
- Ctrl + S 打开这个音高
- Ctrl + D 下一个音高
- Ctrl + C 保存
遍历:
此功能用于检查处理后的文件。
在任何模式下View All和Stop按钮都是可用的,View All用于把所有文件按音高顺序打开一遍,Stop是停止View All。
波形预处理:
此功能是在载入波形时对波形进行的处理,为了方便拆帧和语音分析。
从Settings -> Preprocess可以进入。
为了方便拆帧,TDPSMStudio会对波形进行(多次)移动平均。
Moving Average: - Enabled: 启用移动平均预处理
- Twice:二次移动平均
- Extra:再多一次移动平均
- 2/3 Periods:移动平均长度为基频周期长度的2/3
- 1/2 Periods:移动平均长度为基频周期长度的1/2
- 1/3 Periods:移动平均长度为基频周期长度的1/3
- 1/4 Periods:移动平均长度为基频周期长度的1/4
Envelope Mapping:
- 1 Period:包络精确到1个基频周期长度
- 2 Periods:包络精确到2个基频周期长度
- 4 Periods:包络精确到4个基频周期长度
Start Position:
- Fixed:拆帧的开始点是固定的
- Delayed:拆帧的开始点在音量突破静音阀值(在Analyzer中设置)之后。
- 下面的文本框设定Delayed的延迟时间。
TDPSMStudio的原理
关键字:移动平均,自相关算法,自差分算法。
如果你加入TDPSMStudio的开发,请读下面:
前面的说明中应该已经能看到一些原理了。
移动平均之所以能利于之后的拆帧,是因为经过两次长度大约1/3基频周期长度的移动平均后,大多数语音波形会变成一峰一谷的形式。
如果仅是选取任意点为周期分界进行拆帧,在PSM混合时可能会对波形造成比较大的损害。例:“i”和“u”是波形类似正弦的简单波形,假如我以i的波峰前的过零点为周期(语音帧之间的)分界;以u的波谷前的过零点为周期分界,那么在从i到u的过渡中可能有一刻,i和u的波峰波谷互相抵消,这个过渡就被断开了。 将波形移动平均后变为一峰一谷的形式,TDPSM选择波峰前的过零点作为周期分界,也有助于提高合成质量。不过这么做仅仅是减轻了对音质的损害,这是PSM目前没解决的问题之一。
关于前文中提到的“自差分”算法,我不知道学术上怎么称呼,只是我自己给它取的名字。
[2013-7-25补充]这个“自差分”学术上叫AMDF,自相关在这里称为ACF。
这是离散信号自相关算法的公式,如果你学过DSP,你懂的肯定比我多:
其实它就是把一段长度为l的波形,从x处移动到x+n的位置,并不断把移动前后对应位置上的数据乘起来。正正得正,正负得负,负负得正,所以移动n位后波形重合度越高,On的值也越大。 那么理论上值最高的On(除了O0)就是周期交接处的位置。
自差分就是把乘法改成减法然后取绝对值:
它是把一段长度为l的波形,从x处移动到x+n的位置,并不断计算把移动前后对应位置上的数据的大小区别。所以移动n位后波形重合度越高,On的值也越接近0。 那么理论上值最低的On(除了O0)就是周期交接处的位置。
|