2 leqm-nrt is a non-real-time implementation
3 of Leq(M) measurement according to ISO 21727:2004(E)
4 "Cinematography -- Method of measurement of perceived
5 loudness of motion-picture audio material"
7 Copyright (C) 2011-2013, 2017 Luca Trisciani
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
40 #include <sys/param.h>
41 #include <sys/sysctl.h
45 // Version 0.0.17 (C) Luca Trisciani 2011-2013, 2017
46 // Tool from the DCP-Werkstatt Software Bundle
51 // compile for DEBUG with gcc -g -DEBUG -lsndfile -lfftw3 -lm -lpthread -lrt -o leqm-nrt leqm-nrt.cpp
52 //otherwise gcc -lsndfile -lm -lpthread -lrt -o leqm-nrt leqm-nrt.c
58 double csum; // convolved sum
59 double sum; // flat sum
61 double cmean; //convolved mean
73 struct Sum * ptrtotsum;
76 double * shorttermarray;
80 int equalinterval( double * freqsamples, double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints);
81 int equalinterval2( double freqsamples[], double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints, int bitdepthsoundfile);
82 int convloglin(double * in, double * out, int points);
83 double convlinlog_single(double in);
84 double convloglin_single(double in);
85 int convolv_buff(double * sigin, double * sigout, double * impresp, int sigin_dim, int impresp_dim);
86 double inputcalib (double dbdiffch);
87 int rectify(double * squared, double * inputsamples, int nsamples);
88 int accumulatech(double * chaccumulator, double * inputchannel, int nsamples);
89 int sumsamples(struct Sum * ts, double * inputsamples, double * cinputsamples, int nsamples);
90 int meanoverduration(struct Sum * oldsum);
91 void inversefft1(double * eqfreqresp, double * ir, int npoints);
92 void inversefft2(double * eqfreqresp, double * ir, int npoints);
93 void * worker_function(void * argfunc);
94 void logleqm(FILE * filehandle, double featuretimesec, struct Sum * oldsum);
95 double sumandshorttermavrg(double * channelaccumulator, int nsamples);
96 void logleqm10(FILE * filehandle, double featuretimesec, double longaverage);
99 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
102 int main(int argc, const char ** argv)
104 int npoints = 64; // This value is low for precision. Calibration is done with 32768 point.
105 int origpoints = 21; //number of points in the standard CCIR filter
106 int samplingfreq; // this and the next is defined later taking it from sound file
108 // double normalizer;
110 struct timespec starttime;
111 int fileopenstate = 0;
114 #if defined __unix__ || defined __APPLE__
115 int numCPU = sysconf(_SC_NPROCESSORS_ONLN) - 1;
116 #elif defined _WIN64 || defined _WIN32
118 GetSystemInfo(&sysinfo);
119 int numCPU = sysinfo.dwNumberOfProcessors - 1;
122 double * channelconfcalvector;
123 channelconfcalvector = NULL;
124 printf("leqm-nrt Copyright (C) 2011-2013, 2017 Luca Trisciani\nThis program comes with ABSOLUTELY NO WARRANTY; for details on command line parameters -help\nThis is free software, and you are welcome to redistribute it\nunder the GPL v3 licence.\nProgram will use 1 + %d slave threads.\n", numCPU);
125 //SndfileHandle file;
130 leqm10logfile = NULL;
133 int buffersizems = 850; //ISO 21727:2004 do not contain any indication, TASA seems to indicate 1000, p. 8
134 int buffersizesamples;
135 double tempchcal[128];
137 double * shorttermaveragedarray;
138 shorttermaveragedarray = NULL;
139 int numbershortperiods = 0;
140 int parameterstate = 0;
143 char soundfilename[64];
144 // This is a requirement of sndfile library, do not forget it.
146 memset(&sfinfo, 0, sizeof(sfinfo));
150 { const char helptext[] = "Order of parameters is free.\nPossible parameters are:\n-convpoints <integer number> \tNumber of interpolation points for the filter. Default 64\n-numcpus <integer number> \tNumber of slave threads to speed up operation.\n-timing \t\t\tFor benchmarking speed.\n-chconfcal <db correction> <db correction> <etc. so many times as channels>\n-logleqm10\n-logleqm\n-buffersize <milliseconds>\n";
152 printf("Please indicate a sound file to be processed.\n");
157 for (int in = 1; in < argc;) {
159 if (!(strncmp(argv[in], "-", 1) == 0)) {
160 if (fileopenstate == 0) {
161 if(! (file = sf_open(argv[in], SFM_READ, &sfinfo))) {
162 printf("Error while opening audio file, could not open %s\n.", argv[in]);
163 puts(sf_strerror(NULL));
167 strcpy(soundfilename, argv[in]);
169 printf("Opened file: %s\n", argv[in]);
170 printf("Sample rate: %d\n", sfinfo.samplerate);
171 printf("Channels: %d\n", sfinfo.channels);
172 printf("Format: %d\n", sfinfo.format);
173 printf("Frames: %d\n", (int) sfinfo.frames);
174 channelconfcalvector = malloc(sizeof(double) * sfinfo.channels);
178 free(channelconfcalvector);
179 channelconfcalvector = NULL;
185 if (strcmp(argv[in], "-chconfcal") == 0) {
186 /* as the order of parameter is free I have to postpone
187 the check for consistency with the number of channels.
188 So first create a temporary array, whose number of element will be checked after
189 the parsing of the command line parameters is finished.
190 The calibration will be expressed in dB on the command line and converted to multiplier
191 here so that it can be stored as a factor in the channelconfcalvector.
197 //if (!(strncmp(argv[in], "-", 1) == 0)) { //changed this to allow negative numbers
198 if (!(strncmp(argv[in], "-", 1) == 0) || isdigit(argv[in][1])) {
199 tempchcal[numcalread++]=atof(argv[in++]);
207 if (strcmp(argv[in], "-convpoints") == 0) {
208 npoints = atoi(argv[in + 1]);
210 printf("Convolution points sets to %d.\n", npoints);
214 if (strcmp(argv[in], "-numcpus") == 0) {
215 numCPU= atoi(argv[in + 1]);
217 printf("Number of threads manually set to %d. Default is number of cores in the system minus one.\n", numCPU);
221 if (strcmp(argv[in], "-timing") == 0) {
224 printf("Execution time will be measured.\n");
229 if (strcmp(argv[in], "-logleqm10") == 0) {
232 printf("Leq(M)10 data will be logged to the file leqm10.txt\n");
236 if (strcmp(argv[in], "-logleqm") == 0) {
239 printf("Leq(M) data will be logged to the file leqmlog.txt\n");
244 if (strcmp(argv[in], "-leqnw") == 0) {
247 printf("Leq(nW) - unweighted - will be outputted.\n");
252 if (strcmp(argv[in], "-buffersize") == 0) {
253 buffersizems = atoi(argv[in + 1]);
255 printf("Buffersize will be set to %d milliseconds.\n", buffersizems);
260 if (parameterstate==0) {
266 //postprocessing parameters
267 if (numcalread == sfinfo.channels) {
268 for (int cind = 0; cind < sfinfo.channels; cind++) {
269 channelconfcalvector[cind] = convloglin_single(tempchcal[cind]);
273 else if ((numcalread == 0) && (sfinfo.channels == 6)) {
274 double conf51[6] = {0, 0, 0, 0, -3, -3};
275 for (int cind = 0; cind < sfinfo.channels; cind++) {
276 channelconfcalvector[cind] = convloglin_single(conf51[cind]);
281 printf("Either you specified a different number of calibration than number of channels in the file or you do not indicate any calibration and the program cannot infer one from the number of channels. Please specify a channel calibration on the command line.\n");
283 free(channelconfcalvector);
284 channelconfcalvector = NULL;
292 char tempstring[128];
293 strcpy(tempstring, soundfilename);
294 strcat(tempstring, ".leqm10.txt");
295 leqm10logfile = fopen(tempstring, "w");
296 if (leqm10logfile == NULL) {
297 printf("Could not open file to write log leqm10 data!\n");
305 char tempstring[128];
306 strcpy(tempstring, soundfilename);
307 strcat(tempstring, ".leqmlog.txt");
308 leqmlogfile = fopen(tempstring, "w");
309 if (leqmlogfile == NULL) {
310 printf("Could not open file to write log leqm data!\n");
317 clock_gettime(CLOCK_MONOTONIC, &starttime);
324 // reading to a double or float buffer with sndfile take care of normalization
326 static double buffer[BUFFER_LEN]; // it seems this must be static. I don't know why
329 // buffer = new double [BUFFER_LEN];
330 //buffersizesamples = (sfinfo.samplerate*sfinfo.channels*buffersizems)/1000;
331 if ((sfinfo.samplerate*buffersizems)%1000) {
332 printf("Please fine tune the buffersize according to the sample rate\n");
335 // write a function to do that
339 buffersizesamples = (sfinfo.samplerate*sfinfo.channels*buffersizems)/1000;
340 buffer = malloc(sizeof(double)*buffersizesamples);
342 samplingfreq = sfinfo.samplerate;
346 //if duration < 10 mm exit
348 double featdursec = sfinfo.frames / sfinfo.samplerate;
349 if ((featdursec/60.0) < 10.0) {
350 printf("The audio file is too short to measure Leq(m10).\n");
354 //how many short periods in overall duration
355 int remainder = sfinfo.frames % (sfinfo.samplerate*buffersizems/1000);
356 if (remainder == 0) numbershortperiods = sfinfo.frames/(sfinfo.samplerate*buffersizems/1000);
357 else numbershortperiods = sfinfo.frames/(sfinfo.samplerate*buffersizems/1000) + 1;
360 shorttermaveragedarray = malloc(sizeof(*shorttermaveragedarray)*numbershortperiods);
364 //End opening audio file
368 double freqsamples[] = {31, 63, 100, 200, 400, 800, 1000, 2000, 3150, 4000, 5000, 6300, 7100, 8000, 9000, 10000, 12500, 14000, 16000, 20000, 31500};
369 double freqresp_db[] = {-35.5, -29.5, -25.4, -19.4, -13.4, -7.5, -5.6, 0.0, 3.4, 4.9, 6.1, 6.6, 6.4, 5.8, 4.5, 2.5, -5.6, -10.9, -17.3, -27.8, -48.3};
371 double * eqfreqresp_db;
372 eqfreqresp_db = malloc(sizeof(*eqfreqresp_db)*npoints);
374 double * eqfreqsamples;
375 eqfreqsamples = malloc(sizeof(*eqfreqsamples)*npoints);
377 eqfreqresp = malloc(sizeof(*eqfreqresp)*npoints);
379 ir = malloc(sizeof(*ir)*npoints*2);
382 // And what to do for floating point sample coding?
384 switch(sfinfo.format & SF_FORMAT_SUBMASK) {
385 // all signed bitdepth
399 printf("No known bitdepth! Exiting ...\n");
406 equalinterval2(freqsamples, freqresp_db, eqfreqsamples, eqfreqresp_db, npoints, samplingfreq, origpoints, bitdepth);
407 convloglin(eqfreqresp_db, eqfreqresp, npoints);
410 for (int i=0; i < npoints; i++) {
411 printf("%d\t%.2f\t%.2f\t%.2f\n", i, eqfreqsamples[i], eqfreqresp_db[i], eqfreqresp[i]);
415 inversefft2(eqfreqresp, ir, npoints);
417 // read through the entire file
420 totsum = malloc(sizeof(struct Sum));
423 totsum->nsamples = 0;
425 totsum->mean = 0.0; // Do I write anything here?
428 sf_count_t samples_read = 0;
430 // Main loop through audio file
433 pthread_t tid[numCPU];
434 struct WorkerArgs ** WorkerArgsArray;
435 WorkerArgsArray = malloc(sizeof(struct WorkerArgs *)*numCPU);
436 int staindex = 0; //shorttermarrayindex
439 while((samples_read = sf_read_double(file, buffer, buffersizesamples)) > 0) {
441 WorkerArgsArray[worker_id]=malloc(sizeof(struct WorkerArgs));
442 WorkerArgsArray[worker_id]->nsamples = samples_read;
443 WorkerArgsArray[worker_id]->nch = sfinfo.channels;
444 WorkerArgsArray[worker_id]->npoints=npoints;
445 WorkerArgsArray[worker_id]->ir = ir;
446 WorkerArgsArray[worker_id]->ptrtotsum = totsum;
448 WorkerArgsArray[worker_id]->chconf = channelconfcalvector;
450 WorkerArgsArray[worker_id]->shorttermindex = staindex++;
451 WorkerArgsArray[worker_id]->leqm10flag = 1;
452 WorkerArgsArray[worker_id]->shorttermarray = shorttermaveragedarray;
454 WorkerArgsArray[worker_id]->shorttermindex = 0;
455 WorkerArgsArray[worker_id]->leqm10flag = 0;
458 WorkerArgsArray[worker_id]->argbuffer = malloc(sizeof(double)*buffersizesamples);
459 memcpy(WorkerArgsArray[worker_id]->argbuffer, buffer, samples_read*sizeof(double));
463 pthread_attr_init(&attr);
464 pthread_create(&tid[worker_id], &attr, worker_function, WorkerArgsArray[worker_id]);
467 if (worker_id == numCPU) {
469 //maybe here wait for all cores to output before going on
470 for (int idxcpu = 0; idxcpu < numCPU; idxcpu++) {
471 pthread_join(tid[idxcpu], NULL);
472 free(WorkerArgsArray[idxcpu]->argbuffer);
473 WorkerArgsArray[idxcpu]->argbuffer = NULL;
474 free(WorkerArgsArray[idxcpu]);
475 WorkerArgsArray[idxcpu] = NULL;
477 //simply log here your measurement it will be a multiple of your threads and your buffer
479 meanoverduration(totsum); //update leq(m) until now and log it
480 logleqm(leqmlogfile, ((double) totsum->nsamples)/((double) sfinfo.samplerate), totsum );
486 //end while worker_id
487 /// End looping cores
488 } // main loop through file
490 //here I should wait for rest worker (< numcpu)
491 //but I need to dispose of thread id.
492 if (worker_id != 0) { // worker_id = 0 means the number of samples was divisible through the number of cpus
493 for (int idxcpu = 0; idxcpu < worker_id; idxcpu++) { //worker_id is at this point one unit more than threads launched
494 pthread_join(tid[idxcpu], NULL);
495 free(WorkerArgsArray[idxcpu]->argbuffer);
496 WorkerArgsArray[idxcpu]->argbuffer = NULL;
497 free(WorkerArgsArray[idxcpu]);
498 WorkerArgsArray[idxcpu] = NULL;
500 //also log here for a last value
502 meanoverduration(totsum); //update leq(m) until now and log it
503 logleqm(leqmlogfile, ((double) totsum->nsamples)/((double) sfinfo.samplerate), totsum );
506 // mean of scalar sum over duration
508 meanoverduration(totsum);
510 printf("Leq(noW): %.4f\n", totsum->rms); // Leq(no Weighting)
512 printf("Leq(M): %.4f\n", totsum->leqm);
515 struct timespec stoptime;
516 long stoptimenanoseconds;
517 long executionnanoseconds;
518 clock_gettime(CLOCK_MONOTONIC, &stoptime);
520 if (stoptime.tv_nsec < starttime.tv_nsec) {
521 stoptimenanoseconds = 1000000000 + stoptime.tv_nsec;
523 stoptimenanoseconds = stoptime.tv_nsec;
525 executionnanoseconds = stoptimenanoseconds - starttime.tv_nsec;
526 printf("Total execution time is %.6f seconds\n", ((double) stoptime.tv_sec) - ((double) starttime.tv_sec) + ((double) executionnanoseconds / 1000000000.00));
532 //Take the array with the short term accumulators
533 double interval = 10.0;
534 //create a rolling average according to rolling interval
535 int rollint; // in short 10*60 = 600 sec 600/0.850
538 //how many element of the array to consider for the rollint?
539 //that is how many buffersizems in the interval - interval could be parameterized(?)
540 double tempint = 60.0 * interval / (((double) buffersizems) /1000.0);
541 rollint = (int) tempint;
542 //dispose of the rest
543 if (tempint - ((double) rollint) > 0) {
549 while(indexlong < (numbershortperiods - rollint)) {
551 double accumulator = 0;
553 double averagedaccumulator = 0;
554 for (int indexshort = 0; indexshort < rollint; indexshort++) {
556 accumulator += shorttermaveragedarray[indexshort+indexlong];
557 } //end internal loop
558 averagedaccumulator = accumulator/((double) rollint);
559 logleqm10(leqm10logfile, ((double) (indexlong+rollint)) * ((double) buffersizems / 1000.0), averagedaccumulator);
561 } //end external loop
563 fclose(leqm10logfile);
564 free(shorttermaveragedarray);
565 shorttermaveragedarray = NULL;
577 eqfreqsamples = NULL;
584 free(channelconfcalvector);
585 channelconfcalvector = NULL;
586 free(WorkerArgsArray);
587 WorkerArgsArray = NULL;
598 void * worker_function(void * argstruct) {
600 struct WorkerArgs * thisWorkerArgs = (struct WorkerArgs *) argstruct;
602 double * sumandsquarebuffer;
603 double * csumandsquarebuffer;
604 double * chsumaccumulator_norm;
605 double * chsumaccumulator_conv;
608 sumandsquarebuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
611 csumandsquarebuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
613 chsumaccumulator_norm = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
615 chsumaccumulator_conv = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
619 for (int i = 0; i < thisWorkerArgs->nsamples / thisWorkerArgs->nch; i++) {
620 sumandsquarebuffer[i] = 0.0;
621 csumandsquarebuffer[i] = 0.0;
622 chsumaccumulator_norm[i] = 0.0;
623 chsumaccumulator_conv[i] = 0.0;
628 for (int ch = 0; ch < thisWorkerArgs->nch; ch++) {
630 double * normalizedbuffer;
631 double * convolvedbuffer;
634 normalizedbuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
636 convolvedbuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
639 for (int n=ch, m= 0; n < thisWorkerArgs->nsamples; n += thisWorkerArgs->nch, m++) {
640 // use this for calibration depending on channel config for ex. chconf[6] = {1.0, 1.0, 1.0, 1.0, 0.707945784, 0.707945784} could be the default for 5.1 soundtracks
641 //so not normalized but calibrated
642 normalizedbuffer[m] = thisWorkerArgs->argbuffer[n]*thisWorkerArgs->chconf[ch]; //this scale amplitude according to specified calibration
648 convolv_buff(normalizedbuffer, convolvedbuffer, thisWorkerArgs->ir, thisWorkerArgs->nsamples / thisWorkerArgs->nch, thisWorkerArgs->npoints * 2);
649 //rectify, square und sum
650 rectify(csumandsquarebuffer,convolvedbuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
651 rectify(sumandsquarebuffer,normalizedbuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
653 accumulatech(chsumaccumulator_norm, sumandsquarebuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
654 accumulatech(chsumaccumulator_conv, csumandsquarebuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
657 free(normalizedbuffer);
658 normalizedbuffer= NULL;
660 free(convolvedbuffer);
661 convolvedbuffer=NULL;
663 } // loop through channels
665 //Create a function for this also a tag so that the worker know if he has to do this or not
667 if (thisWorkerArgs->leqm10flag) {
668 thisWorkerArgs->shorttermarray[thisWorkerArgs->shorttermindex] = sumandshorttermavrg(chsumaccumulator_conv, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
670 printf("%d: %.6f\n", thisWorkerArgs->shorttermindex, thisWorkerArgs->shorttermarray[thisWorkerArgs->shorttermindex]);
673 pthread_mutex_lock(&mutex);
674 // this should be done under mutex conditions -> shared resources!
675 sumsamples(thisWorkerArgs->ptrtotsum, chsumaccumulator_norm, chsumaccumulator_conv, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
676 pthread_mutex_unlock(&mutex);
679 free(sumandsquarebuffer);
680 sumandsquarebuffer=NULL;
682 free(csumandsquarebuffer);
683 csumandsquarebuffer=NULL;
685 free(chsumaccumulator_norm);
686 chsumaccumulator_norm=NULL;
688 free(chsumaccumulator_conv);
689 chsumaccumulator_conv=NULL;
691 free(thisWorkerArgs->argbuffer);
692 thisWorkerArgs->argbuffer = NULL;
693 // the memory pointed to by this pointer is freed in main
694 // it is the same memory for all worker
695 // but it is necessary to set pointer to NULL otherwise free will not work later (really?)
696 thisWorkerArgs->chconf = NULL;
702 //to get impulse response frequency response at equally spaced intervals is needed
704 int equalinterval( double * freqsamples, double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints) {
708 double pass = ((double) (samplingfreq >> 1)) / ((double) points);
709 for (int ieq = 0, i = 0; ieq < points; ieq++) {
711 eqfreqsamples[ieq] = freq;
713 if ((freq == 0.0) || (freq < freqsamples[1])) {
714 eqfreqresp[ieq] = freqresp[0];
718 if ((freq >= freqsamples[i]) && (freq < freqsamples[i+1])) {
719 eqfreqresp[ieq] = ((freqresp[i+1] - freqresp[i])/(freqsamples[i+1] - freqsamples[i]))*(freq - freqsamples[i]) + freqresp[i];
720 } else if (freq >=freqsamples[i+1]) {
721 while(freq >= freqsamples[i+1]) {
723 if ((i + 1) >= origpoints) {
727 if ((i+1) < origpoints) {
728 eqfreqresp[ieq] = ((freqresp[i+1] - freqresp[i])/(freqsamples[i+1] - freqsamples[i]))*(freq- freqsamples[i]) + freqresp[i];
730 eqfreqresp[ieq] = ((1 - freqresp[i])/(((double) (samplingfreq >> 1)) - freqsamples[i]))*(freq- freqsamples[i]) + freqresp[i];
742 //the following is different from version 1 because interpolate between db and not linear. Conversion from db to lin must be done after.
743 //it is also different for the way it interpolates between DC and 31 Hz
744 // Pay attention that also arguments to the functions are changed
745 int equalinterval2( double freqsamples[], double freqresp_db[], double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints, int bitdepthsoundfile) {
749 //calculate miminum attenuation depending on the bitdeph (minus one), that is −6.020599913 dB per bit in eccess to sign
750 double dcatt = ((double) (bitdepthsoundfile - 1))*(-6.020599913) + 20.00; //in dB
751 //double dcatt = -90.3;
752 double pass = ((double) (samplingfreq >> 1)) / ((double) points);
753 for (int ieq = 0, i = 0; ieq < points; ieq++) {
755 eqfreqsamples[ieq] = freq;
758 eqfreqresp[ieq] = dcatt;
759 } else if (freq < freqsamples[0]) { // this has a lot of influence on final Leq(M) value
760 eqfreqresp[ieq] = ((freqresp_db[0] - dcatt) / (freqsamples[0] - 0)) * freq + dcatt;
761 //eqfreqresp[ieq] = freqresp_db[0]; // Is this meaningful? Shouldn't I interpolate between 0 Hz and 31 Hz? Otherwise for DC I have -35.5 dB
765 if ((freq >= freqsamples[i]) && (freq < freqsamples[i+1])) {
766 eqfreqresp[ieq] = ((freqresp_db[i+1] - freqresp_db[i])/(freqsamples[i+1] - freqsamples[i]))*(freq - freqsamples[i]) + freqresp_db[i];
767 } else if (freq >=freqsamples[i+1]) {
768 while(freq >= freqsamples[i+1]) {
770 if ((i + 1) >= origpoints) {
774 if ((i+1) < origpoints) {
775 eqfreqresp[ieq] = ((freqresp_db[i+1] - freqresp_db[i])/(freqsamples[i+1] - freqsamples[i]))*(freq- freqsamples[i]) + freqresp_db[i];
777 eqfreqresp[ieq] = ((1 - freqresp_db[i])/(((double) (samplingfreq >> 1)) - freqsamples[i]))*(freq- freqsamples[i]) + freqresp_db[i];
790 int convloglin(double * in, double * out, int points) {
791 for (int i = 0; i < points; i++) {
792 out[i] = powf(10, (in[i]/20.0));
799 double convlinlog_single(double in) {
806 double convloglin_single(double in) {
808 out = powf(10, in/20.0f);
814 int convolv_buff(double * sigin, double * sigout, double * impresp, int sigin_dim, int impresp_dim) {
818 for (int i = 0; i < sigin_dim; i++) {
821 for (int l = impresp_dim - 1; l >=0; l--,m++) {
822 if (m >= sigin_dim) {
825 sum += sigin[m]*impresp[l];
835 void inversefft2(double * eqfreqresp, double * ir, int npoints) {
836 for (int n = 0; n < npoints; n++) {
838 double partial = 0.0;
840 for (int m = 1; m <= npoints -1; m++) {
841 partial = cos(2.0*M_PI*((double) m)*( ( ((double) n) - ( ((double) npoints) * 2.0 -1 ) / 2 ) / ( ((double) npoints) * 2.0) ));
842 parsum = parsum + eqfreqresp[m]*partial;
844 ir[n] = (eqfreqresp[0] + 2.0 * parsum)/((double) npoints * 2.0);
846 printf("%.4f\n", ir[n]);
849 for (int n = 0; n < npoints; n++) {
850 ir[npoints+n] = ir[npoints-(n + 1)];
852 printf("%.4f\n", ir[npoints+n]);
859 // scale input according to required calibration
860 // this could be different for certain digital cinema formats
861 double inputcalib (double dbdiffch) {
863 double coeff = pow(10, dbdiffch/20);
868 //rectify, square and sum
869 int rectify(double * squared, double * inputsamples, int nsamples){
870 for (int i = 0; i < nsamples; i++) {
871 squared[i] = (double) powf(inputsamples[i], 2);
877 int initbuffer(double * buffertoinit, int nsamples) {
878 for (int i = 0; i < nsamples; i++) {
879 buffertoinit[i] = 0.0;
885 int accumulatech(double * chaccumulator, double * inputchannel, int nsamples) {
886 for (int i = 0; i < nsamples; i++) {
887 chaccumulator[i] += inputchannel[i];
892 int sumsamples(struct Sum * ts, double * inputsamples, double * cinputsamples, int nsamples) {
893 ts->nsamples += nsamples;
894 for (int i=0; i < nsamples; i++) {
895 ts->sum += inputsamples[i];
896 ts->csum += cinputsamples[i];
902 int meanoverduration(struct Sum * oldsum) {
903 oldsum->mean = pow(oldsum->sum / ((double) oldsum->nsamples), 0.500);
904 oldsum->cmean = pow(oldsum->csum / ((double) oldsum->nsamples), 0.500);
905 oldsum->rms = 20*log10(oldsum->mean);
906 oldsum->leqm = 20*log10(oldsum->cmean) + 108.0851;//
907 //This must be right because M filter is -5.6 @ 1k Hz that is -25.6 dBFS and to have 85.0 as reference level we must add 25.56 + 85.00 that is 110.6 dB.
908 //this value is obtained calibrating with a -20 dBFS.
913 double sumandshorttermavrg(double * channelaccumulator, int nsamples) {
915 for (int i=0; i < nsamples; i++) {
916 stsum += channelaccumulator[i];
919 return stsum / (double) nsamples;
922 void logleqm(FILE * filehandle, double featuretimesec, struct Sum * oldsum) {
924 fprintf(filehandle, "%.4f", featuretimesec);
925 fprintf(filehandle, "\t");
926 fprintf(filehandle, "%.4f\n", oldsum->leqm);
931 void logleqm10(FILE * filehandle, double featuretimesec, double longaverage) {
932 double leqm10 = 20*log10(pow(longaverage, 0.500)) + 108.0851;
933 fprintf(filehandle, "%.4f", featuretimesec);
934 fprintf(filehandle, "\t");
935 fprintf(filehandle, "%.4f\n", leqm10);