package totem.sound;
import java.io.File;
import java.io.IOException;
import java.util.Observer;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import processing.core.PApplet;
import ddf.minim.AudioInput;
import ddf.minim.AudioPlayer;
import ddf.minim.Minim;
import ddf.minim.analysis.BeatDetect;
/**
* Wrapper for processing player and beat detection functionality. It can send
* audio signals to the output and receive them through the microphone.
* The output signal will be analyzed by the beat detection.
* @author alex
*
*/
public class TPlayer {
Minim minim;
AudioInput in;
AudioPlayer player;
BeatDetect beat;
TBeatListener bl;
TPlayerThread runnable;
SongQueue songs;
/**
* Initialize the TPlayer object. the parent object is needed to initialize the
* sound framework minim. Later the minim object is held directly and the parent
* reference is not used anylonger. The file given will be played if the player
* is activated.
* @param file mp3 file to be player
*/
public TPlayer(PApplet parent, String file){
this.minim = new Minim(parent);
this.in = minim.getLineIn(Minim.STEREO, 512);
this.player = minim.loadFile(file);
beat = new BeatDetect(this.player.bufferSize(), 44100.0f);
beat.detectMode(BeatDetect.FREQ_ENERGY);
beat.setSensitivity(1);
bl = new TBeatListener(beat, this.player);
}
public SongQueue getSongs() {
return this.songs;
}
/** Returns the audio input source offered by minim.
*
*/
public AudioInput getInput(){
return this.in;
};
// TODO let this method break to eliminate calls
/**
* Starts playing the actual song in a loop.
*/
public void play(){
this.player.loop();
}
//TODO ganz machen
/**
* Set the volume of the output.
* @param gain the new gain volume
*/
public void setGain(float gain){
this.player.setGain(gain);
}
/**
* Returns the actual input noise level.
* @return actual microphone noise level
*/
public float getInLevel(){
return this.in.left.level();
}
public float getOutLevel(){
return this.player.left.level();
}
/**
* Returns if a beat is detected right now or not. Right now the implementation
* just includes lower pitch beat detection and has to be called manually.
* @return
*/
public boolean beatDetected(){
boolean is = this.beat.isKick();
return is;
};
public byte[] loadSample(String fileString) {
AudioInputStream ain;
File file = new File(fileString);
byte bs[] = new byte[0];
try {
ain = AudioSystem.getAudioInputStream(file);
// How long, in *samples*, is the file?
long len = ain.getFrameLength();
// 16-bit audio means 4 bytes per sample, so we need
// a byte array twice as long as the number of samples
bs = new byte[(int) len * 4];
// Read everything, and make sure we got it all
int r = ain.read(bs);
if (r != len * 4)
throw new RuntimeException("Read only " + r + " of " + file
+ " out of " + (len * 4) + " sound bytes");
} catch (UnsupportedAudioFileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
System.out.println("could not load " + file.getAbsolutePath());
e.printStackTrace();
}
return bs;
}
//TODO ganz machen
/**
* Shut down the TPlayer. This method stops the song and shut down the minim
* framework. It should be called if the application is terminated to avoid locks
* of the audio channels.
*/
public void shutdown(){
//player.close();
in.close();
minim.stop();
}
public void addAudioObserver(Observer o){
this.player.addAudioObserver(o);
}
public void addToQueue(String file){
byte[] sample = this.loadSample(file);
if (sample.length > 0){
this.player.getPlayList().add(sample);
}
}
}