I have a bunch of code that will, when run, produce procedural sound. Unfortunately, it only lasts a few seconds. Ideally it would run until I tell it to stop. I'm not talking about looping, the algorithm to generate it provides 2^64 samples, at the moment, so it isn't going to run out within the foreseeable future. The constructor for AudioInputStream takes a third input, which I could ideally just remove. I could just provide a huge number, but that seems like the wrong way to go about it.
I thought about using SourceDataLine, but the algorithm ideally would be called on-demand, not running ahead and writing the path. Thoughts?
It seems I've answered my own question.
Upon further research, using the SourceDataLine
is the way to go, as it'll block when you've given it enough to work with.
Apologies for the lack of proper Javadoc.
class SoundPlayer
{
// plays an InputStream for a given number of samples, length
public static void play(InputStream stream, float sampleRate, int sampleSize, int length) throws LineUnavailableException
{
// you can specify whatever format you want...I just don't need much flexibility here
AudioFormat format = new AudioFormat(sampleRate, sampleSize, 1, false, true);
AudioInputStream audioStream = new AudioInputStream(stream, format, length);
Clip clip = AudioSystem.getClip();
clip.open(audioStream);
clip.start();
}
public static void play(InputStream stream, float sampleRate, int sampleSize) throws LineUnavailableException
{
AudioFormat format = new AudioFormat(sampleRate, sampleSize, 1, false, true);
SourceDataLine line = AudioSystem.getSourceDataLine(format);
line.open(format);
line.start();
// if you wanted to block, you could just run the loop in here
SoundThread soundThread = new SoundThread(stream, line);
soundThread.start();
}
private static class SoundThread extends Thread
{
private static final int buffersize = 1024;
private InputStream stream;
private SourceDataLine line;
SoundThread(InputStream stream, SourceDataLine line)
{
this.stream = stream;
this.line = line;
}
public void run()
{
byte[] b = new byte[buffersize];
// you could, of course, have a way of stopping this...
for (;;)
{
stream.read(b);
line.write(b, 0, buffersize);
}
}
}
}