Hot questions for Using Lightweight Java Game Library in audio

Question:

I am trying to load sound in LWJGL 3 according to this tutorial ( http://wiki.lwjgl.org/index.php?title=OpenAL_Tutorial_1_-_Single_Static_Source ), but I found a problem that the class WaveData, which was most probably in the older version of LWJGL 2.X, is not there. There for I cant even compile the code. Is there any other way how to load sounds in lwjgl using openAL...

in LWJGL 2 I used to use paulscode sound system ( http://www.paulscode.com/forum/index.php?topic=4.0 ) but I am not sure if it works now in the newer version of LWJGL 3. Thank you for your answer :)

and if there would be any tutorial around sound in lwjgl3, could you please include the link in your answer, I tried googling theese tutorials for ages but I failed.


Answer:

In a forum post it is stated:

LWJGL3 doesn't include the WaveData from LWJGL2 but it still works the same in LWJGL3, just grab it from the LWJGL2 source code and include it in your project.

So it should be safe to just copy the old WaveData class and use it with LWJGL3, because the loading algorithm and OpenAL internals have not been changed.


Recently, LWJGL included bindings for the STB library. This provides a set of utility functions for different things, like image loading, font loading and perlin noise calculation. It also has an Ogg Vorbis Decoder. Be warned however, that, like OpenGL and GLFW, STB provides only static functions instead of an object-oriented interface. It is also not very optimized.

Question:

So I'm writing a program in Java that must be able to play wav files. It works perfectly when run from within Intellij, but when I run it from the jar it crashes immediately when it tries to retrieve the sound files and returns this error:

Unable to create from inputstream, Stream closed
Exception in thread "main" java.lang.NullPointerException

Here is the code that I'm using to retrieve the sound files:

protected int loadSound(String file) {

    int data = AL10.alGenBuffers(); //Create new buffer object
    buffers.add(data); //Store buffer ID in array list
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    InputStream filePath = loader.getResourceAsStream("/res/sound/" + file);
    WaveData wavFile = WaveData.create(new BufferedInputStream(filePath)); //Retrieve wav file
    AL10.alBufferData(data, wavFile.format, wavFile.data, wavFile.samplerate); //Store wav file data and properties in buffer object
    wavFile.dispose(); //Discard wav file from stored memory

    return data; //Return buffer ID
}

I cannot understand why this does not work when run from the jar, since when I look inside the jar file I can see that the res folder is indeed inside of it. What's stranger still is that I'm using more or less identical code to retrieve a text file in another part of the program and have been able to confirm that this is working correctly when run inside the IDE and from the jar. That code is as follows:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream mapPath = loader.getResourceAsStream("dat/maps/" + mapName);

I know similar questions have been asked here many times before, but I have not had any success with the solutions I found to those questions. I am pretty sure it's something to do with the files not being packaged correctly, but I cannot say how it should be done.

Here is the complete stack trace:

C:\Users\Jack>java -jar C:\Users\Jack\IdeaProjects\ProjectBlackSpace\out\artifacts\ProjectBlackSpace_jar\ProjectBlackSpace.jar
OpenALC10: true
OpenALC11: true
caps.ALC_EXT_EFX = true

Num HRTF specifiers = 2: true
Sample rate: default-44100
HRTF enabled: true
HRTF state: 0x3

OpenGL version: 4.5.0 NVIDIA 368.81
[LWJGL] Failed to load a library. Possible solutions:
        a) Set -Djava.library.path or -Dorg.lwjgl.librarypath to the directory that contains the shared libraries.
        b) Add the JAR(s) containing the shared libraries to the classpath.
[LWJGL] Enable debug mode with -Dorg.lwjgl.util.Debug=true for better diagnostics.
Unable to create from inputstream, Stream closed
Exception in thread "main" java.lang.NullPointerException
        at projectBlackSpaceApp.Sounds.loadSound(Sounds.java:22)
        at projectBlackSpaceApp.Player.init(Player.java:94)
        at projectBlackSpaceApp.Game.init(Game.java:72)
        at projectBlackSpaceApp.Main.run(Main.java:159)
        at projectBlackSpaceApp.Main.init(Main.java:82)
        at projectBlackSpaceApp.Main.main(Main.java:195)
AL lib: (EE) alc_cleanup: 1 device not closed

When running the program with -Dorg.lwjgl.util.Debug=true The results when running from the command line are no different, but when run from within the IDE it provides some more information:

[LWJGL] Version: 3.0.0 build 90
[LWJGL]      OS: Windows 10 v10.0
[LWJGL]     JRE: 1.8.0_60 amd64
[LWJGL]     JVM: Java HotSpot(TM) 64-Bit Server VM v25.60-b23 by Oracle Corporation
[LWJGL] Loading library (system): lwjgl
[LWJGL]     Loaded from java.library.path: libs\lwjgl.dll
[LWJGL] MemoryUtil accessor: MemoryAccessorUnsafe
[LWJGL] Loading library: OpenAL
[LWJGL] ThreadLocalUtil state: UnsafeState
[LWJGL]     Loaded from java.library.path: libs\OpenAL.dll
OpenALC10: true
OpenALC11: true
caps.ALC_EXT_EFX = true

Num HRTF specifiers = 2: true
Sample rate: default-44100
HRTF enabled: true
HRTF state: 0x3
[LWJGL] Loading library: glfw
[LWJGL]     Loaded from java.library.path: libs\glfw.dll
[LWJGL] Loading library: opengl32
[LWJGL]     opengl32.dll not found in java.library.path=libs/
[LWJGL]     Loaded from system paths

OpenGL version: 4.5.0 NVIDIA 368.81
[LWJGL] Loading library: jemalloc
[LWJGL]     jemalloc.dll not found in java.library.path=libs/
[LWJGL]     jemalloc.dll not found in system paths
[LWJGL]     Using SharedLibraryLoader...
java.lang.RuntimeException:     Failed to extract jemalloc library
    at org.lwjgl.system.SharedLibraryLoader.load(SharedLibraryLoader.java:65)
    at org.lwjgl.system.Library.loadNative(Library.java:139)
    at org.lwjgl.system.jemalloc.JEmalloc.<clinit>(JEmalloc.java:37)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at org.lwjgl.system.MemoryManage.getInstance(MemoryManage.java:36)
    at org.lwjgl.system.MemoryUtil$LazyInit.<clinit>(MemoryUtil.java:76)
    at org.lwjgl.system.MemoryUtil.nmemAlloc(MemoryUtil.java:162)
    at org.lwjgl.system.MemoryUtil.memAlloc(MemoryUtil.java:180)
    at org.lwjgl.system.MemoryUtil.memUTF8(MemoryUtil.java:1530)
    at org.lwjgl.system.APIUtil.apiArrayi(APIUtil.java:430)
    at org.lwjgl.opengl.GL20.glShaderSource(GL20.java:425)
    at projectBlackSpaceApp.Shaders.init(Shaders.java:29)
    at projectBlackSpaceApp.Main.run(Main.java:123)
    at projectBlackSpaceApp.Main.init(Main.java:82)
    at projectBlackSpaceApp.Main.main(Main.java:195)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.RuntimeException: Failed to locate resource: jemalloc.dll
    at org.lwjgl.system.SharedLibraryLoader.extractFile(SharedLibraryLoader.java:80)
    at org.lwjgl.system.SharedLibraryLoader.load(SharedLibraryLoader.java:63)
    ... 20 more
[LWJGL] Failed to load a library. Possible solutions:
    a) Set -Djava.library.path or -Dorg.lwjgl.librarypath to the directory that contains the shared libraries.
    b) Add the JAR(s) containing the shared libraries to the classpath.
