Package com.meapsoft

Source Code of com.meapsoft.FeatExtractor

/*
*  Copyright 2006-2007 Columbia University.
*
*  This file is part of MEAPsoft.
*
*  MEAPsoft is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License version 2 as
*  published by the Free Software Foundation.
*
*  MEAPsoft 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 MEAPsoft; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
*  02110-1301 USA
*
*  See the file "COPYING" for the text of the license.
*/

package com.meapsoft;

import gnu.getopt.Getopt;

import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;

import com.meapsoft.featextractors.AvgMelSpec;
import com.meapsoft.featextractors.FeatureExtractor;
import com.meapsoft.featextractors.MetaFeatureExtractor;

/**
* Program that extracts features from the chunks listed in the input files.
*
* @author Ron Weiss (ronw@ee.columbia.edu)
*/
public class FeatExtractor extends MEAPUtil
{
  // Files to use
  private FeatFile[] featFiles;

  private FeatFile outFile = null;

  // all of our feature extractors...
  private Vector featExts;

  // and their associated weights
  private Vector featExtWeights;

  // names of our feature extractors
  private String feat_names = "";

  // should this FeatExtractor clear any non meta features?
  private boolean clearNonMetaFeatures = true;

  public static final int feSamplingRate = 22050;

  // big enough to get good frequency resolution for AvgChroma
  public static int nfft = 1024;

  public static int nhop = 256;

  // if this buffer is smaller than a chunk's length, that chunk's
  // features not be calculated correctly
  // Doulgas upped this to from 2000 to 4000. Shouldn't this be dynamic
  // or set depending on the input .seg file?
 
  // yes, now we're setting this dynamically in setup()
  private int stftBufferSize = 4000;

  /**
   * FeatExtractor constructor. If no extractors is empty, defaults to
   * AvgMelSpec.
   */
  public FeatExtractor(String infile, String outfile, Vector extractors)
  {
    this(new FeatFile(infile), new FeatFile(outfile), extractors);
  }

  /**
   * FeatExtractor constructor. If no extractors is empty, defaults to
   * AvgMelSpec.
   */
  public FeatExtractor(FeatFile infile, FeatFile outfile, Vector extractors)
  {
    this((FeatFile[]) null, outfile, extractors);

    featFiles = new FeatFile[1];
    featFiles[0] = infile;
   
    //System.out.println("FeatExtractor constructor. outfile: " + outfile.filename + " infile: " + infile.filename);
  }

  /**
   * FeatExtractor constructor. If no extractors is empty, defaults to
   * AvgMelSpec.
   */
  public FeatExtractor(FeatFile[] infiles, FeatFile outfile, Vector extractors)
  {
    featFiles = infiles;
    outFile = outfile;
    featExts = extractors;

    if (extractors.size() == 0)
      extractors.add(new AvgMelSpec());
      }

  public void printUsageAndExit()
  {
    System.out
        .println("Usage: FeatExtractor [-options] file1.feat file2.feat ... \n\n"
            + "  where options include:\n"
            + "    -o output_file  append features into output file (defaults to input file)\n"
            + "    -w winSize      set STFT window size in seconds (defaults to "
            + getWindowSize()
            + ")\n"
            + "    -o hopSize      set STFT hop size in seconds (defaults to "
            + getHopSize() + ")" + "");
    printCommandLineOptions('f');
    System.out.println();
    System.exit(0);
  }

  /**
   * FeatExtractor constructor. Parses command line arguments
   */
  public FeatExtractor(String[] args)
  {
    if (args.length == 0)
      printUsageAndExit();

    // Parse arguments
    String argString = "f:o:w:h:";
    featExts = parseFeatureExtractor(args, argString);

    Getopt opt = new Getopt("FeatExtracter", args, argString);
    opt.setOpterr(false);

    int c = -1;
    while ((c = opt.getopt()) != -1)
    {
      switch (c)
      {
      case 'o':
        outFile = new FeatFile(opt.getOptarg());
        break;
      case 'h':
        setHopSize(Double.parseDouble(opt.getOptarg()));
        break;
      case 'w':
        setWindowSize(Double.parseDouble(opt.getOptarg()));
        break;
      case 'f': // already handled above
        break;
      case '?':
        printUsageAndExit();
        break;
      default:
        System.out.print("getopt() returned " + c + "\n");
      }
    }

    // parse arguments
    int ind = opt.getOptind();
    if (ind > args.length)
      printUsageAndExit();

    featFiles = new FeatFile[args.length - ind];
    for (int i = ind; i < args.length; i++)
      featFiles[i - ind] = new FeatFile(args[i]);

    // What are the feature names?
    for (int i = 0; i < featExts.size(); i++)
      feat_names += featExts.get(i).getClass().getName() + " ";
    // chop off last space
    feat_names = feat_names.substring(0, feat_names.length() - 1);
  }

