sox_ng/libdolbyb/HPF2SetVals.c
Martin Guy e7190574aa Sync with libdolbyb-1.1
One change: from #include "configure.h" to "../src/soxconfig.h"
2026-02-20 22:44:21 +01:00

292 lines
9.1 KiB
C

/*
* HPF2SetVals.c, part of libdolbyb:
*
* Copyright (C) 2025 Martin Guy <martinwguy@gmail.com>
* based on dolbybcsoftwaredecode by Richard Evans 2018.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. See COPYING for details.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dolbyb.h"
#include "HPF2SetVals.h"
#include "HPFAdj.h"
#include "Param.h"
#include "SetGate.h"
#include <stdlib.h> /* for malloc() and calloc() */
#include <math.h>
/* These are not defined/declared when compiling -ansi (C90) */
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
extern double round(double x);
/* Try adding a facility to start attenuating the filter output */
/* rather than keep increasing to fc of the filter */
/* Amend to upsample and then downsample the audio */
/* going through the filter according to Param.UpSmp */
#define HPF2SetValsPotTarget 1000000L
#define HPF2SetValsMaxAlpVal 1000000L
/* Calculate the resistance of a FET from its gate voltage. */
/* I will attempt to use */
/*1/Rds=1/rDS=2IDSS/-Vgs(off)*(1-vgs/Vgs(off)+Vds/Vgs(off))*/
static double FETRes(double Vgs)
{
double MinVgs, NewVgs, Val1, val2, OutVal;
/* Vgs must be at least slightly more than ParamVgsOff */
/* to avoid a division by zero */
MinVgs = ParamVgsOff + 0.0001;
/* Check input is within range */
if (Vgs < MinVgs)
NewVgs = MinVgs;
else
NewVgs = Vgs;
/* Lower part of the equation */
Val1 = 1.0 - NewVgs / ParamVgsOff;
/* Upper part of the equation */
val2 = 1.0 / Val1;
/* Result */
OutVal = 2000.0 / ParamIDSS * val2;
if (OutVal > 1000000.0) OutVal = 1000000.0;
if (OutVal < 100.0) OutVal = 100.0;
return OutVal;
}
/*********************************/
/**** Management of tables ****/
/*********************************/
static uint16_t HPF2SetValsTabPos(dolbyb_t *Param, int64_t VltDif)
{
/* Return table position for an input voltage */
return (uint16_t)(VltDif / Param->HPF2SetValsTabRes);
}
static void HPF2SetValsTableRes(dolbyb_t *Param)
{
/* Set table resolution and maximum voltage */
Param->HPF2SetValsMaxVlt = round(ParamVltMux * -ParamVgsOff);
Param->HPF2SetValsTabRes = Param->HPF2SetValsMaxVlt / HPF2SetValsTableSize;
while (HPF2SetValsTabPos(Param, Param->HPF2SetValsMaxVlt) < HPF2SetValsTableSize)
Param->HPF2SetValsTabRes++;
while (HPF2SetValsTabPos(Param, Param->HPF2SetValsMaxVlt) > HPF2SetValsTableSize)
Param->HPF2SetValsTabRes--;
}
static double HPF2SetValsRes(dolbyb_t *Param, uint16_t TabPos)
{
/* Return FET resistance for different table positions */
int64_t Vlt;
double Vgs, Res;
Vlt = TabPos * Param->HPF2SetValsTabRes;
Vgs = 0.0 - (double)Vlt / ParamVltMux;
Res = FETRes(Vgs);
return Res;
}
static void HPF2SetValsMakePotTable(dolbyb_t *Param)
{
/* Make table for first attenuation stage */
uint16_t TabCnt;
double ResVal, PotVal;
/* Set lowest resistance to get multiplier */
ResVal = HPF2SetValsRes(Param, 0);
PotVal = ResVal / (ResVal + ParamR2);
Param->HPF2SetValsPotMux = ParamMuxValue(PotVal, HPF2SetValsPotTarget);
/* Set table values */
for (TabCnt = 0; TabCnt <= HPF2SetValsTableSize; TabCnt++) {
ResVal = HPF2SetValsRes(Param, TabCnt);
PotVal = ResVal / (ResVal + ParamR2);
Param->HPF2SetValsPotTab[TabCnt] = round(Param->HPF2SetValsPotMux * PotVal);
}
}
static double HPF2SetValsMakeAlpVal(dolbyb_t *Param, uint16_t TabPos, uint32_t SmpSec)
{
/* Calculate alpha value for different table positions */
/* Also calculate additional attenuation, */
/* rather than set filter frequency too high */
double dt, fc, RC, Att;
dt = 1.0 / SmpSec;
RC = HPF2SetValsRes(Param, TabPos) * ParamC2;
/* Minimise frequency if required */
if (Param->FltTyp == 2 || Param->FltTyp == 4) {
if (RC > Param->HPF2SetValsMaxRC)
RC = Param->HPF2SetValsMaxRC;
}
/* Maximise frequency if necessary and add attenuation instead */
if (Param->HPF2SetValsRCDif > 0.0 && RC < Param->HPF2SetValsMinRC) {
Att = 1.0 - (Param->HPF2SetValsMinRC - RC) / Param->HPF2SetValsRCDif;
RC = Param->HPF2SetValsMinRC;
} else
Att = 1.0;
Param->HPF2SetValsFLTATb[TabPos] = round(HPF2SetValsFltAttMux * Att);
/* Adjust RC and calculate alpha */
fc = 1 / (2 * M_PI * RC);
RC *= HPFAdj(fc / SmpSec);
return (RC / (RC + dt));
}
static void HPF2SetValsMakeAlpTable(dolbyb_t *Param)
{
/* Create table of alpha values for filter */
uint16_t TabCnt;
uint32_t SmpSec;
int64_t AlpVal;
double a;
int64_t PrvAlp = 0;
/* Set some initial values */
SmpSec = Param->UpSmp * Param->SmpSec;
/* Set high value to get multiplier */
a = HPF2SetValsMakeAlpVal(Param, HPF2SetValsTableSize, SmpSec);
Param->HPF2SetValsAlpMux = ParamMuxValue(a, ParamAlpTgt);
/* Now calculate table values */
for (TabCnt = 0; TabCnt <= HPF2SetValsTableSize; TabCnt++) {
a = HPF2SetValsMakeAlpVal(Param, TabCnt, SmpSec);
AlpVal = round(Param->HPF2SetValsAlpMux * a);
if (AlpVal < PrvAlp)
AlpVal = PrvAlp;
PrvAlp = AlpVal;
Param->HPF2SetValsAlpTab[TabCnt] = AlpVal;
}
}
/********************************************************/
/**** Extra table for attenuation of filter output ****/
/********************************************************/
static void HPF2SetValsSetHighestFreq(dolbyb_t *Param)
{
/* Set highest frequency for filter, and so set minimum RC value */
/* Also set difference in RC when program would like to use higher frequencies */
uint32_t SmpSec;
double ResVal, MaxFrq;
SmpSec = Param->UpSmp * Param->SmpSec;
MaxFrq = (double)SmpSec * ParamMxFqRt; /* Max filter frequency allowed */
Param->HPF2SetValsMinRC = 1 / (2 * M_PI * MaxFrq); /* RC for max frequency */
/* Now calculate highest frequency that the program might want to use */
/* and calculate difference in RC */
ResVal = HPF2SetValsRes(Param, 0); /* Lowest resistance FET value */
Param->HPF2SetValsLowRC = ResVal * ParamC2; /* RC for highst frequency wanted */
if (Param->HPF2SetValsMinRC <= Param->HPF2SetValsLowRC)
Param->HPF2SetValsMinRC = Param->HPF2SetValsLowRC;
Param->HPF2SetValsRCDif = Param->HPF2SetValsMinRC - Param->HPF2SetValsLowRC;
}
/****************************/
/**** Initialisation ****/
/****************************/
char *HPF2SetValsInit(dolbyb_t *Param)
{
if (Param->HPF2SetValsPotTab == NULL)
Param->HPF2SetValsPotTab = calloc(HPF2SetValsTableSize + 1, sizeof(*Param->HPF2SetValsPotTab));
if (Param->HPF2SetValsAlpTab == NULL)
Param->HPF2SetValsAlpTab = calloc(HPF2SetValsTableSize + 1, sizeof(*Param->HPF2SetValsAlpTab));
if (Param->HPF2SetValsFLTATb == NULL)
Param->HPF2SetValsFLTATb = calloc(HPF2SetValsTableSize + 1, sizeof(*Param->HPF2SetValsFLTATb));
if (Param->HPF2SetValsPotTab == NULL ||
Param->HPF2SetValsAlpTab == NULL ||
Param->HPF2SetValsFLTATb == NULL) return "Out of memory";
HPF2SetValsSetHighestFreq(Param);
Param->HPF2SetValsMaxRC = ParamR1 * ParamC1;
HPF2SetValsTableRes(Param);
HPF2SetValsMakePotTable(Param);
HPF2SetValsMakeAlpTable(Param);
return NULL;
}
/************************/
/**** Set Values ****/
/************************/
void HPF2SetVals(dolbyb_t *Param, uint16_t FltNum)
{
int64_t VltDif, TabVlt, TbVtDf, PotVal, PotDif, AlpVal, AlpDif, FAtVal,
FAtDif, SVlt;
uint16_t TabPos, NxTbPs;
/* Find voltage value */
SVlt = Param->FETSVt;
VltDif = SVlt - Param->FETGVt - Param->SetGateOut[FltNum-1];
if (VltDif < 0)
VltDif = 0;
if (VltDif > Param->HPF2SetValsMaxVlt)
VltDif = Param->HPF2SetValsMaxVlt;
/* Set table positions from voltage */
TabPos = HPF2SetValsTabPos(Param, VltDif);
if (TabPos < HPF2SetValsTableSize)
NxTbPs = TabPos + 1; /* Next position in table if possible */
else
NxTbPs = HPF2SetValsTableSize;
/* Work out effective voltage for table position */
TabVlt = TabPos * Param->HPF2SetValsTabRes; /* Voltage for table position */
TbVtDf = VltDif - TabVlt; /* Difference between actual voltage
* and table voltage*/
/* Get values for table position and next table position */
PotVal = Param->HPF2SetValsPotTab[TabPos];
PotDif = Param->HPF2SetValsPotTab[NxTbPs] - PotVal;
AlpVal = Param->HPF2SetValsAlpTab[TabPos];
AlpDif = Param->HPF2SetValsAlpTab[NxTbPs] - AlpVal;
FAtVal = Param->HPF2SetValsFLTATb[TabPos];
FAtDif = Param->HPF2SetValsFLTATb[NxTbPs] - FAtVal;
/* Set final values */
PotVal += TbVtDf * PotDif / Param->HPF2SetValsTabRes;
AlpVal += TbVtDf * AlpDif / Param->HPF2SetValsTabRes;
FAtVal += TbVtDf * FAtDif / Param->HPF2SetValsTabRes;
Param->HPF2SetValsPot[FltNum-1] = PotVal;
Param->HPF2SetValsAlp[FltNum-1] = AlpVal;
Param->HPF2SetValsFPt[FltNum-1] = FAtVal;
}