Created
July 10, 2015 09:30
-
-
Save tuxzz/9bb9688147152274a48c to your computer and use it in GitHub Desktop.
RUCE_PCode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Function main(arg) | |
{ | |
/* 解析参数 */ | |
RUCE_UnitParam para = RUCE_ParsePara(arg); | |
/* 从输入文件名提出音名 例如a.wav变成a */ | |
String inputPath = para.input; | |
String outputPath = para.output; | |
String inputFileName = BaseFromFilePath(inputPath); | |
String inputDirName = DirFromFilePath(inputPath); | |
String unitName = Left(inputFileName, "."); | |
/* 载入RUDB和PitchModel(以下简称PM) */ | |
// Load {inputDirName}/{unitName}.rudb | |
RUCE_DB_Entry dbEntry = RUCE_RUDB_Load(inputDirName + "/" + unitName ".rudb"); | |
// Load {inputDirName}"/PitchModel.json" | |
CSVP_PitchModel pmEntry = RUCE_LoadPitchModel(inputDirName + "/PitchModel.json", unitName); | |
/* 从dbEntry导入Wave */ | |
Wave inWave, outWave; | |
inWave.size = dbEntry.waveSize + 3000; // 为何要比dbEntry的大3000? | |
inWave.write(dbEntry.wave); | |
outWave.samprate = inWave.samprate = dbEntry.wave.samprate; // 采样率什么的 | |
// 调整持续时间 | |
if(para.lenRequire < 0) | |
para.lenRequire = dbEntry.frameList[0].position / inWave.samprate; // 取第一帧所在时间当作lenRequire | |
para.lenRequire += para.flagPara.deltaDuration; | |
outWave = RUCE_SynthUnit(inWave, dbEntry, pmEntry, para); // 开始合成! | |
outWave.writeToFile(outputPath); // 写文件 | |
} | |
Function RUCE_RUDB_Load(inWave, srcDB, srcPM, para) | |
{ | |
Wave dest; | |
// 初始化 分析/合成 窗 | |
Real window[WINSIZE] = CDSP2_GenHanning.Real(WINSIZE); // 生成WINSIZE大小的Hann窗 | |
FWindow dyWin; // ? | |
dyWin.minVar = 30; | |
.maxVar = 3000; | |
.interval = 20; | |
.sizeFunc = RFNL_Hanning_Size_Gnrc_Float; | |
.valuFunc = RFNL_Hanning_Valu_Gnrc_Float; | |
dyWin.init(); | |
// 初始化Waves | |
Wave conWave, vowWave, nozWave; | |
int samprare = conWave.samprate = vowWave.samprate = nozWave.samprate = inWave.samprate; // 设定采样率 | |
conWave.size = vowWave.size = nozWave.size = para.lenRequire * inWave.samprate; // resize | |
conWave.window = vowWave.window = nozWave.window = window; // 加窗 | |
int DestSize = para.lenRequire * samprate; | |
dest.size = DestSize; | |
// 初始化HNM帧 | |
int frameNum = srcDB.frameList.size; | |
List_HNMFrame vowList; | |
List_DataFrame phseList; | |
List_Int vowPulse; | |
PMatch vowMatch; | |
for(i = 0 to frameNum) | |
{ | |
RUCE_DB_Frame srcFrame = srcDB.frameList[i]; // 应取引用 | |
destFrame = vowList.frames[i]; // 同上 | |
vowPulse.frames[i] = sorcFrame.position; | |
int HNum = srcFrame.freq.size; // 计算 | |
destFrame.resize(WINSIZE, HNum); | |
dataFrame.resize(phseList.frames[i], HNum); | |
destFrame.noiz = -999 // 数组赋值 | |
//srcDB.noizSize长度的源resample到WINSIZE / 2 + 1长度 | |
destFrame.noiz = CDSP2_Resample_Linear.Real(srcFrame.noiz, srcDB.noizSize, WINSIZE / 2 + 1); | |
} | |
vowPulse.frames.size = frameNum; | |
vowMatch = CDSP2_List_Int.ToPMatch(vowPulse); // Int list转成PMatch | |
// 初始化非周期成分采样 | |
int VOTSample = srcDB.VOT * samprate; | |
int SOTSample = srcDB.SOT * samprate; | |
/* 不必要部分 这个F0曲线有一天可能要用 */ | |
PMatch F0List; | |
Synth.c:193 RCall(_List_HNMFrame, HToPMatch)(& VowList, & F0List, & VowPulse, 0); | |
int stretchSample = para.flagPara.CStretch * samprate; | |
conWave.size = vowWave.size; // resize | |
ConWave = StretchConsonant(inWave, VOTSample, -stretchSample); | |
// Time scale | |
// X: Dest -> Y: Sorc | |
PMatch timeMatch; | |
int ILSample = srcDB.invarLeft * samprate; | |
int IRSample = srcDB.invarRight * samprate; | |
timeMatch.addPair(-stretchSample, 0); | |
timeMatch.addPair(VOTSample, VOTSample); | |
/* ? */ | |
int srcSize = srcDB.frameList[0].position; | |
Segmentation orig, nseg; | |
orig.p1 = srcDB.invarLeft - srcDB.VOT; | |
orig.p2 = srcDB.invarRight - srcDB.VOT; | |
orig.p3 = src - srcDB.VOT; | |
nseg = Resegment(orig, | |
dest.size / samprate - srcDB.VOT, | |
para.flagPara.DeltaSeg1, para.flagPara.DeltaSeg2); | |
if(nseg.p1 == nseg.p2) | |
{ | |
timeMatch.addPair(VOTSample + samprate * 0.9 * nseg.p1, ILSample); | |
timeMatch.addPair(VOTSample + samprate * 1.1 * nseg.p1, IRSample); | |
} | |
else | |
{ | |
timeMatch.addPair(VOTSample + nseg.p1, ILSample); | |
timeMatch.addPair(VOTSample + nseg.p2, IRSample); | |
} | |
timeMatch.addPair(dest.size, srcSize); | |
// Interpolate & pitch-scale target HNM frames | |
HNMItersizer vowSynth; | |
vowSynth.size = WINSIZE; | |
.hopSize = srcDB.hopSize; | |
.wave = vowWave; | |
.noizWave = nozWave; | |
HNMFrame TempHNM; | |
HNMContour TempCont; | |
int position = vowPulse.frames[0]; | |
int count = 1; | |
para.flagPara.gender = Math.min(Math.max(para.flagPara.gender, -99), 99); // 限制在[-99,99](jsXD) | |
while(position < dest.size) | |
{ | |
//TODO: Add linear interpolation | |
int srcPosition = timeMatch.query(position).y; | |
Transition trans = vowMatch.query(srcPosition); | |
Real F0 = para.freq.query(position / samprate).y; | |
TempHNM = InterpFetchHNMFrame(vowList, trans); | |
TempCont = CSVP_PitchConvertHNMFrame_Float(TempHNM, PM, F0, 10000, samprate); | |
if(Para.flagPara.breathness != 50) | |
TempCont.Noiz += log(Para.flagPara.breathness / 50.0); | |
if(Para.flagPara.gender != 0) | |
{ | |
HNMContour newCont; | |
newCont.size = WINSIZE; | |
Real genderCoef = (100.0 - para.flagParam.gender) / 100.0; | |
Real srcAnchor[2], destAnchor[2]; | |
srcAnchor[0] = 0; | |
destAnchor[0] = 0; | |
if(GenderCoef > 1) | |
{ | |
destAnchor[1] = WINSIZE / 2 + 1; | |
srcAnchor[1] = destAnchor[1] / genderCoef; | |
}int CenterIndex = CDSP2_List_Int_IndexAfter( | |
& VowSynth.PulseList, CenterPos); | |
else | |
{ | |
srcAnchor[1] = WINSIZE / 2 + 1; | |
destAnchor[1] = srcAnchor[1] * genderCoef; | |
} | |
newCont.Hmnz = -999; // 数组赋值 | |
newCont.Noiz = -999; // 同上 | |
_MapStretch(newCont.Hmnc, TempCont.Hmnc, DestAnchor, SorcAnchor, | |
2, WINSIZE / 2 + 1); | |
_MapStretch(newCont.Noiz, TempCont.Noiz, DestAnchor, SorcAnchor, | |
2, WINSIZE / 2 + 1); | |
TempCont = newCont; | |
} | |
tempHNM.fromContour(tempCont, F0, 8000); | |
if(Para.flagPara.breathness > 50.0) | |
{ | |
// 衰减谐波分量 | |
tempHNM.Hmnc.Ampl -= (100.0 - para.flagPara.breathness) / 50.0; | |
} | |
vowSynth.add(tempHNM, position); | |
if(count % 10 == 0) | |
{ | |
CSVP_PhaseSyncH_Float(phseList.frames[trans.LowerIndex], 0); | |
CSVP_PhaseContract_Float(phseList.frames[trans.lowerIndex], | |
CSVP_PitchModel_GetPhseCoh(PM, F0) * para.flagPara.PhaseSync); | |
vowSynth.addPhase(phseList.frames[trans.LowerIndex], position); | |
} | |
position += srcDB.hopSize; | |
++count; | |
} | |
// 平滑化 | |
float decayRate = para.flagPara.smoothenRate; | |
int decayLen = para.flagPara.smoothenRadius / 2.0 * samprate / srcDB -> hopSize; | |
int CenterPos = mseg.P1 * samprate + VOTSample; | |
int CenterIndex = CDSP2_List_Int_IndexAfter(vowSynth.pulseList, CenterPos); | |
CenterIndex = Math.max(CenterIndex, DecayLen); | |
int LDecay = CenterIndex - DecayLen > 0 ? CenterIndex - DecayLen : 1; | |
int HDecay = CenterIndex + DecayLen < VowSynth.PulseList.Frames_Index ? | |
CenterIndex + DecayLen : VowSynth.PulseList.Frames_Index - 1; | |
for(i = LDecay to HDecay) | |
{ | |
TempHNM.from(vowSynth.HNMList.frames[i]); | |
vowSynth.HNMList.frames[i].InterpFrom(TempHNM, vowSynth.HNMList.frames[i - 1], DecayRate); | |
} | |
// HNM合成 | |
vowSynth.Option.PhaseControl = 1; | |
int ConcatLen = 3000; | |
int FirstPos = vowSynth.pulseList.frames[0]; | |
int ConcatPos = Math.max(SOTSample, FirstPos); | |
if(ConcatPos > DestSize - ConcatLen) ConcatPos = DestSize - ConcatLen; | |
if(ConcatLen > inWave.size - ConcatPos) ConcatLen = inWave.size - ConcatPos; | |
int phseIndex = CDSP2_List_Int_IndexAfter(vowSynth.PulseList, ConcatPos); | |
vowSynth.SetPosition(ConcatPos); | |
vowSynth.SetInitPhase(phseList.frames[phseIndex]); | |
vowSynth.IterNextTo(vowSynth.pulseList.frames[0]); | |
vowSynth.prevTo(FirstPos); | |
// Concatenation | |
// Shift unvoiced consonant | |
int COffset = Para.flagPara.COffset * samprate; | |
Real[conWave.Size] Temp; | |
conWave.Read(Temp, 0, conWave.size); | |
conWave = 0; // 数组赋值 | |
if(para.flagPara.CLoudness != 1.0) | |
Temp * para.flagPara.CLoudness; | |
conWave.write(Temp, COffset); | |
for(i = 0 to ConcatLen) | |
{ | |
conWave[ConcatPos + i] *= 1.0 - i / ConcatLen; | |
nozWave[ConcatPos + i] *= i / ConcatLen; | |
} | |
//End tapering | |
for(i = 0 to 300) | |
{ | |
vowWave[FirstPos + i] *= i / 300.0; | |
vowWave[vowSynth.pulseList.frames - i] *= i / 300.0; | |
} | |
nozWave[:ContactPos] = 0; | |
conWave[ContactLen + ContactPos:-ConcatLen - ConcatPos] = 0 | |
dest.from(nozWave); | |
dest += conWave; | |
dest += vowWave; | |
dest *= para.volume / 100.0; | |
return dest; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment