Odd Null Pointer error

Started by jmguillemette, November 02, 2013, 22:14:10

Previous topic - Next topic

jmguillemette

Im trying to play a wav file. the file is located in my resource folder which i used to load images and other game assets.

I first create a File and ensure the wav file exists.
I then use the WaveData utility to create WaveData.
The wave data utility return null every time.

I can use a String or  FileInputStream when calling the create() and i get the same result

thoughts?

Please not this is test code not final :)

package com.iowind.mocha.sound;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
import org.lwjgl.util.WaveData;

public class SoundUtil {

	private IntBuffer buffer = BufferUtils.createIntBuffer(1); // hold sound data
	private IntBuffer source = BufferUtils.createIntBuffer(1); // sources of sounds
	FloatBuffer sourcePos = BufferUtils.createFloatBuffer(3).put(new float[] { 0.0f, 0.0f, 0.0f }); // postion of sound source
	FloatBuffer sourceVel = BufferUtils.createFloatBuffer(3).put(new float[] { 0.0f, 0.0f, 0.0f }); // velocity of sound
	FloatBuffer listenerPos = BufferUtils.createFloatBuffer(3).put(new float[] { 0.0f, 0.0f, 0.0f }); // position of listener
	FloatBuffer listenerVel = BufferUtils.createFloatBuffer(3).put(new float[] { 0.0f, 0.0f, 0.0f }); // velocity of listener
	FloatBuffer listenerOri = BufferUtils.createFloatBuffer(6).put(new float[] { 0.0f, 0.0f, -1.0f,  0.0f, 1.0f, 0.0f });/** Orientation of the listener. (first 3 elements are "at", second 3 are "up") */
	
	
	public void play(){
		try{
			String wavFile  = "resources/sounds/music/DreamRaidPartI.wav";
			
			File file = new File(wavFile);
			if(file.exists()){
				System.out.println("File Exists");
				//WaveData waveData = WaveData.create(wavFile);
				WaveData waveData = WaveData.create(new FileInputStream(file));
				
				System.out.println("WaveData = "+ waveData);
				AL.create();
				if(AL10.alGetError() == AL10.AL_NO_ERROR){
					System.out.println("No Errors");
				}
				AL10.alGenBuffers(buffer);
				AL10.alBufferData(buffer.get(0), waveData.format, waveData.data, waveData.samplerate);
				waveData.dispose();
				
				AL10.alGenSources(source);
				AL10.alSourcei(source.get(0), AL10.AL_BUFFER,   buffer.get(0) );
			    AL10.alSourcef(source.get(0), AL10.AL_PITCH,    1.0f          );
			    AL10.alSourcef(source.get(0), AL10.AL_GAIN,     1.0f          );
			    AL10.alSource (source.get(0), AL10.AL_POSITION, sourcePos     );
			    AL10.alSource (source.get(0), AL10.AL_VELOCITY, sourceVel     );
			    
		
			    AL10.alListener(AL10.AL_POSITION,    listenerPos);
			    AL10.alListener(AL10.AL_VELOCITY,    listenerVel);
			    AL10.alListener(AL10.AL_ORIENTATION, listenerOri);
		
			    AL10.alSourcePlay(source.get(0));
			}
		}catch(LWJGLException | IOException e){
			e.printStackTrace();
		}	
		
	}
	
	@Override
	protected void finalize() throws Throwable {
		 AL.destroy();
	}
	
	public static void main(String[] args) {
		SoundUtil util = new SoundUtil();
		util.play();
	}
}


The output of this code is:

File Exists
WaveData = null
No Errors
Exception in thread "main" java.lang.NullPointerException
	at com.iowind.mocha.sound.SoundUtil.play(SoundUtil.java:43)
	at com.iowind.game.apollo.MusicTest.main(MusicTest.java:9)
AL lib: (EE) alc_cleanup: 1 device not closed

jmguillemette

I resolved the problem by preloading the file into an ByteArrayOutput stream and then converting it to an ByteArrayInputStream and feeding that to the exact same code, in place of my file input stream.

To me this is a bug.

If someone can point me to the LWJGL source repo for this util ill do some work and submit a patch.

j.

jmguillemette

next challenge i ran into was having to rewind the buffers...

Thoughts:

Is it really the developers responsibility to rewind position buffers before calling the utility? or should the utility do this for you to be nice "just in case".

I'd be happy to code up a proposed patch.. just point me to the source :)

j.

quew8

LWJGL does not do this because in the event that you don't want to rewind the buffer, ie the data started mid-way through the buffer (which is often the case when sharing buffers), it would be impossible.

Essentially these buffers work like pointers in C. In C you could just specify a new pointer with an offset into the first one, but this isn't possible with Java so we use the position of the buffer. Likewise with length, we son't have to specify the size of the data as we would in C by using the limit of the buffer. 

Just call flip() after writing the data into the buffer and everything will turn out fine.

jmguillemette

that would address the buffer rewind.. but thats just a nice to have..

the null pointer when loading a file that is within the classpath but not within a jar .. that we should improve.
Im not sure if the fact that wav files are fairly large is also a factor.. but using the exact same code and loading the data to a byteArrayInputStream vs using FileInputStream was the difference between working and and receiving a WaveData that was null.

I think we can make improvements in this util to account for this. Thoughts?

j.