| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- /*
- При выходе сигнала из диапазона порог компрессора начинает опускаться,
- наклонная компрессирования начинает также опускаться. Также в пропорции
- ослабляеться сигнал.
- in ->[Gain]->[compressor]->[soft limiter]-> out
- */
- #include "FxPremaster.h"
- FxPremaster::FxPremaster()
- {
- FXRegistrationInfo(FxPremaster, L"Storm engine FxPremaster", L"Spirenkov Maxim");
- Assert(c_comp_threshold_up > c_comp_threshold_down);
- Assert(c_comp_threshold_down > 0);
- Assert(c_comp_threshold_up < 100);
- Assert(c_limit_threshold > c_comp_threshold_up);
- Assert(c_limit_threshold < 100);
- Assert((c_samples_per_block & (c_samples_per_block - 1)) == 0);
- Assert(c_samples_per_block >= 16);
- Reset();
- }
- FxPremaster::~FxPremaster()
- {
- }
- //Сбросить параметры
- void STDMETHODCALLTYPE FxPremaster::Reset()
- {
- compressorThreshold = c_comp_threshold_up*0.01f;
- compressorThresholdStep = 0.0f;
- compressorRatio = 1.0f;
- compressorRatioStep = 0.0f;
- compressorGain = 1.0f;
- compressorGainStep = 0.0f;
- softLimitGain = 1.0f;
- softLimitNormalizer = 1.0f;
- blockPosition = 0;
- blockCounter = 0;
- for(dword i = 0; i < ARRSIZE(history); i++) history[i] = 0.0f;
- }
- //Процессировать пришедший буфер
- void STDMETHODCALLTYPE FxPremaster::Process(float * __restrict buffer, dword samples)
- {
- //Расчитываем максимальное значение на каждый блок
- dword count = samples << 1;
- float maxVolume = 0.0f;
- dword counter = blockCounter;
- for(dword i = 0; i < count; i++)
- {
- //Считываем значение и получаем абсолютное
- float v = buffer[i];
- float absv = fabsf(v);
- //Максимальное значение для текущего блока
- maxVolume = coremax(absv, maxVolume);
- counter++;
- if(counter == c_samples_per_block)
- {
- //Сохраняем громкость блока
- history[blockPosition] = maxVolume;
- blockPosition = (blockPosition + 1) & (ARRSIZE(history) - 1);
- //Вычисляем текущие параметры компрессора
- float historyMax = 0.0f;
- for(dword j = 0; j < ARRSIZE(history); j++)
- {
- historyMax = coremax(historyMax, history[j]);
- }
- //Расчитываем требуемый коэфициент усиления
- float compressorGainNew = coremin(1.0f/historyMax, 1.0f);
- float blendTimeInSec;
- if(compressorGainNew < compressorGain)
- {
- blendTimeInSec = 2.0f;
- }else{
- blendTimeInSec = 4.0f;
- }
- compressorGainStep = (compressorGainNew - compressorGain)/(44100*blendTimeInSec);
- //Корректируем максимальное значение в соответствие текущего коэфициента усиления
- historyMax *= compressorGain;
- //Порог компрессора
- float thresholdK = Clampf((historyMax - 1.0f)/(3.0f - 1.0f));
- float threshold = c_comp_threshold_up*0.01f + thresholdK*0.01f*(c_comp_threshold_down - c_comp_threshold_up);
- compressorThresholdStep = (threshold - compressorThreshold)*(1.0f/c_samples_per_block);
- //Коэфициент ослабления сигнала выше порогового уровня
- if(historyMax > compressorThreshold)
- {
- float ratio = (1.0f - compressorThreshold)/(historyMax - compressorThreshold);
- compressorRatioStep = (ratio - compressorRatio)*(1.0f/c_samples_per_block);
- }else{
- compressorRatioStep = 0.0f;
- }
- //Начинаем расчёт нового блока
- maxVolume = 0.0f;
- counter = 0;
- }
- //Ослабление сигнала
- absv *= compressorGain;
- //Компрессирование сигнала
- if(absv > compressorThreshold)
- {
- absv = (absv - compressorThreshold)*compressorRatio + compressorThreshold;
- }
- //Константное приведение полного диапазона под лимитер
- absv *= c_limit_threshold*0.01f;
- //Обновляем параметры компресора
- compressorThreshold += compressorThresholdStep;
- compressorRatio += compressorRatioStep;
- compressorGain += compressorGainStep;
- //Лимитирование сигнала
- static const float limitThreshold = c_limit_threshold*0.01f;
- static const float limitNormalize = 1.0f/(1.0f - c_limit_threshold*0.01f);
- static const float limitScale = 1.0f - c_limit_threshold*0.01f;
- if(absv > limitThreshold)
- {
- float limitValue = (absv - limitThreshold)*limitNormalize;
- float limitedValue = 1.0f - 1.0f/(1.0f + limitValue);
- absv = limitedValue*limitScale + limitThreshold;
- }
- //Сохраняем полученое значение в соответствие со знаком
- if(v >= 0.0f)
- {
- buffer[i] = absv;
- }else{
- buffer[i] = -absv;
- }
- }
- blockCounter = counter;
- }
|