#include
/*
gcc -o autolvl4.out autolvl4.c;./autolvl4.out
*/
// Auto-adjust the gain to keep a fairly constant volume.
#define g_numsamples 11000 // Min 12000 ok
#define g_max_clip_level 32767
#define d_max_ampl 5000.0 // 4000 -> -17dB, 5000 -> -15dB, 5500 -> -14dB
char g_input[] = "seesound.wav";
char g_output[100] = {0};
double gain_ceiling=5.0;
short signed int scale_data(short signed int data, double gain)
{
short signed int n_result=0;
double d_result=(double)data * gain;
if (d_result < -32768.0)
{
d_result = -32768.0;
}
if (d_result > 32767.0)
{
d_result = 32767.0;
}
n_result = (short signed int)d_result;
return n_result;
}
double abs_scale_data(short signed int data, double gain)
{
double d_result=(double)data * gain;
if (d_result<0.0) d_result=-d_result;
return d_result;
}
int main(void)
{
FILE *fin;
long i=0;
long j=0;
double sumL=0.0;
double sumR=0.0;
double count=0.0;
g_output[0] = '0';
g_output[1] = '_';
for (i=0; i<99; i++)
{
g_output[i+2]=g_input[i];
}
double locgainl=0.0;
double locgainr=0.0;
long loccount=0;
short signed int ndata[g_numsamples]={0};
short signed int cheader[88]={0};
char b_make_output=0;
long num_blocks=0;
long num_gains=0;
double l_gains[40000]={0.0};
double r_gains[40000]={0.0};
double l_avg_gains[40000]={0.0};
double r_avg_gains[40000]={0.0};
fin=fopen(g_input,"rb");
if (!fin)
{
printf("Error opening input file\n");
return 0;
}
else
{
printf("Opening %s\n", g_input);
}
fseek(fin,88,SEEK_SET);
/*_____________________________
MAIN LOOP
_____________________________*/
double dgains[2]={0.0};
long int gainptr=0;
while(1)
{
if (feof(fin)) break;
num_blocks++;
fread(ndata,sizeof(ndata),1,fin);
i=0;
long int j=0;
locgainl=0.0;
locgainr=0.0;
loccount=0;
for (i=0;i gain_ceiling) locgainl = gain_ceiling;
if (locgainr > gain_ceiling) locgainr = gain_ceiling;
l_gains[gainptr]=locgainl;
r_gains[gainptr]=locgainr;
gainptr++;
}
num_gains=gainptr;
sumL/=count;
sumR/=count;
/*__________________________________________
Make sure that no interval clips or
exceeds the gain specification.
____________________________________________*/
fseek(fin,0,SEEK_SET);
gainptr=0;
double locdatal=0.0;
double locdatar=0.0;
double maxlocdata=0.0;
while(1)
{
if (feof(fin)) break;
fread(ndata,sizeof(ndata),1,fin);
i=0;
long int j=0;
maxlocdata=0;
for (i=0;i maxlocdata) maxlocdata = locdatal;
if (locdatar > maxlocdata) maxlocdata = locdatar;
}
if (maxlocdata >= g_max_clip_level)
{
double factor=g_max_clip_level / maxlocdata;
l_gains[gainptr] *= factor;
r_gains[gainptr] *= factor;
}
gainptr++;
}
// l_avg_gains
long llim=0;
long ulim=0;
for (i=0; i l_avg_gains[i])
{
dfactor=l_gains[i]/l_avg_gains[i];
dnewgain=(l_gains[i] * dfactor) + l_avg_gains[i];
dnewgain /= (dfactor + 1);
l_gains[i] = dnewgain;
}
if (r_gains[i] > r_avg_gains[i])
{
dfactor=r_gains[i]/r_avg_gains[i];
dnewgain=(r_gains[i] * dfactor) + r_avg_gains[i];
dnewgain /= (dfactor + 1);
r_gains[i] = dnewgain;
}
}
// Make it so that the gains can decrease rapidly, but not increase as fast.
// If a future gain is a lot bigger than a previous gain, then scale it back.
for (i=1; il_gains[i-1])
{
l_gains[i]=(l_gains[i]+l_gains[i-1]*3.0)/4.0;
}
if (r_gains[i]>r_gains[i-1])
{
r_gains[i]=(r_gains[i]+r_gains[i-1]*3.0)/4.0;
}
}
long block=0;
double d_ldata=0.0;
double d_rdata=0.0;
double lgain=0.0;
double rgain=0.0;
/*_____________________________________
Do the dynamic compression here
_______________________________________*/
i=0;
printf("Auto-scale volume\n");
lgain=d_max_ampl/sumL;
rgain=d_max_ampl/sumR;
double lgaininc=0.0;
double rgaininc=0.0;
double dlastgains[2] = {0.0};
double lptgain=0.0;
double rptgain=0.0;
double dpercent_in_file=0.0;
FILE *fout;
fout=fopen(g_output,"wb");
if (fout)
{
fseek(fin,0,SEEK_SET);
fread(cheader,sizeof(cheader),1,fin);
fwrite(cheader,sizeof(cheader),1,fout);
gainptr=0;
dgains[0]=l_gains[gainptr];
dgains[1]=r_gains[gainptr++];
for (block=0; block gain_ceiling) lptgain = gain_ceiling;
if (rptgain > gain_ceiling) rptgain = gain_ceiling;
dgains[0]=l_gains[gainptr];
dgains[1]=r_gains[gainptr++];
lgaininc=(dgains[0]-dlastgains[0]) / (double)g_numsamples;
rgaininc=(dgains[1]-dlastgains[1]) / (double)g_numsamples;
}
else
{
lgaininc=0;
rgaininc=0;
}
long i=0;
for (i=0;i