Main Page   Class Hierarchy   Compound List   File List   Compound Members  

FeatExtractor.java

00001 /*
00002  *  Copyright 2006 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.Vector;
00030 
00031 import javax.sound.sampled.AudioInputStream;
00032 
00033 import com.meapsoft.featextractors.AvgMelSpec;
00034 import com.meapsoft.featextractors.FeatureExtractor;
00035 
00042 public class FeatExtractor extends MEAPUtil
00043 {
00044     // Files to use
00045     FeatFile[] featFiles;
00046     FeatFile outFile = null;
00047     
00048     // all of our feature extractors...
00049     Vector featExts;
00050     String feat_names = "";
00051 
00056     public FeatExtractor(String infile, String outfile, Vector extractors)
00057     {
00058         this(new FeatFile(infile), new FeatFile(outfile), extractors);
00059     }
00060 
00065     public FeatExtractor(FeatFile infile, FeatFile outfile, Vector extractors)
00066     {
00067         this((FeatFile[])null, outfile, extractors);       
00068         
00069         featFiles = new FeatFile[1];
00070         featFiles[0] = infile;
00071     }
00072 
00077     public FeatExtractor(FeatFile[] infiles, FeatFile outfile, Vector extractors)
00078     {
00079         featFiles = infiles;
00080         outFile = outfile;
00081         featExts = extractors;
00082 
00083         if(extractors.size() == 0)
00084             extractors.add(new AvgMelSpec());
00085     }
00086 
00087     public void printUsageAndExit() 
00088     {
00089         System.out.println("Usage: FeatExtractor [-options] file1.feat file2.feat ... \n\n" + 
00090              "  where options include:\n" + 
00091              "    -o output_file  append features into output file (defaults to input file)");
00092         printCommandLineOptions('f');
00093         System.out.println();
00094         System.exit(0);
00095     }
00096 
00100     public FeatExtractor(String[] args) 
00101     {
00102         if(args.length == 0)
00103             printUsageAndExit();
00104         
00105         // Parse arguments
00106         String argString = "f:o:";
00107         featExts = parseFeatureExtractor(args, argString);
00108 
00109         Getopt opt = new Getopt("FeatExtracter", args, argString);
00110         opt.setOpterr(false);
00111         
00112         int c = -1;
00113         while ((c = opt.getopt()) != -1) 
00114         {
00115             switch(c) 
00116             {
00117             case 'o':
00118                 outFile = new FeatFile(opt.getOptarg());
00119                 break;
00120             case 'f': // already handled above
00121                 break;
00122             case '?':
00123                 printUsageAndExit();
00124                 break;
00125             default:
00126                 System.out.print("getopt() returned " + c + "\n");
00127             }
00128         }
00129         
00130         // parse arguments
00131         int ind = opt.getOptind();
00132         if(ind > args.length)
00133             printUsageAndExit();
00134 
00135         featFiles = new FeatFile[args.length - ind];
00136         for(int i=ind; i<args.length; i++)
00137             featFiles[i-ind] = new FeatFile(args[i]);
00138         
00139         // What are the feature names?
00140         for(int i = 0; i < featExts.size(); i++)
00141             feat_names += featExts.get(i).getClass().getName() + " ";
00142         //chop off last space
00143         feat_names = feat_names.substring(0, feat_names.length()-1);
00144     }
00145 
00146     public void setup() throws IOException, ParserException
00147     {
00148         for(int i = 0; i < featFiles.length; i++) 
00149             if(!featFiles[i].haveReadFile)
00150                 featFiles[i].readFile();
00151     }
00152  
00153 
00157     public FeatFile[] processFeatFiles() throws IOException
00158     {
00159         for(int i = 0; i < featFiles.length; i++) 
00160             processFeatFile(featFiles[i]);
00161 
00162         return featFiles;
00163     }
00164 
00168     public FeatFile processFeatFile(FeatFile f) throws IOException
00169     {
00170         FeatFile file = (FeatFile)f.clone();
00171 
00172         STFT stft = null;
00173 
00174         file.featureDescription = "";
00175         boolean wroteFeatDesc = false;
00176         
00177         String lastAudioFile="";
00178         Iterator c = file.chunks.iterator();
00179         while(c.hasNext())
00180         {
00181             FeatChunk ch = (FeatChunk)c.next();
00182 
00183             // lets get some new features
00184             // compute the STFT of the whole file if this is the first 
00185             // time we have seen it
00186             if(!ch.srcFile.equals(lastAudioFile))
00187             {
00188                 AudioInputStream ais = openInputStream(ch.srcFile);
00189 
00190                 // store STFT of the whole file
00191                 int histSize = (int)(ais.getFrameLength()/frameSize); 
00192 
00193                 // weird bug when reading in some MP3 files -
00194                 // ais.getFrameLength() returns -1 for some reason.
00195                 // Hardcode a history of 10 minutes for this (I hope
00196                 // you have a lot of RAM).  Hopefully this is big
00197                 // enough to hold the entire file - problems will
00198                 // occur when reading in files that are longer than 10
00199                 // minutes and are affected by this bug
00200                 if(histSize <= 0)
00201                 {
00202                     histSize = 10*60*samplingRate/frameSize;
00203                     System.out.println("Warning - problem reading audio file... guessing file length.  If this doesn't "
00204                                        + "work like you expected it to, try again with a 44.1kHz mono WAV file.");
00205                 }
00206 
00207                 stft = new STFT(ais, frameSize, histSize);
00208                 stft.start();
00209                 ais.close();
00210             }
00211             lastAudioFile = ch.srcFile;
00212 
00213             // compute features from the STFT
00214             Iterator i = featExts.listIterator();
00215             while(i.hasNext())
00216             {
00217                 FeatureExtractor fe = (FeatureExtractor)i.next();
00218                 double[] feats = fe.features(stft, stft.seconds2fr(ch.startTime), 
00219                                              (int)stft.seconds2fr(ch.length));
00220                 ch.addFeature(feats);
00221 
00222                 // what features are we adding?  
00223                 if(!wroteFeatDesc)
00224                     file.featureDescription += fe.getClass().getName() + "(" + feats.length + ") ";
00225             }
00226 
00227             wroteFeatDesc = true;
00228         }
00229 
00230         if(outFile != null)
00231         {
00232             outFile.chunks.addAll(file.chunks);
00233             outFile.featureDescription = file.featureDescription;
00234             
00235             // outFile now contains some chunks.
00236             outFile.haveReadFile = true;
00237         }
00238 
00239         return file;
00240     }
00241     
00242 
00246     public void go() 
00247     {
00248         try
00249         {
00250             setup();
00251         }
00252         catch(Exception e) 
00253         {
00254             e.printStackTrace();
00255             System.exit(1);
00256         }
00257 
00258         FeatFile fn = outFile;
00259 
00260         // process supplied files
00261         for(int i = 0; i < featFiles.length; i++) 
00262         {
00263             if(outFile == null)
00264                 fn = featFiles[i];
00265             System.out.println("Extracting features (" + feat_names + 
00266                                ") from " + featFiles[i].filename + " to " 
00267                                + fn.filename + "."); 
00268             
00269             long startTime = System.currentTimeMillis();
00270             try
00271             {
00272                 FeatFile f = processFeatFile(featFiles[i]);
00273                 f.writeFile(fn.filename);
00274             }
00275             catch(Exception e) 
00276             {
00277                 e.printStackTrace();
00278                 System.exit(1);
00279             }
00280             System.out.println("Done.  Took " + 
00281                                ((System.currentTimeMillis() - startTime)/1000.0)
00282                                + "s");
00283         }
00284     }
00285     
00286     
00287     public static void main(String[] args) 
00288     {
00289         FeatExtractor o2or = new FeatExtractor(args);
00290         o2or.go();
00291         System.exit(0);
00292     }
00293 }
00294 

Generated on Thu May 11 15:04:10 2006 for MEAPsoft by doxygen1.2.18