package electrosphere.audio; import electrosphere.logger.LoggerInterface; import electrosphere.util.FileUtils; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import org.lwjgl.BufferUtils; import static org.lwjgl.BufferUtils.createByteBuffer; import static org.lwjgl.openal.AL10.*; import static org.lwjgl.stb.STBVorbis.*; import org.lwjgl.stb.STBVorbisInfo; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil; import static org.lwjgl.system.MemoryUtil.NULL; public class AudioBuffer { private int bufferId; private ByteBuffer vorbis = null; private ShortBuffer pcm = null; public AudioBuffer(String fileName) { bufferId = alGenBuffers(); try (STBVorbisInfo info = STBVorbisInfo.malloc()) { ShortBuffer pcm = readVorbis(fileName, 32 * 1024, info); // Copy to buffer alBufferData(bufferId, info.channels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, pcm, info.sample_rate()); } catch (Exception e){ LoggerInterface.loggerEngine.ERROR("Failed to load audio", e); // e.printStackTrace(); } } private ShortBuffer readVorbis(String resource, int bufferSize, STBVorbisInfo info) throws Exception { try (MemoryStack stack = MemoryStack.stackPush()) { vorbis = AudioBuffer.ioResourceToByteBuffer(resource, bufferSize); IntBuffer error = stack.mallocInt(1); long decoder = stb_vorbis_open_memory(vorbis, error, null); if (decoder == NULL) { throw new RuntimeException("Failed to open Ogg Vorbis file. Error: " + error.get(0)); } stb_vorbis_get_info(decoder, info); int channels = info.channels(); int lengthSamples = stb_vorbis_stream_length_in_samples(decoder); pcm = MemoryUtil.memAllocShort(lengthSamples); pcm.limit(stb_vorbis_get_samples_short_interleaved(decoder, channels, pcm) * channels); stb_vorbis_close(decoder); return pcm; } } public static ByteBuffer ioResourceToByteBuffer(String resource, int bufferSize) throws IOException { ByteBuffer buffer; Path path = Paths.get(resource); if (Files.isReadable(path)) { try (SeekableByteChannel fc = Files.newByteChannel(path)) { buffer = BufferUtils.createByteBuffer((int) fc.size() + 1); while (fc.read(buffer) != -1) ; } } else { try ( InputStream source = FileUtils.getAssetFileAsStream(resource); ReadableByteChannel rbc = Channels.newChannel(source) ) { buffer = createByteBuffer(bufferSize); while (true) { int bytes = rbc.read(buffer); if (bytes == -1) { break; } if (buffer.remaining() == 0) { int capacity = buffer.capacity(); ByteBuffer newBuffer = createByteBuffer(capacity * 2); for(int i = 0; i < capacity; i++){ newBuffer.put(buffer.get()); } buffer = newBuffer; } } } } buffer.flip(); return buffer; } public int getBufferId() { return this.bufferId; } public void cleanup() { alDeleteBuffers(this.bufferId); } }