1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <assert.h>
17 #include <inttypes.h>
18 #include <math.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <vector>
23 
24 template <typename T, typename A = float>
getSignalNoise(FILE * finp,FILE * fref)25 std::pair<A, A> getSignalNoise(FILE *finp, FILE *fref) {
26   constexpr size_t framesize = 256;
27   std::vector<T> in(framesize);
28   std::vector<T> ref(framesize);
29   A signal{};
30   A noise{};
31 
32   for (;;) {
33     size_t read_samples_in = fread(&in[0], sizeof(T), framesize, finp);
34     const size_t read_samples_ref = fread(&ref[0], sizeof(T), framesize, fref);
35     if (read_samples_in != read_samples_ref) {
36       printf("file sizes do not match (last %zu %zu)", read_samples_in, read_samples_ref);
37       read_samples_in = std::min(read_samples_in, read_samples_ref);
38     }
39     if (read_samples_in == 0) {
40         return { signal, noise };
41     }
42     for (size_t i = 0; i < read_samples_in; ++i) {
43        const A value(ref[i]);
44        const A diff(A(in[i]) - value);
45        signal += value * value;
46        noise += diff * diff;
47     }
48   }
49 }
50 
printUsage()51 void printUsage() {
52   printf("\nUsage: ");
53   printf("\n     snr <ref_file> <test_file> [options]\n");
54   printf("\nwhere, \n     <ref_file>  is the reference file name");
55   printf("\n                  on which will be taken as pure signal");
56   printf("\n     <test_file> is test file for snr calculation");
57   printf("\n     and options are mentioned below");
58   printf("\n");
59   printf("\n     -pcm_format:<pcm format of input files>");
60   printf("\n           0 - 16 bit pcm");
61   printf("\n           1 - 32 bit float");
62   printf("\n           default 0");
63   printf("\n     -thr:<threshold value>");
64   printf("\n           default - negative infinity\n\n");
65 }
66 
main(int argc,const char * argv[])67 int main(int argc, const char *argv[]) {
68   if (argc < 3) {
69     printUsage();
70     return -1;
71   }
72   int pcm_format = 0;
73   float thr = - std::numeric_limits<float>::infinity();
74   FILE *fref = fopen(argv[1], "rb");
75   FILE *finp = fopen(argv[2], "rb");
76   for (int i = 3; i < argc; i++) {
77     if (!strncmp(argv[i], "-pcm_format:", 12)) {
78       pcm_format = atoi(argv[i] + 12);
79     } else if (!strncmp(argv[i], "-thr:", 5)) {
80       thr = atof(argv[i] + 5);
81     }
82   }
83   if (finp == nullptr || fref == nullptr) {
84     printf("\nError: missing input/reference files\n");
85     return -1;
86   }
87   int ret = EXIT_SUCCESS;
88   auto sn = pcm_format == 0
89       ? getSignalNoise<short>(finp, fref)
90       : getSignalNoise<float>(finp, fref);
91   if (sn.first > 0.f && sn.second > 0.f) {
92     float snr = 10.f * log(sn.first / sn.second);
93     // compare the measured snr value with threshold
94     if (snr < thr) {
95       printf("%.6f less than threshold %.6f\n", snr, thr);
96       ret = EXIT_FAILURE;
97     } else {
98       printf("%.6f\n", snr);
99     }
100   }
101   fclose(finp);
102   fclose(fref);
103 
104   return ret;
105 }
106