#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