From: nathan.sweet Date: Sun, 23 Oct 2011 20:45:00 +0000 (+0000) Subject: [added] OpenALAudioDevice. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=18459375e19091771139f1fbf6644f30ab77b30f;p=mikumikustudio%2Flibgdx-mikumikustudio.git [added] OpenALAudioDevice. --- diff --git a/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglPreferences.java b/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglPreferences.java index 543751cb4..dd4d82e1c 100644 --- a/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglPreferences.java +++ b/backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglPreferences.java @@ -28,6 +28,7 @@ import java.util.Properties; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Preferences; import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.GdxRuntimeException; public class LwjglPreferences implements Preferences { private final String name; @@ -173,11 +174,13 @@ public class LwjglPreferences implements Preferences { @Override public void flush () { if (Gdx.files == null) return; + FileHandle file = Gdx.files.external(LwjglPreferences.this.name); OutputStream out = null; try { - out = new BufferedOutputStream(Gdx.files.external(LwjglPreferences.this.name).write(false)); + out = new BufferedOutputStream(file.write(false)); properties.storeToXML(out, null); - } catch (Throwable t) { + } catch (Exception ex) { + throw new GdxRuntimeException("Error writing preferences: " + file, ex); } finally { if (out != null) try { out.close(); diff --git a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/JavaSoundAudioDevice.java b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/JavaSoundAudioDevice.java deleted file mode 100644 index f580fef33..000000000 --- a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/JavaSoundAudioDevice.java +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * Copyright 2011 See AUTHORS file. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ - -package com.badlogic.gdx.backends.openal; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.SourceDataLine; - -import com.badlogic.gdx.audio.AudioDevice; -import com.badlogic.gdx.utils.GdxRuntimeException; - -/** @author mzechner */ -public class JavaSoundAudioDevice implements AudioDevice { - private SourceDataLine line; - private final boolean isMono; - private byte[] bytes = new byte[44100 * 2 * 2]; - - public JavaSoundAudioDevice (int samplingRate, boolean isMono) { - this.isMono = isMono; - - try { - AudioFormat format = new AudioFormat(samplingRate, 16, isMono ? 1 : 2, true, false); - line = AudioSystem.getSourceDataLine(format); - line.open(format, 2048 * 10);// Math.min(2048*10, samplingRate / 5) * 2); - line.start(); - } catch (Exception ex) { - throw new GdxRuntimeException("Error creating JavaSoundAudioDevice.", ex); - } - } - - public void dispose () { - line.drain(); - line.close(); - } - - public boolean isMono () { - return isMono; - } - - public void writeSamples (short[] samples, int offset, int numSamples) { - if (bytes.length < samples.length * 2) bytes = new byte[samples.length * 2]; - - for (int i = offset, j = 0; i < offset + numSamples; i++, j += 2) { - short value = samples[i]; - bytes[j] = (byte)(value & 0xff); - bytes[j + 1] = (byte)(value >> 8); - } - - int writtenBytes = line.write(bytes, 0, numSamples * 2); - while (writtenBytes != numSamples * 2) - writtenBytes += line.write(bytes, writtenBytes, numSamples * 2 - writtenBytes); - } - - public void writeSamples (float[] samples, int offset, int numSamples) { - if (bytes.length < samples.length * 2) bytes = new byte[samples.length * 2]; - - for (int i = offset, j = 0; i < offset + numSamples; i++, j += 2) { - float fValue = samples[i]; - if (fValue > 1) fValue = 1; - if (fValue < -1) fValue = -1; - short value = (short)(fValue * Short.MAX_VALUE); - bytes[j] = (byte)(value & 0xff); - bytes[j + 1] = (byte)(value >> 8); - } - - int writtenBytes = line.write(bytes, 0, numSamples * 2); - while (writtenBytes != numSamples * 2) - writtenBytes += line.write(bytes, writtenBytes, numSamples * 2 - writtenBytes); - } - - @Override - public int getLatency () { - return 0; - } -} diff --git a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudio.java b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudio.java index c2cc95413..723dfe84d 100644 --- a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudio.java +++ b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudio.java @@ -143,12 +143,12 @@ public class OpenALAudio implements Audio { if (isMusic) { idleSources.removeIndex(i); } else { - if(sourceToSoundId.containsKey(sourceId)) { + if (sourceToSoundId.containsKey(sourceId)) { long soundId = sourceToSoundId.get(sourceId); sourceToSoundId.remove(sourceId); soundIdToSource.remove(soundId); } - + long soundId = nextSoundId++; sourceToSoundId.put(sourceId, soundId); soundIdToSource.put(soundId, sourceId); @@ -167,7 +167,7 @@ public class OpenALAudio implements Audio { void freeSource (int sourceID) { alSourceStop(sourceID); alSourcei(sourceID, AL_BUFFER, 0); - if(sourceToSoundId.containsKey(sourceID)) { + if (sourceToSoundId.containsKey(sourceID)) { long soundId = sourceToSoundId.remove(sourceID); soundIdToSource.remove(soundId); } @@ -180,7 +180,7 @@ public class OpenALAudio implements Audio { if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) { long soundId = sourceToSoundId.remove(sourceID); soundIdToSource.remove(soundId); - + alSourceStop(sourceID); alSourcei(sourceID, AL_BUFFER, 0); } @@ -193,7 +193,7 @@ public class OpenALAudio implements Audio { if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) { long soundId = sourceToSoundId.remove(sourceID); soundIdToSource.remove(soundId); - + alSourceStop(sourceID); } } @@ -204,42 +204,42 @@ public class OpenALAudio implements Audio { music.items[i].update(); } - public long getSoundId(int sourceId) { - if(!sourceToSoundId.containsKey(sourceId)) return -1; + public long getSoundId (int sourceId) { + if (!sourceToSoundId.containsKey(sourceId)) return -1; return sourceToSoundId.get(sourceId); } - - public void stopSound(long soundId) { - if(!soundIdToSource.containsKey(soundId)) return; + + public void stopSound (long soundId) { + if (!soundIdToSource.containsKey(soundId)) return; int sourceId = soundIdToSource.get(soundId); alSourceStop(sourceId); } - - public void setSoundGain(long soundId, float volume) { - if(!soundIdToSource.containsKey(soundId)) return; + + public void setSoundGain (long soundId, float volume) { + if (!soundIdToSource.containsKey(soundId)) return; int sourceId = soundIdToSource.get(soundId); AL10.alSourcef(sourceId, AL10.AL_GAIN, volume); } public void setSoundLooping (long soundId, boolean looping) { - if(!soundIdToSource.containsKey(soundId)) return; + if (!soundIdToSource.containsKey(soundId)) return; int sourceId = soundIdToSource.get(soundId); - alSourcei(sourceId, AL10.AL_LOOPING, looping?AL10.AL_TRUE:AL10.AL_FALSE); + alSourcei(sourceId, AL10.AL_LOOPING, looping ? AL10.AL_TRUE : AL10.AL_FALSE); } - - public void setSoundPitch(long soundId, float pitch) { - if(!soundIdToSource.containsKey(soundId)) return; + + public void setSoundPitch (long soundId, float pitch) { + if (!soundIdToSource.containsKey(soundId)) return; int sourceId = soundIdToSource.get(soundId); AL10.alSourcef(sourceId, AL10.AL_PITCH, pitch); } - - public void setSoundPan(long soundId, float pan, float volume) { - if(!soundIdToSource.containsKey(soundId)) return; + + public void setSoundPan (long soundId, float pan, float volume) { + if (!soundIdToSource.containsKey(soundId)) return; int sourceId = soundIdToSource.get(soundId); - - AL10.alSource3f(sourceId, AL10.AL_POSITION, -pan, 0, 0); + + AL10.alSource3f(sourceId, AL10.AL_POSITION, -pan, 0, 0); } - + public void dispose () { for (int i = 0, n = allSources.size; i < n; i++) { int sourceID = allSources.get(i); @@ -250,9 +250,9 @@ public class OpenALAudio implements Audio { sourceToSoundId.clear(); soundIdToSource.clear(); - + AL.destroy(); - while(AL.isCreated()) { + while (AL.isCreated()) { try { Thread.sleep(10); } catch (InterruptedException e) { @@ -260,12 +260,12 @@ public class OpenALAudio implements Audio { } } - public AudioDevice newAudioDevice (int samplingRate, boolean isMono) { - // BOZO - Write OpenAL device. - return new JavaSoundAudioDevice(samplingRate, isMono); + public AudioDevice newAudioDevice (int sampleRate, boolean isMono) { + return new OpenALAudioDevice(this, sampleRate, isMono); } public AudioRecorder newAudioRecoder (int samplingRate, boolean isMono) { + // BOZO - Write OpenAL recorder. return new JavaSoundAudioRecorder(samplingRate, isMono); } diff --git a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudioDevice.java b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudioDevice.java new file mode 100644 index 000000000..874e778b6 --- /dev/null +++ b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudioDevice.java @@ -0,0 +1,179 @@ + +package com.badlogic.gdx.backends.openal; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import org.lwjgl.BufferUtils; +import org.lwjgl.openal.AL11; + +import com.badlogic.gdx.audio.AudioDevice; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.utils.GdxRuntimeException; + +import static org.lwjgl.openal.AL10.*; + +/** @author Nathan Sweet */ +public class OpenALAudioDevice implements AudioDevice { + static private final int bufferSize = 512; + static private final int bufferCount = 9; + static private final int bytesPerSample = 2; + static private final ByteBuffer tempBuffer = BufferUtils.createByteBuffer(bufferSize); + + private final OpenALAudio audio; + private final int channels; + private IntBuffer buffers; + private int sourceID = -1; + private int format, sampleRate; + private boolean isPlaying; + private float volume = 1; + private float renderedSeconds, secondsPerBuffer; + private byte[] bytes; + + public OpenALAudioDevice (OpenALAudio audio, int sampleRate, boolean isMono) { + this.audio = audio; + channels = isMono ? 1 : 2; + this.format = channels > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; + this.sampleRate = sampleRate; + secondsPerBuffer = (float)bufferSize / bytesPerSample / channels / sampleRate; + } + + public void writeSamples (short[] samples, int offset, int numSamples) { + if (bytes == null || bytes.length < numSamples * 2) bytes = new byte[numSamples * 2]; + for (int i = offset, ii = 0; i < numSamples; i++) { + short sample = samples[i]; + bytes[ii++] = (byte)(sample & 0xFF); + bytes[ii++] = (byte)((sample >> 8) & 0xFF); + } + writeSamples(bytes, 0, numSamples * 2); + } + + public void writeSamples (float[] samples, int offset, int numSamples) { + if (bytes == null || bytes.length < numSamples * 2) bytes = new byte[numSamples * 2]; + for (int i = offset, ii = 0; i < numSamples; i++) { + float floatSample = samples[i]; + floatSample = MathUtils.clamp(floatSample, -1f, 1f); + int intSample = (int)(floatSample * 32767); + bytes[ii++] = (byte)(intSample & 0xFF); + bytes[ii++] = (byte)((intSample >> 8) & 0xFF); + } + writeSamples(bytes, 0, numSamples * 2); + } + + public void writeSamples (byte[] data, int offset, int length) { + if (length < 0) throw new IllegalArgumentException("length cannot be < 0."); + + if (sourceID == -1) { + sourceID = audio.obtainSource(true); + if (sourceID == -1) return; + if (buffers == null) { + buffers = BufferUtils.createIntBuffer(bufferCount); + alGenBuffers(buffers); + if (alGetError() != AL_NO_ERROR) throw new GdxRuntimeException("Unabe to allocate audio buffers."); + } + alSourcei(sourceID, AL_LOOPING, AL_FALSE); + alSourcef(sourceID, AL_GAIN, volume); + // Queue empty buffers. + tempBuffer.clear().flip(); + for (int i = 0; i < bufferCount; i++) { + int bufferID = buffers.get(i); + alBufferData(bufferID, format, tempBuffer, sampleRate); + alSourceQueueBuffers(sourceID, bufferID); + } + alSourcePlay(sourceID); + isPlaying = true; + return; + } + + while (length > 0) { + int written = fillBuffer(data, offset, length); + length -= written; + offset += written; + } + } + + /** Blocks until some of the data could be buffered. */ + private int fillBuffer (byte[] data, int offset, int length) { + int written = Math.min(bufferSize, length); + + outer: + while (true) { + int buffers = alGetSourcei(sourceID, AL_BUFFERS_PROCESSED); + while (buffers-- > 0) { + int bufferID = alSourceUnqueueBuffers(sourceID); + if (bufferID == AL_INVALID_VALUE) break; + renderedSeconds += secondsPerBuffer; + + tempBuffer.clear(); + tempBuffer.put(data, offset, written).flip(); + alBufferData(bufferID, format, tempBuffer, sampleRate); + + alSourceQueueBuffers(sourceID, bufferID); + break outer; + } + // Wait for buffer to be free. + try { + Thread.sleep((long)(1000 * secondsPerBuffer / bufferCount)); + } catch (InterruptedException ignored) { + } + } + + // A buffer underflow will cause the source to stop. + if (!isPlaying || alGetSourcei(sourceID, AL_SOURCE_STATE) != AL_PLAYING) { + System.out.println("underflow!"); + alSourcePlay(sourceID); + isPlaying = true; + } + + return written; + } + + public void stop () { + if (sourceID == -1) return; + audio.freeSource(sourceID); + sourceID = -1; + renderedSeconds = 0; + isPlaying = false; + } + + public boolean isPlaying () { + if (sourceID == -1) return false; + return isPlaying; + } + + public void setVolume (float volume) { + this.volume = volume; + if (sourceID != -1) alSourcef(sourceID, AL_GAIN, volume); + } + + public float getPosition () { + if (sourceID == -1) return 0; + return renderedSeconds + alGetSourcef(sourceID, AL11.AL_SEC_OFFSET); + } + + public int getChannels () { + return format == AL_FORMAT_STEREO16 ? 2 : 1; + } + + public int getRate () { + return sampleRate; + } + + public void dispose () { + if (buffers == null) return; + if (sourceID != -1) { + audio.freeSource(sourceID); + sourceID = -1; + } + alDeleteBuffers(buffers); + buffers = null; + } + + public boolean isMono () { + return false; + } + + public int getLatency () { + return (int)(secondsPerBuffer * bufferCount * 1000); + } +} diff --git a/gdx/src/com/badlogic/gdx/ApplicationAdapter.java b/gdx/src/com/badlogic/gdx/ApplicationAdapter.java index c8684c5f8..fdf04bb55 100644 --- a/gdx/src/com/badlogic/gdx/ApplicationAdapter.java +++ b/gdx/src/com/badlogic/gdx/ApplicationAdapter.java @@ -1,47 +1,30 @@ + package com.badlogic.gdx; -/** - * Convenience implementation of {@link ApplicationListener}. Derrive from this and only - * override what you need. - * @author mzechner - * - */ +/** Convenience implementation of {@link ApplicationListener}. Derrive from this and only override what you need. + * @author mzechner */ public abstract class ApplicationAdapter implements ApplicationListener { - @Override public void create () { - // TODO Auto-generated method stub - } @Override public void resize (int width, int height) { - // TODO Auto-generated method stub - } @Override public void render () { - // TODO Auto-generated method stub - } @Override public void pause () { - // TODO Auto-generated method stub - } @Override public void resume () { - // TODO Auto-generated method stub - } @Override public void dispose () { - // TODO Auto-generated method stub - } - } diff --git a/gdx/src/com/badlogic/gdx/graphics/glutils/ShapeRenderer.java b/gdx/src/com/badlogic/gdx/graphics/glutils/ShapeRenderer.java index 3f5e6c88e..02cfc385e 100644 --- a/gdx/src/com/badlogic/gdx/graphics/glutils/ShapeRenderer.java +++ b/gdx/src/com/badlogic/gdx/graphics/glutils/ShapeRenderer.java @@ -378,7 +378,7 @@ public class ShapeRenderer { /** Calls {@link #circle(float, float, float, int)} by estimating the number of segments needed for a smooth circle. */ public void circle (float x, float y, float radius) { - circle(x, y, radius, (int)(4 * (float)Math.sqrt(radius))); + circle(x, y, radius, (int)(6 * (float)Math.cbrt(radius))); } public void circle (float x, float y, float radius, int segments) {