Hello all,
I have some songs I am playing using SourceDataLine and I was wondering if anyone knows if there is a way to start from a specific point in the song. I have a song that has a couple bars of intro before going into the main part, and I want to play the whole song once, then loop starting just after the intro, instead of playing the entire intro again. Here is the class I’m using for reference. Sorry for the wall of code! Also, any constructive criticism of my code is welcome, as I am new to Java’s sound API and coded this as a first effort, referencing members of this site, javadocs, and stackoverflow.com.
package com.noah.breakit.assets;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import com.noah.breakit.util.Util;
public class Song {
// music credit to sketchylogic
public static final Song titlesong = new Song("songs/titlesong.wav");
public static final Song playfieldsong = new Song("songs/playfieldsong.wav");
public static final Song briefingsong = new Song("songs/briefingsong.wav");
public static final Song gameoversong = new Song("songs/gameoversong.wav");
private static boolean playing;
private boolean looping;
private boolean killThread;
private URL url;
private AudioInputStream ais;
private AudioFormat baseFormat;
private AudioFormat decodeFormat;
private DataLine.Info info;
private SourceDataLine sdl;
private FloatControl gainControl;
private String name;
private Song(String filename) {
name = filename;
try {
url = this.getClass().getClassLoader().getResource(filename);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void loopSong() {
SoundThreadPool.execute(new Runnable() {
public void run() {
while (playing){
System.out.println(name + " waiting...");
}//wait for any other song threads to finish executing...
playing = true;
looping = true;
while (looping)
play();
playing = false;
}
});
}
public synchronized void playSong() {
playing = true;
SoundThreadPool.execute(new Runnable() {
public void run() {
play();
playing = false;
}
});
}
private void play() {
try {
ais = AudioSystem.getAudioInputStream(url);
baseFormat = ais.getFormat();
decodeFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
info = new DataLine.Info(SourceDataLine.class, decodeFormat);
sdl = (SourceDataLine) AudioSystem.getLine(info);
sdl.open();
gainControl = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
sdl.start();
int nBytesRead = 0;
byte[] data = new byte[sdl.getBufferSize()];
int offset;
while ((nBytesRead = ais.read(data, 0, data.length)) >= 0) {
offset = 0;
System.out.println(name + " reading...");
while (offset < nBytesRead){
System.out.println(name + " writing...");
offset += sdl.write(data, 0, nBytesRead);
}
if(killThread){
System.out.println(name + " killing...");
break;
}
System.out.println(name + " reading...");
}
System.out.println(name + " draining, stopping, closing...");
sdl.drain();
sdl.stop();
sdl.close();
System.out.println(name + " drain, stop, close complete!");
if(killThread){
looping = false;
killThread = false;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void adjustGain(float gain) {
if (gainControl == null) return;
float value = Util.clamp((gainControl.getValue() + gain), gainControl.getMinimum(), gainControl.getMaximum());
gainControl.setValue(value);
}
public void setGain(float gain) {
gainControl.setValue(Util.clamp(gain, gainControl.getMinimum(), gainControl.getMaximum()));
}
public boolean atMin() {
return gainControl.getValue() == gainControl.getMinimum();
}
public boolean atMax() {
return gainControl.getValue() == gainControl.getMaximum();
}
public boolean isPlaying() {
return playing;
}
public boolean fadeToBlack() {
adjustGain(-0.4f);
if (atMin()){
killThread = true;
System.out.println(name + " killThread set to true...");
}
return atMin();
}
}