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/>.
37 // Version 0.0.17 (C) Luca Trisciani 2011-2013, 2017
38 // Tool from the DCP-Werkstatt Software Bundle
43 // compile for DEBUG with gcc -g -DEBUG -lsndfile -lfftw3 -lm -lpthread -lrt -o leqm-nrt leqm-nrt.cpp
44 //otherwise gcc -lsndfile -lm -lpthread -lrt -o leqm-nrt leqm-nrt.c
50 double csum; // convolved sum
51 double sum; // flat sum
53 double cmean; //convolved mean
65 struct Sum * ptrtotsum;
68 double * shorttermarray;
72 int equalinterval( double * freqsamples, double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints);
73 int equalinterval2( double freqsamples[], double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints, int bitdepthsoundfile);
74 int convloglin(double * in, double * out, int points);
75 double convlinlog_single(double in);
76 double convloglin_single(double in);
77 int convolv_buff(double * sigin, double * sigout, double * impresp, int sigin_dim, int impresp_dim);
78 double inputcalib (double dbdiffch);
79 int rectify(double * squared, double * inputsamples, int nsamples);
80 int accumulatech(double * chaccumulator, double * inputchannel, int nsamples);
81 int sumsamples(struct Sum * ts, double * inputsamples, double * cinputsamples, int nsamples);
82 int meanoverduration(struct Sum * oldsum);
83 void inversefft1(double * eqfreqresp, double * ir, int npoints);
84 void inversefft2(double * eqfreqresp, double * ir, int npoints);
85 void * worker_function(void * argfunc);
86 void logleqm(FILE * filehandle, double featuretimesec, struct Sum * oldsum);
87 double sumandshorttermavrg(double * channelaccumulator, int nsamples);
88 void logleqm10(FILE * filehandle, double featuretimesec, double longaverage);
91 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
94 int main(int argc, const char ** argv)
96 int npoints = 64; // This value is low for precision. Calibration is done with 32768 point.
97 int origpoints = 21; //number of points in the standard CCIR filter
98 int samplingfreq; // this and the next is defined later taking it from sound file
100 // double normalizer;
102 struct timespec starttime;
103 int fileopenstate = 0;
106 int numCPU = sysconf(_SC_NPROCESSORS_ONLN) - 1;
107 double * channelconfcalvector;
108 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);
109 //SndfileHandle file;
114 int buffersizems = 850; //ISO 21727:2004 do not contain any indication, TASA seems to indicate 1000, p. 8
115 int buffersizesamples;
116 double tempchcal[128];
118 double * shorttermaveragedarray;
119 int numbershortperiods;
120 int parameterstate = 0;
123 char soundfilename[64];
124 // This is a requirement of sndfile library, do not forget it.
126 memset(&sfinfo, 0, sizeof(sfinfo));
130 { const char helptext[] = "The order of the parameter 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";
132 printf("Please indicate a sound file to be processed.\n");
137 for (int in = 1; in < argc;) {
139 if (!(strncmp(argv[in], "-", 1) == 0)) {
140 if (fileopenstate == 0) {
141 if(! (file = sf_open(argv[in], SFM_READ, &sfinfo))) {
142 printf("Error while opening audio file, could not open %s\n.", argv[in]);
143 puts(sf_strerror(NULL));
147 strcpy(soundfilename, argv[in]);
149 printf("Opened file: %s\n", argv[in]);
150 printf("Sample rate: %d\n", sfinfo.samplerate);
151 printf("Channels: %d\n", sfinfo.channels);
152 printf("Format: %d\n", sfinfo.format);
153 printf("Frames: %d\n", sfinfo.frames);
154 channelconfcalvector = malloc(sizeof(double) * sfinfo.channels);
158 free(channelconfcalvector);
159 channelconfcalvector = NULL;
165 if (strcmp(argv[in], "-chconfcal") == 0) {
166 /* as the order of parameter is free I have to postpone
167 the check for consistency with the number of channels.
168 So first create a temporary array, whose number of element will be checked after
169 the parsing of the command line parameters is finished.
170 The calibration will be expressed in dB on the command line and converted to multiplier
171 here so that it can be stored as a factor in the channelconfcalvector.
177 //if (!(strncmp(argv[in], "-", 1) == 0)) { //changed this to allow negative numbers
178 if (!(strncmp(argv[in], "-", 1) == 0) || isdigit(argv[in][1])) {
179 tempchcal[numcalread++]=atof(argv[in++]);
187 if (strcmp(argv[in], "-convpoints") == 0) {
188 npoints = atoi(argv[in + 1]);
190 printf("Convolution points sets to %d.\n");
194 if (strcmp(argv[in], "-numcpus") == 0) {
195 numCPU= atoi(argv[in + 1]);
197 printf("Number of threads manually set to %d. Default is number of cores in the system minus one.\n", numCPU);
201 if (strcmp(argv[in], "-timing") == 0) {
204 printf("Execution time will be measured.\n", numCPU);
209 if (strcmp(argv[in], "-logleqm10") == 0) {
212 printf("Leq(M)10 data will be logged to the file leqm10.txt\n");
216 if (strcmp(argv[in], "-logleqm") == 0) {
219 printf("Leq(M) data will be logged to the file leqmlog.txt\n");
224 if (strcmp(argv[in], "-leqnw") == 0) {
227 printf("Leq(nW) - unweighted - will be outputted.\n");
232 if (strcmp(argv[in], "-buffersize") == 0) {
233 buffersizems = atoi(argv[in + 1]);
235 printf("Buffersize will be set to %d milliseconds.\n", buffersizems);
240 if (parameterstate==0) {
246 //postprocessing parameters
247 if (numcalread == sfinfo.channels) {
248 for (int cind = 0; cind < sfinfo.channels; cind++) {
249 channelconfcalvector[cind] = convloglin_single(tempchcal[cind]);
253 else if ((numcalread == 0) && (sfinfo.channels == 6)) {
254 double conf51[6] = {0, 0, 0, 0, -3, -3};
255 for (int cind = 0; cind < sfinfo.channels; cind++) {
256 channelconfcalvector[cind] = convloglin_single(conf51[cind]);
261 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");
263 free(channelconfcalvector);
264 channelconfcalvector = NULL;
272 char tempstring[128];
273 strcpy(tempstring, soundfilename);
274 strcat(tempstring, ".leqm10.txt");
275 leqm10logfile = fopen(tempstring, "w");
276 if (leqm10logfile == NULL) {
277 printf("Could not open file to write log leqm10 data!\n");
285 char tempstring[128];
286 strcpy(tempstring, soundfilename);
287 strcat(tempstring, ".leqmlog.txt");
288 leqmlogfile = fopen(tempstring, "w");
289 if (leqmlogfile == NULL) {
290 printf("Could not open file to write log leqm data!\n");
297 clock_gettime(CLOCK_MONOTONIC, &starttime);
304 // reading to a double or float buffer with sndfile take care of normalization
306 static double buffer[BUFFER_LEN]; // it seems this must be static. I don't know why
309 // buffer = new double [BUFFER_LEN];
310 buffersizesamples = (sfinfo.samplerate*sfinfo.channels*buffersizems)/1000;
311 if ((sfinfo.samplerate*buffersizems)%1000) {
312 printf("Please fine tune the buffersize according to the sample rate\n");
315 // write a function to do that
319 buffersizesamples = (sfinfo.samplerate*sfinfo.channels*buffersizems)/1000;
320 buffer = malloc(sizeof(double)*buffersizesamples);
322 samplingfreq = sfinfo.samplerate;
326 //if duration < 10 mm exit
328 double featdursec = sfinfo.frames / sfinfo.samplerate;
329 if ((featdursec/60.0) < 10.0) {
330 printf("The audio file is too short to measure Leq(m10).\n");
334 //how many short periods in overall duration
335 int remainder = sfinfo.frames % (sfinfo.samplerate*buffersizems/1000);
336 if (remainder == 0) numbershortperiods = sfinfo.frames/(sfinfo.samplerate*buffersizems/1000);
337 else numbershortperiods = sfinfo.frames/(sfinfo.samplerate*buffersizems/1000) + 1;
340 shorttermaveragedarray = malloc(sizeof(*shorttermaveragedarray)*numbershortperiods);
344 //End opening audio file
348 double freqsamples[] = {31, 63, 100, 200, 400, 800, 1000, 2000, 3150, 4000, 5000, 6300, 7100, 8000, 9000, 10000, 12500, 14000, 16000, 20000, 31500};
349 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};
351 double * eqfreqresp_db;
352 eqfreqresp_db = malloc(sizeof(*eqfreqresp_db)*npoints);
354 double * eqfreqsamples;
355 eqfreqsamples = malloc(sizeof(*eqfreqsamples)*npoints);
357 eqfreqresp = malloc(sizeof(*eqfreqresp)*npoints);
359 ir = malloc(sizeof(*ir)*npoints*2);
362 // And what to do for floating point sample coding?
364 switch(sfinfo.format & SF_FORMAT_SUBMASK) {
365 // all signed bitdepth
379 printf("No known bitdepth! Exiting ...\n");
386 equalinterval2(freqsamples, freqresp_db, eqfreqsamples, eqfreqresp_db, npoints, samplingfreq, origpoints, bitdepth);
387 convloglin(eqfreqresp_db, eqfreqresp, npoints);
390 for (int i=0; i < npoints; i++) {
391 printf("%d\t%.2f\t%.2f\t%.2f\n", i, eqfreqsamples[i], eqfreqresp_db[i], eqfreqresp[i]);
395 inversefft2(eqfreqresp, ir, npoints);
397 // read through the entire file
400 totsum = malloc(sizeof(struct Sum));
403 totsum->nsamples = 0;
405 totsum->mean = 0.0; // Do I write anything here?
408 sf_count_t samples_read = 0;
410 // Main loop through audio file
413 pthread_t tid[numCPU];
414 struct WorkerArgs ** WorkerArgsArray;
415 WorkerArgsArray = malloc(sizeof(struct WorkerArgs *)*numCPU);
416 int staindex = 0; //shorttermarrayindex
419 while((samples_read = sf_read_double(file, buffer, buffersizesamples)) > 0) {
421 WorkerArgsArray[worker_id]=malloc(sizeof(struct WorkerArgs));
422 WorkerArgsArray[worker_id]->nsamples = samples_read;
423 WorkerArgsArray[worker_id]->nch = sfinfo.channels;
424 WorkerArgsArray[worker_id]->npoints=npoints;
425 WorkerArgsArray[worker_id]->ir = ir;
426 WorkerArgsArray[worker_id]->ptrtotsum = totsum;
428 WorkerArgsArray[worker_id]->chconf = channelconfcalvector;
430 WorkerArgsArray[worker_id]->shorttermindex = staindex++;
431 WorkerArgsArray[worker_id]->leqm10flag = 1;
432 WorkerArgsArray[worker_id]->shorttermarray = shorttermaveragedarray;
434 WorkerArgsArray[worker_id]->shorttermindex = 0;
435 WorkerArgsArray[worker_id]->leqm10flag = 0;
438 WorkerArgsArray[worker_id]->argbuffer = malloc(sizeof(double)*buffersizesamples);
439 memcpy(WorkerArgsArray[worker_id]->argbuffer, buffer, samples_read*sizeof(double));
443 pthread_attr_init(&attr);
444 pthread_create(&tid[worker_id], &attr, worker_function, WorkerArgsArray[worker_id]);
447 if (worker_id == numCPU) {
449 //maybe here wait for all cores to output before going on
450 for (int idxcpu = 0; idxcpu < numCPU; idxcpu++) {
451 pthread_join(tid[idxcpu], NULL);
452 free(WorkerArgsArray[idxcpu]);
453 WorkerArgsArray[idxcpu] = NULL;
455 //simply log here your measurement it will be a multiple of your threads and your buffer
457 meanoverduration(totsum); //update leq(m) until now and log it
458 logleqm(leqmlogfile, ((double) totsum->nsamples)/((double) sfinfo.samplerate), totsum );
464 //end while worker_id
465 /// End looping cores
466 } // main loop through file
468 //here I should wait for rest worker (< numcpu)
469 //but I need to dispose of thread id.
470 if (worker_id != 0) { // worker_id = 0 means the number of samples was divisible through the number of cpus
471 for (int idxcpu = 0; idxcpu < worker_id; idxcpu++) { //worker_id is at this point one unit more than threads launched
472 pthread_join(tid[idxcpu], NULL);
473 free(WorkerArgsArray[idxcpu]);
474 WorkerArgsArray[idxcpu] = NULL;
476 //also log here for a last value
478 meanoverduration(totsum); //update leq(m) until now and log it
479 logleqm(leqmlogfile, ((double) totsum->nsamples)/((double) sfinfo.samplerate), totsum );
482 // mean of scalar sum over duration
484 meanoverduration(totsum);
486 printf("Leq(noW): %.4f\n", totsum->rms); // Leq(no Weighting)
488 printf("Leq(M): %.4f\n", totsum->leqm);
491 struct timespec stoptime;
492 long stoptimenanoseconds;
493 long executionnanoseconds;
494 clock_gettime(CLOCK_MONOTONIC, &stoptime);
496 if (stoptime.tv_nsec < starttime.tv_nsec) {
497 stoptimenanoseconds = 1000000000 + stoptime.tv_nsec;
499 stoptimenanoseconds = stoptime.tv_nsec;
501 executionnanoseconds = stoptimenanoseconds - starttime.tv_nsec;
502 printf("Total execution time is %.6f seconds\n", ((double) stoptime.tv_sec) - ((double) starttime.tv_sec) + ((double) executionnanoseconds / 1000000000.00));
508 //Take the array with the short term accumulators
509 double interval = 10.0;
510 //create a rolling average according to rolling interval
511 int rollint; // in short 10*60 = 600 sec 600/0.850
514 //how many element of the array to consider for the rollint?
515 //that is how many buffersizems in the interval - interval could be parameterized(?)
516 double tempint = 60.0 * interval / (((double) buffersizems) /1000.0);
517 rollint = (int) tempint;
518 //dispose of the rest
519 if (tempint - ((double) rollint) > 0) {
525 while(indexlong < (numbershortperiods - rollint)) {
527 double accumulator = 0;
529 double averagedaccumulator = 0;
530 for (int indexshort = 0; indexshort < rollint; indexshort++) {
532 accumulator += shorttermaveragedarray[indexshort+indexlong];
533 } //end internal loop
534 averagedaccumulator = accumulator/((double) rollint);
535 logleqm10(leqm10logfile, ((double) (indexlong+rollint)) * ((double) buffersizems / 1000.0), averagedaccumulator);
537 } //end external loop
539 fclose(leqm10logfile);
540 free(shorttermaveragedarray);
541 shorttermaveragedarray = NULL;
553 eqfreqsamples = NULL;
560 free(channelconfcalvector);
561 channelconfcalvector = NULL;
562 free(WorkerArgsArray);
563 WorkerArgsArray = NULL;
574 void * worker_function(void * argstruct) {
576 struct WorkerArgs * thisWorkerArgs = (struct WorkerArgs *) argstruct;
578 double * sumandsquarebuffer;
579 double * csumandsquarebuffer;
580 double * chsumaccumulator_norm;
581 double * chsumaccumulator_conv;
584 sumandsquarebuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
587 csumandsquarebuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
589 chsumaccumulator_norm = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
591 chsumaccumulator_conv = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
595 for (int i = 0; i < thisWorkerArgs->nsamples / thisWorkerArgs->nch; i++) {
596 sumandsquarebuffer[i] = 0.0;
597 csumandsquarebuffer[i] = 0.0;
598 chsumaccumulator_norm[i] = 0.0;
599 chsumaccumulator_conv[i] = 0.0;
604 for (int ch = 0; ch < thisWorkerArgs->nch; ch++) {
606 double * normalizedbuffer;
607 double * convolvedbuffer;
610 normalizedbuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
612 convolvedbuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
615 for (int n=ch, m= 0; n < thisWorkerArgs->nsamples; n += thisWorkerArgs->nch, m++) {
616 // 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
617 //so not normalized but calibrated
618 normalizedbuffer[m] = thisWorkerArgs->argbuffer[n]*thisWorkerArgs->chconf[ch]; //this scale amplitude according to specified calibration
624 convolv_buff(normalizedbuffer, convolvedbuffer, thisWorkerArgs->ir, thisWorkerArgs->nsamples / thisWorkerArgs->nch, thisWorkerArgs->npoints * 2);
625 //rectify, square und sum
626 rectify(csumandsquarebuffer,convolvedbuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
627 rectify(sumandsquarebuffer,normalizedbuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
629 accumulatech(chsumaccumulator_norm, sumandsquarebuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
630 accumulatech(chsumaccumulator_conv, csumandsquarebuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
633 free(normalizedbuffer);
634 normalizedbuffer= NULL;
636 free(convolvedbuffer);
637 convolvedbuffer=NULL;
639 } // loop through channels
641 //Create a function for this also a tag so that the worker know if he has to do this or not
643 if (thisWorkerArgs->leqm10flag) {
644 thisWorkerArgs->shorttermarray[thisWorkerArgs->shorttermindex] = sumandshorttermavrg(chsumaccumulator_conv, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
646 printf("%d: %.6f\n", thisWorkerArgs->shorttermindex, thisWorkerArgs->shorttermarray[thisWorkerArgs->shorttermindex]);
649 pthread_mutex_lock(&mutex);
650 // this should be done under mutex conditions -> shared resources!
651 sumsamples(thisWorkerArgs->ptrtotsum, chsumaccumulator_norm, chsumaccumulator_conv, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
652 pthread_mutex_unlock(&mutex);
655 free(sumandsquarebuffer);
656 sumandsquarebuffer=NULL;
658 free(csumandsquarebuffer);
659 csumandsquarebuffer=NULL;
661 free(chsumaccumulator_norm);
662 chsumaccumulator_norm=NULL;
664 free(chsumaccumulator_conv);
665 chsumaccumulator_conv=NULL;
667 free(thisWorkerArgs->argbuffer);
668 thisWorkerArgs->argbuffer = NULL;
669 // the memory pointed to by this pointer is freed in main
670 // it is the same memory for all worker
671 // but it is necessary to set pointer to NULL otherwise free will not work later (really?)
672 thisWorkerArgs->chconf = NULL;
678 //to get impulse response frequency response at equally spaced intervals is needed
680 int equalinterval( double * freqsamples, double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints) {
684 double pass = ((double) (samplingfreq >> 1)) / ((double) points);
685 for (int ieq = 0, i = 0; ieq < points; ieq++) {
687 eqfreqsamples[ieq] = freq;
689 if ((freq == 0.0) || (freq < freqsamples[1])) {
690 eqfreqresp[ieq] = freqresp[0];
694 if ((freq >= freqsamples[i]) && (freq < freqsamples[i+1])) {
695 eqfreqresp[ieq] = ((freqresp[i+1] - freqresp[i])/(freqsamples[i+1] - freqsamples[i]))*(freq - freqsamples[i]) + freqresp[i];
696 } else if (freq >=freqsamples[i+1]) {
697 while(freq >= freqsamples[i+1]) {
699 if ((i + 1) >= origpoints) {
703 if ((i+1) < origpoints) {
704 eqfreqresp[ieq] = ((freqresp[i+1] - freqresp[i])/(freqsamples[i+1] - freqsamples[i]))*(freq- freqsamples[i]) + freqresp[i];
706 eqfreqresp[ieq] = ((1 - freqresp[i])/(((double) (samplingfreq >> 1)) - freqsamples[i]))*(freq- freqsamples[i]) + freqresp[i];
718 //the following is different from version 1 because interpolate between db and not linear. Conversion from db to lin must be done after.
719 //it is also different for the way it interpolates between DC and 31 Hz
720 // Pay attention that also arguments to the functions are changed
721 int equalinterval2( double freqsamples[], double freqresp_db[], double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints, int bitdepthsoundfile) {
725 //calculate miminum attenuation depending on the bitdeph (minus one), that is −6.020599913 dB per bit in eccess to sign
726 double dcatt = ((double) (bitdepthsoundfile - 1))*(-6.020599913) + 20.00; //in dB
727 //double dcatt = -90.3;
728 double pass = ((double) (samplingfreq >> 1)) / ((double) points);
729 for (int ieq = 0, i = 0; ieq < points; ieq++) {
731 eqfreqsamples[ieq] = freq;
734 eqfreqresp[ieq] = dcatt;
735 } else if (freq < freqsamples[0]) { // this has a lot of influence on final Leq(M) value
736 eqfreqresp[ieq] = ((freqresp_db[0] - dcatt) / (freqsamples[0] - 0)) * freq + dcatt;
737 //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
741 if ((freq >= freqsamples[i]) && (freq < freqsamples[i+1])) {
742 eqfreqresp[ieq] = ((freqresp_db[i+1] - freqresp_db[i])/(freqsamples[i+1] - freqsamples[i]))*(freq - freqsamples[i]) + freqresp_db[i];
743 } else if (freq >=freqsamples[i+1]) {
744 while(freq >= freqsamples[i+1]) {
746 if ((i + 1) >= origpoints) {
750 if ((i+1) < origpoints) {
751 eqfreqresp[ieq] = ((freqresp_db[i+1] - freqresp_db[i])/(freqsamples[i+1] - freqsamples[i]))*(freq- freqsamples[i]) + freqresp_db[i];
753 eqfreqresp[ieq] = ((1 - freqresp_db[i])/(((double) (samplingfreq >> 1)) - freqsamples[i]))*(freq- freqsamples[i]) + freqresp_db[i];
766 int convloglin(double * in, double * out, int points) {
767 for (int i = 0; i < points; i++) {
768 out[i] = powf(10, (in[i]/20.0));
775 double convlinlog_single(double in) {
782 double convloglin_single(double in) {
784 out = powf(10, in/20.0f);
790 int convolv_buff(double * sigin, double * sigout, double * impresp, int sigin_dim, int impresp_dim) {
794 for (int i = 0; i < sigin_dim; i++) {
797 for (int l = impresp_dim - 1; l >=0; l--,m++) {
798 if (m >= sigin_dim) {
801 sum += sigin[m]*impresp[l];
811 void inversefft2(double * eqfreqresp, double * ir, int npoints) {
812 for (int n = 0; n < npoints; n++) {
814 double partial = 0.0;
816 for (int m = 1; m <= npoints -1; m++) {
817 partial = cos(2.0*M_PI*((double) m)*( ( ((double) n) - ( ((double) npoints) * 2.0 -1 ) / 2 ) / ( ((double) npoints) * 2.0) ));
818 parsum = parsum + eqfreqresp[m]*partial;
820 ir[n] = (eqfreqresp[0] + 2.0 * parsum)/((double) npoints * 2.0);
822 printf("%.4f\n", ir[n]);
825 for (int n = 0; n < npoints; n++) {
826 ir[npoints+n] = ir[npoints-(n + 1)];
828 printf("%.4f\n", ir[npoints+n]);
835 // scale input according to required calibration
836 // this could be different for certain digital cinema formats
837 double inputcalib (double dbdiffch) {
839 double coeff = pow(10, dbdiffch/20);
844 //rectify, square and sum
845 int rectify(double * squared, double * inputsamples, int nsamples){
846 for (int i = 0; i < nsamples; i++) {
847 squared[i] = (double) powf(inputsamples[i], 2);
853 int initbuffer(double * buffertoinit, int nsamples) {
854 for (int i = 0; i < nsamples; i++) {
855 buffertoinit[i] = 0.0;
861 int accumulatech(double * chaccumulator, double * inputchannel, int nsamples) {
862 for (int i = 0; i < nsamples; i++) {
863 chaccumulator[i] += inputchannel[i];
868 int sumsamples(struct Sum * ts, double * inputsamples, double * cinputsamples, int nsamples) {
869 ts->nsamples += nsamples;
870 for (int i=0; i < nsamples; i++) {
871 ts->sum += inputsamples[i];
872 ts->csum += cinputsamples[i];
878 int meanoverduration(struct Sum * oldsum) {
879 oldsum->mean = pow(oldsum->sum / ((double) oldsum->nsamples), 0.500);
880 oldsum->cmean = pow(oldsum->csum / ((double) oldsum->nsamples), 0.500);
881 oldsum->rms = 20*log10(oldsum->mean);
882 oldsum->leqm = 20*log10(oldsum->cmean) + 110.600;//
883 // and 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.
884 //this value is obtained calibrating with a -20 dBFS Dolby Tone (RMS) I think this is correct
885 //But ISO 21727:2004(E) ask for a reference level "measured using an average responding meter". So reference level is not 0.707, but 0.637 = 2/pi
886 //This is only approximate as you should use a separate calibration according to the Dolby Format. Also for SW the tone should be 100Hz (?)
891 double sumandshorttermavrg(double * channelaccumulator, int nsamples) {
893 for (int i=0; i < nsamples; i++) {
894 stsum += channelaccumulator[i];
897 return stsum / (double) nsamples;
900 void logleqm(FILE * filehandle, double featuretimesec, struct Sum * oldsum) {
902 fprintf(filehandle, "%.4f", featuretimesec);
903 fprintf(filehandle, "\t");
904 fprintf(filehandle, "%.4f\n", oldsum->leqm);
909 void logleqm10(FILE * filehandle, double featuretimesec, double longaverage) {
910 double leqm10 = 20*log10(pow(longaverage, 0.500)) + 110.600;
911 fprintf(filehandle, "%.4f", featuretimesec);
912 fprintf(filehandle, "\t");
913 fprintf(filehandle, "%.4f\n", leqm10);