  public void setup() throws IOException, ParserException
  {
    double longestChunk = 0.0;
   
    //System.out.println("featFiles[0].filename: " + featFiles[0].filename);
    //System.out.println("featFiles.length: " + featFiles.length);
   
    for (int i = 0; i < featFiles.length; i++)
    {
      if (!featFiles[i].haveReadFile)
        featFiles[i].readFile();
     
      List chunks = featFiles[i].chunks;
      int numChunks = chunks.size();
     
      //System.out.println("numChunks: " + numChunks);
      for (int j = 0; j < numChunks; j++)
      {
        FeatChunk fC = (FeatChunk)chunks.get(j);
       
        double length = fC.length;
       
        if (length > longestChunk)
          longestChunk = length;
       
        //System.out.println("i: " + i + " j: " + j + " length: " + length + " longest: " + longestChunk);
      }
    }

    stftBufferSize = (int) ((longestChunk * samplingRate)/nhop);
   
    //really short chunks can generate zero length buffers because of int rounding above!
    if (stftBufferSize < 10)
      stftBufferSize = 10;
    //System.out.println("longestChunk: " + longestChunk + " stftBufferSize: " + stftBufferSize);
  }

  /**
   * Where the magic happens. Extract features from featFiles.
   */
  public FeatFile[] processFeatFiles() throws IOException,
      UnsupportedAudioFileException
  {
    for (int i = 0; i < featFiles.length; i++)
      processFeatFile(featFiles[i]);

    return featFiles;
  }

  /**
   * Where the magic happens. Extract features from file.
   */
  public FeatFile processFeatFile(FeatFile f) throws IOException,
      UnsupportedAudioFileException
  {
    FeatFile file = (FeatFile) f.clone();

    // keep track of our progress in extracting features from this FeatFile:
    progress.setMinimum(0);
    progress.setMaximum(file.chunks.size() * featExts.size());
    progress.setValue(0);

    STFT stft = null;

    boolean wroteFeatDesc = false;

    String lastAudioFile = "";
    file.chunks = new Vector(file.chunks);
    Collections.sort(file.chunks);
    Iterator c = file.chunks.iterator();

    // System.out.println("doing regular feature extractors...");

    while (c.hasNext())
    {
      FeatChunk ch = (FeatChunk) c.next();

      // let's get some new features
      if (!ch.srcFile.equals(lastAudioFile))
      {
        AudioReader reader = AudioReaderFactory.getAudioReader(
            ch.srcFile, format);
        stft = new STFT(reader, nfft, nhop, stftBufferSize);
      }
      lastAudioFile = ch.srcFile;

      // compute features from the STFT
      ListIterator i = featExts.listIterator();
      while (i.hasNext())
      {
        FeatureExtractor fe = (FeatureExtractor) i.next();
        // we don't want to run meta feature extractors yet!
        if (!(fe instanceof MetaFeatureExtractor))
        {
          //System.out.println("\ndoing: " + fe.description().substring(0,30));
          long chunkStartFrame = stft.seconds2fr(ch.startTime);
          int nframes = (int) stft.seconds2fr(ch.length);
          long chunkEndFrame = chunkStartFrame + nframes;

          // make sure stft contains valid data for us.
          long lastFrame = stft.getLastFrameAddress();
         
          int numFramesToRead = 0;
          int framesRead = -1;
         
          if (chunkStartFrame > lastFrame)
          {
            numFramesToRead = (int) (chunkStartFrame - lastFrame + nframes + 1);
            framesRead = stft.readFrames(numFramesToRead);
            //System.out.println("chunkStartFrame > lastFrame");
          }
          else if (chunkEndFrame > lastFrame)
          {
            numFramesToRead = (int) (chunkEndFrame - lastFrame + 1);
            framesRead = stft.readFrames(numFramesToRead);
            //System.out.println("chunkEndFrame > lastFrame");
          }
         
          //System.out.println("chunkStartFrame: " + chunkStartFrame + " nframes: " + nframes +
          //    " chunkEndFrame: " + chunkEndFrame + " numFramesToRead: " + numFramesToRead +
          //    " framesRead: " + framesRead + " lastFrame: " + lastFrame);
          double[] feats = fe.features(stft, (int) chunkStartFrame,
              nframes, true);

          ch.addFeature(feats);

          // what features are we adding?
          if (!wroteFeatDesc)
          {
            String fullName = fe.getClass().getName();
            //System.out.println("fullName: " + fullName);
            String[] nameParts = fullName.split("\\.");
            String featString = nameParts[nameParts.length - 1] + "("
                + feats.length + ") ";
            //System.out.println("featString: " + featString);
            if (featExtWeights != null)
            {
              int idx = i.nextIndex() - 1;
              if (idx < featExtWeights.size())
                featString = featExtWeights.get(idx) + "*"
                    + featString;
            }
            file.featureDescriptions.add(featString);
          }
        }

        progress.setValue(progress.getValue() + 1);
      }

      wroteFeatDesc = true;
    }

    // now do meta feature extractors
    boolean descriptionsCleared = false;
    ListIterator i = featExts.listIterator();
    while (i.hasNext())
    {
      FeatureExtractor fe = (FeatureExtractor) i.next();
      if (fe instanceof MetaFeatureExtractor)
      {
        if (!descriptionsCleared)
        {
          if (clearNonMetaFeatures)
            file.featureDescriptions.clear();

          file.normalizeFeatures();
          file.applyFeatureWeights();

          descriptionsCleared = true;
        }

        // this obliterates any other features
        ((MetaFeatureExtractor) fe)
            .features(file, clearNonMetaFeatures);

        // what features are we adding?
        String featString = fe.getClass().getName() + "(" + 1 + ") ";
        if (featExtWeights != null)
        {
          int idx = i.nextIndex() - 1;
          if (idx < featExtWeights.size())
            featString = featExtWeights.get(idx) + "*" + featString;
        }
        file.featureDescriptions.add(featString);

        progress.setValue(progress.getValue() + 1);
      }
    }

    stft.stop();

    if (outFile != null)
    {
      outFile.chunks.addAll(file.chunks);
      outFile.featureDescriptions = new Vector(file.featureDescriptions);

      // outFile now contains some chunks.
      outFile.haveReadFile = true;
    }

    return file;
  }

