Blame misc/abx.c

Packit 47f805
/*
Packit 47f805
 *  Usage: abx original_file test_file
Packit 47f805
 *
Packit 47f805
 *  Ask you as long as the probability is below the given percentage that
Packit 47f805
 *  you recognize differences
Packit 47f805
 *
Packit 47f805
 *  Example: abx music.wav music.mp3
Packit 47f805
 *           abx music.wav music.mp3 --help
Packit 47f805
 *
Packit 47f805
 *  Note: several 'decoding' utilites must be on the 'right' place
Packit 47f805
 *
Packit 47f805
 *  Bugs:
Packit 47f805
 *      fix path of decoding utilities
Packit 47f805
 *      only 16 bit support
Packit 47f805
 *      only support of the same sample frequency
Packit 47f805
 *      no exact WAV file header analysis
Packit 47f805
 *      no mouse or joystick support
Packit 47f805
 *      don't uses functionality of ath.c
Packit 47f805
 *      only 2 files are comparable
Packit 47f805
 *      worse user interface
Packit 47f805
 *      quick & dirty hack
Packit 47f805
 *      wastes memory
Packit 47f805
 *      compile time warnings
Packit 47f805
 *      buffer overruns possible
Packit 47f805
 *      no dithering if recalcs are necessary
Packit 47f805
 *      correlation only done with one channel (2 channels, sum, what is better?)
Packit 47f805
 *      lowpass+highpass filtering (300 Hz+2*5 kHz) before delay+amplitude corr
Packit 47f805
 *      cross fade at start/stop
Packit 47f805
 *      non portable keyboard
Packit 47f805
 *      fade out on quit, fade in on start
Packit 47f805
 *      level/delay ajustment should be switchable
Packit 47f805
 *      pause key missing
Packit 47f805
 *      problems with digital silence files (division by 0)
Packit 47f805
 *      Gr��e cross corr fenster 2^16...18
Packit 47f805
 *      Stellensuche, ab 0*len oder 0.1*len oder 0.25*len, nach Effektiv oder Spitzenwert
Packit 47f805
 *      Absturz bei LPAC feeding, warum?
Packit 47f805
 *      Als 'B' beim Ratespiel sollte auch '0'...'9' verwendbar sein
Packit 47f805
 *      Oder mit einem Filter 300 Hz...3 kHz vorher filtern?
Packit 47f805
 *      Multiple encoded differenziertes Signal
Packit 47f805
 *      Amplitudenanpassung schaltbar machen?
Packit 47f805
 *      Direkt auf der Kommandozeile kodieren:
Packit 47f805
 *      abx "test.wav" "!lame -b128 test.wav -"
Packit 47f805
 */
