/** Function to compute the spectral distance between two song models.
         *  This is a fast implementation of the symmetrized Kullback Leibler
         *  Divergence.
         */
        public static float Distance(Scms s1, Scms s2, ScmsConfiguration c)
        {
            float val = 0;
            int i;
            int k;
            int idx = 0;
            int dim = c.Dimension;
            int covlen = c.CovarianceLength;
            float tmp1;

            unsafe {
                fixed (float* s1cov = s1.cov, s2icov = s2.icov,
                        s1icov = s1.icov, s2cov = s2.cov,
                        s1mean = s1.mean, s2mean = s2.mean,
                        mdiff = c.MeanDiff, aicov = c.AddInverseCovariance)
                {
                    for (i = 0; i < covlen; i++) {
                        aicov[i] = s1icov[i] + s2icov[i];
                    }

                    for (i = 0; i < dim; i++) {
                        idx = i*dim - (i*i+i)/2;
                        val += s1cov[idx+i] * s2icov[idx+i] +
                            s2cov[idx+i] * s1icov[idx+i];

                        for (k = i+1; k < dim; k++) {
                            val += 2*s1cov[idx+k] * s2icov[idx+k] +
                                2*s2cov[idx+k] * s1icov[idx+k];
                        }
                    }

                    for (i = 0; i < dim; i++) {
                        mdiff[i] = s1mean[i] - s2mean[i];
                    }

                    for (i = 0; i < dim; i++) {
                        idx = i - dim;
                        tmp1 = 0;

                        for (k = 0; k <= i; k++) {
                            idx += dim - k;
                            tmp1 += aicov[idx] * mdiff[k];
                        }
                        for (k = i + 1; k < dim; k++) {
                            idx++;
                            tmp1 += aicov[idx] * mdiff[k];
                        }
                        val += tmp1 * mdiff[i];
                    }
                }
            }

            // FIXME: fix the negative return values
            //val = Math.Max(0.0f, (val/2 - s1.cov.dim));
            val = val / 4 - c.Dimension / 2;

            return val;
        }
    private static void Test()
    {
        mirageaudio_initgst();

        string song1_filename = "/home/lorentz/Music/Library/Pachelbel/Johann Pachelbel - Canon And Gigue In D Major For 3 Violins And Basso Continuo.mp3";
        string song2_filename = "/home/lorentz/Music/Library/Karajan Adagios/CD 1/Pachelbel - Canon in d Major (Kanon And Gigue in d Major = d Dur) av Johann Pachelbel.mp3";
        Scms song1 = null;
        Scms song2 = null;

        DbgTimer t1 = new DbgTimer();
        t1.Start();
        int runs = 10;
        for (int i = 0; i < runs; i++) {
            Analyzer.Analyze(song1_filename);
        }
        long l1 = 0;
        t1.Stop(ref l1);
        Dbg.WriteLine("Analysis: " + runs + " times - " + l1 + "ms; " +
                      (double)l1/(double)runs + "ms per analysis");

        song1 = Analyzer.Analyze(song1_filename);
        song2 = Analyzer.Analyze(song2_filename);

        ScmsConfiguration config = new ScmsConfiguration (Analyzer.MFCC_COEFFICIENTS);

        Console.WriteLine("Distance = " + Scms.Distance (song1, song2, config));

        DbgTimer t2 = new DbgTimer();
        t2.Start();
        runs = 100000;
        for (int i = 0; i < runs; i++) {
            Scms.Distance (song1, song2, config);
        }
        long l2 = 0;
        t2.Stop(ref l2);
        Dbg.WriteLine("Distance Computation: " + runs + " times - " + l2 + "ms; " +
                      (double)l2/(double)runs + "ms per comparison");
    }
        /** Function to compute the spectral distance between two song models.
         *  This is a fast implementation of the symmetrized Kullback Leibler
         *  Divergence.
         */
        public static float Distance(Scms s1, Scms s2, ScmsConfiguration c)
        {
            float val = 0;
            int   i;
            int   k;
            int   idx    = 0;
            int   dim    = c.Dimension;
            int   covlen = c.CovarianceLength;
            float tmp1;

            unsafe
            {
                fixed(float *s1cov = s1.cov, s2icov    = s2.icov,
                      s1icov       = s1.icov, s2cov    = s2.cov,
                      s1mean       = s1.mean, s2mean   = s2.mean,
                      mdiff        = c.MeanDiff, aicov = c.AddInverseCovariance)
                {
                    for (i = 0; i < covlen; i++)
                    {
                        aicov[i] = s1icov[i] + s2icov[i];
                    }

                    for (i = 0; i < dim; i++)
                    {
                        idx  = i * dim - (i * i + i) / 2;
                        val += s1cov[idx + i] * s2icov[idx + i] +
                               s2cov[idx + i] * s1icov[idx + i];

                        for (k = i + 1; k < dim; k++)
                        {
                            val += 2 * s1cov[idx + k] * s2icov[idx + k] +
                                   2 * s2cov[idx + k] * s1icov[idx + k];
                        }
                    }

                    for (i = 0; i < dim; i++)
                    {
                        mdiff[i] = s1mean[i] - s2mean[i];
                    }

                    for (i = 0; i < dim; i++)
                    {
                        idx  = i - dim;
                        tmp1 = 0;

                        for (k = 0; k <= i; k++)
                        {
                            idx  += dim - k;
                            tmp1 += aicov[idx] * mdiff[k];
                        }
                        for (k = i + 1; k < dim; k++)
                        {
                            idx++;
                            tmp1 += aicov[idx] * mdiff[k];
                        }
                        val += tmp1 * mdiff[i];
                    }
                }
            }

            // FIXME: fix the negative return values
            //val = Math.Max(0.0f, (val/2 - s1.cov.dim));
            val = val / 4 - c.Dimension / 2;

            return(val);
        }