  /**
   * Set everything up, process input, and write output.
   */
  public void run()
  {
    try
    {
      setup();
    }
    catch (Exception e)
    {
      exceptionHandler.handleException(e);
    }

    FeatFile fn = outFile;

    // process supplied files
    for (int i = 0; i < featFiles.length; i++)
    {
      if (outFile == null)
        fn = featFiles[i];

      if (verbose)
        System.out.println("Extracting features (" + feat_names
            + ") from " + featFiles[i].filename + " to "
            + fn.filename + ".");

      long startTime = System.currentTimeMillis();
      try
      {
        FeatFile f = processFeatFile(featFiles[i]);
        if (writeMEAPFile)
          f.writeFile(fn.filename);
      }
      catch (Exception e)
      {
        exceptionHandler.handleException(e);
      }

      if (verbose)
        System.out.println("Done.  Took "
            + ((System.currentTimeMillis() - startTime) / 1000.0)
            + "s");
    }
  }

  /**
   * Set weights associated with the different FeatureExtractors used by this
   * object.
   */
  public void setFeatureExtractorWeights(Vector v)
  {
    featExtWeights = v;
  }

  /**
   * Should this FeatExtractor clear any non meta features?
   */
  public void setClearNonMetaFeatures(boolean clearNonMF)
  {
    clearNonMetaFeatures = clearNonMF;
  }

  /**
   * Set the STFT window size for the feature extractors to use.
   *
   * @param winSize -
   *            window size in seconds
   */
  public void setWindowSize(double winSize)
  {
    nfft = (int) (winSize * feSamplingRate);
    nfft = (int) (winSize);

    System.out.println("window size = " + winSize + ", nfft = " + nfft);
  }

  /**
   * Set the STFT hop size for the feature extractors to use.
   *
   * @param hopSize -
   *            hop size in seconds
   */
  public void setHopSize(double hopSize)
  {
    nhop = (int) (hopSize * feSamplingRate);
    nhop = (int) (hopSize);

    System.out.println("hop size = " + hopSize + ", nhop = " + nhop);
  }

  /**
   * Get the STFT window size used by the feature extractors.
   */
  public double getWindowSize()
  {
    return (double) nfft / feSamplingRate;
  }

  /**
   * Get the STFT hop size used by the feature extractors.
   */
  public double getHopSize()
  {
    return (double) nhop / feSamplingRate;
  }

  public static void main(String[] args)
  {
    FeatExtractor o2or = new FeatExtractor(args);
    o2or.verbose = true;
    o2or.run();
    System.exit(0);
  }
}
TOP

Related Classes of com.meapsoft.FeatExtractor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.