TrackAnalyzer(String[] args) throws Exception {

    JCommander jcommander = new JCommander(c, args);
    jcommander.setProgramName("TrackAnalyzer");
    if ((c.filenames.size() == 0 && Utils.isEmpty(c.filelist)) || c.help) {
      jcommander.usage();
      System.exit(-1);
    }
    if (c.debug) {
      Logger.getLogger(TrackAnalyzer.class.getName()).setLevel(Level.ALL);
    } else {
      Logger.getLogger(TrackAnalyzer.class.getName()).setLevel(Level.WARNING);
    }
    // we have a list, read all the filenames in the list and
    // collect them in 'filenames'
    if (!Utils.isEmpty(c.filelist)) {
      try {
        // use buffering, reading one line at a time
        // FileReader always assumes default encoding is OK!
        BufferedReader input = new BufferedReader(new FileReader(new File(c.filelist)));
        try {
          String line = null; // not declared within while loop
          /*
           * readLine is a bit quirky :
           * it returns the content of a line MINUS the newline.
           * it returns null only for the END of the stream.
           * it returns an empty String if two newlines appear in a row.
           */
          while ((line = input.readLine()) != null) {
            filenames.add(line);
          }
        } finally {
          input.close();
        }
      } catch (IOException ex) {
        ex.printStackTrace();
        System.exit(-1);
      }
    }
    // add filenames from command line
    filenames.addAll(c.filenames);

    if (!Utils.isEmpty(c.writeList)) {
      try {
        writeListWriter = new BufferedWriter(new FileWriter(c.writeList));
      } catch (IOException ex) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
    k = new KeyFinder();
    p = new Parameters();
    p.setHopSize(8192);
  }
  /**
   * This is the main loop of the program. For every file in the filenames list, the file gets
   * decoded and downsampled to a 4410 hz mono wav file. Then key and bpm detectors are run, the
   * result is logged in a txt file and written to the tag if possible.
   */
  public void run() throws ExecutionException {
    int nThreads = Runtime.getRuntime().availableProcessors();
    ExecutorService threadPool = Executors.newFixedThreadPool(nThreads);
    CompletionService<Boolean> pool;
    pool = new ExecutorCompletionService<Boolean>(threadPool);

    nextFile:
    for (String filename : filenames) {
      // new worker thread
      pool.submit(new WorkTrack(filename));
    }
    for (int i = 0; i < filenames.size(); i++) {
      Boolean result;
      // Compute the result
      try {
        result = pool.take().get();
      } catch (InterruptedException e) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, e);
      }
    }
    threadPool.shutdown();
    if (!Utils.isEmpty(c.writeList)) {
      try {
        writeListWriter.close();
      } catch (IOException ex) {
        Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
    System.exit(0);
  }
 /**
  * this writes a line to a txt file with the result of the detection process for one file.
  *
  * @param filename the filename of the audio file we just processed
  * @param key the result of the key detector (or "-")
  * @param bpm the result of the bpm detector (or "-")
  * @param wroteTags true if tags were written successfully
  */
 public void logDetectionResult(String filename, String key, String bpm, boolean wroteTags) {
   if (!Utils.isEmpty(c.writeList)) {
     try {
       writeListWriter.write(filename + ";" + key + ";" + bpm + ";" + wroteTags);
       writeListWriter.newLine();
       writeListWriter.flush();
     } catch (IOException ex) {
       Logger.getLogger(TrackAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
     }
   }
 }