好的,我终于开始编写代码并对其进行测试。结果?太棒了=D
我按照 pichenettes 的原始建议将系数存储为 RFC 而不是 LPC,然后执行矢量量化(我尝试了使用 15 个“全局”预测器和 1 个块预测器的想法。结果没有我想象的那么好,即使有许多不同的预测变量和精度 =/)。
就个人而言,我认为最困难的部分是试图弄清楚如何安全地插入数据,而我对 DSP 的影响缺乏深入的了解。但是,在被指出正确的方向之后,我很高兴地说,结果正是我在将近一年前开始时所希望的(是的,我一直在尝试这样做很长时间 =P) .
稍微棘手的另一部分是编写具有可接受结果的快速矢量量化。虽然我可能可以用质心等正确的方式完成它。但我的做法略有不同(我不确定如何显示/隐藏预先格式化的文本块,所以如果你不想看,只需阅读粗体线我写的 C++ 代码来解释):
1)生成第一个系数集作为所有未处理系数的平均值(一种量化训练)
// Quantized coefficient sets
double VQCoef[CodebookSize][Order];
// For all original coefficients...
for(int i=0; i < NumberOfCoef; i++) {
// For each coefficient in the set...
for(int j=0; j < Order; j++) {
// Accumulate
VQCoef[0][j] += Coef[i][j];
}
}
// Average out coefficients
// For each coefficient in the set...
for(int i=0; i < Order; i++) {
// Normalize [clamped to (-1.0,+1.0) but omitted for brevity]
VQCoef[0][i] /= (double)NumberOfCoef;
}
2) 根据最后一个稍微偏移的系数集计算下一个 2^n 系数集
// For each final coefficient set...
for(int i=0; i < CodebookSize;) {
// Quantization buffer. Counter and accumulator.
int VQCnt[CodebookSize]; memset(VQCnt, 0, sizeof(VQCnt));
double VQAcc[CodebookSize][Order]; memset(VQAcc, 0, sizeof(VQAcc));
// Estimate the next set by slightly offsetting the original data
for(int j=0; j < i; j++) for(int k=0; k < Order; k++) VQCoef[i+j][k] = VQCoef[j][k] + 0.01;
}
// Now we have double the amount of coefficients, so adjust 'i' accordingly
i *= 2;
3)遍历未处理的系数列表并找到具有最接近相关性(点积)的目标系数。找到后,将数据累积到临时缓冲区中
// For each original coefficient...
for(int i=0; i < NumCoef; i++) {
// Find target coefficient set with best correlation
int BestPos = 0; // Best target [reset when code runs]
double BestDst = -1.0e99; // Best distance [just a really large negative value]
for(int j=0; j < CodebookSize; j++) {
// Get correlation between the original coefficient set and the tested target
double Dist = NormalizedDotProduct(Coef[i], VQCoef[j], Order);
// If the correlation was better, save this as the target
if(Dist > BestDst) {
BestPos = j;
BestDst = Dist;
}
}
// Now that we know the target, save it to the accumulation buffer
VQCnt[BestPos]++;
for(int j=0; j < Order; j++) VQAcc[BestPos][j] += Coef[i][j];
}
4)当这批系数集完成后,将其平均以找到新的集
// For all sets done up to now...
for(int i=0; i < CoefSetsDone; i++) {
// Fetch count/normalization coefficient. If zero sets, don't bother doing this set
double Cnt = VQCnt[i];
if(Cnt != 0.0) {
// We have sets, so average the coefficients out
for(int j=0; j < Order; j++) {
VQCoef[i][j] /= Cnt; // [again, this is clamped to (-1.0,+1.0)]
}
}
}
重复步骤 2-4,直到我得到我想要的 2^n 组,此时我只需将反射系数转换为 LP 系数就完成了。=)
虽然我打算使用它的项目是非常长期的(想想十多年),你能同意我把声音设计的关键部分归功于你吗?