Packit 47f805
Packit 47f805
// If the program should increase it priority while playing define USE_NICE.
Packit 47f805
// Program must be installed SUID root. Decompressing phase is using NORMAL priority
Packit 47f805
#define USE_NICE
Packit 47f805
Packit 47f805
// Not only increase priority but change to relatime scheduling. Program must be installed SUID root
Packit 47f805
#define USE_REALTIME
Packit 47f805
Packit 47f805
// Path of the programs: mpg123, mppdec, faad, ac3dec, ogg123, lpac, shorten, MAC, flac
Packit 47f805
//#define PATH_OF_EXTERNAL_TOOLS_FOR_UNCOMPRESSING   "/usr/local/bin/"
Packit 47f805
#define PATH_OF_EXTERNAL_TOOLS_FOR_UNCOMPRESSING   ""
Packit 47f805
Packit 47f805
Packit 47f805
#if defined HAVE_CONFIG_H
Packit 47f805
# include <config.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#include <assert.h>
Packit 47f805
#include <ctype.h>
Packit 47f805
#include <fcntl.h>
Packit 47f805
#include <limits.h>
Packit 47f805
#include <math.h>
Packit 47f805
#include <memory.h>
Packit 47f805
#include <signal.h>
Packit 47f805
#include <stdio.h>
Packit 47f805
#include <stdlib.h>
Packit 47f805
#include <string.h>
Packit 47f805
#include <termios.h>
Packit 47f805
#include <time.h>
Packit 47f805
#include <unistd.h>
Packit 47f805
#include <sys/ioctl.h>
Packit 47f805
#include <sys/mman.h>
Packit 47f805
#include <sys/stat.h>
Packit 47f805
#include <sys/time.h>
Packit 47f805
#include <sys/types.h>
Packit 47f805
Packit 47f805
#define  MAX  (1<<17)
Packit 47f805
Packit 47f805
#if   defined HAVE_SYS_SOUNDCARD_H
Packit 47f805
# include <sys/soundcard.h>
Packit 47f805
#elif defined HAVE_LINUX_SOUNDCARD_H
Packit 47f805
# include <linux/soundcard.h>
Packit 47f805
#else
Packit 47f805
# include <linux/soundcard.h>         /* stand alone compilable for my tests */
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#if defined USE_NICE
Packit 47f805
# include <sys/resource.h>
Packit 47f805
#endif
Packit 47f805
#if defined USE_REALTIME
Packit 47f805
# include <sched.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#define  BF           ((freq)/25)
Packit 47f805
#define  MAX_LEN      (210 * 44100)
Packit 47f805
#define  DMA_SAMPLES  512	    	/* My Linux driver uses a DMA buffer of 65536*16 bit, which is 32768 samples in 16 bit stereo mode */
Packit 47f805
Packit 47f805
void  Set_Realtime ( void )
Packit 47f805
{
Packit 47f805
#if defined USE_REALTIME
Packit 47f805
    struct sched_param  sp;
Packit 47f805
    int                 ret;
Packit 47f805
Packit 47f805
    memset      ( &sp, 0, sizeof(sp) );
Packit 47f805
    seteuid     ( 0 );
Packit 47f805
    sp.sched_priority = sched_get_priority_min ( SCHED_FIFO );
Packit 47f805
    ret               = sched_setscheduler ( 0, SCHED_RR, &sp );
Packit 47f805
    seteuid     ( getuid() );
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#if defined USE_NICE
Packit 47f805
    seteuid     ( 0 );
Packit 47f805
    setpriority ( PRIO_PROCESS, getpid(), -20 );
Packit 47f805
    seteuid     ( getuid() );
Packit 47f805
#endif
Packit 47f805
}
Packit 47f805
Packit 47f805
int verbose = 0;
Packit 47f805
Packit 47f805
static struct termios stored_settings;
Packit 47f805
Packit 47f805
Packit 47f805
void reset ( void )
Packit 47f805
{
Packit 47f805
    tcsetattr ( 0, TCSANOW, &stored_settings );
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void set ( void )
Packit 47f805
{
Packit 47f805
    struct termios new_settings;
Packit 47f805
Packit 47f805
    tcgetattr ( 0, &stored_settings );
Packit 47f805
    new_settings = stored_settings;
Packit 47f805
Packit 47f805
    new_settings.c_lflag    &= ~ECHO;
Packit 47f805
    /* Disable canonical mode, and set buffer size to 1 byte */
Packit 47f805
    new_settings.c_lflag    &= ~ICANON;
Packit 47f805
    new_settings.c_cc[VTIME] = 0;
Packit 47f805
    new_settings.c_cc[VMIN]  = 1;
Packit 47f805
Packit 47f805
    tcsetattr(0,TCSANOW,&new_settings);
Packit 47f805
    return;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int sel ( void )
Packit 47f805
{
Packit 47f805
    struct timeval  t;
Packit 47f805
    fd_set          fd [1];
Packit 47f805
    int             ret;
Packit 47f805
    unsigned char   c;
Packit 47f805
Packit 47f805
    FD_SET (0, fd);
Packit 47f805
    t.tv_sec  = 0;
Packit 47f805
    t.tv_usec = 0;
Packit 47f805
Packit 47f805
    ret = select ( 1, fd, NULL, NULL, &t );
Packit 47f805
Packit 47f805
    switch ( ret ) {
Packit 47f805
    case  0:
Packit 47f805
        return -1;
Packit 47f805
    case  1:
Packit 47f805
        ret = read (0, &c, 1);
Packit 47f805
        return ret == 1  ?  c  :  -1;
Packit 47f805
    default:
Packit 47f805
        return -2;
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
#define FFT_ERR_OK      0               // no error
Packit 47f805
#define FFT_ERR_LD      1               // len is not a power of 2
Packit 47f805
#define FFT_ERR_MAX     2               // len too large
Packit 47f805
Packit 47f805
typedef float   f_t;
Packit 47f805
typedef f_t     compl [2];
Packit 47f805
compl           root    [MAX >> 1];             // Sinus-/Kosinustabelle
Packit 47f805
size_t          shuffle [MAX >> 1] [2];         // Shuffle-Tabelle
Packit 47f805
size_t          shuffle_len;
Packit 47f805
Packit 47f805
// Bitinversion
Packit 47f805
Packit 47f805
size_t  swap ( size_t number, int bits )
Packit 47f805
{
Packit 47f805
    size_t  ret;
Packit 47f805
    for ( ret = 0; bits--; number >>= 1 ) {
Packit 47f805
        ret = ret + ret + (number & 1);
Packit 47f805
    }
Packit 47f805
    return ret;
Packit 47f805
}
Packit 47f805
Packit 47f805
// Bestimmen des Logarithmus dualis
Packit 47f805
Packit 47f805
int  ld ( size_t number )
Packit 47f805
{
Packit 47f805
    size_t i;
Packit 47f805
    for ( i = 0; i < sizeof(size_t)*CHAR_BIT; i++ )
Packit 47f805
        if ( ((size_t)1 << i) == number )
Packit 47f805
            return i;
Packit 47f805
    return -1;
Packit 47f805
}
Packit 47f805
Packit 47f805
// Die eigentliche FFT
Packit 47f805
Packit 47f805
int  fft ( compl* fn, const size_t newlen )
Packit 47f805
{
Packit 47f805
    static size_t  len  = 0;
Packit 47f805
    static int     bits = 0;
Packit 47f805
    size_t         i;
Packit 47f805
    size_t         j;
Packit 47f805
    size_t         k;
Packit 47f805
    size_t         p;
Packit 47f805
Packit 47f805
    /* Tabellen initialisieren */
Packit 47f805
Packit 47f805
    if ( newlen != len ) {
Packit 47f805
        len  = newlen;
Packit 47f805
Packit 47f805
        if ( (bits=ld(len)) == -1 )
Packit 47f805
            return FFT_ERR_LD;
Packit 47f805
Packit 47f805
        for ( i = 0; i < len; i++ ) {
Packit 47f805
            j = swap ( i, bits );
Packit 47f805
            if ( i < j ) {
Packit 47f805
                shuffle [shuffle_len] [0] = i;
Packit 47f805
                shuffle [shuffle_len] [1] = j;
Packit 47f805
                shuffle_len++;
Packit 47f805
            }
Packit 47f805
        }
Packit 47f805
        for ( i = 0; i < (len>>1); i++ ) {
Packit 47f805
            double x = (double) swap ( i+i, bits ) * 2*M_PI/len;
Packit 47f805
            root [i] [0] = cos (x);
Packit 47f805
            root [i] [1] = sin (x);
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
Packit 47f805
    /* Eigentliche Transformation */
Packit 47f805
Packit 47f805
    p = len >> 1;
Packit 47f805
    do {
Packit 47f805
        f_t*  bp = (f_t*) root;
Packit 47f805
        f_t*  si = (f_t*) fn;
Packit 47f805
        f_t*  di = (f_t*) fn+p+p;
Packit 47f805
Packit 47f805
        do {
Packit 47f805
            k = p;
Packit 47f805
            do {
Packit 47f805
                f_t  mulr = bp[0]*di[0] - bp[1]*di[1];
Packit 47f805
                f_t  muli = bp[1]*di[0] + bp[0]*di[1];
Packit 47f805
Packit 47f805
                di[0]  = si[0] - mulr;
Packit 47f805
                di[1]  = si[1] - muli;
Packit 47f805
                si[0] += mulr;
Packit 47f805
                si[1] += muli;
Packit 47f805
Packit 47f805
                si += 2, di += 2;
Packit 47f805
            } while ( --k );
Packit 47f805
            si += p+p, di += p+p, bp += 2;
Packit 47f805
        } while ( si < &fn[len][0] );
Packit 47f805
    } while (p >>= 1);
Packit 47f805
Packit 47f805
    /* Bitinversion */
Packit 47f805
Packit 47f805
    for ( k = 0; k < shuffle_len; k++ ) {
Packit 47f805
        f_t  tmp;
Packit 47f805
        i   = shuffle [k] [0];
Packit 47f805
        j   = shuffle [k] [1];
Packit 47f805
        tmp = fn [i][0]; fn [i][0] = fn [j][0]; fn [j][0] = tmp;
Packit 47f805
        tmp = fn [i][1]; fn [i][1] = fn [j][1]; fn [j][1] = tmp;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    return FFT_ERR_OK;
Packit 47f805
}
Packit 47f805
Packit 47f805
void  printnumber ( long double x )
Packit 47f805
{
Packit 47f805
    unsigned  exp = 0;
Packit 47f805
Packit 47f805
    if      ( x < 9.999995  ) fprintf ( stderr, "%7.5f",  (double)x );
Packit 47f805
    else if ( x < 99.99995  ) fprintf ( stderr, "%7.4f",  (double)x );
Packit 47f805
    else if ( x < 999.9995  ) fprintf ( stderr, "%7.3f",  (double)x );
Packit 47f805
    else if ( x < 9999.995  ) fprintf ( stderr, "%7.2f",  (double)x );
Packit 47f805
    else if ( x < 99999.95  ) fprintf ( stderr, "%7.1f",  (double)x );
Packit 47f805
    else if ( x < 999999.5  ) fprintf ( stderr, "%6.0f.", (double)x );
Packit 47f805
    else if ( x < 9999999.5 ) fprintf ( stderr, "%7.0f",  (double)x );
Packit 47f805
    else if ( x < 9.9995e9  ) {
Packit 47f805
        while ( x >= 9.9995 ) exp++  , x /= 10;
Packit 47f805
        fprintf ( stderr, "%5.3fe%01u", (double)x, exp );
Packit 47f805
    } else if ( x < 9.995e99 ) {
Packit 47f805
        while ( x >= 9.5e6  ) exp+=6 , x /= 1.e6;
Packit 47f805
        while ( x >= 9.995  ) exp++  , x /= 10;
Packit 47f805
        fprintf ( stderr, "%4.2fe%02u", (double)x, exp );
Packit 47f805
    } else if ( x < 9.95e999L ) {
Packit 47f805
        while ( x >= 9.5e18 ) exp+=18, x /= 1.e18;
Packit 47f805
        while ( x >= 9.95   ) exp++  , x /= 10;
Packit 47f805
        fprintf ( stderr, "%3.1fe%03u", (double)x, exp );
Packit 47f805
    } else {
Packit 47f805
        while ( x >= 9.5e48 ) exp+=48, x /= 1.e48;
Packit 47f805
        while ( x >= 9.5    ) exp++  , x /= 10;
Packit 47f805
        fprintf ( stderr, "%1.0f.e%04u", (double)x, exp );
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
double logdual ( long double x )
Packit 47f805
{
Packit 47f805
    unsigned exp = 0;
Packit 47f805
Packit 47f805
    while ( x >= 18446744073709551616. )
Packit 47f805
        x /= 18446744073709551616., exp += 64;
Packit 47f805
    while ( x >= 256. )
Packit 47f805
        x /= 256., exp += 8;
Packit 47f805
    while ( x >= 2. )
Packit 47f805
        x /= 2., exp += 1;
Packit 47f805
    return exp + log (x)/log(2);
Packit 47f805
}
Packit 47f805
Packit 47f805
int  random_number ( void )
Packit 47f805
{
Packit 47f805
    struct timeval  t;
Packit 47f805
    unsigned long   val;
Packit 47f805
Packit 47f805
    gettimeofday ( &t, NULL );
Packit 47f805
Packit 47f805
    val  = t.tv_sec ^ t.tv_usec ^ rand();
Packit 47f805
    val ^= val >> 16;
Packit 47f805
    val ^= val >>  8;
Packit 47f805
    val ^= val >>  4;
Packit 47f805
    val ^= val >>  2;
Packit 47f805
    val ^= val >>  1;
Packit 47f805
Packit 47f805
    return val & 1;
Packit 47f805
}
Packit 47f805
Packit 47f805
long double  prob ( int last, int total )
Packit 47f805
{
Packit 47f805
    long double  sum = 0.;
Packit 47f805
    long double  tmp = 1.;
Packit 47f805
    int          i;
Packit 47f805
    int          j   = total;
Packit 47f805
Packit 47f805
    if ( 2*last == total )
Packit 47f805
        return 1.;
Packit 47f805
    if ( 2*last > total )
Packit 47f805
        last = total - last;
Packit 47f805
Packit 47f805
    for ( i = 0; i <= last; i++ ) {
Packit 47f805
        sum += tmp;
Packit 47f805
        tmp  = tmp * (total-i) / (1+i);
Packit 47f805
        while ( j > 0  &&  tmp > 1 )
Packit 47f805
            j--, sum *= 0.5, tmp *= 0.5;
Packit 47f805
    }
Packit 47f805
    while ( j > 0 )
Packit 47f805
        j--, sum *= 0.5;
Packit 47f805
Packit 47f805
    return 2.*sum;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void  eval ( int right )
Packit 47f805
{
Packit 47f805
    static int   count = 0;
Packit 47f805
    static int   okay  = 0;
Packit 47f805
    long double  val;
Packit 47f805
Packit 47f805
    count ++;
Packit 47f805
    okay  += right;
Packit 47f805
Packit 47f805
    val    = 1.L / prob ( okay, count );
Packit 47f805
Packit 47f805
    fprintf (stderr, "   %s %5u/%-5u ", right ? "OK" : "- " , okay, count );
Packit 47f805
    printnumber (val);
Packit 47f805
    if ( count > 1 )
Packit 47f805
        fprintf (stderr, "   %4.2f bit", 0.01 * (int)(logdual(val) / (count-1) * 100.) );
Packit 47f805
    fprintf ( stderr, "\n" );
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
typedef signed short  sample_t;
Packit 47f805
typedef sample_t      mono_t   [1];
Packit 47f805
typedef sample_t      stereo_t [2];
Packit 47f805
typedef struct {
Packit 47f805
    unsigned long       n;
Packit 47f805
    long double         x;
Packit 47f805
    long double         x2;
Packit 47f805
    long double         y;
Packit 47f805
    long double         y2;
Packit 47f805
    long double         xy;
Packit 47f805
} korr_t;
Packit 47f805
Packit 47f805
Packit 47f805
void  analyze_stereo ( const stereo_t* p1, const stereo_t* p2, size_t len, korr_t* const k )
Packit 47f805
{
Packit 47f805
    long double  _x = 0, _x2 = 0, _y = 0, _y2 = 0, _xy = 0;
Packit 47f805
    double       t1;
Packit 47f805
    double       t2;
Packit 47f805
Packit 47f805
    k -> n  += 2*len;
Packit 47f805
Packit 47f805
    for ( ; len--; p1++, p2++ ) {
Packit 47f805
        _x  += (t1 = (*p1)[0]); _x2 += t1 * t1;
Packit 47f805
        _y  += (t2 = (*p2)[0]); _y2 += t2 * t2;
Packit 47f805
                                _xy += t1 * t2;
Packit 47f805
        _x  += (t1 = (*p1)[1]); _x2 += t1 * t1;
Packit 47f805
        _y  += (t2 = (*p2)[1]); _y2 += t2 * t2;
Packit 47f805
                                _xy += t1 * t2;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    k -> x  += _x ;
Packit 47f805
    k -> x2 += _x2;
Packit 47f805
    k -> y  += _y ;
Packit 47f805
    k -> y2 += _y2;
Packit 47f805
    k -> xy += _xy;
Packit 47f805
}
Packit 47f805
Packit 47f805
int  sgn ( double x )
Packit 47f805
{
Packit 47f805
    if ( x == 0 ) return 0;
Packit 47f805
    if ( x <  0 ) return -1;
Packit 47f805
    return +1;
Packit 47f805
}
Packit 47f805
Packit 47f805
long double  report ( const korr_t* const k )
Packit 47f805
{
Packit 47f805
    long double  r;
Packit 47f805
    long double  sx;
Packit 47f805
    long double  sy;
Packit 47f805
    long double  x;
Packit 47f805
    long double  y;
Packit 47f805
    long double  b;
Packit 47f805
Packit 47f805
    r  = (k->x2*k->n - k->x*k->x) * (k->y2*k->n - k->y*k->y);
Packit 47f805
    r  = r  > 0.l  ?  (k->xy*k->n - k->x*k->y) / sqrt (r)  :  1.l;
Packit 47f805
    sx = k->n > 1  ?  sqrt ( (k->x2 - k->x*k->x/k->n) / (k->n - 1) )  :  0.l;
Packit 47f805
    sy = k->n > 1  ?  sqrt ( (k->y2 - k->y*k->y/k->n) / (k->n - 1) )  :  0.l;
Packit 47f805
    x  = k->n > 0  ?  k->x/k->n  :  0.l;
Packit 47f805
    y  = k->n > 0  ?  k->y/k->n  :  0.l;
Packit 47f805
Packit 47f805
    b  = sx != 0   ?  sy/sx * sgn(r)  :  0.l;
Packit 47f805
    if (verbose)
Packit 47f805
        fprintf ( stderr, "r=%Lf  sx=%Lf  sy=%Lf  x=%Lf  y=%Lf  b=%Lf\n", r, sx, sy, x, y, b );
Packit 47f805
    return b;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
/* Input: an unsigned short n.
Packit 47f805
 * Output: the swapped bytes of n if the arch is big-endian or n itself
Packit 47f805
 *         if the arch is little-endian.
Packit 47f805
 * Comment: should be replaced latter with a better solution than this
Packit 47f805
 *          home-brewed hack (rbrito). The name should be better also.
Packit 47f805
 */
Packit 47f805
inline unsigned short be16_le(unsigned short n)
Packit 47f805
{
Packit 47f805
#ifdef _WORDS_BIGENDIAN
Packit 47f805
     return (n << 8) | (n >> 8);
Packit 47f805
#else
Packit 47f805
     return n;
Packit 47f805
#endif
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int feed ( int fd, const stereo_t* p, int len )
Packit 47f805
{
Packit 47f805
     int i;
Packit 47f805
     stereo_t tmp[30000];	/* An arbitrary size--to be changed latter */
Packit 47f805
Packit 47f805
     if (len > sizeof(tmp)/sizeof(*tmp))
Packit 47f805
	  len = sizeof(tmp)/sizeof(*tmp);
Packit 47f805
Packit 47f805
     for (i = 0; i < len; i++) {
Packit 47f805
	  tmp[i][0] = be16_le(p[i][0]);
Packit 47f805
	  tmp[i][1] = be16_le(p[i][1]);
Packit 47f805
     }
Packit 47f805
Packit 47f805
     write ( fd, tmp, sizeof(stereo_t) * len );
Packit 47f805
     return len;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
short  round ( double f )
Packit 47f805
{
Packit 47f805
    long  x = (long) floor ( f + 0.5 );
Packit 47f805
    return x == (short)x  ?  (short)x  :  (short) ((x >> 31) ^ 0x7FFF);
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int  feed2 ( int fd, const stereo_t* p1, const stereo_t* p2, int len )
Packit 47f805
{
Packit 47f805
     stereo_t  tmp [30000];   /* An arbitrary size, hope that no overruns occure */
Packit 47f805
     int       i;
Packit 47f805
Packit 47f805
     if (len > sizeof(tmp)/sizeof(*tmp))
Packit 47f805
	  len = sizeof(tmp)/sizeof(*tmp);
Packit 47f805
     for ( i = 0; i < len; i++ ) {
Packit 47f805
	  double f = cos ( M_PI/2*i/len );
Packit 47f805
	  f *= f;
Packit 47f805
	  tmp [i] [0] = be16_le(round ( p1 [i] [0] * f + p2 [i] [0] * (1. - f) ));
Packit 47f805
	  tmp [i] [1] = be16_le(round ( p1 [i] [1] * f + p2 [i] [1] * (1. - f) ));
Packit 47f805
     }
Packit 47f805
Packit 47f805
     write ( fd, tmp, sizeof(stereo_t) * len );
Packit 47f805
     return len;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int feedfac ( int fd, const stereo_t* p1, const stereo_t* p2, int len, double fac1, double fac2 )
Packit 47f805
{
Packit 47f805
     stereo_t  tmp [30000];   /* An arbitrary size, hope that no overruns occure */
Packit 47f805
     int       i;
Packit 47f805
Packit 47f805
     if (len > sizeof(tmp)/sizeof(*tmp))
Packit 47f805
	  len = sizeof(tmp)/sizeof(*tmp);
Packit 47f805
     for ( i = 0; i < len; i++ ) {
Packit 47f805
	  tmp [i] [0] = be16_le(round ( p1 [i] [0] * fac1 + p2 [i] [0] * fac2 ));
Packit 47f805
	  tmp [i] [1] = be16_le(round ( p1 [i] [1] * fac1 + p2 [i] [1] * fac2 ));
Packit 47f805
    }
Packit 47f805
Packit 47f805
    write ( fd, tmp, sizeof(stereo_t) * len );
Packit 47f805
    return len;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void setup ( int fdd, int samples, long freq )
Packit 47f805
{
Packit 47f805
    int status, org, arg;
Packit 47f805
Packit 47f805
    // Nach vorn verschoben
Packit 47f805
    if ( -1 == (status = ioctl (fdd, SOUND_PCM_SYNC, 0)) )
Packit 47f805
        perror ("SOUND_PCM_SYNC ioctl failed");
Packit 47f805
Packit 47f805
    org = arg = 2;
Packit 47f805
    if ( -1 == (status = ioctl (fdd, SOUND_PCM_WRITE_CHANNELS, &arg)) )
Packit 47f805
        perror ("SOUND_PCM_WRITE_CHANNELS ioctl failed");
Packit 47f805
    if (arg != org)
Packit 47f805
        perror ("unable to set number of channels");
Packit 47f805
    fprintf (stderr, "%1u*", arg);
Packit 47f805
Packit 47f805
    org = arg = AFMT_S16_LE;
Packit 47f805
    if ( -1 == ioctl (fdd, SNDCTL_DSP_SETFMT, &arg) )
Packit 47f805
        perror ("SNDCTL_DSP_SETFMT ioctl failed");
Packit 47f805
    if ((arg & org) == 0)
Packit 47f805
        perror ("unable to set data format");
Packit 47f805
Packit 47f805
    org = arg = freq;
Packit 47f805
    if ( -1 == (status = ioctl (fdd, SNDCTL_DSP_SPEED, &arg)) )
Packit 47f805
        perror ("SNDCTL_DSP_SPEED ioctl failed");
Packit 47f805
    fprintf (stderr, "%5u Hz*%.3f sec\n", arg, (double)samples/arg );
Packit 47f805
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void Message ( const char* s, size_t index, long freq, size_t start, size_t stop )
Packit 47f805
{
Packit 47f805
    unsigned long  norm_index = 100lu * index / freq;
Packit 47f805
    unsigned long  norm_start = 100lu * start / freq;
Packit 47f805
    unsigned long  norm_stop  = 100lu * stop  / freq;
Packit 47f805
Packit 47f805
    fprintf ( stderr, "\rListening %s  %2lu:%02lu.%02lu  (%1lu:%02lu.%02lu...%1lu:%02lu.%02lu)%*.*s\rListening %s",
Packit 47f805
              s,
Packit 47f805
              norm_index / 6000, norm_index / 100 % 60, norm_index % 100,
Packit 47f805
              norm_start / 6000, norm_start / 100 % 60, norm_start % 100,
Packit 47f805
              norm_stop  / 6000, norm_stop  / 100 % 60, norm_stop  % 100,
Packit 47f805
              36 - (int)strlen(s), 36 - (int)strlen(s), "",
Packit 47f805
              s );
Packit 47f805
Packit 47f805
    fflush  ( stderr );
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
size_t  calc_true_index ( size_t index, size_t start, size_t stop )
Packit 47f805
{
Packit 47f805
    if ( start >= stop )
Packit 47f805
        return start;
Packit 47f805
    while ( index - start < DMA_SAMPLES )
Packit 47f805
        index += stop - start;
Packit 47f805
    return index - DMA_SAMPLES;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void testing ( const stereo_t* A, const stereo_t* B, size_t len, long freq )
Packit 47f805
{
Packit 47f805
    int     c;
Packit 47f805
    int     fd    = open ( "/dev/dsp", O_WRONLY );
Packit 47f805
    int     rnd   = random_number ();   /* Auswahl von X */
Packit 47f805
    int     state = 0;                  /* derzeitiger F�ttungsmodus */
Packit 47f805
    float   fac1  = 0.5;
Packit 47f805
    float   fac2  = 0.5;
Packit 47f805
    size_t  start = 0;
Packit 47f805
    size_t  stop  = len;
Packit 47f805
    size_t  index = start;                  /* derzeitiger Offset auf den Audiostr�men */
Packit 47f805
    char    message [80] = "A  ";
Packit 47f805
Packit 47f805
    setup ( fd, len, freq );
Packit 47f805
Packit 47f805
    while ( 1 ) {
Packit 47f805
        c = sel ();
Packit 47f805
        if ( c == 27 )
Packit 47f805
            c = sel () + 0x100;
Packit 47f805
Packit 47f805
        switch ( c ) {
Packit 47f805
        case 'A' :
Packit 47f805
        case 'a' :
Packit 47f805
            strcpy ( message, "A  " );
Packit 47f805
            if ( state != 0 )
Packit 47f805
                state = 2;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 0x100+'0' :
Packit 47f805
        case '0' :
Packit 47f805
        case 'B' :
Packit 47f805
        case 'b' :
Packit 47f805
            strcpy ( message, "  B" );
Packit 47f805
            if ( state != 1 )
Packit 47f805
                state = 3;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'X' :
Packit 47f805
        case 'x' :
Packit 47f805
            strcpy ( message, " X " );
Packit 47f805
            if ( state != rnd )
Packit 47f805
                state = rnd + 2;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'm' :
Packit 47f805
            state = 8;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'M' :
Packit 47f805
            state = (state & 1) + 4;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'x'&0x1F:
Packit 47f805
            state = (state & 1) + 6;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case ' ':
Packit 47f805
            start = 0;
Packit 47f805
            stop  = len;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'o'  :
Packit 47f805
	    start = calc_true_index ( index, start, stop);
Packit 47f805
            break;
Packit 47f805
        case 'p'  :
Packit 47f805
	    stop  = calc_true_index ( index, start, stop);
Packit 47f805
            break;
Packit 47f805
        case 'h'  :
Packit 47f805
            if ( start > freq/100 )
Packit 47f805
                start -= freq/100;
Packit 47f805
            else
Packit 47f805
                start = 0;
Packit 47f805
            index = start;
Packit 47f805
            continue;
Packit 47f805
        case 'j'  :
Packit 47f805
            if ( start < stop-freq/100 )
Packit 47f805
                start += freq/100;
Packit 47f805
            else
Packit 47f805
                start = stop;
Packit 47f805
            index = start;
Packit 47f805
            continue;
Packit 47f805
        case 'k'  :
Packit 47f805
            if ( stop > start+freq/100 )
Packit 47f805
                stop -= freq/100;
Packit 47f805
            else
Packit 47f805
                stop = start;
Packit 47f805
            continue;
Packit 47f805
        case 'l'  :
Packit 47f805
            if ( stop < len-freq/100 )
Packit 47f805
                stop += freq/100;
Packit 47f805
            else
Packit 47f805
                stop = len;
Packit 47f805
            continue;
Packit 47f805
        case '\n':
Packit 47f805
            index = start;
Packit 47f805
            continue;
Packit 47f805
Packit 47f805
        case 'D'+0x100:
Packit 47f805
            strcpy ( message, "Difference (+40 dB)" );
Packit 47f805
            state = 9;
Packit 47f805
            fac1  = -100.;
Packit 47f805
            fac2  = +100.;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'd'+0x100:
Packit 47f805
            strcpy ( message, "Difference (+30 dB)" );
Packit 47f805
            state = 9;
Packit 47f805
            fac1  = -32.;
Packit 47f805
            fac2  = +32.;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'D' & 0x1F :
Packit 47f805
            strcpy ( message, "Difference (+20 dB)" );
Packit 47f805
            state = 9;
Packit 47f805
            fac1  = -10.;
Packit 47f805
            fac2  = +10.;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'D' :
Packit 47f805
            strcpy ( message, "Difference (+10 dB)" );
Packit 47f805
            state = 9;
Packit 47f805
            fac1  = -3.;
Packit 47f805
            fac2  = +3.;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'd' :
Packit 47f805
            strcpy ( message, "Difference (  0 dB)" );
Packit 47f805
            state = 9;
Packit 47f805
            fac1  = -1.;
Packit 47f805
            fac2  = +1.;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 0x100+'1' :
Packit 47f805
        case 0x100+'2' :
Packit 47f805
        case 0x100+'3' :
Packit 47f805
        case 0x100+'4' :
Packit 47f805
        case 0x100+'5' :
Packit 47f805
        case 0x100+'6' :
Packit 47f805
        case 0x100+'7' :
Packit 47f805
        case 0x100+'8' :
Packit 47f805
        case 0x100+'9' :
Packit 47f805
            sprintf ( message, "  B (Errors -%c dB)", (char)c );
Packit 47f805
            state = 9;
Packit 47f805
            fac2  = pow (10., -0.05*(c-0x100-'0') );
Packit 47f805
            fac1  = 1. - fac2;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case '1' :
Packit 47f805
        case '2' :
Packit 47f805
        case '3' :
Packit 47f805
        case '4' :
Packit 47f805
        case '5' :
Packit 47f805
        case '6' :
Packit 47f805
        case '7' :
Packit 47f805
        case '8' :
Packit 47f805
        case '9' :
Packit 47f805
            sprintf ( message, "  B (Errors +%c dB)", c );
Packit 47f805
            state = 9;
Packit 47f805
            fac2  = pow (10., 0.05*(c-'0') );
Packit 47f805
            fac1  = 1. - fac2;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'A' & 0x1F:
Packit 47f805
            fprintf (stderr, "   Vote for X:=A" );
Packit 47f805
            eval ( rnd == 0 );
Packit 47f805
            rnd   = random_number ();
Packit 47f805
            if ( state == 6  &&  state == 7 )
Packit 47f805
                state = 6 + rnd;
Packit 47f805
            else if ( state != rnd )
Packit 47f805
                state = rnd + 2;
Packit 47f805
            strcpy ( message," X " );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'B' & 0x1F:
Packit 47f805
            fprintf (stderr, "   Vote for X:=B" );
Packit 47f805
            eval ( rnd == 1 );
Packit 47f805
            rnd   = random_number ();
Packit 47f805
            if ( state == 6  &&  state == 7 )
Packit 47f805
                state = 6 + rnd;
Packit 47f805
            else if ( state != rnd )
Packit 47f805
                state = rnd + 2;
Packit 47f805
            strcpy ( message," X " );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case -1:
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        default:
Packit 47f805
            fprintf (stderr, "\a" );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 'Q':
Packit 47f805
        case 'q':
Packit 47f805
            fprintf ( stderr, "\n%-79.79s\r", "Quit program" );
Packit 47f805
            close (fd);
Packit 47f805
            fprintf ( stderr, "\n\n");
Packit 47f805
            return;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        switch (state) {
Packit 47f805
        case 0: /* A */
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, A+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed (fd, A+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 1: /* B */
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, B+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed (fd, B+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 2: /* B => A */
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed2 (fd, B+index, A+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed2 (fd, B+index, A+index, BF );
Packit 47f805
            state = 0;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 3: /* A => B */
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed2 (fd, A+index, B+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed2 (fd, A+index, B+index, BF );
Packit 47f805
            state = 1;
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 4: /* A */
Packit 47f805
            strcpy ( message, "A  " );
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, A+index, stop-index ),
Packit 47f805
                state++;
Packit 47f805
            else
Packit 47f805
                index += feed (fd, A+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 5: /* B */
Packit 47f805
            strcpy ( message, "  B" );
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, B+index, stop-index ),
Packit 47f805
                state--;
Packit 47f805
            else
Packit 47f805
                index += feed (fd, B+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 6: /* X */
Packit 47f805
            strcpy ( message, " X " );
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, (rnd ? B : A)+index, stop-index ),
Packit 47f805
                state++;
Packit 47f805
            else
Packit 47f805
                index += feed (fd, (rnd ? B : A)+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 7: /* !X */
Packit 47f805
            strcpy ( message, "!X " );
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, (rnd ? A : B)+index, stop-index ),
Packit 47f805
                state--;
Packit 47f805
            else
Packit 47f805
                index += feed (fd, (rnd ? A : B)+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 8:
Packit 47f805
            if ( index + BF/2 >= stop )
Packit 47f805
                index += feed2 (fd, A+index, B+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed2 (fd, A+index, B+index, BF/2 );
Packit 47f805
            Message ( "  B", index, freq, start, stop );
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, B+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed (fd, B+index, BF );
Packit 47f805
            if ( index + BF/2 >= stop )
Packit 47f805
                index += feed2 (fd, B+index, A+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed2 (fd, B+index, A+index, BF/2 );
Packit 47f805
            Message ( "A  ", index, freq, start, stop );
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feed (fd, A+index, stop-index );
Packit 47f805
            else
Packit 47f805
                index += feed (fd, A+index, BF );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        case 9: /* Liko */
Packit 47f805
            if ( index + BF >= stop )
Packit 47f805
                index += feedfac (fd, A+index, B+index, stop-index, fac1, fac2 );
Packit 47f805
            else
Packit 47f805
                index += feedfac (fd, A+index, B+index, BF        , fac1, fac2 );
Packit 47f805
            break;
Packit 47f805
Packit 47f805
        default:
Packit 47f805
            assert (0);
Packit 47f805
        }
Packit 47f805
Packit 47f805
        if (index >= stop)
Packit 47f805
            index = start;
Packit 47f805
        Message ( message, calc_true_index ( index, start, stop), freq, start, stop );
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int  has_ext ( const char* name, const char* ext )
Packit 47f805
{
Packit 47f805
    if ( strlen (name) < strlen (ext) )
Packit 47f805
        return 0;
Packit 47f805
    name += strlen (name) - strlen (ext);
Packit 47f805
    return strcasecmp (name, ext)  ?  0  :  1;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
typedef struct {
Packit 47f805
    const char* const  extention;
Packit 47f805
    const char* const  command;
Packit 47f805
} decoder_t;
Packit 47f805
Packit 47f805
Packit 47f805
#define REDIR     " 2> /dev/null"
Packit 47f805
#define STDOUT    "/dev/fd/1"
Packit 47f805
#define PATH      PATH_OF_EXTERNAL_TOOLS_FOR_UNCOMPRESSING
Packit 47f805
Packit 47f805
const decoder_t  decoder [] = {
Packit 47f805
    { ".mp1"    , PATH"mpg123 -w - %s"                         REDIR },  // MPEG Layer I         : www.iis.fhg.de, www.mpeg.org
Packit 47f805
    { ".mp2"    , PATH"mpg123 -w - %s"                         REDIR },  // MPEG Layer II        : www.iis.fhg.de, www.uq.net.au/~zzmcheng, www.mpeg.org
Packit 47f805
    { ".mp3"    , PATH"mpg123 -w - %s"                         REDIR },  // MPEG Layer III       : www.iis.fhg.de, www.mp3dev.org, www.mpeg.org
Packit 47f805
    { ".mp3pro" , PATH"mpg123 -w - %s"                         REDIR },  // MPEG Layer III       : www.iis.fhg.de, www.mp3dev.org, www.mpeg.org
Packit 47f805
    { ".mpt"    , PATH"mpg123 -w - %s"                         REDIR },  // MPEG Layer III       : www.iis.fhg.de, www.mp3dev.org, www.mpeg.org
Packit 47f805
    { ".mpp"    , PATH"mppdec %s -"                            REDIR },  // MPEGplus             : www.stud.uni-hannover.de/user/73884
Packit 47f805
    { ".mpc"    , PATH"mppdec %s -"                            REDIR },  // MPEGplus             : www.stud.uni-hannover.de/user/73884
Packit 47f805
    { ".mp+"    , PATH"mppdec %s -"                            REDIR },  // MPEGplus             : www.stud.uni-hannover.de/user/73884
Packit 47f805
    { ".aac"    , PATH"faad -t.wav -w %s"                      REDIR },  // Advanced Audio Coding: psytel.hypermart.net, www.aac-tech.com, sourceforge.net/projects/faac, www.aac-audio.com, www.mpeg.org
Packit 47f805
    { "aac.lqt" , PATH"faad -t.wav -w %s"                      REDIR },  // Advanced Audio Coding: psytel.hypermart.net, www.aac-tech.com, sourceforge.net/projects/faac, www.aac-audio.com, www.mpeg.org
Packit 47f805
    { ".ac3"    , PATH"ac3dec %s"                              REDIR },  // Dolby AC3            : www.att.com
Packit 47f805
    { "ac3.lqt" , PATH"ac3dec %s"                              REDIR },  // Dolby AC3            : www.att.com
Packit 47f805
    { ".ogg"    , PATH"ogg123 -d wav -o file:"STDOUT" %s"      REDIR },  // Ogg Vorbis           : www.xiph.org/ogg/vorbis/index.html
Packit 47f805
    { ".pac"    , PATH"lpac -x %s "STDOUT                      REDIR },  // Lossless predictive Audio Compression: www-ft.ee.tu-berlin.de/~liebchen/lpac.html (liebchen@ft.ee.tu-berlin.de)
Packit 47f805
    { ".shn"    , PATH"shorten -x < %s"                        REDIR },  // Shorten              : shnutils.freeshell.org, www.softsound.com/Shorten.html (shnutils@freeshell.org, shorten@softsound.com)
Packit 47f805
    { ".wav.gz" , PATH"gzip  -d < %s | sox -twav - -twav -sw -"REDIR },  // gziped WAV
Packit 47f805
    { ".wav.sz" , PATH"szip  -d < %s | sox -twav - -twav -sw -"REDIR },  // sziped WAV
Packit 47f805
    { ".wav.sz2", PATH"szip2 -d < %s | sox -twav - -twav -sw -"REDIR },  // sziped WAV
Packit 47f805
    { ".raw"    , PATH"sox -r44100 -sw -c2 -traw %s -twav -sw -"REDIR },  // raw files are treated as CD like audio
Packit 47f805
    { ".cdr"    , PATH"sox -r44100 -sw -c2 -traw %s -twav -sw -"REDIR },  // CD-DA files are treated as CD like audio, no preemphasis info available
Packit 47f805
    { ".rm"     , "echo %s '???'"                              REDIR },  // Real Audio           : www.real.com
Packit 47f805
    { ".epc"    , "echo %s '???'"                              REDIR },  // ePAC                 : www.audioveda.com, www.lucent.com/ldr
Packit 47f805
    { ".mov"    , "echo %s '???'"                              REDIR },  // QDesign Music 2      : www.qdesign.com
Packit 47f805
    { ".vqf"    , "echo %s '???'"                              REDIR },  // TwinVQ               : www.yamaha-xg.com/english/xg/SoundVQ, www.vqf.com, sound.splab.ecl.ntt.co.jp/twinvq-e
Packit 47f805
    { ".wma"    , "echo %s '???'"                              REDIR },  // Microsoft Media Audio: www.windowsmedia.com, www.microsoft.com/windows/windowsmedia
Packit 47f805
    { ".flac"   , PATH"flac -c -d %s"                          REDIR },  // Free Lossless Audio Coder: flac.sourceforge.net/
Packit 47f805
    { ".fla"    , PATH"flac -c -d %s"                          REDIR },  // Free Lossless Audio Coder: flac.sourceforge.net/
Packit 47f805
    { ".ape"    , "( "PATH"MAC %s _._.wav -d > /dev/null; cat _._.wav; rm _._.wav )"  REDIR },  // Monkey's Audio Codec : www.monkeysaudio.com (email@monkeysaudio.com)
Packit 47f805
    { ".rka"    , "( "PATH"rkau %s _._.wav   > /dev/null; cat _._.wav; rm _._.wav )"  REDIR },  // RK Audio:
Packit 47f805
    { ".rkau"   , "( "PATH"rkau %s _._.wav   > /dev/null; cat _._.wav; rm _._.wav )"  REDIR },  // RK Audio:
Packit 47f805
    { ".mod"    , PATH"xmp -b16 -c -f44100 --stereo -o- %s | sox -r44100 -sw -c2 -traw - -twav -sw -"
Packit 47f805
                                                               REDIR },  // Amiga's Music on Disk:
Packit 47f805
    { ""        , PATH"sox %s -twav -sw -"                     REDIR },  // Rest, may be sox can handle it
Packit 47f805
};
Packit 47f805
Packit 47f805
#undef REDIR
Packit 47f805
#undef STDOUT
Packit 47f805
#undef PATH
Packit 47f805
Packit 47f805
Packit 47f805
int  readwave ( stereo_t* buff, size_t maxlen, const char* name, size_t* len )
Packit 47f805
{
Packit 47f805
    char*           command = malloc (2*strlen(name) + 512);
Packit 47f805
    char*           name_q  = malloc (2*strlen(name) + 128);
Packit 47f805
    unsigned short  header [22];
Packit 47f805
    FILE*           fp;
Packit 47f805
    size_t          i;
Packit 47f805
    size_t          j;
Packit 47f805
Packit 47f805
    // The *nice* shell quoting
Packit 47f805
    i = j = 0;
Packit 47f805
    if ( name[i] == '-' )
Packit 47f805
        name_q[j++] = '.',
Packit 47f805
        name_q[j++] = '/';
Packit 47f805
Packit 47f805
    while (name[i]) {
Packit 47f805
        if ( !isalnum (name[i]) && name[i]!='-' && name[i]!='_' && name[i]!='.' )
Packit 47f805
            name_q[j++] = '\\';
Packit 47f805
        name_q[j++] = name[i++];
Packit 47f805
    }
Packit 47f805
    name_q[j] = '\0';
Packit 47f805
Packit 47f805
    fprintf (stderr, "Reading %s", name );
Packit 47f805
    for ( i = 0; i < sizeof(decoder)/sizeof(*decoder); i++ )
Packit 47f805
        if ( has_ext (name, decoder[i].extention) ) {
Packit 47f805
            sprintf ( command, decoder[i].command, name_q );
Packit 47f805
            break;
Packit 47f805
        }
Packit 47f805
Packit 47f805
    free (name_q);
Packit 47f805
    if ( (fp = popen (command, "r")) == NULL ) {
Packit 47f805
        fprintf (stderr, "Can't exec:\n%s\n", command );
Packit 47f805
        exit (1);
Packit 47f805
    }
Packit 47f805
    free (command);
Packit 47f805
Packit 47f805
    fprintf (stderr, " ..." );
Packit 47f805
    fread ( header, sizeof(*header), sizeof(header)/sizeof(*header), fp );
Packit 47f805
Packit 47f805
    switch (be16_le(header[11])) {
Packit 47f805
        case 2:
Packit 47f805
            *len = fread ( buff, sizeof(stereo_t), maxlen, fp );
Packit 47f805
	    for (i = 0; i < *len; i ++) {
Packit 47f805
		 buff[i][0] = be16_le(buff[i][0]);
Packit 47f805
		 buff[i][1] = be16_le(buff[i][1]);
Packit 47f805
	    }
Packit 47f805
            break;
Packit 47f805
        case 1:
Packit 47f805
            *len = fread ( buff, sizeof(sample_t), maxlen, fp );
Packit 47f805
            for ( i = *len; i-- > 0; )
Packit 47f805
                buff[i][0] = buff[i][1] = ((sample_t*)buff) [i];
Packit 47f805
            break;
Packit 47f805
        case 0:
Packit 47f805
            fprintf (stderr, "\b\b\b\b, Standard Open Source Bug detected, try murksaround ..." );
Packit 47f805
            *len = fread ( buff, sizeof(stereo_t), maxlen, fp );
Packit 47f805
            header[11] =     2;
Packit 47f805
            header[12] = 65534;  /* use that of the other channel */
Packit 47f805
            break;
Packit 47f805
        default:
Packit 47f805
            fprintf (stderr, "Only 1 or 2 channels are supported, not %u\n", header[11] );
Packit 47f805
            pclose (fp);
Packit 47f805
            return -1;
Packit 47f805
    }
Packit 47f805
    pclose ( fp );
Packit 47f805
    fprintf (stderr, "\n" );
Packit 47f805
    return be16_le(header[12]) ? be16_le(header[12]) : 65534;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
double  cross_analyze ( const stereo_t* p1, const stereo_t *p2, size_t len )
Packit 47f805
{
Packit 47f805
    float   P1 [MAX] [2];
Packit 47f805
    float   P2 [MAX] [2];
Packit 47f805
    int     i;
Packit 47f805
    int     maxindex;
Packit 47f805
    double  sum1;
Packit 47f805
    double  sum2;
Packit 47f805
    double  max;
Packit 47f805
    double  y1;
Packit 47f805
    double  y2;
Packit 47f805
    double  y3;
Packit 47f805
    double  yo;
Packit 47f805
    double  xo;
Packit 47f805
    double  tmp;
Packit 47f805
    double  tmp1;
Packit 47f805
    double  tmp2;
Packit 47f805
    int     ret = 0;
Packit 47f805
    int     cnt = 5;
Packit 47f805
Packit 47f805
    // Calculating effective voltage
Packit 47f805
    sum1 = sum2 = 0.;
Packit 47f805
    for ( i = 0; i < len; i++ ) {
Packit 47f805
        sum1 += (double)p1[i][0] * p1[i][0];
Packit 47f805
        sum2 += (double)p2[i][0] * p2[i][0];
Packit 47f805
    }
Packit 47f805
    sum1 = sqrt ( sum1/len );
Packit 47f805
    sum2 = sqrt ( sum2/len );
Packit 47f805
Packit 47f805
    // Searching beginning of signal (not stable for pathological signals)
Packit 47f805
    for ( i = 0; i < len; i++ )
Packit 47f805
        if ( abs (p1[i][0]) >= sum1  &&  abs (p2[i][0]) >= sum2 )
Packit 47f805
            break;
Packit 47f805
    p1  += i;
Packit 47f805
    p2  += i;
Packit 47f805
    len -= i;
Packit 47f805
Packit 47f805
    if ( len <= MAX )
Packit 47f805
        return 0;
Packit 47f805
Packit 47f805
    // Filling arrays for FFT
Packit 47f805
    do {
Packit 47f805
        sum1 = sum2 = 0.;
Packit 47f805
        for ( i = 0; i < MAX; i++ ) {
Packit 47f805
#ifdef USEDIFF
Packit 47f805
            tmp1  = p1 [i][0] - p1 [i+1][0];
Packit 47f805
            tmp2  = p2 [i+ret][0] - p2 [i+ret+1][0];
Packit 47f805
#else
Packit 47f805
            tmp1  = p1 [i][0];
Packit 47f805
            tmp2  = p2 [i+ret][0];
Packit 47f805
#endif
Packit 47f805
            sum1 += tmp1*tmp1;
Packit 47f805
            sum2 += tmp2*tmp2;
Packit 47f805
            P1 [i][0] = tmp1;
Packit 47f805
            P2 [i][0] = tmp2;
Packit 47f805
            P1 [i][1] = 0.;
Packit 47f805
            P2 [i][1] = 0.;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        fft (P1, MAX);
Packit 47f805
        fft (P2, MAX);
Packit 47f805
Packit 47f805
        for ( i = 0; i < MAX; i++ ) {
Packit 47f805
            double  a0 = P1 [i][0];
Packit 47f805
            double  a1 = P1 [i][1];
Packit 47f805
            double  b0 = P2 [(MAX-i)&(MAX-1)][0];
Packit 47f805
            double  b1 = P2 [(MAX-i)&(MAX-1)][1];
Packit 47f805
            P1 [i][0] = a0*b0 - a1*b1;
Packit 47f805
            P1 [i][1] = a0*b1 + a1*b0;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        fft (P1, MAX);
Packit 47f805
Packit 47f805
        max = P1 [maxindex = 0][0];
Packit 47f805
        for ( i = 1; i < MAX; i++ )
Packit 47f805
            if ( P1[i][0] > max )
Packit 47f805
                max = P1 [maxindex = i][0];
Packit 47f805
Packit 47f805
        y2 = P1 [ maxindex           ][0];
Packit 47f805
        y1 = P1 [(maxindex-1)&(MAX-1)][0] - y2;
Packit 47f805
        y3 = P1 [(maxindex+1)&(MAX-1)][0] - y2;
Packit 47f805
Packit 47f805
        xo = 0.5 * (y1-y3) / (y1+y3);
Packit 47f805
        yo = 0.5 * ( (y1+y3)*xo + (y3-y1) ) * xo;
Packit 47f805
Packit 47f805
        if (maxindex > MAX/2 )
Packit 47f805
            maxindex -= MAX;
Packit 47f805
Packit 47f805
        ret += maxindex;
Packit 47f805
        tmp = 100./MAX/sqrt(sum1*sum2);
Packit 47f805
        if (verbose)
Packit 47f805
            printf ( "[%5d]%8.4f  [%5d]%8.4f  [%5d]%8.4f  [%10.4f]%8.4f\n",
Packit 47f805
                     ret- 1, (y1+y2)*tmp,
Packit 47f805
                     ret   ,     y2 *tmp,
Packit 47f805
                     ret+ 1, (y3+y2)*tmp,
Packit 47f805
                     ret+xo, (yo+y2)*tmp );
Packit 47f805
Packit 47f805
    } while ( maxindex  &&  cnt-- );
Packit 47f805
Packit 47f805
    return ret + xo;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
short  to_short ( int x )
Packit 47f805
{
Packit 47f805
    return x == (short)x  ?  (short)x  :  (short) ((x >> 31) ^ 0x7FFF);
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void  DC_cancel ( stereo_t* p, size_t len )
Packit 47f805
{
Packit 47f805
    double  sum1 = 0;
Packit 47f805
    double  sum2 = 0;
Packit 47f805
    size_t  i;
Packit 47f805
    int     diff1;
Packit 47f805
    int     diff2;
Packit 47f805
Packit 47f805
    for (i = 0; i < len; i++ ) {
Packit 47f805
        sum1 += p[i][0];
Packit 47f805
        sum2 += p[i][1];
Packit 47f805
    }
Packit 47f805
    if ( fabs(sum1) < len  &&  fabs(sum2) < len )
Packit 47f805
        return;
Packit 47f805
Packit 47f805
    diff1 = round ( sum1 / len );
Packit 47f805
    diff2 = round ( sum2 / len );
Packit 47f805
    if (verbose)
Packit 47f805
        fprintf (stderr, "Removing DC (left=%d, right=%d)\n", diff1, diff2 );
Packit 47f805
Packit 47f805
    for (i = 0; i < len; i++ ) {
Packit 47f805
        p[i][0] = to_short ( p[i][0] - diff1);
Packit 47f805
        p[i][1] = to_short ( p[i][1] - diff2);
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
void  multiply ( char c, stereo_t* p, size_t len, double fact )
Packit 47f805
{
Packit 47f805
    size_t  i;
Packit 47f805
Packit 47f805
    if ( fact == 1. )
Packit 47f805
        return;
Packit 47f805
    if (verbose)
Packit 47f805
        fprintf (stderr, "Multiplying %c by %7.5f\n", c, fact );
Packit 47f805
Packit 47f805
    for (i = 0; i < len; i++ ) {
Packit 47f805
        p[i][0] = to_short ( p[i][0] * fact );
Packit 47f805
        p[i][1] = to_short ( p[i][1] * fact );
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int  maximum ( stereo_t* p, size_t len )
Packit 47f805
{
Packit 47f805
    int     max = 0;
Packit 47f805
    size_t  i;
Packit 47f805
Packit 47f805
    for (i = 0; i < len; i++ ) {
Packit 47f805
        if (abs(p[i][0]) > max) max = abs(p[i][0]);
Packit 47f805
        if (abs(p[i][1]) > max) max = abs(p[i][1]);
Packit 47f805
    }
Packit 47f805
    return max;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void  usage ( void )
Packit 47f805
{
Packit 47f805
    fprintf ( stderr,
Packit 47f805
        "usage:  abx [-v] File_A File_B\n"
Packit 47f805
        "\n"
Packit 47f805
        "File_A and File_B loaded and played. File_A should be the better/reference\n"
Packit 47f805
        "file, File_B the other. You can press the following keys:\n"
Packit 47f805
        "\n"
Packit 47f805
        "  a/A:    Listen to File A\n"
Packit 47f805
        "  b/B:    Listen to File B\n"
Packit 47f805
        "  x/X:    Listen to the randomly selected File X, which is A or B\n"
Packit 47f805
        "  Ctrl-A: You vote for X=A\n"
Packit 47f805
        "  Ctrl-B: You vote for X=B\n"
Packit 47f805
        "  m:      Alternating playing A and B. Fast switching\n"
Packit 47f805
        "  M:      Alternating playing A and B. Slow switching\n"
Packit 47f805
        "  d/D/Ctrl-D/Alt-d/Alt-D:\n"
Packit 47f805
        "          Listen to the difference A-B (+0 dB...+40 dB)\n"
Packit 47f805
        "  o/p:    Chunk select\n"
Packit 47f805
        "  hjkl:   Chunk fine adjust (hj: start, kl: stop)\n"
Packit 47f805
        "  Space:  Chunk deselect\n"
Packit 47f805
        "  0...9:  Listen to B, but difference A-B is amplified by 0-9 dB\n"
Packit 47f805
        "  Q:      Quit the program\n"
Packit 47f805
        "\n"
Packit 47f805
    );
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
int  main ( int argc, char** argv )
Packit 47f805
{
Packit 47f805
    stereo_t*  _A = calloc ( MAX_LEN, sizeof(stereo_t) );
Packit 47f805
    stereo_t*  _B = calloc ( MAX_LEN, sizeof(stereo_t) );
Packit 47f805
    stereo_t*  A  = _A;
Packit 47f805
    stereo_t*  B  = _B;
Packit 47f805
    size_t     len_A;
Packit 47f805
    size_t     len_B;
Packit 47f805
    size_t     len;
Packit 47f805
    int        max_A;
Packit 47f805
    int        max_B;
Packit 47f805
    int        max;
Packit 47f805
    long       freq1;
Packit 47f805
    long       freq2;
Packit 47f805
    int        shift;
Packit 47f805
    double     fshift;
Packit 47f805
    double     ampl;
Packit 47f805
    int        ampl_X;
Packit 47f805
    korr_t     k;
Packit 47f805
Packit 47f805
    if (argc > 1  &&  0 == strcmp (argv[1], "-v") ) {
Packit 47f805
        verbose = 1;
Packit 47f805
        argc--;
Packit 47f805
        argv++;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    switch ( argc ) {
Packit 47f805
    case 0:
Packit 47f805
    case 1:
Packit 47f805
    case 2:
Packit 47f805
    default:
Packit 47f805
        usage ();
Packit 47f805
        return 1;
Packit 47f805
    case 3:
Packit 47f805
        usage();
Packit 47f805
        break;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    freq1 = readwave ( A, MAX_LEN, argv[1], &len_A );
Packit 47f805
    DC_cancel ( A, len_A );
Packit 47f805
    freq2 = readwave ( B, MAX_LEN, argv[2], &len_B );
Packit 47f805
    DC_cancel ( B, len_B );
Packit 47f805
Packit 47f805
    if      ( freq1 == 65534  &&  freq2 != 65534 )
Packit 47f805
        freq1 = freq2;
Packit 47f805
    else if ( freq2 == 65534  &&  freq1 != 65534 )
Packit 47f805
        freq2 = freq1;
Packit 47f805
    else if ( freq1 == 65534  &&  freq2 == 65534 )
Packit 47f805
        freq1 = freq2 = 44100;
Packit 47f805
Packit 47f805
    if ( freq1 != freq2 ) {
Packit 47f805
        fprintf ( stderr, "Different sample frequencies currently not supported\n");
Packit 47f805
        fprintf ( stderr, "A: %ld, B: %ld\n", freq1, freq2 );
Packit 47f805
        return 2;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    len    = len_A < len_B  ?  len_A  :  len_B;
Packit 47f805
    fshift = cross_analyze ( A, B, len );
Packit 47f805
    shift  = floor ( fshift + 0.5 );
Packit 47f805
Packit 47f805
    if ( verbose ) {
Packit 47f805
        fprintf ( stderr, "Delay Ch1 is %.4f samples\n", fshift );
Packit 47f805
	fprintf ( stderr, "Delay Ch2 is %.4f samples\n",
Packit 47f805
	          cross_analyze ( (stereo_t*)(((sample_t*)A)+1), (stereo_t*)(((sample_t*)B)+1), len ) );
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if (shift > 0) {
Packit 47f805
        if (verbose)
Packit 47f805
            fprintf ( stderr, "Delaying A by %d samples\n", +shift);
Packit 47f805
        B     += shift;
Packit 47f805
        len_B -= shift;
Packit 47f805
    }
Packit 47f805
    if (shift < 0) {
Packit 47f805
        if (verbose)
Packit 47f805
            fprintf ( stderr, "Delaying B by %d samples\n", -shift);
Packit 47f805
        A     -= shift;
Packit 47f805
        len_A += shift;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    len    = len_A < len_B  ?  len_A  :  len_B;
Packit 47f805
    memset ( &k, 0, sizeof(k) );
Packit 47f805
    analyze_stereo ( A, B, len, &k );
Packit 47f805
    ampl  = report (&k);
Packit 47f805
    max_A = maximum ( A, len );
Packit 47f805
    max_B = maximum ( B, len );
Packit 47f805
Packit 47f805
    if ( ampl <= 0.98855 ) { /* < -0.05 dB */
Packit 47f805
        max    = max_A*ampl < max_B  ?  max_B  :  max_A*ampl;
Packit 47f805
        ampl_X = (int)(29203 / max);
Packit 47f805
        if ( ampl_X < 2 ) ampl_X = 1;
Packit 47f805
        multiply ( 'A', A, len, ampl*ampl_X );
Packit 47f805
        multiply ( 'B', B, len,      ampl_X );
Packit 47f805
    } else if ( ampl >= 1.01158 ) { /* > +0.05 dB */
Packit 47f805
        max    = max_A < max_B/ampl  ?  max_B/ampl  :  max_A;
Packit 47f805
        ampl_X = (int)(29203 / max);
Packit 47f805
        if ( ampl_X < 2 ) ampl_X = 1;
Packit 47f805
        multiply ( 'A', A, len,         ampl_X );
Packit 47f805
        multiply ( 'B', B, len, 1./ampl*ampl_X );
Packit 47f805
    } else {
Packit 47f805
        max    = max_A < max_B ? max_B : max_A;
Packit 47f805
        ampl_X = (int)(29203 / max);
Packit 47f805
        if ( ampl_X < 2 ) ampl_X = 1;
Packit 47f805
        multiply ( 'A', A, len, ampl_X );
Packit 47f805
        multiply ( 'B', B, len, ampl_X );
Packit 47f805
    }
Packit 47f805
Packit 47f805
    set ();
Packit 47f805
    Set_Realtime ();
Packit 47f805
    testing ( A, B, len, freq1 );
Packit 47f805
    reset ();
Packit 47f805
Packit 47f805
    free (_A);
Packit 47f805
    free (_B);
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
/* end of abx.c */