java.lang.UnsatisfiedLinkError: Failed to locate library: jemalloc.dll
    at org.lwjgl.system.Library.loadNativeRelative(Library.java:177)
    at org.lwjgl.system.Library.loadNative(Library.java:134)
    at org.lwjgl.system.jemalloc.JEmalloc.<clinit>(JEmalloc.java:37)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at org.lwjgl.system.MemoryManage.getInstance(MemoryManage.java:36)
    at org.lwjgl.system.MemoryUtil$LazyInit.<clinit>(MemoryUtil.java:76)
    at org.lwjgl.system.MemoryUtil.nmemAlloc(MemoryUtil.java:162)
    at org.lwjgl.system.MemoryUtil.memAlloc(MemoryUtil.java:180)
    at org.lwjgl.system.MemoryUtil.memUTF8(MemoryUtil.java:1530)
    at org.lwjgl.system.APIUtil.apiArrayi(APIUtil.java:430)
    at org.lwjgl.opengl.GL20.glShaderSource(GL20.java:425)
    at projectBlackSpaceApp.Shaders.init(Shaders.java:29)
    at projectBlackSpaceApp.Main.run(Main.java:123)
    at projectBlackSpaceApp.Main.init(Main.java:82)
    at projectBlackSpaceApp.Main.main(Main.java:195)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
[LWJGL] [MemoryAllocator] Failed to load the jemalloc library.
[LWJGL] MemoryUtil allocator: StdlibAllocator

Adding the jemalloc.dll to the library directory does stop the runtime exception from happening, but it doesn't seem to have any other effect for better or worse.

Any help would be greatly appreciated.


Answer:

check the difference between: "/res/sound/" and "dat/maps/". That is the /

UPDATE

From the stacktrace it looks like a shared library is expected to be present. Please do what is suggested:

Possible solutions: a) Set -Djava.library.path or -Dorg.lwjgl.librarypath to the directory that contains the shared libraries. b) Add the JAR(s) containing the shared libraries to the classpath.

Question:

I am trying to make a simple sound player in OpenAL as a learning exercise. I've looked through several examples and tutorials and I always got the same result: no sound and no errors. I've read the OpenAL Documentation and it never mentions something like that.

I eventually thought that I may not have OpenAL installed, which funny enough, I didn't. So after installing it, I also had no sound and no errors.

Then I thought that my buffer was filling incorrectly, so I tried to play it with just the Java library. Turns out it plays completely fine!

[After lots of test, EDITED]

Now I have audio, but it's only one "bump" after calling alSourcePlay and sometimes when the application ends. This occurs if I use AL_FORMAT_STEREO8 or AL_FORMAT_MONO8 instead of the 16 bit formats. I suppose this is a problem with the format, but with the otherwise correct format nothing happens; not even a "bump".

I just don't know what could be wrong. I must admit, this is my first time working with OpenAL. There is little information about troubleshooting OpenAL, it seems the big focus is on OpenGL and Vulkan.

Here is the code I've written so far. I am using LWJGL to access OpenAL and Java 8.

import static org.lwjgl.openal.AL10.AL_BUFFER;
import static org.lwjgl.openal.AL10.AL_FORMAT_MONO16;
import static org.lwjgl.openal.AL10.AL_FORMAT_MONO8;
import static org.lwjgl.openal.AL10.AL_FORMAT_STEREO16;
import static org.lwjgl.openal.AL10.AL_FORMAT_STEREO8;
import static org.lwjgl.openal.AL10.AL_GAIN;
import static org.lwjgl.openal.AL10.AL_INVALID_ENUM;
import static org.lwjgl.openal.AL10.AL_INVALID_VALUE;
import static org.lwjgl.openal.AL10.AL_NO_ERROR;
import static org.lwjgl.openal.AL10.AL_OUT_OF_MEMORY;
import static org.lwjgl.openal.AL10.AL_PITCH;
import static org.lwjgl.openal.AL10.AL_POSITION;
import static org.lwjgl.openal.AL10.AL_VELOCITY;
import static org.lwjgl.openal.AL10.alBufferData;
import static org.lwjgl.openal.AL10.alDeleteBuffers;
import static org.lwjgl.openal.AL10.alDeleteSources;
import static org.lwjgl.openal.AL10.alGenBuffers;
import static org.lwjgl.openal.AL10.alGenSources;
import static org.lwjgl.openal.AL10.alGetError;
import static org.lwjgl.openal.AL10.alListener3f;
import static org.lwjgl.openal.AL10.alSource3f;
import static org.lwjgl.openal.AL10.alSourcePlay;
import static org.lwjgl.openal.AL10.alSourcef;
import static org.lwjgl.openal.AL10.alSourcei;
import static org.lwjgl.openal.ALC10.alcCloseDevice;
import static org.lwjgl.openal.ALC10.alcCreateContext;
import static org.lwjgl.openal.ALC10.alcMakeContextCurrent;
import static org.lwjgl.openal.ALC10.alcOpenDevice;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import org.lwjgl.openal.AL;
import org.lwjgl.openal.ALC;
import org.lwjgl.openal.ALC10;
import org.lwjgl.openal.ALCCapabilities;

