FPSAnimator affected by... javax audio?

I’m currently developing an application with jogl and discovered that although I created an FPSAnimator with 60 FPS target framerate it’s only actually producing 30 (refresh rate sync disabled). This happens although nothing is going on in display(). The funny thing is… once I play a sound with the javax sound facility (see below) it suddently accelerates to 60 Hz. What is going on here?


Clip clip = clips.get(clipURL);
clip.setFramePosition(0);
clip.start();

I’ll try to reproduce this behavior in a somewhat vanilla demo application to explore it further but before I do I’d like to know if anyone of you experienced the same.

Cheers
Jo

When I try to use an animator, my sound system goes crazy, I gave it up, I don’t use an animator for the moment.

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