I’ve created a little app that demonstrates the problem. Essentially it creates a GLCanvas with nothing in it except the framerate measurement. Additionally, when you hit the F key, it uses javax sound to play a beep.
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.text.NumberFormat;
import java.util.Locale;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
import com.sun.opengl.util.Animator;
import com.sun.opengl.util.FPSAnimator;
/**
* Little app to test the JOGL animator and sound issue.
* @date 2008-09-11
* @author jobieg
*/
public class AnimatorSoundIssue implements GLEventListener, KeyListener {
private JFrame mainWindow;
private GLCanvas glCanvas;
private Animator animator;
private Clip clip;
private static NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
static {
nf.setMinimumFractionDigits(4);
nf.setMaximumFractionDigits(4);
}
public static void main(String[] args) {
new AnimatorSoundIssue();
}
public AnimatorSoundIssue() {
// Create window
mainWindow = new JFrame("GLwindow");
mainWindow.setSize(800, 600);
mainWindow.setResizable(false);
// Create canvas
glCanvas = new GLCanvas();
glCanvas.addGLEventListener(this);
glCanvas.addKeyListener(this);
// Prepare window
mainWindow.add(glCanvas);
mainWindow.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
new Point(0, 0), "transparent"));
mainWindow.addWindowListener(new WindowAdapter() {
@Override
public void windowActivated(WindowEvent e) {
glCanvas.requestFocusInWindow();
super.windowActivated(e);
}
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// Load audio
URL url = ClassLoader.getSystemResource("beep.wav"); // TODO: add your sound here
try {
clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(url));
} catch (Exception e1) {
e1.printStackTrace();
System.exit(-1);
}
// Create animator
animator = new FPSAnimator(glCanvas, 60, true);
animator.start();
// Show window
mainWindow.setUndecorated(true);
mainWindow.setVisible(true);
}
/* ==============================================================
* Time measurement
* ==============================================================
*/
private static final int N_SAMPLES = 100;
private long[] frameT = new long[N_SAMPLES];
private int frame_i = -1;
private void frameStart() {
frame_i = (frame_i + 1) % N_SAMPLES;
}
/**
* Logs the framerate every time N_SAMPLES have been gathered.
*/
private void frameEnd() {
if(frame_i == N_SAMPLES-1) {
double frameTime = averaged(frameT);
System.out.println("frameTime=" + nf.format(frameTime) + "ms");
double frameRate = 1000.0d/frameTime;
System.out.println("frameRate=" + nf.format(frameRate));
frame_i = -1;
}
}
/**
* Calculates the average of the frame time (delta between measurements at
* beginning of adjacent frames).
* @param m array of measurements
* @return averaged delta of measurements
*/
private double averaged(long[] m) {
long sum = 0;
for (int i = 0; i < m.length-1; i++) {
sum += m[i+1]-m[i];
}
return (double)sum/(double)N_SAMPLES;
}
private void measureFrameTime() {
frameT[frame_i] = System.currentTimeMillis();
}
/* ==============================================================
* GL callbacks
* ==============================================================
*/
@Override
public void display(GLAutoDrawable drawable) {
frameStart();
measureFrameTime();
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
frameEnd();
}
@Override
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
boolean deviceChanged) {
}
@Override
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
// Set GL parameters
gl.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
gl.glShadeModel(GL.GL_SMOOTH);
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width,
int height) {
}
/* ==============================================================
* KeyListener
* ==============================================================
*/
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_Q) {
System.exit(0);
} else if(e.getKeyCode() == KeyEvent.VK_F) {
System.out.println("Beep.");
clip.setFramePosition(0);
clip.start();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
I obtained the following results with this program:
Windows Vista
Java version: 1.6.0_05-b13
JOGL version: 1.1.1-rc8
VariableRate scheduling:
new FPSAnimator(glCanvas, 60, false)
frameTime=30.8800ms
frameRate=32.3834
frameTime=30.8900ms
frameRate=32.3729
frameTime=30.8900ms
frameRate=32.3729
frameTime=30.8900ms
frameRate=32.3729
frameTime=30.8900ms
frameRate=32.3729
frameTime=31.0400ms
frameRate=32.2165
Beep.
frameTime=18.7200ms
frameRate=53.4188
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8500ms
frameRate=63.0915
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8500ms
frameRate=63.0915
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8400ms
frameRate=63.1313
Windows Vista
Java version: 1.6.0_05-b13
JOGL version: 1.1.1-rc8
Fixed rate scheduling
new FPSAnimator(glCanvas, 60, true)
frameTime=14.8200ms
frameRate=67.4764
frameTime=15.7600ms
frameRate=63.4518
frameTime=15.9100ms
frameRate=62.8536
frameTime=15.7600ms
frameRate=63.4518
Beep.
frameTime=15.8500ms
frameRate=63.0915
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8400ms
frameRate=63.1313
Linux (Ubuntu Gutsy Gibbon)
Java version: 1.6.0_03-b05
JOGL version: 1.1.1-rc8
VariableRate scheduling:
new FPSAnimator(glCanvas, 60, false);
frameTime=17.1600ms
frameRate=58.2751
frameTime=15.9400ms
frameRate=62.7353
frameTime=15.8900ms
frameRate=62.9327
frameTime=15.8700ms
frameRate=63.0120
frameTime=15.9200ms
frameRate=62.8141
frameTime=15.9100ms
frameRate=62.8536
Beep.
frameTime=15.8600ms
frameRate=63.0517
frameTime=15.9100ms
frameRate=62.8536
frameTime=15.8800ms
frameRate=62.9723
frameTime=15.8400ms
frameRate=63.1313
Linux (Ubuntu Gutsy Gibbon)
Java version: 1.6.0_03-b05
JOGL version: 1.1.1-rc8
FixedRate scheduling
new FPSAnimator(glCanvas, 60, true);
frameTime=12.3200ms
frameRate=81.1688
frameTime=15.8300ms
frameRate=63.1712
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8300ms
frameRate=63.1712
frameTime=15.8400ms
frameRate=63.1313
Beep.
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8400ms
frameRate=63.1313
frameTime=15.8500ms
frameRate=63.0915
As can be seen the framerate rises to around 60 AFTER the sound has been played. But this is not the case if either FPSAnimator uses fixed rate scheduling or one is using Linux.
Suggestions anyone?
Jo