import dev.ckitty.engine.kc.io.AutoByteBuffer;
import dev.ckitty.engine.kc.io.FileLoader;
import dev.ckitty.engine.kc.main.Engine;
import dev.ckitty.engine.kc.utils.Util;

public class AudioMaster {

    private long device, context;
    private int buffer, source;

    public AudioMaster() {
        init();
        load();
        source();

        Engine.log("Playing!");
        play();
        Util.waitSec(10);

        deinit();
    }

    public void init() {
        device = alcOpenDevice((ByteBuffer) null);
        if (device == 0)
            throw new IllegalStateException("Failed to open the default device.");

        ALCCapabilities deviceCaps = ALC.createCapabilities(device);

        context = alcCreateContext(device, (IntBuffer) null);
        if (context == 0)
            throw new IllegalStateException("Failed to create an OpenAL context.");

        alcMakeContextCurrent(context);
        Engine.log(erroralc());

        AL.createCapabilities(deviceCaps);
        Engine.log(error());
    }

    public void load() {
        AutoByteBuffer abb = new AutoByteBuffer();
        AudioFormat format = null;

        try {
            InputStream is = FileLoader.Internal.getInputStream("/kc/audios/LFZ - Popsicle.wav");
            BufferedInputStream bis = new BufferedInputStream(is);
            AudioInputStream ais = AudioSystem.getAudioInputStream(bis);
            abb.put(ais);
            format = ais.getFormat();

            ais.close();
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        buffer = alGenBuffers();
        int samplerate = (int) format.getSampleRate();
        alBufferData(buffer, AL_FORMAT_STEREO8, abb.flip(), samplerate);
    }

    public void source() {
        source = alGenSources();
        Engine.log(error());
        alSourcef(source, AL_GAIN, 1f);
        alSourcef(source, AL_PITCH, 1f);
        alSource3f(source, AL_POSITION, 0f, 0f, 0f);
        alSourcei(source, AL_BUFFER, buffer);
    }

    public void play() {
        alListener3f(AL_POSITION, 0, 0, 0);
        alListener3f(AL_VELOCITY, 0, 0, 0);



        Engine.log("PLAYING");
        alSourcePlay(source);
    }

    public String erroralc() {
        switch (ALC10.alcGetError(device)) {
          case AL_NO_ERROR: return "ALC_NO_ERROR";
          case AL_INVALID_ENUM: return "ALC_INVALID_ENUM";
          case AL_INVALID_VALUE: return "ALC_INVALID_VALUE";
          case AL_OUT_OF_MEMORY: return "ALC_OUT_OF_MEMORY";
          /* ... */
          default:
            return "Unknown error code";
        }
    }

    public String error() {
        switch (alGetError()) {
          case AL_NO_ERROR: return "AL_NO_ERROR";
          case AL_INVALID_ENUM: return "AL_INVALID_ENUM";
          case AL_INVALID_VALUE: return "AL_INVALID_VALUE";
          case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY";
          /* ... */
          default:
            return "Unknown error code";
        }
    }

    public void deinit() {
        alDeleteSources(source);
        alDeleteBuffers(buffer);
        alcCloseDevice(device);
    }

}

AutoByteBuffer

import java.io.InputStream;
import java.nio.ByteBuffer;

public class AutoByteBuffer {

    private byte[] array = new byte[0];
    private int index;

