diff options
Diffstat (limited to 'misc/mlame_corr.c')
-rw-r--r-- | misc/mlame_corr.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/misc/mlame_corr.c b/misc/mlame_corr.c new file mode 100644 index 0000000..4305b63 --- /dev/null +++ b/misc/mlame_corr.c @@ -0,0 +1,220 @@ +/* + Bug: + - runs only on little endian machines for WAV files + - Not all WAV files are recognized + */ + +#include <stdio.h> +#include <unistd.h> +#include <math.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <memory.h> + +typedef signed short stereo [2]; +typedef signed short mono; +typedef struct { + unsigned long long n; + long double x; + long double x2; + long double y; + long double y2; + long double xy; +} korr_t; + +void analyze_stereo ( const stereo* p, size_t len, korr_t* k ) +{ + long double _x = 0, _x2 = 0, _y = 0, _y2 = 0, _xy = 0; + double t1; + double t2; + + k -> n += len; + + for ( ; len--; p++ ) { + _x += (t1 = (*p)[0]); _x2 += t1 * t1; + _y += (t2 = (*p)[1]); _y2 += t2 * t2; + _xy += t1 * t2; + } + + k -> x += _x ; + k -> x2 += _x2; + k -> y += _y ; + k -> y2 += _y2; + k -> xy += _xy; +} + +void analyze_dstereo ( const stereo* p, size_t len, korr_t* k ) +{ + static double l0 = 0; + static double l1 = 0; + long double _x = 0, _x2 = 0, _y = 0, _y2 = 0, _xy = 0; + double t1; + double t2; + + k -> n += len; + + for ( ; len--; p++ ) { + _x += (t1 = (*p)[0] - l0); _x2 += t1 * t1; + _y += (t2 = (*p)[1] - l1); _y2 += t2 * t2; + _xy += t1 * t2; + l0 = (*p)[0]; + l1 = (*p)[1]; + } + + k -> x += _x ; + k -> x2 += _x2; + k -> y += _y ; + k -> y2 += _y2; + k -> xy += _xy; +} + + +void analyze_mono ( const mono* p, size_t len, korr_t* k ) +{ + long double _x = 0, _x2 = 0; + double t1; + + k -> n += len; + + for ( ; len--; p++ ) { + _x += (t1 = (*p)); _x2 += t1 * t1; + } + + k -> x += _x ; + k -> x2 += _x2; + k -> y += _x ; + k -> y2 += _x2; + k -> xy += _x2; +} + +void analyze_dmono ( const mono* p, size_t len, korr_t* k ) +{ + static double l0 = 0; + long double _x = 0, _x2 = 0; + double t1; + + k -> n += len; + + for ( ; len--; p++ ) { + _x += (t1 = (*p) - l0); _x2 += t1 * t1; + l0 = *p; + } + + k -> x += _x ; + k -> x2 += _x2; + k -> y += _x ; + k -> y2 += _x2; + k -> xy += _x2; +} + +int sgn ( long double x ) +{ + if ( x > 0 ) return +1; + if ( x < 0 ) return -1; + return 0; +} + +int report ( const korr_t* k ) +{ + long double scale = sqrt ( 1.e5 / (1<<29) ); // Sine Full Scale is +10 dB, 7327 = 100% + long double r; + long double rd; + long double sx; + long double sy; + long double x; + long double y; + long double b; + + r = (k->x2*k->n - k->x*k->x) * (k->y2*k->n - k->y*k->y); + r = r > 0.l ? (k->xy*k->n - k->x*k->y) / sqrt (r) : 1.l; + sx = k->n > 1 ? sqrt ( (k->x2 - k->x*k->x/k->n) / (k->n - 1) ) : 0.l; + sy = k->n > 1 ? sqrt ( (k->y2 - k->y*k->y/k->n) / (k->n - 1) ) : 0.l; + x = k->n > 0 ? k->x/k->n : 0.l; + y = k->n > 0 ? k->y/k->n : 0.l; + + b = atan2 ( sy, sx * sgn (r) ) * ( 8 / M_PI); + +// 6 5 4 3 2 +// _______________________________ +// |\ | /| +// 7 | \ | / | 1 +// | \ | / | +// | \ | / | +// | \ | / | +// 8 |--------------+--------------| 0 +// | / | \ | +// | / | \ | +// -7 | / | \ | -1 +// | / | \ | +// |/_____________|_____________\| +// +// -6 -5 -4 -3 -2 + + if ( r > 0.98 ) { + printf ("-mm"); // disguised mono file + return; + } + if ( fabs (b-2) > 0.666 ) { + printf ("-ms"); // low profit for joint stereo + return; + } + if ( r < 0.333 ) { + printf ("-ms"); // low profit for joint stereo + return; + } +} + +void readfile ( const char* name, int fd ) +{ + unsigned short header [22]; + stereo s [4096]; + mono m [8192]; + size_t samples; + korr_t k0; + korr_t k1; + + memset ( &k0, 0, sizeof(k0) ); + memset ( &k1, 0, sizeof(k1) ); + + read ( fd, header, sizeof(header) ); + + switch ( header[11] ) { + case 1: + printf ("-mm\n"); + break; + + case 2: + while ( ( samples = read (fd, s, sizeof(s)) ) > 0 ) { + analyze_stereo ( s, samples / sizeof (*s), &k0 ); + analyze_dstereo ( s, samples / sizeof (*s), &k1 ); + } + report (&k0); + report (&k1); + break; + + default: + fprintf ( stderr, "%u Channels not supported: %s\n", header[11], name ); + break; + } +} + +int main ( int argc, char** argv ) +{ + char* name; + int fd; + + if (argc < 2) + readfile ( "<stdin>", 0 ); + else + while ( (name = *++argv) != NULL ) { + if ( (fd = open ( name, O_RDONLY )) >= 0 ) { + readfile ( name, fd ); + close ( fd ); + } else { + fprintf ( stderr, "Can't open: %s\n", name ); + } + } + + return 0; +} |