diff options
| author | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-11-28 20:16:46 +0100 |
|---|---|---|
| committer | Markus Mittendrein <maxmitti@maxmitti.tk> | 2022-11-28 20:16:46 +0100 |
| commit | 4cb83acddbe154312b74d2d63985ac1100bad7c5 (patch) | |
| tree | d49dc904acc9af57acca8864fb6a40e340accacc /lib/param.cpp | |
| download | fresample-master.tar.gz fresample-master.zip | |
Diffstat (limited to 'lib/param.cpp')
| -rw-r--r-- | lib/param.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/lib/param.cpp b/lib/param.cpp new file mode 100644 index 0000000..58bcf5b --- /dev/null +++ b/lib/param.cpp @@ -0,0 +1,236 @@ +/* Copyright 2012 Dietrich Epp <depp@zdome.net> */ +#include "param.h" + +void lfr_param::seti(lfr_param_t pname, int value) +{ + int n = pname; + if (n < 0 || n >= LFR_PARAM_COUNT) + return; + set |= 1u << n; + current = 0; + param[n] = (double) value; +} + +void lfr_param::setf(lfr_param_t pname, double value) +{ + int n = pname; + if (n < 0 || n >= LFR_PARAM_COUNT) + return; + set |= 1u << n; + current = 0; + param[n] = value; +} + +void lfr_param::geti(lfr_param_t pname, int *value) +{ + int n = pname; + if (n < 0 || n >= LFR_PARAM_COUNT) + return; + if (!current) + calculate(); + *value = static_cast<int>(param[n] + 0.5); +} + +void lfr_param::getf(lfr_param_t pname, double *value) +{ + int n = pname; + if (n < 0 || n >= LFR_PARAM_COUNT) + return; + if (!current) + calculate(); + *value = param[n]; +} + +constexpr auto MAX_QUALITY = 10; + +struct lfr_quality { + unsigned short atten; /* dB */ + unsigned short transition; /* out of 1000 */ + unsigned short kind; /* 0 = loose, 2 = maxfreq=0 */ + unsigned short minfpass; /* out of 1000 */ +}; + +constexpr lfr_quality LFR_QUALITY[MAX_QUALITY + 1] = { + { 35, 350, 0, 500 }, + { 35, 350, 0, 500 }, + { 35, 350, 0, 500 }, /* low */ + { 35, 350, 0, 500 }, + { 50, 290, 0, 600 }, + { 60, 230, 1, 700 }, /* medium */ + { 80, 180, 1, 800 }, + { 90, 140, 1, 850 }, + { 96, 100, 1, 900 }, /* high */ + { 108, 60, 2, 915 }, + { 120, 30, 2, 930 } /* ultra */ +}; + +constexpr auto MIN_OUTPUT = 1.0 / 128; +constexpr auto MIN_ATTEN = 13; +constexpr auto MAX_ATTEN = 144; +constexpr auto MIN_TRANSITION = 1.0 / 256.0; +constexpr auto MAX_MINPASS = 31.0 / 32.0; +constexpr auto MIN_MINPASS = 8.0 / 32.0; + +#define ISSET(n) ((set & (1u << (LFR_PARAM_ ## n))) != 0) +#define GETF(n) (param[LFR_PARAM_ ## n]) +#define GETI(n) (static_cast<int>(GETF(n) + 0.5)) + +void lfr_param::calculate() +{ + int qual; + double rate; + double f_output, f_transition, f_maxfreq, f_minpass; + double atten, f_stop, f_pass; + double t; + int loose; + + /* Quality */ + if (ISSET(QUALITY)) { + qual = GETI(QUALITY); + if (qual < 0) + qual = 0; + else if (qual > MAX_QUALITY) + qual = MAX_QUALITY; + } else { + qual = 8; + } + GETF(QUALITY) = qual; + + /* Input rate */ + if (ISSET(INRATE)) { + rate = GETF(INRATE); + if (rate <= 0) + rate = -1.0; + } else { + rate = -1.0; + } + GETF(INRATE) = rate; + + /* Output rate */ + if (ISSET(OUTRATE)) { + t = GETF(OUTRATE); + if (rate > 0) { + if (t > rate) { + f_output = 1.0; + GETF(OUTRATE) = rate; + } else { + f_output = t / rate; + if (f_output < MIN_OUTPUT) { + f_output = MIN_OUTPUT; + GETF(OUTRATE) = MIN_OUTPUT * rate; + } + } + } else { + if (t >= 1.0) { + f_output = 1.0; + GETF(OUTRATE) = 1.0; + } else { + f_output = t; + if (f_output < MIN_OUTPUT) { + f_output = MIN_OUTPUT; + GETF(OUTRATE) = MIN_OUTPUT; + } + } + } + } else { + f_output = 1.0; + if (rate > 0) + GETF(OUTRATE) = 1.0; + else + GETF(OUTRATE) = rate; + } + + /* Transition bandwidth */ + if (ISSET(FTRANSITION)) { + f_transition = GETF(FTRANSITION); + if (f_transition < MIN_TRANSITION) + f_transition = 1.0/32; + if (f_transition > 1.0) + f_transition = 1.0; + } else { + f_transition = (0.5/1000) * (double) LFR_QUALITY[qual].transition; + } + GETF(FTRANSITION) = f_transition; + + /* Maximum audible frequency */ + if (ISSET(MAXFREQ)) { + f_maxfreq = GETF(MAXFREQ); + } else { + if (LFR_QUALITY[qual].kind < 2) + f_maxfreq = 20000.0; + else + f_maxfreq = -1; + GETF(MAXFREQ) = f_maxfreq; + } + if (rate > 0) + f_maxfreq = f_maxfreq / rate; + else + f_maxfreq = 1.0; + + /* "Loose" flag */ + if (ISSET(LOOSE)) { + loose = GETI(LOOSE) > 0; + } else { + loose = LFR_QUALITY[qual].kind < 1; + } + GETF(LOOSE) = (double) loose; + + /* Minimum output bandwidth */ + if (ISSET(MINFPASS)) { + f_minpass = GETF(MINFPASS); + if (f_minpass < MIN_MINPASS) + f_minpass = MIN_MINPASS; + else if (f_minpass > MAX_MINPASS) + f_minpass = MAX_MINPASS; + } else { + f_minpass = 0.001 * LFR_QUALITY[qual].minfpass; + } + GETF(MINFPASS) = f_minpass; + + /* Stop band attenuation */ + if (ISSET(ATTEN)) { + atten = GETF(ATTEN); + if (atten < MIN_ATTEN) + atten = MIN_ATTEN; + else if (atten > MAX_ATTEN) + atten = MAX_ATTEN; + } else { + atten = (double) LFR_QUALITY[qual].atten; + } + GETF(ATTEN) = atten; + + /* Stop band frequency */ + if (ISSET(FSTOP)) { + f_stop = GETF(FSTOP); + if (f_stop > 1.0) + f_stop = 1.0; + else if (f_stop < MIN_TRANSITION) + f_stop = MIN_TRANSITION; + } else { + f_stop = 0.5 * f_output; + if (loose && f_maxfreq > 0) { + t = f_output - f_maxfreq; + if (t > f_stop) + f_stop = t; + } + } + GETF(FSTOP) = f_stop; + + /* Pass band frequency */ + if (ISSET(ATTEN)) { + f_pass = GETF(FPASS); + } else { + f_pass = f_stop - f_transition; + t = 0.5 * f_output * f_minpass; + if (t > f_pass) + f_pass = t; + if (f_maxfreq > 0 && f_pass > f_maxfreq) + f_pass = f_maxfreq; + } + t = f_stop - MIN_TRANSITION; + if (t < 0) + t = 0; + if (t < f_pass) + f_pass = t; + GETF(FPASS) = f_pass; +} |
