This works with the latest nightly build:
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.*;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.openal.AL10.*;
import static org.lwjgl.openal.ALC10.*;
import static org.lwjgl.system.MemoryUtil.*;
public final class Synth {
public static void main(String[] args) throws Exception {
long device = alcOpenDevice((ByteBuffer)null);
if ( device == NULL )
throw new IllegalStateException("Failed to open the default device.");
ALCCapabilities deviceCaps = ALC.createCapabilities(device);
long context = alcCreateContext(device, (IntBuffer)null);
if ( context == NULL )
throw new IllegalStateException("Failed to create an OpenAL context.");
alcMakeContextCurrent(context);
AL.createCapabilities(deviceCaps);
// a sound maker
int source = alGenSources();
// hold new data for transfer to AL
ByteBuffer pcm = BufferUtils.createByteBuffer(11025); // about 1/4 second at 44.1khz
float ang = 0;
// throw 3 chunks of sound into a queue
for ( int i = 0; i < 3; i++ ) {
ang = fillBuffer(ang, pcm);
int b = alGenBuffers();
alBufferData(b, AL_FORMAT_MONO8, pcm, 44100);
AL10.alSourceQueueBuffers(source, b);
}
System.out.println("Playing sound ...");
alSourcePlay(source);
boolean done = false;
int elapsed = 0;
while ( !done ) {
// processed since last asked
int p = alGetSourcei(source, AL_BUFFERS_PROCESSED);
while ( p != 0 ) {
elapsed++;
if ( elapsed > 15 ) break; // stop adding to queue
// at least 1 buffer had played so remove it from the queue
int b = alSourceUnqueueBuffers(source);
// refill the next byte buffer with the next chunk of sound
ang = fillBuffer(ang, pcm);
// send the buffer to AL
alBufferData(b, AL_FORMAT_MONO8, pcm, 44100);
// requeue the buffer
alSourceQueueBuffers(source, b);
// check if any more buffers have played
p = alGetSourcei(source, AL_BUFFERS_PROCESSED);
}
Thread.sleep(20); // lets not hog the cpu... (we're not some crappy AAA game!)
// just to show if we stop filling buffers it stops!
if ( alGetSourcei(source, AL_SOURCE_STATE) == AL_STOPPED ) {
done = true;
System.out.println("source stopped ");
}
}
alcDestroyContext(context);
alcCloseDevice(device);
}
// make a new chunk of sound picking off from where we where
// when we made the last chunk of sound
static int trig = -1;
public static float fillBuffer(float ang, ByteBuffer buff) {
int size = buff.capacity();
trig++;
for ( int i = 0; i < size; i++ ) {
int source1 = (int)(Math.sin(ang) * 127 + 128);
int source2 = 0;
if ( trig > 1 ) source2 = (int)(Math.sin(ang * 4) * 127 + 128);
if ( trig > 2 ) trig = 0;
// yes this really is how you do it.... *sigh*
buff.put(i, (byte)((source1 + source2) / 2));
ang += 0.1f;
}
return ang;
}
}
The ALContext class was a simple wrapper over a context handle and has been removed.