00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package com.meapsoft.featextractors;
00024
00025 import java.util.Arrays;
00026
00027 import com.meapsoft.MEAPUtil;
00028 import com.meapsoft.RingMatrix;
00029 import com.meapsoft.STFT;
00030
00040 public class AvgChroma extends FeatureExtractor {
00041
00042
00043 static final int FIRSTBAND = 3;
00044
00045 double[][] chromaWts;
00046 double[] linSpec;
00047 int N, outDim;
00048
00049
00050
00051 public double hz2octs(double fq) {
00052 return Math.log(fq / 440.0)/0.69314718055995;
00053 }
00054
00055
00056 public AvgChroma() {
00057
00058
00059 this(1025, 12, MEAPUtil.samplingRate);
00060 }
00061
00062 public AvgChroma(int N, int outDim, double sampleRate) {
00063 this.N = N;
00064 this.outDim = outDim;
00065 linSpec = new double[N];
00066
00067 chromaWts = new double[outDim][N];
00068
00069
00070
00071 double bin2hz = sampleRate / (2*(N-1));
00072 for (int i = FIRSTBAND; i < N; ++i) {
00073 double tot = 0;
00074
00075
00076 double binwidth = hz2octs(bin2hz*(i+1)) - hz2octs(bin2hz*(i-1));
00077 if ( binwidth < 0.083333)
00078 binwidth = 0.083333;
00079 binwidth /= 4;
00080 double binocts = hz2octs(bin2hz*i);
00081
00082 double binwt = 1.0;
00083 if (bin2hz*i > 1000)
00084 binwt = Math.exp( -(bin2hz*i - 1000)/500);
00085 for (int j = 0; j < outDim; ++j) {
00086 double bindelta = binocts - (((double)j)/outDim);
00087 bindelta = bindelta - Math.rint(bindelta);
00088 chromaWts[j][i] = binwt*Math.exp(-0.5*Math.pow(bindelta/binwidth,2));
00089 tot = tot + chromaWts[j][i];
00090 }
00091
00092 for (int j = 0; j < outDim; ++j) {
00093 chromaWts[j][i] /= tot;
00094 }
00095 }
00096 }
00097
00098
00099 public double[] features(STFT stft, long startFrame, int length) {
00100 int boff = 0;
00101 double[] chromSpec = new double[boff + outDim];
00102 double[] curFrame;
00103 double sum = 0;
00104 double sum2 = 0;
00105
00106 boolean recalculateSTFT = stft.getRows() != N;
00107 RingMatrix newstft = null;
00108 if(recalculateSTFT)
00109 {
00110
00111 newstft = STFT.getSTFT(stft.getSamples(startFrame, startFrame+length), (N-1)*2, MEAPUtil.frameSize);
00112
00113 length = newstft.getColumns();
00114 }
00115
00116
00117 Arrays.fill(linSpec, 0);
00118
00119
00120 for(int frame=0; frame<length; frame++) {
00121
00122 if(!recalculateSTFT)
00123 curFrame = stft.getFrame(startFrame+frame);
00124 else
00125 curFrame = newstft.getColumn(frame);
00126
00127 if(curFrame != null)
00128 for(int band=0; band<linSpec.length; band++)
00129 linSpec[band] += Math.pow(10,curFrame[band]/10) / length;
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139 for(int bin=0; bin<outDim; bin++) {
00140 double val = 0;
00141 for(int band=FIRSTBAND; band<linSpec.length; band++) {
00142 val += linSpec[band] * chromaWts[bin][band];
00143 }
00144 chromSpec[boff+bin] = val;
00145 sum += val;
00146 sum2 += val*val;
00147 }
00148
00149
00150 double mean = sum/outDim;
00151 double sd = Math.sqrt( sum2/outDim - Math.pow(mean,2));
00152 double rms = Math.sqrt(sum2/outDim);
00153 for(int bin=0; bin<outDim; bin++) {
00154
00155 chromSpec[boff+bin] = chromSpec[boff+bin]/rms;
00156 }
00157
00158
00159 if (boff > 0) {
00160
00161 double re = 0, im = 0;
00162 for (int bin = 0; bin < outDim; ++bin) {
00163 re = re + chromSpec[boff+bin] * Math.cos(6.28318531*bin/outDim);
00164 im = im + chromSpec[boff+bin] * Math.sin(6.28318531*bin/outDim);
00165 }
00166
00167 double meanchrom = outDim * (Math.atan2(im, re) / 6.28318531);
00168
00169
00170 if (meanchrom < 0)
00171 meanchrom += outDim;
00172
00173 chromSpec[0] = meanchrom;
00174
00175 }
00176 return chromSpec;
00177 }
00178
00179
00180 public String description()
00181 {
00182 return "I am a generic FeatureExtractor";
00183 }
00184 }