Reworked audio
This commit is contained in:
parent
ececa9506d
commit
f3ec9911ae
@ -18,7 +18,7 @@
|
|||||||
package ru.windcorp.progressia.client;
|
package ru.windcorp.progressia.client;
|
||||||
|
|
||||||
import ru.windcorp.progressia.ProgressiaLauncher;
|
import ru.windcorp.progressia.ProgressiaLauncher;
|
||||||
import ru.windcorp.progressia.client.audio.backend.ALTest;
|
import ru.windcorp.progressia.client.audio.ALTest;
|
||||||
|
|
||||||
public class ProgressiaClientMain {
|
public class ProgressiaClientMain {
|
||||||
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
public class ALTest {
|
||||||
|
static private void initializeAL() {
|
||||||
|
AudioManager.initAL();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadALData() {
|
||||||
|
AudioManager.loadSound("assets/sounds/sample_stereo.ogg",
|
||||||
|
"Progressia", "SampleStereo",
|
||||||
|
AudioFormat.STEREO);
|
||||||
|
Music music = new Music("Progressia", "SampleStereo");
|
||||||
|
music.play(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void killALData() {
|
||||||
|
//TODO implement the method or its analogue
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute() {
|
||||||
|
initializeAL();
|
||||||
|
loadALData();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
public enum AudioFormat {
|
||||||
|
MONO, STEREO
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
import org.lwjgl.openal.AL;
|
||||||
|
import org.lwjgl.openal.ALC;
|
||||||
|
import org.lwjgl.openal.ALCCapabilities;
|
||||||
|
import org.lwjgl.openal.ALCapabilities;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.AudioReader;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.Listener;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||||
|
|
||||||
|
import static org.lwjgl.openal.AL11.*;
|
||||||
|
import static org.lwjgl.openal.ALC10.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AudioManager {
|
||||||
|
private static long device;
|
||||||
|
private static ALCCapabilities deviceCapabilities;
|
||||||
|
private static ALCapabilities alCapabilities;
|
||||||
|
|
||||||
|
private static final int SOUNDS_NUM = 64;
|
||||||
|
private static int lastSoundIndex = 0;
|
||||||
|
|
||||||
|
private static List<Speaker> soundSpeakers = new ArrayList<>(SOUNDS_NUM);
|
||||||
|
private static Speaker musicSpeaker;
|
||||||
|
private static ArrayList<SoundType> soundsBuffer = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void initAL() {
|
||||||
|
String defaultDeviceName = alcGetString(
|
||||||
|
0,
|
||||||
|
ALC_DEFAULT_DEVICE_SPECIFIER
|
||||||
|
);
|
||||||
|
|
||||||
|
device = alcOpenDevice(defaultDeviceName);
|
||||||
|
|
||||||
|
int[] attributes = new int[1];
|
||||||
|
long context = alcCreateContext(device, attributes);
|
||||||
|
alcMakeContextCurrent(context);
|
||||||
|
|
||||||
|
deviceCapabilities = ALC.createCapabilities(device);
|
||||||
|
alCapabilities = AL.createCapabilities(deviceCapabilities);
|
||||||
|
|
||||||
|
checkALError();
|
||||||
|
createBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void update() {
|
||||||
|
// Position of the listener
|
||||||
|
Listener.getInstance().update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Speaker getLastSpeaker() {
|
||||||
|
Speaker speaker;
|
||||||
|
do {
|
||||||
|
lastSoundIndex++;
|
||||||
|
if (lastSoundIndex >= SOUNDS_NUM) {
|
||||||
|
lastSoundIndex = 0;
|
||||||
|
}
|
||||||
|
speaker = soundSpeakers.get(lastSoundIndex);
|
||||||
|
} while (speaker.getState()
|
||||||
|
.equals(Speaker.State.PLAYING_LOOP));
|
||||||
|
return speaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SoundType findSoundType(String soundID) throws Exception {
|
||||||
|
for (SoundType s : soundsBuffer) {
|
||||||
|
if (s.getId().equals(soundID)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("ERROR: The selected sound is not loaded or" +
|
||||||
|
" not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Speaker initSpeaker(String soundID) {
|
||||||
|
Speaker speaker = getLastSpeaker();
|
||||||
|
try {
|
||||||
|
findSoundType(soundID).initSpeaker(speaker);
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
return speaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Speaker initMusicSpeaker(String soundID) {
|
||||||
|
try {
|
||||||
|
findSoundType(soundID).initSpeaker(musicSpeaker);
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
return musicSpeaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkALError() {
|
||||||
|
int errorCode = alGetError();
|
||||||
|
if (alGetError() != AL_NO_ERROR) {
|
||||||
|
throw new RuntimeException(String.valueOf(errorCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadSound(String path, String namespace, String name,
|
||||||
|
AudioFormat format) {
|
||||||
|
if (format == AudioFormat.MONO) {
|
||||||
|
soundsBuffer.add(AudioReader.readAsMono(path, namespace, name));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
soundsBuffer.add(AudioReader.readAsStereo(path, namespace, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeAL() {
|
||||||
|
//clearSounds();
|
||||||
|
//TODO replace alDeleteSources(SOURCES);
|
||||||
|
for (Speaker s : soundSpeakers) {
|
||||||
|
alDeleteBuffers(s.getAudioData());
|
||||||
|
}
|
||||||
|
alcCloseDevice(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ALCapabilities getALCapabilities() {
|
||||||
|
return alCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ALCCapabilities getDeviceCapabilities() {
|
||||||
|
return deviceCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createBuffers()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SOUNDS_NUM; ++i) {
|
||||||
|
soundSpeakers.add(new Speaker());
|
||||||
|
}
|
||||||
|
|
||||||
|
musicSpeaker = new Speaker();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
package ru.windcorp.progressia.client.audio;
|
|
||||||
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
import ru.windcorp.progressia.common.resource.*;
|
|
||||||
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.nio.ShortBuffer;
|
|
||||||
|
|
||||||
import static org.lwjgl.stb.STBVorbis.*;
|
|
||||||
import static org.lwjgl.openal.AL10.*;
|
|
||||||
|
|
||||||
public class AudioReader {
|
|
||||||
|
|
||||||
private AudioReader() {};
|
|
||||||
|
|
||||||
// TODO fix converting from mono-stereo
|
|
||||||
|
|
||||||
private static SoundType readAsSpecified(String audioName, int format) {
|
|
||||||
IntBuffer channelBuffer = BufferUtils.createIntBuffer(1);
|
|
||||||
IntBuffer rateBuffer = BufferUtils.createIntBuffer(1);
|
|
||||||
|
|
||||||
Resource res = ResourceManager.getResource(audioName);
|
|
||||||
|
|
||||||
ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer);
|
|
||||||
|
|
||||||
return new SoundType(rawAudio, format, rateBuffer.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoundType readAsMono(String audioName) {
|
|
||||||
return readAsSpecified(audioName, AL_FORMAT_MONO16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SoundType readAsStereo(String audioName) {
|
|
||||||
return readAsSpecified(audioName, AL_FORMAT_STEREO16);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ShortBuffer decodeVorbis(
|
|
||||||
Resource dataToDecode,
|
|
||||||
IntBuffer channelsBuffer,
|
|
||||||
IntBuffer rateBuffer
|
|
||||||
) {
|
|
||||||
return stb_vorbis_decode_memory(
|
|
||||||
dataToDecode.readAsBytes(),
|
|
||||||
channelsBuffer,
|
|
||||||
rateBuffer
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
76
src/main/java/ru/windcorp/progressia/client/audio/Music.java
Normal file
76
src/main/java/ru/windcorp/progressia/client/audio/Music.java
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||||
|
import ru.windcorp.progressia.common.util.Namespaced;
|
||||||
|
|
||||||
|
public class Music
|
||||||
|
extends Namespaced {
|
||||||
|
private Vec3 position = new Vec3();
|
||||||
|
private Vec3 velocity = new Vec3();
|
||||||
|
private float pitch = 1.0f;
|
||||||
|
private float gain = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
|
public Music(String namespace,
|
||||||
|
String name)
|
||||||
|
{
|
||||||
|
super(namespace, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Music(String namespace,
|
||||||
|
String name,
|
||||||
|
Vec3 position,
|
||||||
|
Vec3 velocity,
|
||||||
|
float pitch,
|
||||||
|
float gain)
|
||||||
|
{
|
||||||
|
this(namespace, name);
|
||||||
|
this.position = position;
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play(boolean loop)
|
||||||
|
{
|
||||||
|
Speaker speaker = AudioManager.initMusicSpeaker(this.getId());
|
||||||
|
speaker.setGain(gain);
|
||||||
|
speaker.setPitch(pitch);
|
||||||
|
speaker.setPosition(position);
|
||||||
|
speaker.setVelocity(velocity);
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
speaker.playLoop();
|
||||||
|
} else {
|
||||||
|
speaker.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO implement
|
||||||
|
public void stop() {}
|
||||||
|
|
||||||
|
public void setGain(float gain) {
|
||||||
|
this.gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPitch(float pitch) { this.pitch = pitch; }
|
||||||
|
|
||||||
|
public void setVelocity(Vec3 velocity) {
|
||||||
|
this.velocity = velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getPosition() { return position; }
|
||||||
|
|
||||||
|
public float getGain() {
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getVelocity() {
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
}
|
@ -1,142 +0,0 @@
|
|||||||
package ru.windcorp.progressia.client.audio;
|
|
||||||
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
import static org.lwjgl.openal.AL11.*;
|
|
||||||
|
|
||||||
public class Sound {
|
|
||||||
|
|
||||||
// Buffers
|
|
||||||
private int audio;
|
|
||||||
private int source;
|
|
||||||
|
|
||||||
// Characteristics
|
|
||||||
private FloatBuffer position = (FloatBuffer) BufferUtils.createFloatBuffer(
|
|
||||||
3
|
|
||||||
).put(new float[] {
|
|
||||||
0.0f, 0.0f, 0.0f
|
|
||||||
}).rewind();
|
|
||||||
|
|
||||||
private FloatBuffer velocity = (FloatBuffer) BufferUtils.createFloatBuffer(
|
|
||||||
3
|
|
||||||
).put(new float[] {
|
|
||||||
0.0f, 0.0f, 0.0f
|
|
||||||
}).rewind();
|
|
||||||
|
|
||||||
private float pitch = 1.0f;
|
|
||||||
private float gain = 1.0f;
|
|
||||||
|
|
||||||
public Sound() {}
|
|
||||||
|
|
||||||
public Sound(int audio, int source) {
|
|
||||||
setAudio(audio);
|
|
||||||
setSource(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Sound(
|
|
||||||
int audio,
|
|
||||||
FloatBuffer position,
|
|
||||||
FloatBuffer velocity,
|
|
||||||
float pitch,
|
|
||||||
float gain
|
|
||||||
) {
|
|
||||||
setAudio(audio);
|
|
||||||
setPosition(position);
|
|
||||||
setVelocity(velocity);
|
|
||||||
setPitch(pitch);
|
|
||||||
setGain(gain);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Sound(
|
|
||||||
FloatBuffer position,
|
|
||||||
FloatBuffer velocity,
|
|
||||||
float pitch,
|
|
||||||
float gain
|
|
||||||
) {
|
|
||||||
setPosition(position);
|
|
||||||
setVelocity(velocity);
|
|
||||||
setPitch(pitch);
|
|
||||||
setGain(gain);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playOnce() {
|
|
||||||
alSourcePlay(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playLoop() {
|
|
||||||
alSourcei(source, AL_LOOPING, AL_TRUE);
|
|
||||||
playOnce();
|
|
||||||
alSourcei(source, AL_LOOPING, AL_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
alSourceStop(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void pause() {
|
|
||||||
alSourcePause(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPlaying() {
|
|
||||||
final int state = alGetSourcei(source, AL_SOURCE_STATE);
|
|
||||||
return state == AL_PLAYING;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAudio() {
|
|
||||||
return audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAudio(int audio) {
|
|
||||||
this.audio = audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSource(int source) {
|
|
||||||
this.source = source;
|
|
||||||
alSourcei(this.source, AL_BUFFER, audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
// OTHER
|
|
||||||
|
|
||||||
public void setPosition(FloatBuffer position) {
|
|
||||||
this.position = position;
|
|
||||||
alSourcefv(source, AL_POSITION, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FloatBuffer getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVelocity(FloatBuffer velocity) {
|
|
||||||
alSourcefv(source, AL_VELOCITY, velocity);
|
|
||||||
this.velocity = velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FloatBuffer getVelocity() {
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPitch(float pitch) {
|
|
||||||
alSourcef(source, AL_PITCH, pitch);
|
|
||||||
this.pitch = pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getPitch() {
|
|
||||||
return pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGain(float gain) {
|
|
||||||
alSourcef(source, AL_GAIN, gain);
|
|
||||||
this.gain = gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getGain() {
|
|
||||||
return gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,83 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.Speaker;
|
||||||
|
import ru.windcorp.progressia.common.util.Namespaced;
|
||||||
|
|
||||||
|
public class SoundEffect
|
||||||
|
extends Namespaced {
|
||||||
|
|
||||||
|
private Vec3 position = new Vec3();
|
||||||
|
private Vec3 velocity = new Vec3();
|
||||||
|
private float pitch = 1.0f;
|
||||||
|
private float gain = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
|
public SoundEffect(String namespace,
|
||||||
|
String name)
|
||||||
|
{
|
||||||
|
super(namespace, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SoundEffect(String namespace,
|
||||||
|
String name,
|
||||||
|
Vec3 position,
|
||||||
|
Vec3 velocity,
|
||||||
|
float pitch,
|
||||||
|
float gain)
|
||||||
|
{
|
||||||
|
this(namespace, name);
|
||||||
|
this.position = position;
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play(boolean loop)
|
||||||
|
{
|
||||||
|
Speaker speaker = AudioManager.initSpeaker(this.getId());
|
||||||
|
speaker.setGain(gain);
|
||||||
|
speaker.setPitch(pitch);
|
||||||
|
speaker.setPosition(position);
|
||||||
|
speaker.setVelocity(velocity);
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
speaker.playLoop();
|
||||||
|
} else {
|
||||||
|
speaker.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO implement
|
||||||
|
public void stop() {}
|
||||||
|
|
||||||
|
public void setGain(float gain) {
|
||||||
|
this.gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPitch(float pitch) { this.pitch = pitch; }
|
||||||
|
|
||||||
|
public void setPosition(Vec3 position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVelocity(Vec3 velocity) {
|
||||||
|
this.velocity = velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getGain() {
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getVelocity() {
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
}
|
@ -1,107 +0,0 @@
|
|||||||
package ru.windcorp.progressia.client.audio;
|
|
||||||
|
|
||||||
import org.lwjgl.openal.AL;
|
|
||||||
import org.lwjgl.openal.ALC;
|
|
||||||
import org.lwjgl.openal.ALCCapabilities;
|
|
||||||
import org.lwjgl.openal.ALCapabilities;
|
|
||||||
|
|
||||||
import static org.lwjgl.openal.AL11.*;
|
|
||||||
import static org.lwjgl.openal.ALC10.*;
|
|
||||||
|
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
|
||||||
|
|
||||||
public class SoundManager {
|
|
||||||
|
|
||||||
private static final int SOURCES_NUM = 64;
|
|
||||||
private static int lastSourceIndex = -1;
|
|
||||||
private static final int[] SOURCES = new int[SOURCES_NUM];
|
|
||||||
|
|
||||||
private static final ArrayBlockingQueue<Sound> SOUNDS =
|
|
||||||
new ArrayBlockingQueue<>(SOURCES_NUM);
|
|
||||||
|
|
||||||
private static long device;
|
|
||||||
|
|
||||||
private static ALCCapabilities deviceCapabilities;
|
|
||||||
private static ALCapabilities alCapabilities;
|
|
||||||
|
|
||||||
public static void initAL() {
|
|
||||||
String defaultDeviceName = alcGetString(
|
|
||||||
0,
|
|
||||||
ALC_DEFAULT_DEVICE_SPECIFIER
|
|
||||||
);
|
|
||||||
|
|
||||||
device = alcOpenDevice(defaultDeviceName);
|
|
||||||
|
|
||||||
int[] attributes = new int[1];
|
|
||||||
long context = alcCreateContext(device, attributes);
|
|
||||||
alcMakeContextCurrent(context);
|
|
||||||
|
|
||||||
deviceCapabilities = ALC.createCapabilities(device);
|
|
||||||
alCapabilities = AL.createCapabilities(deviceCapabilities);
|
|
||||||
|
|
||||||
checkALError();
|
|
||||||
|
|
||||||
alGenSources(SOURCES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void update() {
|
|
||||||
// Position of the listener
|
|
||||||
Listener.getInstance().update();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addSound(Sound sound) {
|
|
||||||
if (!SOUNDS.offer(sound)) {
|
|
||||||
Sound polled = SOUNDS.poll();
|
|
||||||
assert polled != null;
|
|
||||||
polled.stop();
|
|
||||||
if (!SOUNDS.offer(sound)) {
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getNextSource() {
|
|
||||||
if (++lastSourceIndex > SOURCES_NUM)
|
|
||||||
lastSourceIndex = 0;
|
|
||||||
return SOURCES[lastSourceIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Sound createSound(SoundType soundType) {
|
|
||||||
Sound sound = soundType.genSoundSource(getNextSource());
|
|
||||||
addSound(sound);
|
|
||||||
return sound;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearSounds() {
|
|
||||||
Sound polled = SOUNDS.poll();
|
|
||||||
while (polled != null) {
|
|
||||||
polled.stop();
|
|
||||||
polled = SOUNDS.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkALError() {
|
|
||||||
int errorCode = alGetError();
|
|
||||||
if (alGetError() != AL_NO_ERROR) {
|
|
||||||
throw new RuntimeException(String.valueOf(errorCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void closeAL() {
|
|
||||||
clearSounds();
|
|
||||||
alDeleteSources(SOURCES);
|
|
||||||
for (Sound s : SOUNDS) {
|
|
||||||
alDeleteBuffers(s.getAudio());
|
|
||||||
}
|
|
||||||
alcCloseDevice(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ALCapabilities getALCapabilities() {
|
|
||||||
return alCapabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ALCCapabilities getDeviceCapabilities() {
|
|
||||||
return deviceCapabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package ru.windcorp.progressia.client.audio;
|
|
||||||
|
|
||||||
import java.nio.ShortBuffer;
|
|
||||||
import static org.lwjgl.openal.AL11.*;
|
|
||||||
|
|
||||||
public class SoundType {
|
|
||||||
|
|
||||||
private ShortBuffer rawAudio;
|
|
||||||
private int sampleRate;
|
|
||||||
private int format;
|
|
||||||
|
|
||||||
public SoundType(ShortBuffer rawAudio, int format, int sampleRate) {
|
|
||||||
this.rawAudio = rawAudio;
|
|
||||||
this.sampleRate = sampleRate;
|
|
||||||
this.format = format;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int genEmptyAudio() {
|
|
||||||
return alGenBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int genEmptySource() {
|
|
||||||
return alGenSources();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int genAudio() {
|
|
||||||
int audio = alGenBuffers();
|
|
||||||
alBufferData(audio, format, rawAudio, sampleRate);
|
|
||||||
return audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Sound genSoundSource() {
|
|
||||||
return new Sound(genAudio(), alGenSources());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Sound genSoundSource(int source) {
|
|
||||||
if (!alIsSource(source))
|
|
||||||
throw new RuntimeException();
|
|
||||||
|
|
||||||
return new Sound(genAudio(), source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Sound genSoundSource(int source, int audio) {
|
|
||||||
if (!alIsBuffer(audio) || !alIsSource(source))
|
|
||||||
throw new RuntimeException();
|
|
||||||
|
|
||||||
alBufferData(audio, format, rawAudio, sampleRate);
|
|
||||||
return new Sound(audio, alGenSources());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package ru.windcorp.progressia.client.audio.backend;
|
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.audio.AudioReader;
|
|
||||||
import ru.windcorp.progressia.client.audio.Sound;
|
|
||||||
import ru.windcorp.progressia.client.audio.SoundManager;
|
|
||||||
|
|
||||||
public class ALTest {
|
|
||||||
static private void initializeAL() {
|
|
||||||
SoundManager.initAL();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadALData() {
|
|
||||||
Sound music = SoundManager.createSound(AudioReader.readAsMono("assets/sounds/sample_mono.ogg"));
|
|
||||||
music.playOnce();
|
|
||||||
/*music = SoundManager.createSound(AudioReader.readAsStereo("assets/sounds/sample_mono.ogg"));
|
|
||||||
music.playOnce();*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static void killALData() {
|
|
||||||
//TODO implement the method or its analogue
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void execute() {
|
|
||||||
initializeAL();
|
|
||||||
loadALData();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,54 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio.backend;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import ru.windcorp.progressia.client.audio.backend.SoundType;
|
||||||
|
import ru.windcorp.progressia.common.resource.*;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.stb.STBVorbis.*;
|
||||||
|
import static org.lwjgl.openal.AL10.*;
|
||||||
|
|
||||||
|
public class AudioReader {
|
||||||
|
|
||||||
|
private AudioReader() {}
|
||||||
|
|
||||||
|
// TODO fix converting from mono-stereo
|
||||||
|
// TODO change audio naming from full path to just name
|
||||||
|
private static SoundType readAsSpecified(String path, String audioNamespace,
|
||||||
|
String audioName, int format) {
|
||||||
|
IntBuffer channelBuffer = BufferUtils.createIntBuffer(1);
|
||||||
|
IntBuffer rateBuffer = BufferUtils.createIntBuffer(1);
|
||||||
|
|
||||||
|
Resource res = ResourceManager.getResource(path);
|
||||||
|
|
||||||
|
ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer);
|
||||||
|
|
||||||
|
return new SoundType(audioNamespace ,audioName, rawAudio, format,
|
||||||
|
rateBuffer.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SoundType readAsMono(String path, String audioNamespace,
|
||||||
|
String audioName) {
|
||||||
|
return readAsSpecified(path, audioNamespace,
|
||||||
|
audioName, AL_FORMAT_MONO16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SoundType readAsStereo(String path,String audioNamespace,
|
||||||
|
String audioName) {
|
||||||
|
return readAsSpecified(path, audioNamespace, audioName, AL_FORMAT_STEREO16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShortBuffer decodeVorbis(
|
||||||
|
Resource dataToDecode,
|
||||||
|
IntBuffer channelsBuffer,
|
||||||
|
IntBuffer rateBuffer
|
||||||
|
) {
|
||||||
|
return stb_vorbis_decode_memory(
|
||||||
|
dataToDecode.readAsBytes(),
|
||||||
|
channelsBuffer,
|
||||||
|
rateBuffer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package ru.windcorp.progressia.client.audio;
|
package ru.windcorp.progressia.client.audio.backend;
|
||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
import ru.windcorp.progressia.client.Client;
|
import ru.windcorp.progressia.client.Client;
|
@ -0,0 +1,41 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio.backend;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.util.Namespaced;
|
||||||
|
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
import static org.lwjgl.openal.AL11.*;
|
||||||
|
|
||||||
|
public class SoundType extends Namespaced {
|
||||||
|
|
||||||
|
private ShortBuffer rawAudio;
|
||||||
|
private int sampleRate;
|
||||||
|
private int format;
|
||||||
|
private int audioBuffer;
|
||||||
|
|
||||||
|
public SoundType(String namespace, String name, ShortBuffer rawAudio,
|
||||||
|
int format, int sampleRate) {
|
||||||
|
super(namespace, name);
|
||||||
|
this.rawAudio = rawAudio;
|
||||||
|
this.sampleRate = sampleRate;
|
||||||
|
this.format = format;
|
||||||
|
createAudioBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createAudioBuffer() {
|
||||||
|
this.audioBuffer = alGenBuffers();
|
||||||
|
alBufferData(audioBuffer, format, rawAudio, sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO What is this (Eugene Smirnov)
|
||||||
|
private Speaker createSound(int source, int audio) {
|
||||||
|
if (!alIsBuffer(audio) || !alIsSource(source))
|
||||||
|
throw new RuntimeException();
|
||||||
|
|
||||||
|
alBufferData(audio, format, rawAudio, sampleRate);
|
||||||
|
return new Speaker(audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSpeaker(Speaker speaker) {
|
||||||
|
speaker.setAudioData(audioBuffer);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
package ru.windcorp.progressia.client.audio.backend;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import static org.lwjgl.openal.AL11.*;
|
||||||
|
|
||||||
|
public class Speaker {
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
NOT_PLAYING,
|
||||||
|
PLAYING,
|
||||||
|
PLAYING_LOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffers
|
||||||
|
private int audioData;
|
||||||
|
private int sourceData;
|
||||||
|
|
||||||
|
// Characteristics
|
||||||
|
private Vec3 position = new Vec3();
|
||||||
|
private Vec3 velocity = new Vec3();
|
||||||
|
private float pitch = 1.0f;
|
||||||
|
private float gain = 1.0f;
|
||||||
|
private State state = State.NOT_PLAYING;
|
||||||
|
|
||||||
|
public Speaker() {
|
||||||
|
sourceData = alGenSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Speaker(int audioData) {
|
||||||
|
this();
|
||||||
|
setAudioData(audioData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Speaker(
|
||||||
|
int audioData,
|
||||||
|
Vec3 position,
|
||||||
|
Vec3 velocity,
|
||||||
|
float pitch,
|
||||||
|
float gain
|
||||||
|
) {
|
||||||
|
setAudioData(audioData);
|
||||||
|
setPosition(position);
|
||||||
|
setVelocity(velocity);
|
||||||
|
setPitch(pitch);
|
||||||
|
setGain(gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Speaker(
|
||||||
|
Vec3 position,
|
||||||
|
Vec3 velocity,
|
||||||
|
float pitch,
|
||||||
|
float gain
|
||||||
|
) {
|
||||||
|
setPosition(position);
|
||||||
|
setVelocity(velocity);
|
||||||
|
setPitch(pitch);
|
||||||
|
setGain(gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play() {
|
||||||
|
alSourcePlay(sourceData);
|
||||||
|
state = State.PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playLoop() {
|
||||||
|
alSourcei(sourceData, AL_LOOPING, AL_TRUE);
|
||||||
|
alSourcePlay(sourceData);
|
||||||
|
state = State.PLAYING_LOOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
alSourceStop(sourceData);
|
||||||
|
if (state == State.PLAYING_LOOP) {
|
||||||
|
alSourcei(sourceData, AL_LOOPING, AL_FALSE);
|
||||||
|
}
|
||||||
|
state = State.NOT_PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pause() {
|
||||||
|
alSourcePause(sourceData);
|
||||||
|
state = State.NOT_PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlaying() {
|
||||||
|
final int speakerState = alGetSourcei(sourceData, AL_SOURCE_STATE);
|
||||||
|
if (speakerState == AL_PLAYING) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = State.NOT_PLAYING;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GETTERS & SETTERS
|
||||||
|
|
||||||
|
public int getAudioData() {
|
||||||
|
return audioData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioData(int audioData) {
|
||||||
|
this.audioData = audioData;
|
||||||
|
alSourcei(this.sourceData, AL_BUFFER, audioData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(Vec3 position) {
|
||||||
|
this.position = position;
|
||||||
|
alSource3f(sourceData, AL_POSITION, position.x, position.y, position.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVelocity(Vec3 velocity) {
|
||||||
|
alSource3f(sourceData, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
|
||||||
|
this.velocity = velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getVelocity() {
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPitch(float pitch) {
|
||||||
|
alSourcef(sourceData, AL_PITCH, pitch);
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGain(float gain) {
|
||||||
|
alSourcef(sourceData, AL_GAIN, gain);
|
||||||
|
this.gain = gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getGain() {
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState()
|
||||||
|
{
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,7 +20,7 @@ package ru.windcorp.progressia.client.graphics.backend;
|
|||||||
import static org.lwjgl.glfw.GLFW.*;
|
import static org.lwjgl.glfw.GLFW.*;
|
||||||
import static org.lwjgl.opengl.GL11.*;
|
import static org.lwjgl.opengl.GL11.*;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.audio.SoundManager;
|
import ru.windcorp.progressia.client.audio.AudioManager;
|
||||||
import ru.windcorp.progressia.client.graphics.GUI;
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
|
|
||||||
class RenderThread extends Thread {
|
class RenderThread extends Thread {
|
||||||
@ -61,7 +61,7 @@ class RenderThread extends Thread {
|
|||||||
|
|
||||||
private void doRender() {
|
private void doRender() {
|
||||||
GUI.render();
|
GUI.render();
|
||||||
SoundManager.update();
|
AudioManager.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitForFrame() {
|
private void waitForFrame() {
|
||||||
|
Reference in New Issue
Block a user