MelFilter MFCC_to_MelFilter (MFCC me, long first, long last) {
	try {
		long nf = my maximumNumberOfCoefficients + 1;
		autoNUMmatrix<double> cosinesTable (NUMcosinesTable (nf), 1, 1);
		autoNUMvector<double> x (1, nf);
		autoNUMvector<double> y (1, nf);

		if (first >= last) {
			first = 0; last = nf - 1;
		}

		if (first < 0 || last > nf - 1) {
			Melder_throw ("MFCC_to_MelFilter: coefficients must be in interval [0,", my maximumNumberOfCoefficients, "].");
		}
		double df = (my fmax - my fmin) / (nf + 1);
		autoMelFilter thee = MelFilter_create (my xmin, my xmax, my nx, my dx, my x1, my fmin, my fmax, nf, df, df);

		for (long frame = 1; frame <= my nx; frame++) {
			CC_Frame cf = (CC_Frame) & my frame[frame];
			long iend = MIN (last, cf -> numberOfCoefficients);
			x[1] = first == 0 ? cf -> c0 : 0;
			for (long i = 1; i <= my maximumNumberOfCoefficients; i++) {
				x[i + 1] = i < first || i > iend ? 0 : cf -> c[i];
			}
			NUMinverseCosineTransform (x.peek(), y.peek(), nf, cosinesTable.peek());
			for (long i = 1; i <= nf; i++) {
				
				thy z[i][frame] = y[i];
			}
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": no MelFilter created.");
	}
}
MFCC MelFilter_to_MFCC (MelFilter me, long numberOfCoefficients) {
	try {
		autoNUMmatrix<double> cosinesTable (NUMcosinesTable (my ny), 1, 1);
		autoNUMvector<double> x (1, my ny);
		autoNUMvector<double> y (1, my ny);
		
		double fmax_mel = my y1 + (my ny - 1) * my dy;
		numberOfCoefficients = numberOfCoefficients > my ny - 1 ? my ny - 1 : numberOfCoefficients;
		Melder_assert (numberOfCoefficients > 0);
		// 20130220 new interpretation of maximumNumberOfCoefficients necessary for inverse transform 
		autoMFCC thee = MFCC_create (my xmin, my xmax, my nx, my dx, my x1, my ny - 1, my ymin, my ymax);
		for (long frame = 1; frame <= my nx; frame++) {
			CC_Frame cf = (CC_Frame) & thy frame[frame];
			for (long i = 1; i <= my ny; i++) {
				x[i] = my z[i][frame];
			}
			NUMcosineTransform (x.peek(), y.peek(), my ny, cosinesTable.peek());
			CC_Frame_init (cf, numberOfCoefficients);
			for (long i = 1; i <= numberOfCoefficients; i++) {
				cf -> c[i] = y[i + 1];
			}
			cf -> c0 = y[1];
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": no MFCC created.");
	}
}
MFCC MelFilter_to_MFCC (MelFilter me, long numberOfCoefficients) {
	try {
		long nf = my ny;
		double fmax_mel = my y1 + (nf - 1) * my dy;

		Melder_assert (numberOfCoefficients > 0);

		autoNUMmatrix<double> dct (NUMcosinesTable (1, numberOfCoefficients, nf), 1, 1);
		autoMFCC thee = MFCC_create (my xmin, my xmax, my nx, my dx, my x1, numberOfCoefficients, my y1, fmax_mel);
		for (long frame = 1; frame <= my nx; frame++) {
			CC_Frame cf = (CC_Frame) & thy frame[frame];

			CC_Frame_init (cf, numberOfCoefficients);
			for (long i = 1; i <= numberOfCoefficients; i++) {
				double p = 0;
				for (long  j = 1; j <= nf; j++) {
					p += my z[j][frame] * dct[i][j];
				}
				cf -> c[i] = p;
			}

			// c0 equals the average of the filterbank outputs.
			double p = 0;
			for (long j = 1; j <= nf; j++) {
				p += my z[j][frame];
			}
			cf -> c0 = p / nf;
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": no MFCC created.");
	}
}
MelFilter MFCC_to_MelFilter2 (MFCC me, long first_cc, long last_cc, double f1_mel, double df_mel) {
	try {
		int use_c0 = 0;
		long nf = ((my fmax - my fmin) / df_mel + 0.5);
		double fmin = MAX (f1_mel - df_mel, 0), fmax = f1_mel + (nf + 1) * df_mel;

		if (nf < 1) {
			Melder_throw ("MFCC_to_MelFilter: the position of the first filter, the distance between the filters, "
			"and, the maximum do not result in a positive number of filters.");
		}

		// Default values

		if (first_cc == 0) {
			first_cc = 1;
			use_c0 = 1;
		}
		if (last_cc == 0) {
			last_cc = my maximumNumberOfCoefficients;
		}

		// Be strict

		if (last_cc < first_cc || first_cc < 1 || last_cc > my maximumNumberOfCoefficients) {
			Melder_throw ("MFCC_to_MelFilter: coefficients must be in interval [1,", my maximumNumberOfCoefficients, "].");
		}
		autoNUMmatrix<double> dct (NUMcosinesTable (first_cc, last_cc, nf), first_cc, 1); // TODO ??
		//if ((dct = NUMcosinesTable (first_cc, last_cc, nf)) == NULL) return NULL;

		autoMelFilter thee = MelFilter_create (my xmin, my xmax, my nx, my dx, my x1, fmin, fmax, nf, df_mel, f1_mel);

		for (long frame = 1; frame <= my nx; frame++) {
			CC_Frame cf = (CC_Frame) & my frame[frame];
			long ie = MIN (last_cc, cf -> numberOfCoefficients);
			for (long j = 1; j <= nf; j++) {
				double t = 0;
				for (long i = first_cc; i <= ie; i++) {
					t += cf -> c[i] * dct[i][j];
				}

				// The inverse CT has a factor 1/N

				t /= nf;
				if (use_c0) {
					t +=  cf -> c0;
				}
				thy z[j][frame] = t;
			}
		}
		return thee.transfer();
	} catch (MelderError) {
		Melder_throw (me, ": no MelFilter created.");
	}
}
// Preconditions: Domains and number of frames conform
//                0 <= first <= last <= my ny-1
void CC_into_BandFilterSpectrogram (CC me, BandFilterSpectrogram thee, long first, long last, bool use_c0) {
	long nf = my maximumNumberOfCoefficients + 1;
	autoNUMmatrix<double> cosinesTable (NUMcosinesTable (nf), 1, 1);
	autoNUMvector<double> x (1, nf);
	autoNUMvector<double> y (1, nf);
	for (long frame = 1; frame <= my nx; frame++) {
		CC_Frame ccframe = (CC_Frame) & my frame[frame];
		long iend = last < ccframe -> numberOfCoefficients ? last : ccframe -> numberOfCoefficients;
		x[1] = use_c0 ? ccframe -> c0 : 0;
		for (long i = 1; i <= my maximumNumberOfCoefficients; i++) {
			x[i + 1] = i < first || i > iend ? 0 : ccframe -> c[i];
		}
		NUMinverseCosineTransform (x.peek(), y.peek(), nf, cosinesTable.peek());
		for (long i = 1; i <= nf; i++) {
			thy z[i][frame] = BandFilterSpectrogram_DBREF * pow (10, y[i] / BandFilterSpectrogram_DBFAC);
		}
	}
}
/* Precondition: 1. CC object has been created but individual frames not yet initialized
 *               2. Domains and number of frames conform
 * Steps:
 * 1. transform power-spectra to dB-spectra
 * 2. cosine transform of dB-spectrum
*/
void BandFilterSpectrogram_into_CC (BandFilterSpectrogram me, CC thee, long numberOfCoefficients) {
	autoNUMmatrix<double> cosinesTable (NUMcosinesTable (my ny), 1, 1);
	autoNUMvector<double> x (1, my ny);
	autoNUMvector<double> y (1, my ny);
	numberOfCoefficients = numberOfCoefficients > my ny - 1 ? my ny - 1 : numberOfCoefficients;
	Melder_assert (numberOfCoefficients > 0);
	// 20130220 new interpretation of maximumNumberOfCoefficients necessary for inverse transform 
	for (long frame = 1; frame <= my nx; frame++) {
		CC_Frame ccframe = (CC_Frame) & thy frame[frame];
		for (long i = 1; i <= my ny; i++) {
			x[i] = my v_getValueAtSample (frame, i, 1); // z[i][frame];
		}
		NUMcosineTransform (x.peek(), y.peek(), my ny, cosinesTable.peek());
		CC_Frame_init (ccframe, numberOfCoefficients);
		for (long i = 1; i <= numberOfCoefficients; i++) {
			ccframe -> c[i] = y[i + 1];
		}
		ccframe -> c0 = y[1];
	}
}
double testCosineTransform (long n) {
	try {
		autoNUMvector<double> x (1, n);
		autoNUMvector<double> y (1, n);
		autoNUMvector<double> x2 (1, n);
		autoNUMmatrix<double> cosinesTable (NUMcosinesTable (n), 1, 1);
		for (long i = 1 ; i <= n; i++) {
			x[i] = NUMrandomUniform (0, 70);
		}
		NUMcosineTransform (x.peek(), y.peek(), n, cosinesTable.peek());
		NUMinverseCosineTransform (y.peek(), x2.peek(), n, cosinesTable.peek());
		double delta = 0;
		for (long i =1 ; i <= n; i++) {
			double dif = x[i] - x2[i];
			delta += dif * dif;
		}
		delta = sqrt (delta);
		return delta;
	} catch (MelderError) {
		Melder_throw ("Test cosine transform error");
	}
}