mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-03-22 12:18:32 -04:00
Added new audio compressor based on sndfilter library
This commit is contained in:
parent
fbbc9a19b7
commit
8cb4ed57ed
@ -51,6 +51,7 @@ endif(LIBSERIALDV_FOUND)
|
||||
set(sdrbase_SOURCES
|
||||
${sdrbase_SOURCES}
|
||||
audio/audiocompressor.cpp
|
||||
audio/audiocompressorsnd.cpp
|
||||
audio/audiodevicemanager.cpp
|
||||
audio/audiofifo.cpp
|
||||
audio/audiofilter.cpp
|
||||
@ -152,6 +153,7 @@ set(sdrbase_SOURCES
|
||||
set(sdrbase_HEADERS
|
||||
${sdrbase_HEADERS}
|
||||
audio/audiocompressor.h
|
||||
audio/audiocompressorsnd.h
|
||||
audio/audiodevicemanager.h
|
||||
audio/audiofifo.h
|
||||
audio/audiofilter.h
|
||||
|
324
sdrbase/audio/audiocompressorsnd.cpp
Normal file
324
sdrbase/audio/audiocompressorsnd.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// Audio compressor based on sndfilter by Sean Connelly (@voidqk) //
|
||||
// https://github.com/voidqk/sndfilter //
|
||||
// //
|
||||
// Sample by sample interface to facilitate integration in SDRangel modulators. //
|
||||
// Uses mono samples (just floats) //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <algorithm>
|
||||
#include "audiocompressorsnd.h"
|
||||
|
||||
|
||||
AudioCompressorSnd::AudioCompressorSnd()
|
||||
{
|
||||
m_sampleIndex = 0;
|
||||
std::fill(m_processedBuffer, m_processedBuffer+AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE, 0.0f);
|
||||
}
|
||||
|
||||
AudioCompressorSnd::~AudioCompressorSnd()
|
||||
{}
|
||||
|
||||
void AudioCompressorSnd::initState()
|
||||
{
|
||||
m_compressorState.sf_advancecomp(
|
||||
m_rate,
|
||||
m_pregain,
|
||||
m_threshold,
|
||||
m_knee,
|
||||
m_ratio,
|
||||
m_attack,
|
||||
m_release,
|
||||
m_predelay,
|
||||
m_releasezone1,
|
||||
m_releasezone2,
|
||||
m_releasezone3,
|
||||
m_releasezone4,
|
||||
m_postgain,
|
||||
m_wet
|
||||
);
|
||||
}
|
||||
|
||||
float AudioCompressorSnd::compress(float sample)
|
||||
{
|
||||
if (m_sampleIndex >= AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE)
|
||||
{
|
||||
sf_compressor_process(&m_compressorState, AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE, m_storageBuffer, m_processedBuffer);
|
||||
m_sampleIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_storageBuffer[m_sampleIndex] = sample;
|
||||
m_sampleIndex++;
|
||||
}
|
||||
|
||||
return m_processedBuffer[m_sampleIndex];
|
||||
}
|
||||
|
||||
// populate the compressor state with advanced parameters
|
||||
void AudioCompressorSnd::CompressorState::sf_advancecomp(
|
||||
// these parameters are the same as the simple version above:
|
||||
int rate, float pregain, float threshold, float knee, float ratio, float attack, float release,
|
||||
// these are the advanced parameters:
|
||||
float predelay, // seconds, length of the predelay buffer [0 to 1]
|
||||
float releasezone1, // release zones should be increasing between 0 and 1, and are a fraction
|
||||
float releasezone2, // of the release time depending on the input dB -- these parameters define
|
||||
float releasezone3, // the adaptive release curve, which is discussed in further detail in the
|
||||
float releasezone4, // demo: adaptive-release-curve.html
|
||||
float postgain, // dB, amount of gain to apply after compression [0 to 100]
|
||||
float wet) // amount to apply the effect [0 completely dry to 1 completely wet]
|
||||
{
|
||||
// setup the predelay buffer
|
||||
int delaybufsize = rate * predelay;
|
||||
|
||||
if (delaybufsize < 1)
|
||||
{
|
||||
delaybufsize = 1;
|
||||
}
|
||||
else if (delaybufsize > AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY)
|
||||
{
|
||||
delaybufsize = AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY;
|
||||
std::fill(delaybuf, delaybuf+delaybufsize, 0.0f);
|
||||
}
|
||||
|
||||
// useful values
|
||||
float linearpregain = db2lin(pregain);
|
||||
float linearthreshold = db2lin(threshold);
|
||||
float slope = 1.0f / ratio;
|
||||
float attacksamples = rate * attack;
|
||||
float attacksamplesinv = 1.0f / attacksamples;
|
||||
float releasesamples = rate * release;
|
||||
float satrelease = 0.0025f; // seconds
|
||||
float satreleasesamplesinv = 1.0f / ((float)rate * satrelease);
|
||||
float dry = 1.0f - wet;
|
||||
|
||||
// metering values (not used in core algorithm, but used to output a meter if desired)
|
||||
float metergain = 1.0f; // gets overwritten immediately because gain will always be negative
|
||||
float meterfalloff = 0.325f; // seconds
|
||||
float meterrelease = 1.0f - expf(-1.0f / ((float)rate * meterfalloff));
|
||||
|
||||
// calculate knee curve parameters
|
||||
float k = 5.0f; // initial guess
|
||||
float kneedboffset = 0.0f;
|
||||
float linearthresholdknee = 0.0f;
|
||||
|
||||
if (knee > 0.0f) // if a knee exists, search for a good k value
|
||||
{
|
||||
float xknee = db2lin(threshold + knee);
|
||||
float mink = 0.1f;
|
||||
float maxk = 10000.0f;
|
||||
|
||||
// search by comparing the knee slope at the current k guess, to the ideal slope
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
if (kneeslope(xknee, k, linearthreshold) < slope) {
|
||||
maxk = k;
|
||||
} else {
|
||||
mink = k;
|
||||
}
|
||||
|
||||
k = sqrtf(mink * maxk);
|
||||
}
|
||||
|
||||
kneedboffset = lin2db(kneecurve(xknee, k, linearthreshold));
|
||||
linearthresholdknee = db2lin(threshold + knee);
|
||||
}
|
||||
|
||||
// calculate a master gain based on what sounds good
|
||||
float fulllevel = compcurve(1.0f, k, slope, linearthreshold, linearthresholdknee, threshold, knee, kneedboffset);
|
||||
float mastergain = db2lin(postgain) * powf(1.0f / fulllevel, 0.6f);
|
||||
|
||||
// calculate the adaptive release curve parameters
|
||||
// solve a,b,c,d in `y = a*x^3 + b*x^2 + c*x + d`
|
||||
// interescting points (0, y1), (1, y2), (2, y3), (3, y4)
|
||||
float y1 = releasesamples * releasezone1;
|
||||
float y2 = releasesamples * releasezone2;
|
||||
float y3 = releasesamples * releasezone3;
|
||||
float y4 = releasesamples * releasezone4;
|
||||
float a = (-y1 + 3.0f * y2 - 3.0f * y3 + y4) / 6.0f;
|
||||
float b = y1 - 2.5f * y2 + 2.0f * y3 - 0.5f * y4;
|
||||
float c = (-11.0f * y1 + 18.0f * y2 - 9.0f * y3 + 2.0f * y4) / 6.0f;
|
||||
float d = y1;
|
||||
|
||||
// save everything
|
||||
this->metergain = 1.0f; // large value overwritten immediately since it's always < 0
|
||||
this->meterrelease = meterrelease;
|
||||
this->threshold = threshold;
|
||||
this->knee = knee;
|
||||
this->wet = wet;
|
||||
this->linearpregain = linearpregain;
|
||||
this->linearthreshold = linearthreshold;
|
||||
this->slope = slope;
|
||||
this->attacksamplesinv = attacksamplesinv;
|
||||
this->satreleasesamplesinv = satreleasesamplesinv;
|
||||
this->dry = dry;
|
||||
this->k = k;
|
||||
this->kneedboffset = kneedboffset;
|
||||
this->linearthresholdknee = linearthresholdknee;
|
||||
this->mastergain = mastergain;
|
||||
this->a = a;
|
||||
this->b = b;
|
||||
this->c = c;
|
||||
this->d = d;
|
||||
this->detectoravg = 0.0f;
|
||||
this->compgain = 1.0f;
|
||||
this->maxcompdiffdb = -1.0f;
|
||||
this->delaybufsize = delaybufsize;
|
||||
this->delaywritepos = 0;
|
||||
this->delayreadpos = delaybufsize > 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
void AudioCompressorSnd::sf_compressor_process(AudioCompressorSnd::CompressorState *state, int size, float *input, float *output)
|
||||
{
|
||||
// pull out the state into local variables
|
||||
float metergain = state->metergain;
|
||||
float meterrelease = state->meterrelease;
|
||||
float threshold = state->threshold;
|
||||
float knee = state->knee;
|
||||
float linearpregain = state->linearpregain;
|
||||
float linearthreshold = state->linearthreshold;
|
||||
float slope = state->slope;
|
||||
float attacksamplesinv = state->attacksamplesinv;
|
||||
float satreleasesamplesinv = state->satreleasesamplesinv;
|
||||
float wet = state->wet;
|
||||
float dry = state->dry;
|
||||
float k = state->k;
|
||||
float kneedboffset = state->kneedboffset;
|
||||
float linearthresholdknee = state->linearthresholdknee;
|
||||
float mastergain = state->mastergain;
|
||||
float a = state->a;
|
||||
float b = state->b;
|
||||
float c = state->c;
|
||||
float d = state->d;
|
||||
float detectoravg = state->detectoravg;
|
||||
float compgain = state->compgain;
|
||||
float maxcompdiffdb = state->maxcompdiffdb;
|
||||
int delaybufsize = state->delaybufsize;
|
||||
int delaywritepos = state->delaywritepos;
|
||||
int delayreadpos = state->delayreadpos;
|
||||
float *delaybuf = state->delaybuf;
|
||||
|
||||
int samplesperchunk = AUDIOCOMPRESSORSND_SF_COMPRESSOR_SPU;
|
||||
int chunks = size / samplesperchunk;
|
||||
float ang90 = (float)M_PI * 0.5f;
|
||||
float ang90inv = 2.0f / (float)M_PI;
|
||||
int samplepos = 0;
|
||||
float spacingdb = AUDIOCOMPRESSORSND_SF_COMPRESSOR_SPACINGDB;
|
||||
|
||||
for (int ch = 0; ch < chunks; ch++)
|
||||
{
|
||||
detectoravg = fixf(detectoravg, 1.0f);
|
||||
float desiredgain = detectoravg;
|
||||
float scaleddesiredgain = asinf(desiredgain) * ang90inv;
|
||||
float compdiffdb = lin2db(compgain / scaleddesiredgain);
|
||||
|
||||
// calculate envelope rate based on whether we're attacking or releasing
|
||||
float enveloperate;
|
||||
if (compdiffdb < 0.0f)
|
||||
{ // compgain < scaleddesiredgain, so we're releasing
|
||||
compdiffdb = fixf(compdiffdb, -1.0f);
|
||||
maxcompdiffdb = -1; // reset for a future attack mode
|
||||
// apply the adaptive release curve
|
||||
// scale compdiffdb between 0-3
|
||||
float x = (clampf(compdiffdb, -12.0f, 0.0f) + 12.0f) * 0.25f;
|
||||
float releasesamples = adaptivereleasecurve(x, a, b, c, d);
|
||||
enveloperate = db2lin(spacingdb / releasesamples);
|
||||
}
|
||||
else
|
||||
{ // compresorgain > scaleddesiredgain, so we're attacking
|
||||
compdiffdb = fixf(compdiffdb, 1.0f);
|
||||
if (maxcompdiffdb == -1 || maxcompdiffdb < compdiffdb)
|
||||
maxcompdiffdb = compdiffdb;
|
||||
float attenuate = maxcompdiffdb;
|
||||
if (attenuate < 0.5f)
|
||||
attenuate = 0.5f;
|
||||
enveloperate = 1.0f - powf(0.25f / attenuate, attacksamplesinv);
|
||||
}
|
||||
|
||||
// process the chunk
|
||||
for (int chi = 0; chi < samplesperchunk; chi++, samplepos++,
|
||||
delayreadpos = (delayreadpos + 1) % delaybufsize,
|
||||
delaywritepos = (delaywritepos + 1) % delaybufsize)
|
||||
{
|
||||
|
||||
float inputL = input[samplepos] * linearpregain;
|
||||
delaybuf[delaywritepos] = inputL;
|
||||
|
||||
inputL = absf(inputL);
|
||||
float inputmax = inputL;
|
||||
|
||||
float attenuation;
|
||||
if (inputmax < 0.0001f)
|
||||
attenuation = 1.0f;
|
||||
else
|
||||
{
|
||||
float inputcomp = compcurve(inputmax, k, slope, linearthreshold,
|
||||
linearthresholdknee, threshold, knee, kneedboffset);
|
||||
attenuation = inputcomp / inputmax;
|
||||
}
|
||||
|
||||
float rate;
|
||||
if (attenuation > detectoravg)
|
||||
{ // if releasing
|
||||
float attenuationdb = -lin2db(attenuation);
|
||||
if (attenuationdb < 2.0f)
|
||||
attenuationdb = 2.0f;
|
||||
float dbpersample = attenuationdb * satreleasesamplesinv;
|
||||
rate = db2lin(dbpersample) - 1.0f;
|
||||
}
|
||||
else
|
||||
rate = 1.0f;
|
||||
|
||||
detectoravg += (attenuation - detectoravg) * rate;
|
||||
if (detectoravg > 1.0f)
|
||||
detectoravg = 1.0f;
|
||||
detectoravg = fixf(detectoravg, 1.0f);
|
||||
|
||||
if (enveloperate < 1) // attack, reduce gain
|
||||
compgain += (scaleddesiredgain - compgain) * enveloperate;
|
||||
else
|
||||
{ // release, increase gain
|
||||
compgain *= enveloperate;
|
||||
if (compgain > 1.0f)
|
||||
compgain = 1.0f;
|
||||
}
|
||||
|
||||
// the final gain value!
|
||||
float premixgain = sinf(ang90 * compgain);
|
||||
float gain = dry + wet * mastergain * premixgain;
|
||||
|
||||
// calculate metering (not used in core algo, but used to output a meter if desired)
|
||||
float premixgaindb = lin2db(premixgain);
|
||||
if (premixgaindb < metergain)
|
||||
metergain = premixgaindb; // spike immediately
|
||||
else
|
||||
metergain += (premixgaindb - metergain) * meterrelease; // fall slowly
|
||||
|
||||
// apply the gain
|
||||
output[samplepos] = delaybuf[delayreadpos] * gain;
|
||||
}
|
||||
}
|
||||
|
||||
state->metergain = metergain;
|
||||
state->detectoravg = detectoravg;
|
||||
state->compgain = compgain;
|
||||
state->maxcompdiffdb = maxcompdiffdb;
|
||||
state->delaywritepos = delaywritepos;
|
||||
state->delayreadpos = delayreadpos;
|
||||
}
|
229
sdrbase/audio/audiocompressorsnd.h
Normal file
229
sdrbase/audio/audiocompressorsnd.h
Normal file
@ -0,0 +1,229 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2019 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// Audio compressor based on sndfilter by Sean Connelly (@voidqk) //
|
||||
// https://github.com/voidqk/sndfilter //
|
||||
// //
|
||||
// Sample by sample interface to facilitate integration in SDRangel modulators. //
|
||||
// Uses mono samples (just floats) //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_
|
||||
#define SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// maximum number of samples in the delay buffer
|
||||
#define AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY 1024
|
||||
|
||||
// samples per update; the compressor works by dividing the input chunks into even smaller sizes,
|
||||
// and performs heavier calculations after each mini-chunk to adjust the final envelope
|
||||
#define AUDIOCOMPRESSORSND_SF_COMPRESSOR_SPU 32
|
||||
|
||||
// not sure what this does exactly, but it is part of the release curve
|
||||
#define AUDIOCOMPRESSORSND_SF_COMPRESSOR_SPACINGDB 5.0f
|
||||
|
||||
// the "chunk" size as defined in original sndfilter library
|
||||
#define AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE 128
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class SDRBASE_API AudioCompressorSnd
|
||||
{
|
||||
public:
|
||||
AudioCompressorSnd();
|
||||
~AudioCompressorSnd();
|
||||
|
||||
void initDefault(int rate)
|
||||
{
|
||||
m_rate = rate;
|
||||
m_pregain = 0.000f;
|
||||
m_threshold = -24.000f;
|
||||
m_knee = 30.000f;
|
||||
m_ratio = 12.000f;
|
||||
m_attack = 0.003f;
|
||||
m_release = 0.250f;
|
||||
m_predelay = 0.006f;
|
||||
m_releasezone1 = 0.090f;
|
||||
m_releasezone2 = 0.160f;
|
||||
m_releasezone3 = 0.420f;
|
||||
m_releasezone4 = 0.980f;
|
||||
m_postgain = 0.000f;
|
||||
m_wet = 1.000f;
|
||||
initState();
|
||||
}
|
||||
|
||||
void initSimple(
|
||||
int rate, // input sample rate (samples per second)
|
||||
float pregain, // dB, amount to boost the signal before applying compression [0 to 100]
|
||||
float threshold, // dB, level where compression kicks in [-100 to 0]
|
||||
float knee, // dB, width of the knee [0 to 40]
|
||||
float ratio, // unitless, amount to inversely scale the output when applying comp [1 to 20]
|
||||
float attack, // seconds, length of the attack phase [0 to 1]
|
||||
float release // seconds, length of the release phase [0 to 1]
|
||||
)
|
||||
{
|
||||
m_rate = rate;
|
||||
m_pregain = pregain;
|
||||
m_threshold = threshold;
|
||||
m_knee = knee;
|
||||
m_ratio = ratio;
|
||||
m_attack = attack;
|
||||
m_release = release;
|
||||
m_predelay = 0.006f;
|
||||
m_releasezone1 = 0.090f;
|
||||
m_releasezone2 = 0.160f;
|
||||
m_releasezone3 = 0.420f;
|
||||
m_releasezone4 = 0.980f;
|
||||
m_postgain = 0.000f;
|
||||
m_wet = 1.000f;
|
||||
initState();
|
||||
}
|
||||
|
||||
void initState();
|
||||
float compress(float sample);
|
||||
|
||||
float m_rate;
|
||||
float m_pregain;
|
||||
float m_threshold;
|
||||
float m_knee;
|
||||
float m_ratio;
|
||||
float m_attack;
|
||||
float m_release;
|
||||
float m_predelay;
|
||||
float m_releasezone1;
|
||||
float m_releasezone2;
|
||||
float m_releasezone3;
|
||||
float m_releasezone4;
|
||||
float m_postgain;
|
||||
float m_wet;
|
||||
|
||||
private:
|
||||
static inline float db2lin(float db){ // dB to linear
|
||||
return powf(10.0f, 0.05f * db);
|
||||
}
|
||||
|
||||
static inline float lin2db(float lin){ // linear to dB
|
||||
return 20.0f * log10f(lin);
|
||||
}
|
||||
|
||||
// for more information on the knee curve, check out the compressor-curve.html demo + source code
|
||||
// included in this repo
|
||||
static inline float kneecurve(float x, float k, float linearthreshold){
|
||||
return linearthreshold + (1.0f - expf(-k * (x - linearthreshold))) / k;
|
||||
}
|
||||
|
||||
static inline float kneeslope(float x, float k, float linearthreshold){
|
||||
return k * x / ((k * linearthreshold + 1.0f) * expf(k * (x - linearthreshold)) - 1);
|
||||
}
|
||||
|
||||
static inline float compcurve(float x, float k, float slope, float linearthreshold,
|
||||
float linearthresholdknee, float threshold, float knee, float kneedboffset){
|
||||
if (x < linearthreshold)
|
||||
return x;
|
||||
if (knee <= 0.0f) // no knee in curve
|
||||
return db2lin(threshold + slope * (lin2db(x) - threshold));
|
||||
if (x < linearthresholdknee)
|
||||
return kneecurve(x, k, linearthreshold);
|
||||
return db2lin(kneedboffset + slope * (lin2db(x) - threshold - knee));
|
||||
}
|
||||
|
||||
// for more information on the adaptive release curve, check out adaptive-release-curve.html demo +
|
||||
// source code included in this repo
|
||||
static inline float adaptivereleasecurve(float x, float a, float b, float c, float d){
|
||||
// a*x^3 + b*x^2 + c*x + d
|
||||
float x2 = x * x;
|
||||
return a * x2 * x + b * x2 + c * x + d;
|
||||
}
|
||||
|
||||
static inline float clampf(float v, float min, float max){
|
||||
return v < min ? min : (v > max ? max : v);
|
||||
}
|
||||
|
||||
static inline float absf(float v){
|
||||
return v < 0.0f ? -v : v;
|
||||
}
|
||||
|
||||
static inline float fixf(float v, float def){
|
||||
// fix NaN and infinity values that sneak in... not sure why this is needed, but it is
|
||||
if (isnan(v) || isinf(v))
|
||||
return def;
|
||||
return v;
|
||||
}
|
||||
|
||||
struct CompressorState
|
||||
{ // sf_compressor_state_st
|
||||
// user can read the metergain state variable after processing a chunk to see how much dB the
|
||||
// compressor would have liked to compress the sample; the meter values aren't used to shape the
|
||||
// sound in any way, only used for output if desired
|
||||
float metergain;
|
||||
|
||||
// everything else shouldn't really be mucked with unless you read the algorithm and feel
|
||||
// comfortable
|
||||
float meterrelease;
|
||||
float threshold;
|
||||
float knee;
|
||||
float linearpregain;
|
||||
float linearthreshold;
|
||||
float slope;
|
||||
float attacksamplesinv;
|
||||
float satreleasesamplesinv;
|
||||
float wet;
|
||||
float dry;
|
||||
float k;
|
||||
float kneedboffset;
|
||||
float linearthresholdknee;
|
||||
float mastergain;
|
||||
float a; // adaptive release polynomial coefficients
|
||||
float b;
|
||||
float c;
|
||||
float d;
|
||||
float detectoravg;
|
||||
float compgain;
|
||||
float maxcompdiffdb;
|
||||
int delaybufsize;
|
||||
int delaywritepos;
|
||||
int delayreadpos;
|
||||
float delaybuf[AUDIOCOMPRESSORSND_SF_COMPRESSOR_MAXDELAY]; // predelay buffer
|
||||
|
||||
// populate the compressor state with advanced parameters
|
||||
void sf_advancecomp(
|
||||
// these parameters are the same as the simple version above:
|
||||
int rate, float pregain, float threshold, float knee, float ratio, float attack, float release,
|
||||
// these are the advanced parameters:
|
||||
float predelay, // seconds, length of the predelay buffer [0 to 1]
|
||||
float releasezone1, // release zones should be increasing between 0 and 1, and are a fraction
|
||||
float releasezone2, // of the release time depending on the input dB -- these parameters define
|
||||
float releasezone3, // the adaptive release curve, which is discussed in further detail in the
|
||||
float releasezone4, // demo: adaptive-release-curve.html
|
||||
float postgain, // dB, amount of gain to apply after compression [0 to 100]
|
||||
float wet // amount to apply the effect [0 completely dry to 1 completely wet]
|
||||
);
|
||||
};
|
||||
|
||||
static void sf_compressor_process(CompressorState *state, int size, float *input, float *output);
|
||||
|
||||
CompressorState m_compressorState;
|
||||
float m_storageBuffer[AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE];
|
||||
float m_processedBuffer[AUDIOCOMPRESSORSND_SF_COMPRESSOR_CHUNKSIZE];
|
||||
int m_sampleIndex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SDRBASE_AUDIO_AUDIOCOMPRESSORSND_H_
|
Loading…
Reference in New Issue
Block a user