Skip to content

Instantly share code, notes, and snippets.

@tuxzz
Created July 10, 2015 09:30
Show Gist options
  • Save tuxzz/9bb9688147152274a48c to your computer and use it in GitHub Desktop.
Save tuxzz/9bb9688147152274a48c to your computer and use it in GitHub Desktop.
RUCE_PCode
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