JD2022-TU1/main/extern/Camcam/LIBS/Input/CDct.cpp

497 lines
14 KiB
C++

// * DCT modifiée pour calculer toutes les matrices utilisables pour le calcul
// * puis, choix de la bonne matrice en fonction de la taille des données d'entrée
// * Malheureusement on ne peut obtenir sans calcul qu'une matrice de taille n à partir
// * d'une autre de taille n², or ici les différentes tailles nécessaires ne sont pas dans ce cas
// * d'une relation de puissance 2 entre elles. D'où le calcul de toutes les matrices.
// * Résultat : Passage du temps de calcul d'environ 15 ms à environ 3 ou 4 ms (en Release)
// * Pour l'instant, il y a un large choix de matrice (10), utilisées ainsi:
// * Les matrices 0 à 5 permettent de calculer la DCT pour des temps de 50 à 100 ms, pour le mode Release
// * Les matrices 4 à 9 permettent de calculer la DCT pour des temps de 90ms au max (environ 157 ms), pour le mode Debug
// * Attention à la valeur de variables de type 'Somme des coefficients' qui vont probablement avoir des
// * valeurs suffisamment différentes pour fausser la détection silence/parole/souffle.
#include "CDct.h"
const double PI = atan(1.0)*4;
#define SND_VALUE_NEUTRAL 0 // ??
//*******************************************************************************
//* Constructeur
//*******************************************************************************
CDct::CDct()
{
m_bCoefficientIsAccessible = false;
isIdentity = true;
isFullProcess = false;
}
//*******************************************************************************
//* Destructeur
//*******************************************************************************
CDct::~CDct()
{
}
//*******************************************************************************
bool CDct::Liberations()
{
m_bCoefficientIsAccessible = false;
return true;
}
//*******************************************************************************
//* Initialisations de la table des bandes de fréquences, des coefficients
//* et de la matrice de la DCT
//*******************************************************************************
bool CDct::Initialisation()
{
// Par défaut, on considère la taille maximale. Pour l'instant, c'est la taille maximale de ce qui est demandé, soit ( ((SND_SOUNDDATA_SIZE_MAX - SND_HEADER_SIZE_OCTET_TOTAL) >> 2) - 18 )<<2)
// Rq : on met ici la 'formule longue', plutôt que le #define correspondant : SND_DCT_SIZE_SAMPLE, au cas où on diminue ce SND_DCT_SIZE_SAMPLE, qui serait alors une valeur de départ, mais qui pourrait augmenter.
memset( m_pfCoeffs, 0, sizeof(m_pfCoeffs) );
memset( m_pfResultat, 0, sizeof(m_pfResultat) );
memset( m_pfMatrice, 0, sizeof(m_pfMatrice) );
memset(m_pfEffectMatrix,0, sizeof(m_pfEffectMatrix));
*m_pfEffectMatrix = 1.0f; // never touch first element
m_uNbFreq = SND_DCT_SIZE_MATRIX_COEFS;
m_uSampleSize = SND_DCT_SIZE_MATRIX_COEFS;
m_uMatrixSize = ( m_uNbFreq ) * ( m_uSampleSize );
// Calcul une fois pour toutes de la matrice utilisée pour la DCT
m_fAlpha1 = sqrt( 1.0f / m_uNbFreq );
m_fAlpha2 = sqrt( 2.0f / m_uNbFreq ); //sqrt( 1.0f / m_uNbFreq );
ComputeMatrix( m_pfMatrice , m_uNbFreq, m_uSampleSize );
// On met les variables globales en paramètres
// en fait, c'est pour pouvoir utiliser ComputeMatrix avec d'autres valeurs
// Prévoir pour ne mettre que iNumMatrix en paramètre.
// Pour l'instant comme ça pour laisser une insertion sans trop de modifs (1ere étape).
return true;
}
//*******************************************************************************
//* Pour le calcul de la DCT, en utilisant la formule :
//* C(u) = alpha(u) * sum( f(x)*cos( (PI(2x+1)u)/2N) ) )
//* avec u les fréquences et x les échantillons
//*******************************************************************************
float CDct::Alpha( UINT uFreq )
{
if ( uFreq == 0 ) return m_fAlpha1;
else return m_fAlpha2;
}
//* Calculer la matrice utilisée pour la DCT ************************************
void CDct::ComputeMatrix( float* pfMatrice, UINT m_uNbFreq, UINT uSampleSize )
{
float fValue;
float* pfTab = pfMatrice;
for ( UINT uNumFreq = 0; uNumFreq < m_uNbFreq; uNumFreq++ )
{
for ( UINT uIndiceData = 0; uIndiceData < uSampleSize; uIndiceData++, pfTab++ )
{
fValue = Alpha( uNumFreq );
float fProduit = 1.0f;
fProduit = fProduit * PI * (float)(uNumFreq) * ((float)(uIndiceData) + 0.5f);
fProduit = fProduit / (float)uSampleSize;
fValue = fValue * cos( fProduit );
*pfTab = fValue;
}
}
}
UINT CDct::ComputeDCT( float* pfSource, UINT uSourceSize )
{
float* pfTabSource;
float* pfTabCoeff;
float* pfTab;
BOOL isEnd = false;
UINT iterations;
for (iterations = 0; !isEnd && uSourceSize != 0; iterations++)
{
if (uSourceSize < m_uSampleSize)
{
// Si la source est plus petite que SND_DCT_SIZE_SAMPLE, on remplit de SND_VALUE_NEUTRAL
pfTabSource = pfSource + uSourceSize;
for( UINT uData = uSourceSize; uData < m_uSampleSize; uData++, pfTabSource++ )
*pfTabSource = (float)SND_VALUE_NEUTRAL;
isEnd = true;
}
// Calcul des coefficients
memset( m_pfCoeffs, 0, m_uNbFreq * sizeof(float));
pfTabSource = pfSource;
pfTabCoeff = m_pfCoeffs;
pfTab = m_pfMatrice;
for ( UINT uNumFreq = 0; uNumFreq < m_uNbFreq; uNumFreq++, pfTabCoeff++ )
{
pfTabSource = pfSource;
for( UINT uIndiceData = 0; uIndiceData < m_uSampleSize; uIndiceData++, pfTab++, pfTabSource++ )
{
*pfTabCoeff += ( *pfTab ) * ( *pfTabSource );
}
}
memcpy(pfSource, m_pfCoeffs, m_uSampleSize*sizeof(float));
pfSource += m_uSampleSize;
uSourceSize -= m_uSampleSize;
}
m_bCoefficientIsAccessible = true;
return iterations*m_uSampleSize;
}
//* Inverse de la DCT à partir de la matrice calculée dans les initialisations **************
//* On considère le tableau rempli des coefficients et normalement on a uDestinationSize = m_uNbFreq
UINT CDct::ComputeInverseDCT( float* pfDestination, UINT uDestinationSize )
{
float* pfTabDestination;
float* pfTabCoeff;
float* pfTab;
float* pfTabResultat;
BOOL isEnd = false;
UINT iterations;
// Si uDestinationSize est supérieur à m_uNbFreq, on ne tient pas compte du surplus
// Si uDestinationSize est plus petit, on remplit la table des coefficients de 0
for (iterations = 0; !isEnd && uDestinationSize != 0; iterations++)
{
if (uDestinationSize < m_uNbFreq)
{
memcpy(m_pfCoeffs, pfDestination, uDestinationSize*sizeof(float));
memset(m_pfCoeffs + uDestinationSize, 0, (m_uNbFreq-uDestinationSize)*sizeof(float));
isEnd = true;
} else
{
memcpy(m_pfCoeffs, pfDestination, m_uNbFreq*sizeof(float));
}
// On récupère les coefficients stockés dans la destination
// Calcul effectué en float
memset( m_pfResultat, 0, m_uSampleSize*sizeof(float));
pfTabCoeff = m_pfCoeffs;
pfTabDestination = pfDestination;
pfTab = m_pfMatrice;
for ( UINT uNumFreq = 0; uNumFreq < m_uNbFreq; uNumFreq++, pfTabCoeff++ )
{
pfTabResultat = m_pfResultat;
for( UINT uIndiceData = 0; uIndiceData < m_uSampleSize; uIndiceData++, pfTabResultat++, pfTab++ )
{
*pfTabResultat += ( *pfTab ) * ( *pfTabCoeff );
}
}
memcpy( pfDestination, m_pfResultat, m_uSampleSize*sizeof(float));
pfDestination += m_uSampleSize;
uDestinationSize-= m_uSampleSize;
}
return iterations*m_uSampleSize;
}
#define MIN_AMPLITUDE 0
#define HEAD_UNIT float
UINT CDct::ToBufferSample(unsigned char *dstBuffer, float *srcCoefs, UINT nbElmts)
{
// first stock coef 0, sp coef ...
*((HEAD_UNIT *)dstBuffer) = (HEAD_UNIT)(*(srcCoefs++));
dstBuffer += sizeof(HEAD_UNIT);
float min, max, amplitude;
float *l_pfSource;
l_pfSource = srcCoefs;
min = max = *(l_pfSource++);
for (UINT iBuff=2; iBuff<nbElmts; iBuff++,l_pfSource++)
{
if (*l_pfSource < min) min = *l_pfSource;
if (*l_pfSource > max) max = *l_pfSource;
}
if (max < -min) max = -min;
if (max < MIN_AMPLITUDE) max = MIN_AMPLITUDE;
*((HEAD_UNIT *)dstBuffer) = (HEAD_UNIT)max;
dstBuffer += sizeof(HEAD_UNIT);
amplitude = 2*max;
l_pfSource = srcCoefs;
for (UINT iBuff=1; iBuff<nbElmts; iBuff++,l_pfSource++)
{
*(dstBuffer++) = (unsigned char)(255*(*l_pfSource + max)/amplitude);
}
return (nbElmts-1) + 2*sizeof(HEAD_UNIT);
}
UINT CDct::FromBufferSample(float *dstCoefs, unsigned char *srcBuffer, UINT nbElmts)
{
if (nbElmts < 2*sizeof(HEAD_UNIT))
return 0;
float max, amplitude;
*(dstCoefs++) = (float)(*((HEAD_UNIT *)srcBuffer)); srcBuffer += sizeof(HEAD_UNIT);
max = (float)(*((HEAD_UNIT *)srcBuffer)); srcBuffer += sizeof(HEAD_UNIT);
amplitude = 2*max;
nbElmts -= 2*sizeof(HEAD_UNIT);
for (UINT iBuff=0; iBuff<nbElmts; iBuff++,srcBuffer++)
{
*(dstCoefs++) = amplitude**srcBuffer / 255.0f - max;
}
return (nbElmts+1);
}
UINT CDct::ToBuffer(unsigned char *pucSource, float *m_pfSource, UINT uResult)
{
UINT uResultOut = 0;
UINT uResultLocal = 0;
UINT local;
while (uResult)
{
if (uResult > m_uSampleSize) local = m_uSampleSize;
else local = uResult;
uResultLocal = ToBufferSample(pucSource, m_pfSource, local);
uResultOut +=uResultLocal;
pucSource +=uResultLocal;
m_pfSource +=local;
uResult -=local;
}
return uResultOut;
}
UINT CDct::FromBuffer(float *m_pfSource, unsigned char *pucSource, UINT uResult)
{
UINT uResultOut = 0;
UINT uResultLocal = 0;
UINT local;
while (uResult) // float ampli and float max
{
if (uResult > m_uSampleSize-1+2*sizeof(HEAD_UNIT)) local = m_uSampleSize-1+2*sizeof(HEAD_UNIT);
else local = uResult;
uResultLocal = FromBufferSample(m_pfSource, pucSource, local);
uResultOut +=uResultLocal;
m_pfSource +=uResultLocal;
pucSource +=local;
uResult -=local;
}
return uResultOut;
}
void CDct::EffectInit()
{
memset(m_pfEffectMatrix, 0, sizeof(m_pfEffectMatrix));
*m_pfEffectMatrix = 1.0f;
isIdentity = true;
isFullProcess = false;
}
void CDct::EffectEnd()
{
if (isIdentity)
{
isFullProcess = false;
return;
}
float m_tmpMatrix[ SND_DCT_SIZE_MATRIX ];
float *m_tmpMatrixPtr = m_tmpMatrix;
// multiply : INVDCT * EFFECTS * DCT and stock it in EFFECTS ...
// step 1 EFFECTS * DCT -> TMP
memset(m_tmpMatrix, 0, sizeof(m_tmpMatrix));
for (int dstY=0; dstY<SND_DCT_SIZE_MATRIX_COEFS; dstY++)
{
for (int dstX=0; dstX<SND_DCT_SIZE_MATRIX_COEFS; dstX++, m_tmpMatrixPtr++)
{
for (int K=0; K<SND_DCT_SIZE_MATRIX_COEFS; K++)
{
*m_tmpMatrixPtr += m_pfEffectMatrix[K+dstY*SND_DCT_SIZE_MATRIX_COEFS]*
m_pfMatrice[dstX+K*SND_DCT_SIZE_MATRIX_COEFS];
// *m_tmpMatrixPtr += m_pfEffectMatrix[K+dstY*SND_DCT_SIZE_MATRIX_COEFS]*
// m_pfCoeffs[K+dstX*SND_DCT_SIZE_MATRIX_COEFS];
}
}
}
// step 2 INVDCT * TMP -> EFFECTS
m_tmpMatrixPtr = m_pfEffectMatrix;
memset(m_pfEffectMatrix, 0, sizeof(m_pfEffectMatrix));
for (int dstY=0; dstY<SND_DCT_SIZE_MATRIX_COEFS; dstY++)
{
for (int dstX=0; dstX<SND_DCT_SIZE_MATRIX_COEFS; dstX++, m_tmpMatrixPtr++)
{
for (int K=0; K<SND_DCT_SIZE_MATRIX_COEFS; K++)
{
*m_tmpMatrixPtr += m_pfMatrice[dstY+K*SND_DCT_SIZE_MATRIX_COEFS]*
m_tmpMatrix[dstX+K*SND_DCT_SIZE_MATRIX_COEFS];
// *m_tmpMatrixPtr += m_pfCoeffs[K+dstY*SND_DCT_SIZE_MATRIX_COEFS]*
// m_tmpMatrix[dstX+K*SND_DCT_SIZE_MATRIX_COEFS];
}
}
}
isFullProcess = true;
}
void CDct::EffectNormalize()
{
float sum;
float *m_pfEffectMatrixPtr, *m_pfEffectMatrixPtrIn;
sum = 0.0f;
m_pfEffectMatrixPtr = m_pfEffectMatrix + SND_DCT_SIZE_MATRIX_COEFS;
for (int y=1; y<SND_DCT_SIZE_MATRIX_COEFS; y++, m_pfEffectMatrixPtr+=SND_DCT_SIZE_MATRIX_COEFS)
{
m_pfEffectMatrixPtrIn = m_pfEffectMatrixPtr + 1;
for (int x=1; x<SND_DCT_SIZE_MATRIX_COEFS; x++, m_pfEffectMatrixPtrIn++)
{
sum += *m_pfEffectMatrixPtrIn;
}
}
sum /= SND_DCT_SIZE_MATRIX_COEFS-1;
m_pfEffectMatrixPtr = m_pfEffectMatrix + SND_DCT_SIZE_MATRIX_COEFS;
if (sum != 0.0f && (abs(sum) < 0.99 || abs(sum) > 1.01))
{
for (int y=1; y<SND_DCT_SIZE_MATRIX_COEFS; y++, m_pfEffectMatrixPtr+=SND_DCT_SIZE_MATRIX_COEFS)
{
m_pfEffectMatrixPtrIn = m_pfEffectMatrixPtr + 1;
for (int x=1; x<SND_DCT_SIZE_MATRIX_COEFS; x++, m_pfEffectMatrixPtrIn++)
{
*m_pfEffectMatrixPtrIn /= sum;
}
}
}
}
float CDct::EffectMatrixXYGet(int x, int y)
{
return m_pfEffectMatrix[x+(y<<SND_DCT_SIZE_MATRIX_POWER)];
}
bool CDct::EffectMatrixXYSet(int x, int y, float value)
{
if (x < 0 || x > SND_DCT_SIZE_MATRIX_COEFS ||
y < 0 || y > SND_DCT_SIZE_MATRIX_COEFS)
return false;
m_pfEffectMatrix[x+(y<<SND_DCT_SIZE_MATRIX_POWER)] = value;
isIdentity = false;
return true;
}
void CDct::EffectAddBase(float factor)
{
for (int i=1; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
m_pfEffectMatrix[i+(i<<SND_DCT_SIZE_MATRIX_POWER)] += factor;
isIdentity = false;
}
void CDct::EffectAddStretch(float factor)
{
float begin, end, width;
float current;
float *m_pfEffectMatrixPtr = m_pfEffectMatrix + SND_DCT_SIZE_MATRIX_COEFS;
for (UINT line=1; line<SND_DCT_SIZE_MATRIX_COEFS; line++, m_pfEffectMatrixPtr+=SND_DCT_SIZE_MATRIX_COEFS)
{
begin = (float) line /factor;
end = (float)(line+1)/factor;
if (end < 1.0f) continue;
if (begin < 1.0f) begin = 1.0f;
if (end > SND_DCT_SIZE_MATRIX_COEFS)
end = SND_DCT_SIZE_MATRIX_COEFS;
width = end - begin;
if (width <= 0) continue;
current = begin;
while (current < end)
{
if ((int)current != (int)end)
{
m_pfEffectMatrixPtr[(int)current] += ((int)(current+1) - current)/width;
current = (float)((int)(current+1));
} else
{
m_pfEffectMatrixPtr[(int)current] += (end - current)/width;
current = end;
}
}
}
isIdentity = false;
}
void CDct::AlterSample(float *srcCoefs, UINT nbElmts, float neutralValue)
{
float *srcCoefsPtr = srcCoefs;
float *m_pfEffectMatrixPtr = m_pfEffectMatrix;
float *m_pfCoeffsPtr;
UINT x,y;
memset(m_pfCoeffs, 0, sizeof(m_pfCoeffs));
m_pfCoeffsPtr = m_pfCoeffs;
for (y=0; y<m_uNbFreq; y++, m_pfCoeffsPtr++)
{
srcCoefsPtr = srcCoefs;
for (x=0; x<nbElmts; x++, srcCoefsPtr++, m_pfEffectMatrixPtr++)
{
*m_pfCoeffsPtr += *srcCoefsPtr * *m_pfEffectMatrixPtr;
}
for (; x<m_uNbFreq; x++, m_pfEffectMatrixPtr++)
{
*m_pfCoeffsPtr += neutralValue * *m_pfEffectMatrixPtr;
}
}
memcpy(srcCoefs, m_pfCoeffs, nbElmts*sizeof(float));
}
void CDct::Alter(float *srcCoefs, UINT nbElmts, float neutralValue)
{
if (isIdentity) return;
UINT sample = m_uSampleSize;
while (nbElmts)
{
if (sample > nbElmts)
sample = nbElmts;
AlterSample(srcCoefs, sample, neutralValue);
srcCoefs+=sample;
nbElmts -=sample;
}
}