Я пишу функцию C # для выполнения сжатия динамического диапазона (звуковой эффект, который в основном подавляет переходные пики и усиливает все остальное, чтобы получить общий более громкий звук). Я написал функцию, которая делает это (я думаю):
альтернативный текст http://www.freeimagehosting.net/uploads/feea390f84.jpg
public static void Compress(ref short[] input, double thresholdDb, double ratio)
{
double maxDb = thresholdDb - (thresholdDb / ratio);
double maxGain = Math.Pow(10, -maxDb / 20.0);
for (int i = 0; i < input.Length; i += 2)
{
// convert sample values to ABS gain and store original signs
int signL = input[i] < 0 ? -1 : 1;
double valL = (double)input[i] / 32768.0;
if (valL < 0.0)
{
valL = -valL;
}
int signR = input[i + 1] < 0 ? -1 : 1;
double valR = (double)input[i + 1] / 32768.0;
if (valR < 0.0)
{
valR = -valR;
}
// calculate mono value and compress
double val = (valL + valR) * 0.5;
double posDb = -Math.Log10(val) * 20.0;
if (posDb < thresholdDb)
{
posDb = thresholdDb - ((thresholdDb - posDb) / ratio);
}
// measure L and R sample values relative to mono value
double multL = valL / val;
double multR = valR / val;
// convert compressed db value to gain and amplify
val = Math.Pow(10, -posDb / 20.0);
val = val / maxGain;
// re-calculate L and R gain values relative to compressed/amplified
// mono value
valL = val * multL;
valR = val * multR;
double lim = 1.5; // determined by experimentation, with the goal
// being that the lines below should never (or rarely) be hit
if (valL > lim)
{
valL = lim;
}
if (valR > lim)
{
valR = lim;
}
double maxval = 32000.0 / lim;
// convert gain values back to sample values
input[i] = (short)(valL * maxval);
input[i] *= (short)signL;
input[i + 1] = (short)(valR * maxval);
input[i + 1] *= (short)signR;
}
}
и я называю его значениями threshold
от 10,0 до 30,0 дБ и соотношениями от 1,5 до 4,0. Эта функция определенно производит более громкий общий звук, но с недопустимым уровнем искажений, даже при низких пороговых значениях и низких соотношениях.
Кто-нибудь может увидеть что-то не так с этой функцией? Правильно ли я отношусь к стерео аспекту (функция предполагает стереовход)? Поскольку я (смутно) понимаю вещи, я не хочу сжимать два канала по отдельности, поэтому мой код пытается сжать «виртуальное» значение моно семпла, а затем применить ту же степень сжатия к значениям семплов L и R по отдельности. , Не уверен, что я все делаю правильно.
Я думаю, что часть проблемы может заключаться в «жестком колене» моей функции, которое резко сжимает сжатие при пересечении порога. Я думаю, что мне может понадобиться использовать «мягкое колено», как это:
альтернативный текст http://www.freeimagehosting.net/uploads/4c1040fda8.jpg
Кто-нибудь может предложить модификацию моей функции для получения кривой мягкого колена?