Package com.neophob.sematrix.core.sound

Source Code of com.neophob.sematrix.core.sound.SoundMinim

/**
* Copyright (C) 2011-2013 Michael Vogt <michu@neophob.com>
*
* This file is part of PixelController.
*
* PixelController is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PixelController 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 PixelController.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.neophob.sematrix.core.sound;

import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import ddf.minim.AudioInput;
import ddf.minim.Minim;
import ddf.minim.analysis.BeatDetect;
import ddf.minim.analysis.FFT;

/**
* The Class SoundMinim.
*/
public final class SoundMinim implements ISound, Runnable {

  //samples per 1/4s
  /** The Constant SOUND_BUFFER_RESOLUTION. */
  private static final int SOUND_BUFFER_RESOLUTION = 8;

  /** The log. */
  private static final Logger LOG = Logger.getLogger(SoundMinim.class.getName());

  /** The minim. */
  private Minim minim;
 
  /** The in. */
  private AudioInput in;
 
  /** The beat. */
  private BeatDetect beat;
 
  /** The bl. */
  @SuppressWarnings("unused")
  private BeatListener bl;

  /** The fft. */
  private FFT fft;

  /* thread to collect volume information */
  /** The runner. */
  private Thread runner;

  /** The snd volume max. */
  private float sndVolumeMax=0;

  private float silenceThreshold;
  private long dropedVolumeRequests;
 
  /**
   * Instantiates a new sound minim.
   */
  public SoundMinim(float silenceThreshold) {
    minim = new Minim(this);
    //in = minim.getLineIn( Minim.STEREO, 512 );
    in = minim.getLineIn( Minim.MONO, 1024 );

    // a beat detection object that is FREQ_ENERGY mode that
    // expects buffers the length of song's buffer size
    // and samples captured at songs's sample rate
    beat = new BeatDetect(in.bufferSize(), in.sampleRate());

    // set the sensitivity to 300 milliseconds
    // After a beat has been detected, the algorithm will wait for 300 milliseconds
    // before allowing another beat to be reported. You can use this to dampen the
    // algorithm if it is giving too many false-positives. The default value is 10,
    // which is essentially no damping. If you try to set the sensitivity to a negative value,
    // an error will be reported and it will be set to 10 instead.
    beat.setSensitivity(250);
    beat.detectMode(BeatDetect.FREQ_ENERGY);

    bl = new BeatListener(beat, in);    

    fft = new FFT(in.bufferSize(), in.sampleRate());
    fft.window(FFT.HAMMING);
    fft.logAverages(120,4); // 32 bands
   
    this.silenceThreshold = silenceThreshold;
   
    this.runner = new Thread(this);
    this.runner.setName("ZZ Sound stuff");
    this.runner.setDaemon(true);
    this.runner.start();
  }

  /**
   * Minim requirement
   * @param fileName
   * @return
   */
  public String sketchPath(String fileName) {
    LOG.log(Level.INFO, "Not implemented, not used, sketchPath: "+fileName);
    return "";
  }

  /**
   * Minim requirement
   * @param fileName
   * @return
   */
  public InputStream createInput(String fileName) {
    LOG.log(Level.INFO, "Not implemented, not used, createInput: "+fileName);
    return null;
  }

  /**
   * Gets the current level of the buffer. It is calculated as
   * the root-mean-squared of all the samples in the buffer.
   * @return the RMS amplitude of the buffer
   */
  public float getVolume() {
    return getVolumeNormalized();
  }

  /* (non-Javadoc)
   * @see com.neophob.sematrix.core.input.SeSound#getVolumeNormalized()
   */
  public float getVolumeNormalized() {
    float max = getSndVolumeMax();   
    //volume is too low, normalization would create wrong results.
    if (max<silenceThreshold) {
      dropedVolumeRequests++;
      if (dropedVolumeRequests%1000==0) {
        LOG.log(Level.INFO, "Ignored volume request, as volume is too low ("+ max +
            "), this happend "+ dropedVolumeRequests+" times.");
      }
      return 0;
    }
   
    float f = in.mix.level();   
    float norm=(1.0f/max)*f; 

    //im a bad coder! limit it!
    if (norm>1f) {
      norm=1f;   
    }

    return norm;
  }

  /* (non-Javadoc)
   * @see com.neophob.sematrix.core.input.SeSound#isKick()
   */
  public boolean isKick() {
    return beat.isKick();
  }

  /* (non-Javadoc)
   * @see com.neophob.sematrix.core.input.SeSound#isSnare()
   */
  public boolean isSnare() {
    return beat.isSnare();
  }

  /* (non-Javadoc)
   * @see com.neophob.sematrix.core.input.SeSound#isHat()
   */
  public boolean isHat() {
    return beat.isHat();
  }

  /* (non-Javadoc)
   * @see com.neophob.sematrix.core.input.SeSound#isPang()
   */
  public boolean isPang() {
    return beat.isHat() || beat.isKick() || beat.isSnare();
  }

  /**
   * Returns the number of averages currently being calculated.
   *
   * @return the fft avg
   */
  public int getFftAvg() {
    // perform a forward FFT on the samples
    fft.forward(in.mix);

    return fft.avgSize();
  }
 
  /**
   * Gets the value of the ith average.
   *
   * @param i the i
   * @return the fft avg
   */
  public float getFftAvg(int i) {
    return fft.getAvg(i);
  }

 
  /* (non-Javadoc)
   * @see com.neophob.sematrix.core.input.SeSound#shutdown()
   */
  public void shutdown() {
    in.close();
    minim.stop();
  }

  /**
   * Dispose.
   */
  public void dispose() {   
    runner = null;
    //XXX     this.shutdown();
  }

  /**
   * the thread runner.
   */
  public void run() {
    long sleep = (int)(250/SOUND_BUFFER_RESOLUTION);
    LOG.log(Level.INFO,  "Sound thread started...");
    int loop=0;
    while (Thread.currentThread() == runner) {
      try {
        Thread.sleep(sleep);
      } catch (InterruptedException e) {}

      // perform a forward FFT on the samples
//      fft.forward(in.mix);
     
      //decrement max volume after 1/4s
      if (loop>SOUND_BUFFER_RESOLUTION) {
        sndVolumeMax*=.93f;
      }

      float f = in.mix.level();
      if (f>sndVolumeMax) {
        sndVolumeMax=f;
        loop=0;
      }

      loop++;
    }
  }


  /**
   * Gets the snd volume max.
   *
   * @return the snd volume max
   */
  public synchronized float getSndVolumeMax() {
    return sndVolumeMax;
  }


  @Override
  public String getImplementationName() {   
    return "Minim Sound";
  }

}
TOP

Related Classes of com.neophob.sematrix.core.sound.SoundMinim

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.