i don’t know anything about sounds so how would i go about to stream a wav-file since apparently AudioClip.loop() loads the whole wav-file into memory. i use mp3s at the moment and convert them into wav-files at startup and they tend to get very big, say 40 mbs, and that’s too much to keep in memory.
AudioClip is an old API and really shouldn’t be used anymore. Look up the javax.sound API form info on streaming sound data. You can also take a look at the GAGESound source for an example of how to stream manually. GAGESound does stream from memory, but the basic concept is the same.
yeah i had a look at javax.sound.sampled but i didn’t understand much of it. i kept looking for something like play() but found nothing. i haven’t experimented though so it might be simpler than i think
EDIT: typos
An article from Sun:
http://developer.java.sun.com/developer/qow/archive/22/
From developer.com
http://www.developer.com/java/article.php/857411
For myself, I’m gravitating towards the great work done by jbanes.
That’s all I have to say about that.
the first article didn’t help much since that’s the way i do it now.
the second was atleast about javax.sound.sampled but unfortunately “The next step is to read the entire file into memory”. that’s what i want to avoid… i’ll check out the GAGE-thing… the gage-timer didn’t work (or i did something wrong since the timer slowed down when in fullscreen – odd behaviour)
Hi mill!
The way I do it in GAGESound should be no different than how you’d do it to stream from disk. The only difference is that you’d read directly from the AudioInputStream and write it out to the SourceDataLine. Both of these are obtained via the AudioSystem object. Here’s some psuedo-code for you. It won’t compile (since this is a rough estimate pulled from memory), but it should give you an idea:
AudioInputStream in = AudioSystem.getAudioInputStream("myfile.wav");
Line.Info info = AudioSystem.getSourceLineInfo(new Line.Info(SourceDataLine.class));
SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
byte[] data = new byte[1024];
int length = 0;
line.open();
while((length = in.read(data, 0, data.length) > 0)
{
line.write(data, 0, length);
}
Also, can you explain what you mean about the timer slowing down when in full screen? It should be impossible for the timer to return anything but the current and correct time. Thanks.
thanks a lot. i managed to get it to work now.
some questions though…
is 1024 a good buffer size btw? i haven’t gor the faintest idea.
i put the stream in a separate thread… is that a good idea?
about the timer… nevermind what i said. i figured out what was wrong!
i used to store the dt in a float and since the main loop was so fast the dt was set to 0 and not to 0.00000000000000000000000000000001 or whatever. since the dt was 0 most of the time, everything moved slowly! solution? use a double instead or multiply the dt with some constant. i’ll give it a go right away!
btw, does the timer only work on win32? (i tried like ten timers that day so i didn’t exercise it thoroughly)
EDIT: typos
It’s hard to come up with a good buffer size. What I do with GAGESound is I keep filling the buffer with enough to play the length of the last rendering loop. This way, my sound lags about 1 or 2 frames behind.
The GAGETimer works on all OSes with a 1/1000 sec resolution. Windows is special because it has a resolution of either 10ms or 50ms without the DLL or better than 1/1000 sec with the DLL. If you’re not sure if the DLL is getting loaded, check the console. It should throw a stack trace if it doesn’t load.
jbanes,
I checked the docs, and I’m still not sure how to do this… if you want to load the dll in Windows, what do you have to do as far as deployment goes? What about if using JavaWebStart?
umm the gage timer makes my game behave oddly. i’ll try to explain.
I don’t use any threads and only use the timer and use that to time motions. this results in 100% cpu usage and it seems like events like KeyPressed lags behind.
i looked at your example and you don’t sleep at all. no AdvancedTimer.sleep(…) or Thread.sleep(…) at all.
If i use AdvancedTimer.sleep(…) i don’t see any difference. If I use Thread.sleep(…) cpu usage goes down to like 1% and the fps goes down to around 50 from 450 which i had when i didn’t use Thread.sleep(…). It doesn’t matter if I sleep 1 ms or 10 ms, I always get 50 fps or below. I have no clue why your game runs just fine and mine lags behind. Loading images are also slowed down by two or three times.
any ideas? i feel so stupid.
GergisKhan,
I guess just putting the DLL in the directory where you run the app should do (I don’t know GAGE though, maybe it’s different there).
Regarding Web Start, I loaded the windows DLL from lwjgl by adding the following element in the jnlp file:
<resources os="Windows">
<nativelib href="lwjgl_win.jar"/>
</resources>
where lwjgl_win.jar is the jarred dll. Something like this will probably work with GAGE as well.
Erik
Mill,
Are you using Java2D? You shouldn’t be able to get 450 fps using a bufferstrategy. The reason why my code doesn’t need sleeps is that the strategy.show() line allows other threads to get some work done. If you’re running flat out at 450 fps, other threads aren’t getting any time. You should be able to fix this by using the AdvancedTimer sleep methods or a Thread.sleep() method. Can you tell me how you were using AdvancedTimer.sleep(…)? Usually, it’s better to use AdvancedTimer.sleepUntil(…) like this:
AdvancedTimer timer = new AdvancedTimer();
long sleepTime = timer.getTicksPerSecond()/60; //60 fps
long ticks = 0;
timer.start();
while(true)
{
//draw stuff
timer.sleepUntil(ticks+sleepTime);
ticks += sleepTime;
}
The beautiful part about this algo is that it automatically catches up if the game falls behind.
Gergis, erikd had the right answer for you. Keep the DLL within the same directory you launch from and you should be fine. And his webstart example is correct as well. You can find more info on this in the Webstart developer docs.
here’s how i use it:
public void run() {
while (running) {
calcDeltaTime();
raceManager.performGameTick(dt);
if (fullscreen)
renderFullscreen();
else
renderWindow(windowGraphics);
}
}
private void calcDeltaTime() {
dt = (float) (atimer.getClockTicks() - lastGameTick);
dt = dt * 0.000001f;
lastGameTick = atimer.getClockTicks();
}
public void renderFullscreen() {
if (!strategy.contentsLost()) {
backgroundGraphics = strategy.getDrawGraphics();
switch (gameState) {
case RACING :
raceManager.updateGfx(backgroundGraphics);
break;
}
try {
strategy.show();
}
catch (IllegalStateException e) {
return;
}
backgroundGraphics.dispose();
}
calcFPS();
}
private void calcFPS() {
currTime = System.currentTimeMillis();
frameCount++;
if ((currTime - prevTime) >= fpsUpdateInterval) {
//System.out.println("Average FPS: " + avgFps);
System.out.println(dt + "\t\t" + fps + "\t\t" + (dt * fps));
fps = (float) frameCount / (currTime - prevTime) * 1000;
frameCount = 0;
prevTime = currTime;
}
}
if i put try {Thread.sleep(1);} catch (InterruptedException e) {} it behaves correctly, but the fps drops to like 50 and cpu utilization is around 3%
usually one would want cpu utilization to be ~100% since if you have a fast machine you want smooth graphics.
anyhow, i’ll try what you suggested. hope the code above makes sense btw. hard to cut and paste only the relevant parts of the code.
hah way cool! i get exactly 85 fps when i request that! it’s super smooth now.
the code below will produce 500 fps btw:
import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.ImageCapabilities;
import java.awt.Panel;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import com.dnsalias.java.timer.AdvancedTimer;
public class Main extends Frame {
static GraphicsDevice defaultDevice;
DisplayMode oldDisplayMode;
private TestPanel testPanel;
public static void main(String[] args) {
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
defaultDevice = env.getDefaultScreenDevice();
Main main = new Main();
}
public Main() {
testPanel = new TestPanel(this);
add(testPanel);
oldDisplayMode = defaultDevice.getDisplayMode();
DisplayMode newDisplayMode = new DisplayMode(640, 480, 32, 85);
setUndecorated(true);
defaultDevice.setFullScreenWindow(this);
defaultDevice.setDisplayMode(newDisplayMode);
validate();
setIgnoreRepaint(true);
testPanel.start();
}
private void quit() {
testPanel.stop();
defaultDevice.setDisplayMode(oldDisplayMode);
defaultDevice.setFullScreenWindow(null);
System.exit(0);
}
public class TestPanel extends Panel implements KeyListener {
private float fps;
private long fpsUpdateInterval;
private long prevTime;
private int frameCount;
private long currTime;
private float dt;
private Main main;
private boolean up, down, left, right;
private boolean running;
private AdvancedTimer timer;
private float x, y;
private long lastGameTick;
private Graphics backgroundGraphics;
private BufferStrategy strategy;
private long sleepTime, ticks;
public TestPanel(Main main) {
this.main = main;
up = down = left = right = false;
running = false;
timer = new AdvancedTimer();
sleepTime = AdvancedTimer.getTicksPerSecond()/500;
ticks = 0;
prevTime = currTime = System.currentTimeMillis();
lastGameTick = 0;
frameCount = 0;
fps = 0.0f;
fpsUpdateInterval = 1000;
x = y = 10;
addKeyListener(this);
}
public void start() {
running = true;
timer.start();
run();
}
public void stop() {
running = false;
timer.stop();
}
private void run() {
BufferCapabilities cap = new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), BufferCapabilities.FlipContents.COPIED);
try {
main.createBufferStrategy(3, cap);
}
catch (AWTException e) {}
strategy = main.getBufferStrategy();
backgroundGraphics = strategy.getDrawGraphics();
while (running) {
calcDeltaTime();
move();
render();
sleep();
}
}
private void sleep() {
timer.sleepUntil(ticks+sleepTime);
ticks += sleepTime;
}
private void move() {
float speed = dt * 2.0f;
if (up)
y -= speed;
if (down)
y += speed;
if (left)
x -= speed;
if (right)
x += speed;
}
private void calcDeltaTime() {
dt = (float) (timer.getClockTicks() - lastGameTick);
dt = dt * 0.00005f;
lastGameTick = timer.getClockTicks();
}
public void render() {
if (!strategy.contentsLost()) {
backgroundGraphics = strategy.getDrawGraphics();
// draw here
backgroundGraphics.setColor(Color.black);
backgroundGraphics.fillRect(0, 0, 640, 480);
backgroundGraphics.setColor(Color.white);
backgroundGraphics.fillRect(Math.round(x), Math.round(y), 10, 10);
try {
strategy.show();
}
catch (IllegalStateException e) {
return;
}
backgroundGraphics.dispose();
calcFPS();
}
}
private void calcFPS() {
currTime = System.currentTimeMillis();
frameCount++;
if ((currTime - prevTime) >= fpsUpdateInterval) {
System.out.println(dt + "\t\t" + fps + "\t\t" + (dt * fps));
fps = (float) frameCount / (currTime - prevTime) * 1000;
frameCount = 0;
prevTime = currTime;
}
}
public void keyTyped(KeyEvent arg0) {}
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyChar();
if (key == 97)
left = true;
if (key == 100)
right = true;
if (key == 119)
up = true;
if (key == 115)
down = true;
if (key == KeyEvent.VK_ESCAPE)
main.quit();
}
public void keyReleased(KeyEvent arg0) {
int key = arg0.getKeyChar();
if (key == 97)
left = false;
if (key == 100)
right = false;
if (key == 119)
up = false;
if (key == 115)
down = false;
}
}
}
Glad you’ve got it figured out mill. BTW, the AdvancedTimer code never actually sleeps. It just uses Thread.yield() to give up some time to other threads. This way, your rendering thread gets returned to quickly without bogging down other threads.
You said you had used AdvancedTimer.sleep() before and that it didn’t help. Why I asked how you were using it was I figured you were probably doing something along the lines of:
timer.sleep(1);
This won’t work. The timer runs so fast that the time will probably already have expired before the code even checks what time it is.
when do you get your own section here for GAGE just as LWJGL has?
just kidding hehe
anyway… yeah i had a look at the source before I tried sleepUntil(). perhaps the docs should mention something about this?
why is it impossible to get 500+ fps using Java2D? i may of course calculate the fps incorrectly
if you incorporate the changes regarding sleepUntil in the example i posted you can easily get lots and lots of fps
It’s supposed to be impossible. That doesn’t mean it is. There have been bugs in the past where the VSync wouldn’t happen and the game would run amok. My first revision of Duke Nukes Stuff had this problem. Apparently when I slept for a second or two while switching to full screen mode, the JDK would fail to acquire a VSync lock. Got 500 fps with good keyboard response. Pretty proud of myself, i was. ;D
I think they’ve fixed that particular problem since then. Jeff? Do you know if that one was fixed?
edit:
when do you get your own section here for GAGE just as
LWJGL has?
Don’t tell me! Tell the admins!
[quote][…]Duke Nukes Stuff[…]
[/quote]
btw i’m currently porting the build engine (used by duke nukem, shadow warrior and bout 10 other games) to lwjgl
so far only the map loading is done and only the geometry of the walls is displayed (i need to figure some of the flags out - the format is somewhat strange) :>
gonna GPL it when the core is done
btw i’m currently porting the build engine (used by duke
nukem, shadow warrior and bout 10 other games) to lwjgl
chuckle I’m sorry. DNS was something I discussed on the old boards. Duke Nukes Stuff was a simple game I made out of everyone’s favorite Java mascot, Duke! It was really just a technology test for the (then new) 1.4 gaming APIs.