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;
00024
00025 import gnu.getopt.Getopt;
00026
00027 import java.io.IOException;
00028 import java.util.Iterator;
00029 import java.util.ListIterator;
00030 import java.util.Vector;
00031
00032 import javax.sound.sampled.AudioInputStream;
00033 import javax.sound.sampled.AudioFormat;
00034 import javax.sound.sampled.AudioSystem;
00035 import javax.sound.sampled.UnsupportedAudioFileException;
00036
00037 import com.meapsoft.featextractors.AvgMelSpec;
00038 import com.meapsoft.featextractors.FeatureExtractor;
00039 import com.meapsoft.featextractors.MetaFeatureExtractor;
00040
00047 public class FeatExtractor extends MEAPUtil
00048 {
00049
00050 private FeatFile[] featFiles;
00051 private FeatFile outFile = null;
00052
00053
00054 private Vector featExts;
00055
00056 private Vector featExtWeights;
00057
00058 private String feat_names = "";
00059
00060 private boolean clearNonMetaFeatures = true;
00061
00062 public static final int feSamplingRate = 22050;
00063
00064 public static int nfft = 1024;
00065 public static int nhop = 256;
00066
00067
00068
00069 private int stftBufferSize = 2000;
00070
00075 public FeatExtractor(String infile, String outfile, Vector extractors)
00076 {
00077 this(new FeatFile(infile), new FeatFile(outfile), extractors);
00078 }
00079
00084 public FeatExtractor(FeatFile infile, FeatFile outfile, Vector extractors)
00085 {
00086 this((FeatFile[])null, outfile, extractors);
00087
00088 featFiles = new FeatFile[1];
00089 featFiles[0] = infile;
00090 }
00091
00096 public FeatExtractor(FeatFile[] infiles, FeatFile outfile, Vector extractors)
00097 {
00098 featFiles = infiles;
00099 outFile = outfile;
00100 featExts = extractors;
00101
00102 if(extractors.size() == 0)
00103 extractors.add(new AvgMelSpec());
00104 }
00105
00106 public void printUsageAndExit()
00107 {
00108 System.out.println("Usage: FeatExtractor [-options] file1.feat file2.feat ... \n\n" +
00109 " where options include:\n" +
00110 " -o output_file append features into output file (defaults to input file)\n" +
00111 " -w winSize set STFT window size in seconds (defaults to "+getWindowSize()+")\n" +
00112 " -o hopSize set STFT hop size in seconds (defaults to "+getHopSize()+")" +
00113 "");
00114 printCommandLineOptions('f');
00115 System.out.println();
00116 System.exit(0);
00117 }
00118
00122 public FeatExtractor(String[] args)
00123 {
00124 if(args.length == 0)
00125 printUsageAndExit();
00126
00127
00128 String argString = "f:o:w:h:";
00129 featExts = parseFeatureExtractor(args, argString);
00130
00131 Getopt opt = new Getopt("FeatExtracter", args, argString);
00132 opt.setOpterr(false);
00133
00134 int c = -1;
00135 while ((c = opt.getopt()) != -1)
00136 {
00137 switch(c)
00138 {
00139 case 'o':
00140 outFile = new FeatFile(opt.getOptarg());
00141 break;
00142 case 'h':
00143 setHopSize(Double.parseDouble(opt.getOptarg()));
00144 break;
00145 case 'w':
00146 setWindowSize(Double.parseDouble(opt.getOptarg()));
00147 break;
00148 case 'f':
00149 break;
00150 case '?':
00151 printUsageAndExit();
00152 break;
00153 default:
00154 System.out.print("getopt() returned " + c + "\n");
00155 }
00156 }
00157
00158
00159 int ind = opt.getOptind();
00160 if(ind > args.length)
00161 printUsageAndExit();
00162
00163 featFiles = new FeatFile[args.length - ind];
00164 for(int i=ind; i<args.length; i++)
00165 featFiles[i-ind] = new FeatFile(args[i]);
00166
00167
00168 for(int i = 0; i < featExts.size(); i++)
00169 feat_names += featExts.get(i).getClass().getName() + " ";
00170
00171 feat_names = feat_names.substring(0, feat_names.length()-1);
00172 }
00173
00174 public void setup() throws IOException, ParserException
00175 {
00176 for(int i = 0; i < featFiles.length; i++)
00177 if(!featFiles[i].haveReadFile)
00178 featFiles[i].readFile();
00179 }
00180
00181
00185 public FeatFile[] processFeatFiles() throws IOException, UnsupportedAudioFileException
00186 {
00187 for(int i = 0; i < featFiles.length; i++)
00188 processFeatFile(featFiles[i]);
00189
00190 return featFiles;
00191 }
00192
00196 public FeatFile processFeatFile(FeatFile f) throws IOException, UnsupportedAudioFileException
00197 {
00198 FeatFile file = (FeatFile)f.clone();
00199
00200
00201 progress.setMinimum(0);
00202 progress.setMaximum(file.chunks.size()*featExts.size());
00203 progress.setValue(0);
00204
00205 STFT stft = null;
00206
00207 boolean wroteFeatDesc = false;
00208
00209 String lastAudioFile = "";
00210 file.chunks = new MinHeap(file.chunks);
00211 ((MinHeap)file.chunks).sort();
00212 Iterator c = file.chunks.iterator();
00213
00214
00215
00216 while(c.hasNext())
00217 {
00218 FeatChunk ch = (FeatChunk)c.next();
00219
00220
00221 if(!ch.srcFile.equals(lastAudioFile))
00222 {
00223 AudioInputStream ais = openInputStream(ch.srcFile);
00224
00225
00226 AudioFormat fmt = new AudioFormat(feSamplingRate,
00227 format.getSampleSizeInBits(),
00228 format.getChannels(),
00229 MEAPUtil.signed,
00230 format.isBigEndian());
00231 ais = AudioSystem.getAudioInputStream(format, ais);
00232
00233 stft = new STFT(ais, nfft, nhop, stftBufferSize);
00234 }
00235 lastAudioFile = ch.srcFile;
00236
00237
00238 ListIterator i = featExts.listIterator();
00239 while(i.hasNext())
00240 {
00241 FeatureExtractor fe = (FeatureExtractor)i.next();
00242
00243 if (!(fe instanceof MetaFeatureExtractor))
00244 {
00245 long chunkStartFrame = stft.seconds2fr(ch.startTime);
00246 int nframes = (int)stft.seconds2fr(ch.length);
00247 long chunkEndFrame = chunkStartFrame + nframes;
00248
00249
00250 long lastFrame = stft.getLastFrameAddress();
00251 if(chunkStartFrame > lastFrame)
00252 stft.readFrames(chunkStartFrame - lastFrame + nframes + 1);
00253 else if(chunkEndFrame > lastFrame)
00254 stft.readFrames(chunkEndFrame - lastFrame + 1);
00255
00256
00257 double[] feats = fe.features(stft, (int)chunkStartFrame, nframes);
00258
00259 ch.addFeature(feats);
00260
00261
00262 if(!wroteFeatDesc)
00263 {
00264 String featString = fe.getClass().getName() + "(" + feats.length + ") ";
00265 if(featExtWeights != null)
00266 {
00267 int idx = i.nextIndex()-1;
00268 if(idx < featExtWeights.size())
00269 featString = featExtWeights.get(idx)+"*"+featString;
00270 }
00271 file.featureDescriptions.add(featString);
00272 }
00273 }
00274
00275 progress.setValue(progress.getValue()+1);
00276 }
00277
00278 wroteFeatDesc = true;
00279 }
00280
00281
00282 boolean descriptionsCleared = false;
00283 ListIterator i = featExts.listIterator();
00284 while(i.hasNext())
00285 {
00286 FeatureExtractor fe = (FeatureExtractor)i.next();
00287 if (fe instanceof MetaFeatureExtractor)
00288 {
00289 if (!descriptionsCleared)
00290 {
00291 if(clearNonMetaFeatures)
00292 file.featureDescriptions.clear();
00293
00294 file.normalizeFeatures();
00295 file.applyFeatureWeights();
00296
00297 descriptionsCleared = true;
00298 }
00299
00300
00301 ((MetaFeatureExtractor)fe).features(file, clearNonMetaFeatures);
00302
00303
00304 String featString = fe.getClass().getName() + "(" + 1 + ") ";
00305 if(featExtWeights != null)
00306 {
00307 int idx = i.nextIndex()-1;
00308 if(idx < featExtWeights.size())
00309 featString = featExtWeights.get(idx)+"*"+featString;
00310 }
00311 file.featureDescriptions.add(featString);
00312
00313 progress.setValue(progress.getValue()+1);
00314 }
00315 }
00316
00317 stft.stop();
00318
00319 if(outFile != null)
00320 {
00321 outFile.chunks.addAll(file.chunks);
00322 outFile.featureDescriptions = new Vector(file.featureDescriptions);
00323
00324
00325 outFile.haveReadFile = true;
00326 }
00327
00328 return file;
00329 }
00330
00331
00335 public void run()
00336 {
00337 try
00338 {
00339 setup();
00340 }
00341 catch(Exception e)
00342 {
00343 exceptionHandler.handleException(e);
00344 }
00345
00346 FeatFile fn = outFile;
00347
00348
00349 for(int i = 0; i < featFiles.length; i++)
00350 {
00351 if(outFile == null)
00352 fn = featFiles[i];
00353
00354 if(verbose)
00355 System.out.println("Extracting features (" + feat_names +
00356 ") from " + featFiles[i].filename + " to "
00357 + fn.filename + ".");
00358
00359 long startTime = System.currentTimeMillis();
00360 try
00361 {
00362 FeatFile f = processFeatFile(featFiles[i]);
00363 if(writeMEAPFile)
00364 f.writeFile(fn.filename);
00365 }
00366 catch(Exception e)
00367 {
00368 exceptionHandler.handleException(e);
00369 }
00370
00371 if(verbose)
00372 System.out.println("Done. Took " +
00373 ((System.currentTimeMillis() - startTime)/1000.0)
00374 + "s");
00375 }
00376 }
00377
00382 public void setFeatureExtractorWeights(Vector v)
00383 {
00384 featExtWeights = v;
00385 }
00386
00387
00391 public void setClearNonMetaFeatures(boolean clearNonMF)
00392 {
00393 clearNonMetaFeatures = clearNonMF;
00394 }
00395
00396
00402 public void setWindowSize(double winSize)
00403 {
00404 nfft = (int)(winSize*feSamplingRate);
00405 nfft = (int)(winSize);
00406
00407 System.out.println("window size = " + winSize + ", nfft = " + nfft);
00408 }
00409
00415 public void setHopSize(double hopSize)
00416 {
00417 nhop = (int)(hopSize*feSamplingRate);
00418 nhop = (int)(hopSize);
00419
00420 System.out.println("hop size = " + hopSize + ", nhop = " + nhop);
00421 }
00422
00426 public double getWindowSize()
00427 {
00428 return (double)nfft/feSamplingRate;
00429 }
00430
00434 public double getHopSize()
00435 {
00436 return (double) nhop/feSamplingRate;
00437 }
00438
00439 public static void main(String[] args)
00440 {
00441 FeatExtractor o2or = new FeatExtractor(args);
00442 o2or.verbose = true;
00443 o2or.run();
00444 System.exit(0);
00445 }
00446 }
00447