Main Page   Packages   Class Hierarchy   Compound List   File List   Compound Members  

FeatExtractor.java

00001 /*
00002  *  Copyright 2006-2007 Columbia University.
00003  *
00004  *  This file is part of MEAPsoft.
00005  *
00006  *  MEAPsoft is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License version 2 as
00008  *  published by the Free Software Foundation.
00009  *
00010  *  MEAPsoft is distributed in the hope that it will be useful, but
00011  *  WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with MEAPsoft; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00018  *  02110-1301 USA
00019  *
00020  *  See the file "COPYING" for the text of the license.
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     // Files to use
00050     private FeatFile[] featFiles;
00051     private FeatFile outFile = null;
00052     
00053     // all of our feature extractors...
00054     private Vector featExts;
00055     // and their associated weights
00056     private Vector featExtWeights;
00057     // names of our feature extractors
00058     private String feat_names = "";
00059     // should this FeatExtractor clear any non meta features?
00060     private boolean clearNonMetaFeatures = true;
00061 
00062     public static final int feSamplingRate = 22050;
00063     // big enough to get good frequency resolution for AvgChroma
00064     public static int nfft = 1024;
00065     public static int nhop = 256;
00066 
00067     // if this buffer is smaller than a chunk's length, that chunk's
00068     // features not be calculated correctly
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         // Parse arguments
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': // already handled above
00149                 break;
00150             case '?':
00151                 printUsageAndExit();
00152                 break;
00153             default:
00154                 System.out.print("getopt() returned " + c + "\n");
00155             }
00156         }
00157         
00158         // parse arguments
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         // What are the feature names?
00168         for(int i = 0; i < featExts.size(); i++)
00169             feat_names += featExts.get(i).getClass().getName() + " ";
00170         //chop off last space
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         // keep track of our progress in extracting features from this FeatFile:
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         //System.out.println("doing regular feature extractors...");
00215         
00216         while(c.hasNext())
00217         {
00218             FeatChunk ch = (FeatChunk)c.next();
00219 
00220             // let's get some new features
00221             if(!ch.srcFile.equals(lastAudioFile))
00222             {
00223                 AudioInputStream ais = openInputStream(ch.srcFile);
00224 
00225                 // resample to feSamplingRate 
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             // compute features from the STFT
00238             ListIterator i = featExts.listIterator();
00239             while(i.hasNext())
00240             {
00241                                 FeatureExtractor fe = (FeatureExtractor)i.next();
00242                                 //we don't want to run meta feature extractors yet!
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                     // make sure stft contains valid data for us.
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                     // what features are we adding?  
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                 //now do meta feature extractors
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                 // this obliterates any other features
00301                 ((MetaFeatureExtractor)fe).features(file, clearNonMetaFeatures);
00302                                 
00303                                 // what features are we adding?  
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             // outFile now contains some chunks.
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         // process supplied files
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 

Generated on Tue Feb 6 19:02:26 2007 for MEAPsoft by doxygen1.2.18