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;
122 // This is a requirement of sndfile library, do not forget it.
124 memset(&sfinfo, 0, sizeof(sfinfo));
128 { 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";
130 printf("Please indicate a sound file to be processed.\n");
135 for (int in = 1; in < argc;) {
137 if (!(strncmp(argv[in], "-", 1) == 0)) {
138 if (fileopenstate == 0) {
139 if(! (file = sf_open(argv[in], SFM_READ, &sfinfo))) {
140 printf("Error while opening audio file, could not open %s\n.", argv[in]);
141 puts(sf_strerror(NULL));
147 printf("Opened file: %s\n", argv[in]);
148 printf("Sample rate: %d\n", sfinfo.samplerate);
149 printf("Channels: %d\n", sfinfo.channels);
150 printf("Format: %d\n", sfinfo.format);
151 printf("Frames: %d\n", sfinfo.frames);
152 channelconfcalvector = malloc(sizeof(double) * sfinfo.channels);
156 free(channelconfcalvector);
157 channelconfcalvector = NULL;
163 if (strcmp(argv[in], "-chconfcal") == 0) {
164 /* as the order of parameter is free I have to postpone
165 the check for consistency with the number of channel.
166 So first create a temporary array, whose number of element will be checked after
167 the parsing of the command line parameters is finished.
168 The calibration will be expressed in dB on the command line and converted to multiplier
169 here so that it can be stored as a factor in the channelconcalvector.
175 //if (!(strncmp(argv[in], "-", 1) == 0)) { //changed this to allow negative numbers
176 if (!(strncmp(argv[in], "-", 1) == 0) || isdigit(argv[in][1])) {
177 tempchcal[numcalread++]=atof(argv[in++]);
185 if (strcmp(argv[in], "-convpoints") == 0) {
186 npoints = atoi(argv[in + 1]);
188 printf("Convolution points sets to %d.\n");
192 if (strcmp(argv[in], "-numcpus") == 0) {
193 numCPU= atoi(argv[in + 1]);
195 printf("Number of threads manually set to %d. Default is number of cores in the system minus one.\n", numCPU);
199 if (strcmp(argv[in], "-timing") == 0) {
202 printf("Execution time will be measured.\n", numCPU);
207 if (strcmp(argv[in], "-logleqm10") == 0) {
210 printf("Leq(M)10 data will be logged in the file leqm10.txt\n");
214 if (strcmp(argv[in], "-logleqm") == 0) {
217 printf("Leq(M)10 data will be logged in the file leqmlog.txt\n");
222 if (strcmp(argv[in], "-leqnw") == 0) {
225 printf("Leq(nW) - unweighted - will be outputted.\n");
230 if (strcmp(argv[in], "-buffersize") == 0) {
231 buffersizems = atoi(argv[in + 1]);
233 printf("Buffersize will be set to %d milliseconds.\n", buffersizems);
238 if (parameterstate==0) {
244 //postprocessing parameters
245 if (numcalread == sfinfo.channels) {
246 for (int cind = 0; cind < sfinfo.channels; cind++) {
247 channelconfcalvector[cind] = convloglin_single(tempchcal[cind]);
251 else if ((numcalread == 0) && (sfinfo.channels == 6)) {
252 double conf51[6] = {0, 0, 0, 0, -3, -3};
253 for (int cind = 0; cind < sfinfo.channels; cind++) {
254 channelconfcalvector[cind] = convloglin_single(conf51[cind]);
259 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");
261 free(channelconfcalvector);
262 channelconfcalvector = NULL;
271 leqm10logfile = fopen("leqm10.txt", "w");
272 if (leqm10logfile == NULL) {
273 printf("Could not open file to write log leqm10 data!\n");
284 leqmlogfile = fopen("leqmlog.txt", "w");
285 if (leqmlogfile == NULL) {
286 printf("Could not open file to write log leqm data!\n");
294 clock_gettime(CLOCK_MONOTONIC, &starttime);
301 // reading to a double or float buffer with sndfile take care of normalization
303 static double buffer[BUFFER_LEN]; // it seems this must be static. I don't know why
306 // buffer = new double [BUFFER_LEN];
307 buffersizesamples = (sfinfo.samplerate*sfinfo.channels*buffersizems)/1000;
308 if ((sfinfo.samplerate*buffersizems)%1000) {
309 printf("Please fine tune the buffersize according to the sample rate\n");
312 // write a function to do that
316 buffersizesamples = (sfinfo.samplerate*sfinfo.channels*buffersizems)/1000;
317 buffer = malloc(sizeof(double)*buffersizesamples);
319 samplingfreq = sfinfo.samplerate;
323 //if duration < 10 mm exit
325 double featdursec = sfinfo.frames / sfinfo.samplerate;
326 if ((featdursec/60.0) < 10.0) {
327 printf("The audio file is too short to measure Leq(m10).\n");
331 //how many short periods in overall duration
332 int remainder = sfinfo.frames % (sfinfo.samplerate*buffersizems/1000);
333 if (remainder == 0) numbershortperiods = sfinfo.frames/(sfinfo.samplerate*buffersizems/1000);
334 else numbershortperiods = sfinfo.frames/(sfinfo.samplerate*buffersizems/1000) + 1;
337 shorttermaveragedarray = malloc(sizeof(*shorttermaveragedarray)*numbershortperiods);
341 //End opening audio file
345 double freqsamples[] = {31, 63, 100, 200, 400, 800, 1000, 2000, 3150, 4000, 5000, 6300, 7100, 8000, 9000, 10000, 12500, 14000, 16000, 20000, 31500};
346 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};
348 double * eqfreqresp_db;
349 eqfreqresp_db = malloc(sizeof(*eqfreqresp_db)*npoints);
351 double * eqfreqsamples;
352 eqfreqsamples = malloc(sizeof(*eqfreqsamples)*npoints);
354 eqfreqresp = malloc(sizeof(*eqfreqresp)*npoints);
356 ir = malloc(sizeof(*ir)*npoints*2);
359 // And what to do for floating point sample coding?
361 switch(sfinfo.format & SF_FORMAT_SUBMASK) {
362 // all signed bitdepth
376 printf("No known bitdepth! Exiting ...\n");
383 equalinterval2(freqsamples, freqresp_db, eqfreqsamples, eqfreqresp_db, npoints, samplingfreq, origpoints, bitdepth);
384 convloglin(eqfreqresp_db, eqfreqresp, npoints);
387 for (int i=0; i < npoints; i++) {
388 printf("%d\t%.2f\t%.2f\t%.2f\n", i, eqfreqsamples[i], eqfreqresp_db[i], eqfreqresp[i]);
392 inversefft2(eqfreqresp, ir, npoints);
394 // read through the entire file
397 totsum = malloc(sizeof(struct Sum));
400 totsum->nsamples = 0;
402 totsum->mean = 0.0; // Do I write anything here?
405 sf_count_t samples_read = 0;
407 // Main loop through audio file
410 pthread_t tid[numCPU];
411 struct WorkerArgs ** WorkerArgsArray;
412 WorkerArgsArray = malloc(sizeof(struct WorkerArgs *)*numCPU);
413 int staindex = 0; //shorttermarrayindex
416 while((samples_read = sf_read_double(file, buffer, buffersizesamples)) > 0) {
418 WorkerArgsArray[worker_id]=malloc(sizeof(struct WorkerArgs));
419 WorkerArgsArray[worker_id]->nsamples = samples_read;
420 WorkerArgsArray[worker_id]->nch = sfinfo.channels;
421 WorkerArgsArray[worker_id]->npoints=npoints;
422 WorkerArgsArray[worker_id]->ir = ir;
423 WorkerArgsArray[worker_id]->ptrtotsum = totsum;
425 WorkerArgsArray[worker_id]->chconf = channelconfcalvector;
427 WorkerArgsArray[worker_id]->shorttermindex = staindex++;
428 WorkerArgsArray[worker_id]->leqm10flag = 1;
429 WorkerArgsArray[worker_id]->shorttermarray = shorttermaveragedarray;
431 WorkerArgsArray[worker_id]->shorttermindex = 0;
432 WorkerArgsArray[worker_id]->leqm10flag = 0;
435 WorkerArgsArray[worker_id]->argbuffer = malloc(sizeof(double)*buffersizesamples);
436 memcpy(WorkerArgsArray[worker_id]->argbuffer, buffer, samples_read*sizeof(double));
440 pthread_attr_init(&attr);
441 pthread_create(&tid[worker_id], &attr, worker_function, WorkerArgsArray[worker_id]);
444 if (worker_id == numCPU) {
446 //maybe here wait for all cores to output before going on
447 for (int idxcpu = 0; idxcpu < numCPU; idxcpu++) {
448 pthread_join(tid[idxcpu], NULL);
449 free(WorkerArgsArray[idxcpu]);
450 WorkerArgsArray[idxcpu] = NULL;
452 //simply log here your measurement it will be a multiple of your threads and your buffer
454 meanoverduration(totsum); //update leq(m) until now and log it
455 logleqm(leqmlogfile, ((double) totsum->nsamples)/((double) sfinfo.samplerate), totsum );
461 //end while worker_id
462 /// End looping cores
463 } // main loop through file
465 //here I should wait for rest worker (< numcpu)
466 //but I need to dispose of thread id.
467 if (worker_id != 0) { // worker_id = 0 means the number of samples was divisible through the number of cpus
468 for (int idxcpu = 0; idxcpu < worker_id; idxcpu++) { //worker_id is at this point one unit more than threads launched
469 pthread_join(tid[idxcpu], NULL);
470 free(WorkerArgsArray[idxcpu]);
471 WorkerArgsArray[idxcpu] = NULL;
473 //also log here for a last value
475 meanoverduration(totsum); //update leq(m) until now and log it
476 logleqm(leqmlogfile, ((double) totsum->nsamples)/((double) sfinfo.samplerate), totsum );
479 // mean of scalar sum over duration
481 meanoverduration(totsum);
483 printf("Leq(noW): %.4f\n", totsum->rms); // Leq(no Weighting)
485 printf("Leq(M): %.4f\n", totsum->leqm);
488 struct timespec stoptime;
489 long stoptimenanoseconds;
490 long executionnanoseconds;
491 clock_gettime(CLOCK_MONOTONIC, &stoptime);
493 if (stoptime.tv_nsec < starttime.tv_nsec) {
494 stoptimenanoseconds = 1000000000 + stoptime.tv_nsec;
496 stoptimenanoseconds = stoptime.tv_nsec;
498 executionnanoseconds = stoptimenanoseconds - starttime.tv_nsec;
499 printf("Total execution time is %.6f seconds\n", ((double) stoptime.tv_sec) - ((double) starttime.tv_sec) + ((double) executionnanoseconds / 1000000000.00));
505 //Take the array with the short term accumulators
506 double interval = 10.0;
507 //create a rolling average according to rolling interval
508 int rollint; // in short 10*60 = 600 sec 600/0.850
511 //how many element of the array to consider for the rollint?
512 //that is how many buffersizems in the interval - interval could be parameterized(?)
513 double tempint = 60.0 * interval / (((double) buffersizems) /1000.0);
514 rollint = (int) tempint;
515 //dispose of the rest
516 if (tempint - ((double) rollint) > 0) {
522 while(indexlong < (numbershortperiods - rollint)) {
524 double accumulator = 0;
526 double averagedaccumulator = 0;
527 for (int indexshort = 0; indexshort < rollint; indexshort++) {
529 accumulator += shorttermaveragedarray[indexshort+indexlong];
530 } //end internal loop
531 averagedaccumulator = accumulator/((double) rollint);
532 logleqm10(leqm10logfile, ((double) (indexlong+rollint)) * ((double) buffersizems / 1000.0), averagedaccumulator);
534 } //end external loop
536 fclose(leqm10logfile);
537 free(shorttermaveragedarray);
538 shorttermaveragedarray = NULL;
550 eqfreqsamples = NULL;
557 free(channelconfcalvector);
558 channelconfcalvector = NULL;
559 free(WorkerArgsArray);
560 WorkerArgsArray = NULL;
571 void * worker_function(void * argstruct) {
573 struct WorkerArgs * thisWorkerArgs = (struct WorkerArgs *) argstruct;
575 double * sumandsquarebuffer;
576 double * csumandsquarebuffer;
577 double * chsumaccumulator_norm;
578 double * chsumaccumulator_conv;
581 sumandsquarebuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
584 csumandsquarebuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
586 chsumaccumulator_norm = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
588 chsumaccumulator_conv = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
592 for (int i = 0; i < thisWorkerArgs->nsamples / thisWorkerArgs->nch; i++) {
593 sumandsquarebuffer[i] = 0.0;
594 csumandsquarebuffer[i] = 0.0;
595 chsumaccumulator_norm[i] = 0.0;
596 chsumaccumulator_conv[i] = 0.0;
601 for (int ch = 0; ch < thisWorkerArgs->nch; ch++) {
603 double * normalizedbuffer;
604 double * convolvedbuffer;
607 normalizedbuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
609 convolvedbuffer = malloc(sizeof(double)*(thisWorkerArgs->nsamples / thisWorkerArgs->nch));
612 for (int n=ch, m= 0; n < thisWorkerArgs->nsamples; n += thisWorkerArgs->nch, m++) {
613 // 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
614 //so not normalized but calibrated
615 normalizedbuffer[m] = thisWorkerArgs->argbuffer[n]*thisWorkerArgs->chconf[ch]; //this scale amplitude according to specified calibration
621 convolv_buff(normalizedbuffer, convolvedbuffer, thisWorkerArgs->ir, thisWorkerArgs->nsamples / thisWorkerArgs->nch, thisWorkerArgs->npoints * 2);
622 //rectify, square und sum
623 rectify(csumandsquarebuffer,convolvedbuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
624 rectify(sumandsquarebuffer,normalizedbuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
626 accumulatech(chsumaccumulator_norm, sumandsquarebuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
627 accumulatech(chsumaccumulator_conv, csumandsquarebuffer, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
630 free(normalizedbuffer);
631 normalizedbuffer= NULL;
633 free(convolvedbuffer);
634 convolvedbuffer=NULL;
636 } // loop through channels
638 //Create a function for this also a tag so that the worker know if he has to do this or not
640 if (thisWorkerArgs->leqm10flag) {
641 thisWorkerArgs->shorttermarray[thisWorkerArgs->shorttermindex] = sumandshorttermavrg(chsumaccumulator_conv, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
643 printf("%d: %.6f\n", thisWorkerArgs->shorttermindex, thisWorkerArgs->shorttermarray[thisWorkerArgs->shorttermindex]);
646 pthread_mutex_lock(&mutex);
647 // this should be done under mutex conditions -> shared resources!
648 sumsamples(thisWorkerArgs->ptrtotsum, chsumaccumulator_norm, chsumaccumulator_conv, thisWorkerArgs->nsamples / thisWorkerArgs->nch);
649 pthread_mutex_unlock(&mutex);
652 free(sumandsquarebuffer);
653 sumandsquarebuffer=NULL;
655 free(csumandsquarebuffer);
656 csumandsquarebuffer=NULL;
658 free(chsumaccumulator_norm);
659 chsumaccumulator_norm=NULL;
661 free(chsumaccumulator_conv);
662 chsumaccumulator_conv=NULL;
664 free(thisWorkerArgs->argbuffer);
665 thisWorkerArgs->argbuffer = NULL;
666 // the memory pointed to by this pointer is freed in main
667 // it is the same memory for all worker
668 // but it is necessary to set pointer to NULL otherwise free will not work later (really?)
669 thisWorkerArgs->chconf = NULL;
675 //to get impulse response frequency response at equally spaced intervals is needed
677 int equalinterval( double * freqsamples, double * freqresp, double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints) {
681 double pass = ((double) (samplingfreq >> 1)) / ((double) points);
682 for (int ieq = 0, i = 0; ieq < points; ieq++) {
684 eqfreqsamples[ieq] = freq;
686 if ((freq == 0.0) || (freq < freqsamples[1])) {
687 eqfreqresp[ieq] = freqresp[0];
691 if ((freq >= freqsamples[i]) && (freq < freqsamples[i+1])) {
692 eqfreqresp[ieq] = ((freqresp[i+1] - freqresp[i])/(freqsamples[i+1] - freqsamples[i]))*(freq - freqsamples[i]) + freqresp[i];
693 } else if (freq >=freqsamples[i+1]) {
694 while(freq >= freqsamples[i+1]) {
696 if ((i + 1) >= origpoints) {
700 if ((i+1) < origpoints) {
701 eqfreqresp[ieq] = ((freqresp[i+1] - freqresp[i])/(freqsamples[i+1] - freqsamples[i]))*(freq- freqsamples[i]) + freqresp[i];
703 eqfreqresp[ieq] = ((1 - freqresp[i])/(((double) (samplingfreq >> 1)) - freqsamples[i]))*(freq- freqsamples[i]) + freqresp[i];
715 //the following is different from version 1 because interpolate between db and not linear. Conversion from db to lin must be done after.
716 //it is also different for the way it interpolates between DC and 31 Hz
717 // Pay attention that also arguments to the functions are changed
718 int equalinterval2( double freqsamples[], double freqresp_db[], double * eqfreqsamples, double * eqfreqresp, int points, int samplingfreq, int origpoints, int bitdepthsoundfile) {
722 //calculate miminum attenuation depending on the bitdeph (minus one), that is −6.020599913 dB per bit in eccess to sign
723 double dcatt = ((double) (bitdepthsoundfile - 1))*(-6.020599913) + 20.00; //in dB
724 //double dcatt = -90.3;
725 double pass = ((double) (samplingfreq >> 1)) / ((double) points);
726 for (int ieq = 0, i = 0; ieq < points; ieq++) {
728 eqfreqsamples[ieq] = freq;
731 eqfreqresp[ieq] = dcatt;
732 } else if (freq < freqsamples[0]) { // this has a lot of influence on final Leq(M) value
733 eqfreqresp[ieq] = ((freqresp_db[0] - dcatt) / (freqsamples[0] - 0)) * freq + dcatt;
734 //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
738 if ((freq >= freqsamples[i]) && (freq < freqsamples[i+1])) {
739 eqfreqresp[ieq] = ((freqresp_db[i+1] - freqresp_db[i])/(freqsamples[i+1] - freqsamples[i]))*(freq - freqsamples[i]) + freqresp_db[i];
740 } else if (freq >=freqsamples[i+1]) {
741 while(freq >= freqsamples[i+1]) {
743 if ((i + 1) >= origpoints) {
747 if ((i+1) < origpoints) {
748 eqfreqresp[ieq] = ((freqresp_db[i+1] - freqresp_db[i])/(freqsamples[i+1] - freqsamples[i]))*(freq- freqsamples[i]) + freqresp_db[i];
750 eqfreqresp[ieq] = ((1 - freqresp_db[i])/(((double) (samplingfreq >> 1)) - freqsamples[i]))*(freq- freqsamples[i]) + freqresp_db[i];
763 int convloglin(double * in, double * out, int points) {
764 for (int i = 0; i < points; i++) {
765 out[i] = powf(10, (in[i]/20.0));
772 double convlinlog_single(double in) {
779 double convloglin_single(double in) {
781 out = powf(10, in/20.0f);
787 int convolv_buff(double * sigin, double * sigout, double * impresp, int sigin_dim, int impresp_dim) {
791 for (int i = 0; i < sigin_dim; i++) {
794 for (int l = impresp_dim - 1; l >=0; l--,m++) {
795 if (m >= sigin_dim) {
798 sum += sigin[m]*impresp[l];
808 void inversefft2(double * eqfreqresp, double * ir, int npoints) {
809 for (int n = 0; n < npoints; n++) {
811 double partial = 0.0;
813 for (int m = 1; m <= npoints -1; m++) {
814 partial = cos(2.0*M_PI*((double) m)*( ( ((double) n) - ( ((double) npoints) * 2.0 -1 ) / 2 ) / ( ((double) npoints) * 2.0) ));
815 parsum = parsum + eqfreqresp[m]*partial;
817 ir[n] = (eqfreqresp[0] + 2.0 * parsum)/((double) npoints * 2.0);
819 printf("%.4f\n", ir[n]);
822 for (int n = 0; n < npoints; n++) {
823 ir[npoints+n] = ir[npoints-(n + 1)];
825 printf("%.4f\n", ir[npoints+n]);
832 // scale input according to required calibration
833 // this could be different for certain digital cinema formats
834 double inputcalib (double dbdiffch) {
836 double coeff = pow(10, dbdiffch/20);
841 //rectify, square and sum
842 int rectify(double * squared, double * inputsamples, int nsamples){
843 for (int i = 0; i < nsamples; i++) {
844 squared[i] = (double) powf(inputsamples[i], 2);
850 int initbuffer(double * buffertoinit, int nsamples) {
851 for (int i = 0; i < nsamples; i++) {
852 buffertoinit[i] = 0.0;
858 int accumulatech(double * chaccumulator, double * inputchannel, int nsamples) {
859 for (int i = 0; i < nsamples; i++) {
860 chaccumulator[i] += inputchannel[i];
865 int sumsamples(struct Sum * ts, double * inputsamples, double * cinputsamples, int nsamples) {
866 ts->nsamples += nsamples;
867 for (int i=0; i < nsamples; i++) {
868 ts->sum += inputsamples[i];
869 ts->csum += cinputsamples[i];
875 int meanoverduration(struct Sum * oldsum) {
876 oldsum->mean = pow(oldsum->sum / ((double) oldsum->nsamples), 0.500);
877 oldsum->cmean = pow(oldsum->csum / ((double) oldsum->nsamples), 0.500);
878 oldsum->rms = 20*log10(oldsum->mean);
879 oldsum->leqm = 20*log10(oldsum->cmean) + 110.600;//
880 // 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.
881 //this value is obtained calibrating with a -20 dBFS Dolby Tone (RMS) I think this is correct
882 //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
883 //This is only approximate as you should use a separate calibration according to the Dolby Format. Also for SW the tone should be 100Hz (?)
888 double sumandshorttermavrg(double * channelaccumulator, int nsamples) {
890 for (int i=0; i < nsamples; i++) {
891 stsum += channelaccumulator[i];
894 return stsum / (double) nsamples;
897 void logleqm(FILE * filehandle, double featuretimesec, struct Sum * oldsum) {
899 fprintf(filehandle, "%.4f", featuretimesec);
900 fprintf(filehandle, "\t");
901 fprintf(filehandle, "%.4f\n", oldsum->leqm);
906 void logleqm10(FILE * filehandle, double featuretimesec, double longaverage) {
907 double leqm10 = 20*log10(pow(longaverage, 0.500)) + 110.600;
908 fprintf(filehandle, "%.4f", featuretimesec);
909 fprintf(filehandle, "\t");
910 fprintf(filehandle, "%.4f\n", leqm10);