1 /*
2 Bug:
3 - runs only on little endian machines for WAV files
4 - Not all WAV files are recognized
5 */
6
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <math.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <memory.h>
14
15 typedef signed short stereo [2];
16 typedef signed short mono;
17 typedef struct {
18 unsigned long long n;
19 long double x;
20 long double x2;
21 long double y;
22 long double y2;
23 long double xy;
24 } korr_t;
25
analyze_stereo(const stereo * p,size_t len,korr_t * k)26 void analyze_stereo ( const stereo* p, size_t len, korr_t* k )
27 {
28 long double _x = 0, _x2 = 0, _y = 0, _y2 = 0, _xy = 0;
29 double t1;
30 double t2;
31
32 k -> n += len;
33
34 for ( ; len--; p++ ) {
35 _x += (t1 = (*p)[0]); _x2 += t1 * t1;
36 _y += (t2 = (*p)[1]); _y2 += t2 * t2;
37 _xy += t1 * t2;
38 }
39
40 k -> x += _x ;
41 k -> x2 += _x2;
42 k -> y += _y ;
43 k -> y2 += _y2;
44 k -> xy += _xy;
45 }
46
analyze_dstereo(const stereo * p,size_t len,korr_t * k)47 void analyze_dstereo ( const stereo* p, size_t len, korr_t* k )
48 {
49 static double l0 = 0;
50 static double l1 = 0;
51 long double _x = 0, _x2 = 0, _y = 0, _y2 = 0, _xy = 0;
52 double t1;
53 double t2;
54
55 k -> n += len;
56
57 for ( ; len--; p++ ) {
58 _x += (t1 = (*p)[0] - l0); _x2 += t1 * t1;
59 _y += (t2 = (*p)[1] - l1); _y2 += t2 * t2;
60 _xy += t1 * t2;
61 l0 = (*p)[0];
62 l1 = (*p)[1];
63 }
64
65 k -> x += _x ;
66 k -> x2 += _x2;
67 k -> y += _y ;
68 k -> y2 += _y2;
69 k -> xy += _xy;
70 }
71
72
analyze_mono(const mono * p,size_t len,korr_t * k)73 void analyze_mono ( const mono* p, size_t len, korr_t* k )
74 {
75 long double _x = 0, _x2 = 0;
76 double t1;
77
78 k -> n += len;
79
80 for ( ; len--; p++ ) {
81 _x += (t1 = (*p)); _x2 += t1 * t1;
82 }
83
84 k -> x += _x ;
85 k -> x2 += _x2;
86 k -> y += _x ;
87 k -> y2 += _x2;
88 k -> xy += _x2;
89 }
90
analyze_dmono(const mono * p,size_t len,korr_t * k)91 void analyze_dmono ( const mono* p, size_t len, korr_t* k )
92 {
93 static double l0 = 0;
94 long double _x = 0, _x2 = 0;
95 double t1;
96
97 k -> n += len;
98
99 for ( ; len--; p++ ) {
100 _x += (t1 = (*p) - l0); _x2 += t1 * t1;
101 l0 = *p;
102 }
103
104 k -> x += _x ;
105 k -> x2 += _x2;
106 k -> y += _x ;
107 k -> y2 += _x2;
108 k -> xy += _x2;
109 }
110
sgn(long double x)111 int sgn ( long double x )
112 {
113 if ( x > 0 ) return +1;
114 if ( x < 0 ) return -1;
115 return 0;
116 }
117
report(const korr_t * k)118 int report ( const korr_t* k )
119 {
120 long double scale = sqrt ( 1.e5 / (1<<29) ); // Sine Full Scale is +10 dB, 7327 = 100%
121 long double r;
122 long double rd;
123 long double sx;
124 long double sy;
125 long double x;
126 long double y;
127 long double b;
128
129 r = (k->x2*k->n - k->x*k->x) * (k->y2*k->n - k->y*k->y);
130 r = r > 0.l ? (k->xy*k->n - k->x*k->y) / sqrt (r) : 1.l;
131 sx = k->n > 1 ? sqrt ( (k->x2 - k->x*k->x/k->n) / (k->n - 1) ) : 0.l;
132 sy = k->n > 1 ? sqrt ( (k->y2 - k->y*k->y/k->n) / (k->n - 1) ) : 0.l;
133 x = k->n > 0 ? k->x/k->n : 0.l;
134 y = k->n > 0 ? k->y/k->n : 0.l;
135
136 b = atan2 ( sy, sx * sgn (r) ) * ( 8 / M_PI);
137
138 // 6 5 4 3 2
139 // _______________________________
140 // |\ | /|
141 // 7 | \ | / | 1
142 // | \ | / |
143 // | \ | / |
144 // | \ | / |
145 // 8 |--------------+--------------| 0
146 // | / | \ |
147 // | / | \ |
148 // -7 | / | \ | -1
149 // | / | \ |
150 // |/_____________|_____________\|
151 //
152 // -6 -5 -4 -3 -2
153
154 if ( r > 0.98 ) {
155 printf ("-mm"); // disguised mono file
156 return;
157 }
158 if ( fabs (b-2) > 0.666 ) {
159 printf ("-ms"); // low profit for joint stereo
160 return;
161 }
162 if ( r < 0.333 ) {
163 printf ("-ms"); // low profit for joint stereo
164 return;
165 }
166 }
167
readfile(const char * name,int fd)168 void readfile ( const char* name, int fd )
169 {
170 unsigned short header [22];
171 stereo s [4096];
172 mono m [8192];
173 size_t samples;
174 korr_t k0;
175 korr_t k1;
176
177 memset ( &k0, 0, sizeof(k0) );
178 memset ( &k1, 0, sizeof(k1) );
179
180 read ( fd, header, sizeof(header) );
181
182 switch ( header[11] ) {
183 case 1:
184 printf ("-mm\n");
185 break;
186
187 case 2:
188 while ( ( samples = read (fd, s, sizeof(s)) ) > 0 ) {
189 analyze_stereo ( s, samples / sizeof (*s), &k0 );
190 analyze_dstereo ( s, samples / sizeof (*s), &k1 );
191 }
192 report (&k0);
193 report (&k1);
194 break;
195
196 default:
197 fprintf ( stderr, "%u Channels not supported: %s\n", header[11], name );
198 break;
199 }
200 }
201
main(int argc,char ** argv)202 int main ( int argc, char** argv )
203 {
204 char* name;
205 int fd;
206
207 if (argc < 2)
208 readfile ( "<stdin>", 0 );
209 else
210 while ( (name = *++argv) != NULL ) {
211 if ( (fd = open ( name, O_RDONLY )) >= 0 ) {
212 readfile ( name, fd );
213 close ( fd );
214 } else {
215 fprintf ( stderr, "Can't open: %s\n", name );
216 }
217 }
218
219 return 0;
220 }
221