    public void put(InputStream is) {
        int n;
        byte[] data = new byte[1024];
        try {
            while ((n = is.read(data)) != -1)
                put(data, 0, n);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void put(byte[] src) {
        put(src, 0, src.length);
    }

    public void put(byte[] src, int off, int length) {
        resize(src.length);
        for (int i = 0; i < length; i++) {
            array[index++] = src[off + i];
        }
    }

    protected void resize(int bytes) {
        Math.addExact(index, bytes);
        if (index + bytes >= array.length) {
            int newsize = (int) ((index + bytes) * 1.5 + 0.5);
            if (newsize < index + bytes)
                throw new RuntimeException("Could not store enough memory!");

            byte[] copy = new byte[newsize];
            System.arraycopy(array, 0, copy, 0, index);
            array = copy;
        }
    }

    public ByteBuffer flip() {
        ByteBuffer buffer = ByteBuffer.allocate(index);
        buffer.put(array, 0, index);
        buffer.flip();
        return buffer;
    }

}

Console Output

 > Starting AudioMaster!
AL lib: (EE) UpdateDeviceParams: Failed to set 44100hz, got 48000hz instead
 > ALC_NO_ERROR
 > AL_NO_ERROR
 > AL_NO_ERROR
 > Playing!
 > PLAYING

Answer:

I still don't know what happened, but how I followed this tutorial. The dude tells us to use this code to load wav files and it seems to work just fine! My theory is that is works well because it uses LWJGL buffers instead of java ones. Looking at the source of LWJGL it seems it does matters as it's trying to get the memory address of the buffers. And, of course, if LWJGL is the one creating the buffer, it will know exactly where it is.

Question:

I make a video games on eclipse and i will make a menu song and stop the song but clip.stop(); not work i don't know why please help me. The menu song Clip.play();and Clip.loop(Clip.LOOP_CONTINUOUSLY); work but i can stop the song only if i close my game.

package Audio;

import java.io.File;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;

import sun.audio.AudioPlayer;


public class MenuAudio {

public static boolean stopped = false;

public static void Start(){
System.out.println(stopped);
try{
File f = new File("C:\\Games\\Test\\Assets\\sound\\menu\\menuLoop.wav");
Clip clip = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.getAudioInputStream(f);
clip.open(ais);
clip.start();
clip.loop(Clip.LOOP_CONTINUOUSLY);
AudioPlayer.player.stop(ais);
if(stopped == true) // work
{
    clip.stop(); //not work
    clip.close(); //not work
    stopped = false; //work
    System.out.println(stopped);//work
} 

}catch(Exception exception){System.out.println("WAV FILES NOT FOUND!! ");}

}

} 

boolean stopped return to true in another class whit this code

    int test = 0;
 //code useless
    ........
 //code useless
    MenuAudio.Start(); // play the sound
 //code useless
    ........
 //code useless

if(Keyboard.isKeyDown(Keyboard.KEY_LEFT)){  //work
            test = 0;
        }

        if(test == 0 && Keyboard.isKeyDown(Keyboard.KEY_RIGHT)){ //work
            MenuAudio.stopped = true;
            MenuAudio.Start();
            test = 1;
        }

this code is work the console return that : true false if i press the key Left after Right. I don't know why Clip.stop(); not work.

(Sorry for the bad english)


Answer:

There are a number of confusing things in your code. For one, I think sun.audio.AudioPlayer is deprecated. I don't see it listed in the Java 7 API. I'm pretty sure it has no role to play in controlling a javax.audio.Clip in the code you have written.

There is more info on sun.audio.AudioPlayer at this past StackOverflow question link.

Another source of confusion is your naming convention. If the first letter is a capital letter, we expect this to be a Class, not a variable or method. Fixing the indentations would also make it a little easier to read.

I don't understand why you are setting a variable to false and then calling a routine to both load and start and stop the playback in quick succession.

Clip's were designed to be opened separately from when they are played. As written, your code has to load the entire clip into RAM before the start command will execute. If you load the Clip beforehand, perhaps in a constructor for MenuAudio, then you could consider a plan such as passing the clip variable to any method responsible for starting or stopping it.