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