Mercurial > hg > nnls-chroma
changeset 13:9ae90fa5fa74 matthiasm-plugin
NNLS is now taken from a file without gpl. more chroma normalisation options.
author | matthiasm |
---|---|
date | Wed, 16 Jun 2010 10:16:13 +0000 |
parents | 54f28d8ac098 |
children | 75fb80542cd2 |
files | NNLSChroma.cpp nnls.cc nnls.o |
diffstat | 3 files changed, 184 insertions(+), 145 deletions(-) [+] |
line wrap: on
line diff
--- a/NNLSChroma.cpp Wed Jun 09 03:33:36 2010 +0000 +++ b/NNLSChroma.cpp Wed Jun 16 10:16:13 2010 +0000 @@ -433,7 +433,7 @@ { // Return something helpful here! if (debug_on) cerr << "--> getDescription" << endl; - return "This plugin provides a number of features derived from a log-frequency amplitude spectrum (LAS) of the DFT: the LAS itself, a standard-tuned version thereof (the local and global tuning estimates can are also be output), an approximate transcription to semitone activation using non-linear least squares (NNLS). Furthermore chroma features and a simple chord estimate derived from this NNLS semitone transcription."; + return "This plugin provides a number of features derived from a log-frequency amplitude spectrum of the DFT: some variants of the log-frequency spectrum, including a semitone spectrum derived from approximate transcription using the NNLS algorithm; based on this semitone spectrum, chroma features and a simple chord estimate."; } string @@ -569,11 +569,13 @@ d4.description = "How shall the chroma vector be normalized?"; d4.unit = ""; d4.minValue = 0; - d4.maxValue = 1; + d4.maxValue = 3; d4.defaultValue = 0; d4.isQuantized = true; - d4.valueNames.push_back("no normalization"); - d4.valueNames.push_back("maximum normalization"); + d4.valueNames.push_back("none"); + d4.valueNames.push_back("maximum norm"); + d4.valueNames.push_back("L1 norm"); + d4.valueNames.push_back("L2 norm"); d4.quantizeStep = 1.0; list.push_back(d4); @@ -1045,8 +1047,9 @@ /** Tune Log-Frequency Spectrogram calculate a tuned log-frequency spectrogram (f2): use the tuning estimated above (kinda f0) to perform linear interpolation on the existing log-frequency spectrogram (kinda f1). - **/ - + **/ + cerr << "[NNLS Chroma Plugin] Tuning Log-Frequency Spectrogram ... "; + float tempValue = 0; float dbThreshold = 0; // relative to the background spectrum float thresh = pow(10,dbThreshold/20); @@ -1094,6 +1097,7 @@ fsOut[2].push_back(f2); count++; } + cerr << "done." << endl; /** Semitone spectrum and chromagrams Semitone-spaced log-frequency spectrum derived from the tuned log-freq spectrum above. the spectrum @@ -1101,7 +1105,12 @@ Three different kinds of chromagram are calculated, "treble", "bass", and "both" (which means bass and treble stacked onto each other). **/ - // taucs_ccs_matrix* A_original_ordering = taucs_construct_sorted_ccs_matrix(nnlsdict06, nnls_m, nnls_n); + if (m_dictID == 1) { + cerr << "[NNLS Chroma Plugin] Mapping to semitone spectrum and chroma ... "; + } else { + cerr << "[NNLS Chroma Plugin] Performing NNLS and mapping to chroma ... "; + } + vector<vector<float> > chordogram; vector<vector<int> > scoreChordogram; @@ -1199,19 +1208,69 @@ } } } + - if (m_doNormalizeChroma > 0) { - float chromamax = *max_element(chroma.begin(), chroma.end()); - for (int i = 0; i < chroma.size(); i++) { - chroma[i] /= chromamax; - } - } + f4.values = chroma; f5.values = basschroma; chroma.insert(chroma.begin(), basschroma.begin(), basschroma.end()); // just stack the both chromas f6.values = chroma; + if (m_doNormalizeChroma > 0) { + vector<float> chromanorm = vector<float>(3,0); + switch (int(m_doNormalizeChroma)) { + case 0: // should never end up here + break; + case 1: + chromanorm[0] = *max_element(f4.values.begin(), f4.values.end()); + chromanorm[1] = *max_element(f5.values.begin(), f5.values.end()); + chromanorm[2] = max(chromanorm[0], chromanorm[1]); + break; + case 2: + for (vector<float>::iterator it = f4.values.begin(); it != f4.values.end(); ++it) { + chromanorm[0] += *it; + } + for (vector<float>::iterator it = f5.values.begin(); it != f5.values.end(); ++it) { + chromanorm[1] += *it; + } + for (vector<float>::iterator it = f6.values.begin(); it != f6.values.end(); ++it) { + chromanorm[2] += *it; + } + break; + case 3: + for (vector<float>::iterator it = f4.values.begin(); it != f4.values.end(); ++it) { + chromanorm[0] += pow(*it,2); + } + chromanorm[0] = sqrt(chromanorm[0]); + for (vector<float>::iterator it = f5.values.begin(); it != f5.values.end(); ++it) { + chromanorm[1] += pow(*it,2); + } + chromanorm[1] = sqrt(chromanorm[1]); + for (vector<float>::iterator it = f6.values.begin(); it != f6.values.end(); ++it) { + chromanorm[2] += pow(*it,2); + } + chromanorm[2] = sqrt(chromanorm[2]); + break; + } + if (chromanorm[0] > 0) { + for (int i = 0; i < f4.values.size(); i++) { + f4.values[i] /= chromanorm[0]; + } + } + if (chromanorm[1] > 0) { + for (int i = 0; i < f5.values.size(); i++) { + f5.values[i] /= chromanorm[1]; + } + } + if (chromanorm[2] > 0) { + for (int i = 0; i < f6.values.size(); i++) { + f6.values[i] /= chromanorm[2]; + } + } + + } + // local chord estimation vector<float> currentChordSalience; float tempchordvalue = 0; @@ -1239,12 +1298,14 @@ fsOut[6].push_back(f6); count++; } - cerr << "******* NNLS done *******" << endl; + cerr << "done." << endl; + /* Simple chord estimation I just take the local chord estimates ("currentChordSalience") and average them over time, then take the maximum. Very simple, don't do this at home... */ + cerr << "[NNLS Chroma Plugin] Chord Estimation ... "; count = 0; int halfwindowlength = m_inputSampleRate / m_stepSize; vector<int> chordSequence; @@ -1330,7 +1391,7 @@ } count++; } - cerr << "******* agent finished *******" << endl; + // cerr << "******* agent finished *******" << endl; count = 0; for (FeatureList::iterator it = fsOut[6].begin(); it != fsOut[6].end(); ++it) { float maxval = 0; // will be the value of the most salient chord in this frame @@ -1346,7 +1407,7 @@ // cerr << "before modefilter, maxindex: " << maxindex << endl; count++; } - cerr << "******* mode filter done *******" << endl; + // cerr << "******* mode filter done *******" << endl; // mode filter on chordSequence @@ -1389,6 +1450,7 @@ } count++; } + cerr << "done." << endl; // // musicity // count = 0; // int oldlabeltype = 0; // start value is 0, music is 1, speech is 2
--- a/nnls.cc Wed Jun 09 03:33:36 2010 +0000 +++ b/nnls.cc Wed Jun 16 10:16:13 2010 +0000 @@ -1,27 +1,6 @@ -// $Id: nnls.cc,v 1.1.2.1 2003/03/06 16:28:07 suvrit Exp $ +// $Id: nnls.cc,v 1.1.1.1 2003/04/02 22:06:19 suvrit Exp $ // File: nnls.cc // Implements the Lawson-Hanson NNLS algorithm -// Copied over from nnls.c so i don't ahve copyright on this -//...somebody else has.....don't know if this should be under GPL or LGPL or -// whatever, but i'll put a lil note here anyways: - -// Copyright (C) 2004 Lawson-Hanson -// Modifications to adapt to c++ by Suvrit Sra. - -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - #include "nnls.h" @@ -31,23 +10,23 @@ x = (a >= 0 ? a : - a); return (b >= 0 ? x : -x); } - + /* Table of constant values */ - + int c__1 = 1; int c__0 = 0; int c__2 = 2; -int nnls(float* a, int mda, int m, int n, float* b, - float* x, float* rnorm, float* w, float* zz, int* index, - int* mode) +int nnls(float* a, int mda, int m, int n, float* b, + float* x, float* rnorm, float* w, float* zz, int* index, + int* mode) { /* System generated locals */ int a_dim1, a_offset, idx1, idx2; float d1, d2; - - + + /* Local variables */ static int iter; static float temp, wmax; @@ -61,12 +40,12 @@ static int iz, jz; static float up, ss; static int rtnkey, iz1, iz2, npp1; - - /* ------------------------------------------------------------------ + + /* ------------------------------------------------------------------ */ /* int INDEX(N) */ /* float precision A(MDA,N), B(M), W(N), X(N), ZZ(M) */ - /* ------------------------------------------------------------------ + /* ------------------------------------------------------------------ */ /* Parameter adjustments */ a_dim1 = mda; @@ -77,7 +56,7 @@ --w; --zz; --index; - + /* Function Body */ *mode = 1; if (m <= 0 || n <= 0) { @@ -86,33 +65,33 @@ } iter = 0; itmax = n * 3; - + /* INITIALIZE THE ARRAYS INDEX() AND X(). */ - + idx1 = n; for (i__ = 1; i__ <= idx1; ++i__) { x[i__] = 0.; /* L20: */ index[i__] = i__; } - + iz2 = n; iz1 = 1; nsetp = 0; npp1 = 1; /* ****** MAIN LOOP BEGINS HERE ****** */ L30: - /* QUIT IF ALL COEFFICIENTS ARE ALREADY IN THE SOLUTION. + /* QUIT IF ALL COEFFICIENTS ARE ALREADY IN THE SOLUTION. */ /* OR IF M COLS OF A HAVE BEEN TRIANGULARIZED. */ - + if (iz1 > iz2 || nsetp >= m) { goto L350; } - - /* COMPUTE COMPONENTS OF THE DUAL (NEGATIVE GRADIENT) VECTOR W(). + + /* COMPUTE COMPONENTS OF THE DUAL (NEGATIVE GRADIENT) VECTOR W(). */ - + idx1 = iz2; for (iz = iz1; iz <= idx1; ++iz) { j = index[iz]; @@ -137,21 +116,21 @@ } /* L70: */ } - + /* IF WMAX .LE. 0. GO TO TERMINATION. */ - /* THIS INDICATES SATISFACTION OF THE KUHN-TUCKER CONDITIONS. + /* THIS INDICATES SATISFACTION OF THE KUHN-TUCKER CONDITIONS. */ - + if (wmax <= 0.) { goto L350; } iz = izmax; j = index[iz]; - + /* THE SIGN OF W(J) IS OK FOR J TO BE MOVED TO SET P. */ /* BEGIN THE TRANSFORMATION AND CHECK NEW DIAGONAL ELEMENT TO AVOID */ /* NEAR LINEAR DEPENDENCE. */ - + asave = a[npp1 + j * a_dim1]; idx1 = npp1 + 1; h12(c__1, &npp1, &idx1, m, &a[j * a_dim1 + 1], &c__1, &up, dummy, & @@ -169,11 +148,11 @@ unorm = sqrt(unorm); d2 = unorm + (d1 = a[npp1 + j * a_dim1], nnls_abs(d1)) * .01; if ((d2- unorm) > 0.) { - + /* COL J IS SUFFICIENTLY INDEPENDENT. COPY B INTO ZZ, UPDATE Z - Z */ + Z */ /* AND SOLVE FOR ZTEST ( = PROPOSED NEW VALUE FOR X(J) ). */ - + idx1 = m; for (l = 1; l <= idx1; ++l) { /* L120: */ @@ -181,53 +160,53 @@ } idx1 = npp1 + 1; h12(c__2, &npp1, &idx1, m, &a[j * a_dim1 + 1], &c__1, &up, (zz+1), & - c__1, &c__1, &c__1); + c__1, &c__1, &c__1); ztest = zz[npp1] / a[npp1 + j * a_dim1]; - + /* SEE IF ZTEST IS POSITIVE */ - + if (ztest > 0.) { goto L140; } } - + /* REJECT J AS A CANDIDATE TO BE MOVED FROM SET Z TO SET P. */ /* RESTORE A(NPP1,J), SET W(J)=0., AND LOOP BACK TO TEST DUAL */ /* COEFFS AGAIN. */ - + a[npp1 + j * a_dim1] = asave; w[j] = 0.; goto L60; - + /* THE INDEX J=INDEX(IZ) HAS BEEN SELECTED TO BE MOVED FROM */ /* SET Z TO SET P. UPDATE B, UPDATE INDICES, APPLY HOUSEHOLDER */ /* TRANSFORMATIONS TO COLS IN NEW SET Z, ZERO SUBDIAGONAL ELTS IN */ /* COL J, SET W(J)=0. */ - + L140: idx1 = m; for (l = 1; l <= idx1; ++l) { /* L150: */ b[l] = zz[l]; } - + index[iz] = index[iz1]; index[iz1] = j; ++iz1; nsetp = npp1; ++npp1; - + if (iz1 <= iz2) { idx1 = iz2; for (jz = iz1; jz <= idx1; ++jz) { jj = index[jz]; - h12(c__2, &nsetp, &npp1, m, - &a[j * a_dim1 + 1], &c__1, &up, - &a[jj * a_dim1 + 1], &c__1, &mda, &c__1); + h12(c__2, &nsetp, &npp1, m, + &a[j * a_dim1 + 1], &c__1, &up, + &a[jj * a_dim1 + 1], &c__1, &mda, &c__1); /* L160: */ } } - + if (nsetp != m) { idx1 = m; for (l = npp1; l <= idx1; ++l) { @@ -236,19 +215,19 @@ a[l + j * a_dim1] = 0.; } } - + w[j] = 0.; /* SOLVE THE TRIANGULAR SYSTEM. */ - /* STORE THE SOLUTION TEMPORARILY IN ZZ(). + /* STORE THE SOLUTION TEMPORARILY IN ZZ(). */ rtnkey = 1; goto L400; L200: - + /* ****** SECONDARY LOOP BEGINS HERE ****** */ - + /* ITERATION COUNTER. */ - + L210: ++iter; if (iter > itmax) { @@ -261,10 +240,10 @@ fflush(stdout); goto L350; } - + /* SEE IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE. */ /* IF NOT COMPUTE ALPHA. */ - + alpha = 2.; idx1 = nsetp; for (ip = 1; ip <= idx1; ++ip) { @@ -272,83 +251,83 @@ if (zz[ip] <= 0.) { t = -x[l] / (zz[ip] - x[l]); if (alpha > t) { - alpha = t; - jj = ip; + alpha = t; + jj = ip; } } /* L240: */ } - + /* IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE THEN ALPHA WILL */ /* STILL = 2. IF SO EXIT FROM SECONDARY LOOP TO MAIN LOOP. */ - + if (alpha == 2.) { goto L330; } - + /* OTHERWISE USE ALPHA WHICH WILL BE BETWEEN 0. AND 1. TO */ /* INTERPOLATE BETWEEN THE OLD X AND THE NEW ZZ. */ - + idx1 = nsetp; for (ip = 1; ip <= idx1; ++ip) { l = index[ip]; x[l] += alpha * (zz[ip] - x[l]); /* L250: */ } - + /* MODIFY A AND B AND THE INDEX ARRAYS TO MOVE COEFFICIENT I */ /* FROM SET P TO SET Z. */ - + i__ = index[jj]; L260: x[i__] = 0.; - + if (jj != nsetp) { ++jj; idx1 = nsetp; for (j = jj; j <= idx1; ++j) { ii = index[j]; index[j - 1] = ii; - g1(&a[j - 1 + ii * a_dim1], &a[j + ii * a_dim1], - &cc, &ss, &a[j - 1 + ii * a_dim1]); + g1(&a[j - 1 + ii * a_dim1], &a[j + ii * a_dim1], + &cc, &ss, &a[j - 1 + ii * a_dim1]); // SS: CHECK THIS DAMAGE... a[j + ii * a_dim1] = 0.; idx2 = n; for (l = 1; l <= idx2; ++l) { - if (l != ii) { - - /* Apply procedure G2 (CC,SS,A(J-1,L),A(J, - L)) */ - - temp = a[j - 1 + l * a_dim1]; - // SS: CHECK THIS DAMAGE - a[j - 1 + l * a_dim1] = cc * temp + ss * a[j + l * a_dim1]; - a[j + l * a_dim1] = -ss * temp + cc * a[j + l * a_dim1]; - } - /* L270: */ + if (l != ii) { + + /* Apply procedure G2 (CC,SS,A(J-1,L),A(J, + L)) */ + + temp = a[j - 1 + l * a_dim1]; + // SS: CHECK THIS DAMAGE + a[j - 1 + l * a_dim1] = cc * temp + ss * a[j + l * a_dim1]; + a[j + l * a_dim1] = -ss * temp + cc * a[j + l * a_dim1]; + } + /* L270: */ } - + /* Apply procedure G2 (CC,SS,B(J-1),B(J)) */ - + temp = b[j - 1]; b[j - 1] = cc * temp + ss * b[j]; b[j] = -ss * temp + cc * b[j]; /* L280: */ } } - + npp1 = nsetp; --nsetp; --iz1; index[iz1] = i__; - - /* SEE IF THE REMAINING COEFFS IN SET P ARE FEASIBLE. THEY SHOULD + + /* SEE IF THE REMAINING COEFFS IN SET P ARE FEASIBLE. THEY SHOULD */ /* BE BECAUSE OF THE WAY ALPHA WAS DETERMINED. */ /* IF ANY ARE INFEASIBLE IT IS DUE TO ROUND-OFF ERROR. ANY */ /* THAT ARE NONPOSITIVE WILL BE SET TO ZERO */ /* AND MOVED FROM SET P TO SET Z. */ - + idx1 = nsetp; for (jj = 1; jj <= idx1; ++jj) { i__ = index[jj]; @@ -357,9 +336,9 @@ } /* L300: */ } - + /* COPY B( ) INTO ZZ( ). THEN SOLVE AGAIN AND LOOP BACK. */ - + idx1 = m; for (i__ = 1; i__ <= idx1; ++i__) { /* L310: */ @@ -370,7 +349,7 @@ L320: goto L210; /* ****** END OF SECONDARY LOOP ****** */ - + L330: idx1 = nsetp; for (ip = 1; ip <= idx1; ++ip) { @@ -380,12 +359,12 @@ } /* ALL NEW COEFFS ARE POSITIVE. LOOP BACK TO BEGINNING. */ goto L30; - + /* ****** END OF MAIN LOOP ****** */ - + /* COME TO HERE FOR TERMINATION. */ /* COMPUTE THE NORM OF THE FINAL RESIDUAL VECTOR. */ - + L350: sm = 0.; if (npp1 <= m) { @@ -405,10 +384,10 @@ } *rnorm = sqrt(sm); return 0; - + /* THE FOLLOWING BLOCK OF CODE IS USED AS AN INTERNAL SUBROUTINE */ /* TO SOLVE THE TRIANGULAR SYSTEM, PUTTING THE SOLUTION IN ZZ(). */ - + L400: idx1 = nsetp; for (l = 1; l <= idx1; ++l) { @@ -416,8 +395,8 @@ if (l != 1) { idx2 = ip; for (ii = 1; ii <= idx2; ++ii) { - zz[ii] -= a[ii + jj * a_dim1] * zz[ip + 1]; - /* L410: */ + zz[ii] -= a[ii + jj * a_dim1] * zz[ip + 1]; + /* L410: */ } } jj = index[ip]; @@ -428,12 +407,12 @@ case 1: goto L200; case 2: goto L320; } - + /* The next line was added after the f2c translation to keep compilers from complaining about a void return from a non-void function. */ return 0; - + } /* nnls_ */ @@ -441,10 +420,10 @@ { /* System generated locals */ float d; - + static float xr, yr; - - + + if (nnls_abs(*a) > nnls_abs(*b)) { xr = *b / *a; /* Computing 2nd power */ @@ -472,21 +451,21 @@ *sterm = 1.; return 0; } /* g1_ */ - + /* See nnls.h for explanation */ -int h12(int mode, int* lpivot, int* l1, - int m, float* u, int* iue, float* up, float* c__, - int* ice, int* icv, int* ncv) +int h12(int mode, int* lpivot, int* l1, + int m, float* u, int* iue, float* up, float* c__, + int* ice, int* icv, int* ncv) { /* System generated locals */ int u_dim1, u_offset, idx1, idx2; float d, d2; - + /* Builtin functions */ /* The following line was commented out after the f2c translation */ /* float sqrt(); */ - + /* Local variables */ static int incr; static float b; @@ -494,18 +473,18 @@ static float clinv; static int i2, i3, i4; static float cl, sm; - - /* ------------------------------------------------------------------ + + /* ------------------------------------------------------------------ */ /* float precision U(IUE,M) */ - /* ------------------------------------------------------------------ + /* ------------------------------------------------------------------ */ /* Parameter adjustments */ u_dim1 = *iue; u_offset = u_dim1 + 1; u -= u_offset; --c__; - + /* Function Body */ if (0 >= *lpivot || *lpivot >= *l1 || *l1 > m) { return 0; @@ -514,7 +493,7 @@ if (mode == 2) { goto L60; } - /* ****** CONSTRUCT THE TRANSFORMATION. ****** + /* ****** CONSTRUCT THE TRANSFORMATION. ****** */ idx1 = m; for (j = *l1; j <= idx1; ++j) { @@ -552,9 +531,9 @@ *up = u[*lpivot * u_dim1 + 1] - cl; u[*lpivot * u_dim1 + 1] = cl; goto L70; - /* ****** APPLY THE TRANSFORMATION I+U*(U**T)/B TO C. ****** + /* ****** APPLY THE TRANSFORMATION I+U*(U**T)/B TO C. ****** */ - + L60: if (cl <= 0.) { goto L130; @@ -566,9 +545,9 @@ return 0; } b = *up * u[*lpivot * u_dim1 + 1]; - /* B MUST BE NONPOSITIVE HERE. IF B = 0., RETURN. + /* B MUST BE NONPOSITIVE HERE. IF B = 0., RETURN. */ - + if (b >= 0.) { goto L130; } else { @@ -610,5 +589,3 @@ L130: return 0; } /* h12 */ - -