Функция постепенного исчезновения звука между изменениями частоты дискретизации
-
21-12-2019 - |
Вопрос
Я пытаюсь создать простую функцию, которая будет уменьшать громкость звука в буфере (например, затухание) на каждой итерации через буфер.Вот моя простая функция.
double iterationSum = 1.0;
double iteration(double sample)
{
iterationSum *= 0.9;
//and then multiply that sum with the current sample.
sample *= iterationSum;
return sample;
}
Это работает нормально, если установлено значение частоты дискретизации 44100 кГц, но проблема, с которой я столкнулся, заключается в том, что если частота дискретизации для примера изменена на 88200 кГц, то каждый раз следует уменьшать громкость только наполовину, потому что частота дискретизации в два раза больше и будет в противном случае завершите «затухание» в перерыве между таймами, и я попытался использовать такой коэффициент, как 44100/88200 = 0,5, но это никоим образом не сделает половину шага меньше.
Я застрял в этой простой проблеме, и мне нужно руководство, которое поможет мне разобраться. Что я могу сделать, чтобы сделать это на полшага на каждой итерации, поскольку эта функция вызывается, если частота дискретизации изменяется во время выполнения программы?
С уважением, Морган
Решение
Самый надежный способ затухания независимо от частоты дискретизации — это отслеживать время с момента начала затухания и использовать явный fadeout(time)
функция.
Если по какой-то причине вы не можете этого сделать, вы можете установить скорость экспоненциального затухания на основе частоты дискретизации следующим образом:
double decay_time = 0.01; // time to fall to ~37% of original amplitude
double sample_time = 1.0 / sampleRate;
double natural_decay_factor = exp(- sample_time / decay_time);
...
double iteration(double sample) {
iterationSum *= natural_decay_factor;
...
}
Причина ~37%
это потому что exp(x) = e^x
, где e — база «натурального логарифма», а 1/e ~ 0.3678...
.Если вам нужен другой коэффициент затухания для вашего времени затухания, вам нужно масштабировать его на константу:
// for decay to 50% amplitude (~ -6dB) over the given decay_time:
double halflife_decay_factor = exp(- log(2) * sample_time / decay_time);
// for decay to 10% amplitude (-20dB) over the given decay_time:
double db20_decay_factor = exp(- log(10) * sample_time / decay_time);
Другие советы
Я не уверен, если я понял, но как насчет чего-то вроде этого:
public void fadeOut(double sampleRate)
{
//run 1 iteration per sec?
int defaultIterations=10;
double decrement = calculateIteration(sampleRate, defaultIterations);
for(int i=0; i < defaultIterations; i++)
{
//maybe run each one of these loops every x ms?
sampleRate = processIteration(sampleRate, decrement);
}
}
public double calculateIteration(double sampleRate, int numIterations)
{
return sampleRate/numIterations;
}
private double processIteration(double sampleRate, double decrement)
{
return sampleRate -= decrement;
}
.