package org.terasology.audio;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.openal.*;
import org.terasology.game.CoreRegistry;
import org.terasology.logic.LocalPlayer;
import org.terasology.logic.manager.AudioManager;
import org.terasology.rendering.cameras.Camera;
import org.terasology.rendering.world.WorldRenderer;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
public class OpenALManager extends AudioManager {
/**
* For faster distance check *
*/
private final static float MAX_DISTANCE_SQUARED = (float) Math.pow(MAX_DISTANCE, 2);
public static OpenALManager getInstance() {
return (OpenALManager) AudioManager.getInstance();
}
@Override
public void initialize() {
logger.info("Initializing OpenAL audio manager");
try {
AL.create();
} catch (LWJGLException e) {
throw new RuntimeException(e);
}
AL10.alGetError();
logger.info("OpenAL " + AL10.alGetString(AL10.AL_VERSION) + " initialized!");
ALCcontext context = ALC10.alcGetCurrentContext();
ALCdevice device = ALC10.alcGetContextsDevice(context);
logger.info("Using OpenAL: " + AL10.alGetString(AL10.AL_RENDERER) + " by " + AL10.alGetString(AL10.AL_VENDOR));
logger.info("Using device: " + ALC10.alcGetString(device, ALC10.ALC_DEVICE_SPECIFIER));
logger.info("Available AL extensions: " + AL10.alGetString(AL10.AL_EXTENSIONS));
logger.info("Available ALC extensions: " + ALC10.alcGetString(device, ALC10.ALC_EXTENSIONS));
IntBuffer buffer = BufferUtils.createIntBuffer(1);
ALC10.alcGetInteger(device, ALC11.ALC_MONO_SOURCES, buffer);
logger.info("Max mono sources: " + buffer.get(0));
buffer.rewind();
ALC10.alcGetInteger(device, ALC11.ALC_STEREO_SOURCES, buffer);
logger.info("Max stereo sources: " + buffer.get(0));
buffer.rewind();
ALC10.alcGetInteger(device, ALC10.ALC_FREQUENCY, buffer);
logger.info("Mixer frequency: " + buffer.get(0));
buffer.rewind();
AL10.alDistanceModel(AL10.AL_INVERSE_DISTANCE_CLAMPED);
// Initialize sound pools
_pools.put("sfx", new BasicSoundPool(30)); // effects pool
_pools.put("music", new BasicStreamingSoundPool(2)); // music pool
}
@Override
public void destroy() {
AL.destroy();
}
@Override
public void update() {
LocalPlayer player = CoreRegistry.get(LocalPlayer.class);
if (player != null) {
Vector3f velocity = player.getVelocity();
// TODO: get this from camera
Vector3f orientation = player.getViewDirection();
AL10.alListener3f(AL10.AL_VELOCITY, velocity.x, velocity.y, velocity.z);
OpenALException.checkState("Setting listener velocity");
FloatBuffer listenerOri = BufferUtils.createFloatBuffer(6).put(new float[]{orientation.x, orientation.y, orientation.z, 0.0f, 1.0f, 0.0f});
listenerOri.flip();
AL10.alListener(AL10.AL_ORIENTATION, listenerOri);
OpenALException.checkState("Setting listener orientation");
}
for (SoundPool pool : _pools.values()) {
pool.update();
}
}
/* @Override
protected Sound createAudio(String name, URL source) {
if (source != null) {
return new OggSound(name, source);
}
return null;
}
@Override
protected Sound createStreamingAudio(String name, URL source) {
return new OggStreamingSound(name, source);
} */
@Override
protected boolean checkDistance(Vector3d soundSource) {
Camera camera = CoreRegistry.get(WorldRenderer.class).getActiveCamera();
if (camera == null) {
return false;
}
Vector3d soundPosition = new Vector3d(soundSource);
soundPosition.sub(camera.getPosition());
return soundPosition.lengthSquared() < MAX_DISTANCE_SQUARED;
}
}