/* Copyright 2012 Dietrich Epp */ #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(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(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; }