Index: trunk/src/org/openstreetmap/josm/actions/OpenAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/OpenAction.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/actions/OpenAction.java	(revision 553)
@@ -89,6 +89,7 @@
 			}
 			r.data.storageFile = file;
-			Main.main.addLayer(new GpxLayer(r.data, fn));
-            MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file);
+			GpxLayer gpxLayer = new GpxLayer(r.data, fn);
+			Main.main.addLayer(gpxLayer);
+            MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer);
             if (ml.data.size() > 0) {
             	Main.main.addLayer(ml);
Index: trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java	(revision 553)
@@ -27,4 +27,8 @@
 	}
 	
+	public EastNorth interpolate(EastNorth en2, double proportion) {
+		return new EastNorth(this.x + proportion * (en2.x - this.x),this.y + proportion * (en2.y - this.y));
+	}
+	
 	@Override public String toString() {
 		return "EastNorth[e="+x+", n="+y+"]";
Index: trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 553)
@@ -16,8 +16,9 @@
 	public final LatLon latlon;
 	public final EastNorth eastNorth;
+	public double time;
 
 	public WayPoint(LatLon ll) {
 		latlon = ll; 
-		eastNorth = Main.proj.latlon2eastNorth(ll); 
+		eastNorth = Main.proj.latlon2eastNorth(ll);
 	}
 
@@ -31,12 +32,12 @@
 	 * @return seconds
 	 */
-	public double time () {
+	public void setTime () {
 		if (! attr.containsKey("time"))
-			return 0.0;
+			time = 0.0;
 		SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); // ignore timezone
 		Date d = f.parse(attr.get("time").toString(), new ParsePosition(0));
 		if (d == null /* failed to parse */)
-			return 0.0;
-		return d.getTime() / 1000.0; /* ms => seconds */
+			time = 0.0;
+		time = d.getTime() / 1000.0; /* ms => seconds */
 	}
 
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 553)
@@ -10,4 +10,6 @@
 import java.awt.event.ComponentEvent;
 import java.awt.event.KeyEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -72,4 +74,5 @@
 	 */
 	private Layer activeLayer;
+	
 	/**
 	 * The listener of the active layer changes.
Index: trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 553)
@@ -69,8 +69,10 @@
 public class GpxLayer extends Layer {
 	public GpxData data;
-
+	private final GpxLayer me;
+	
 	public GpxLayer(GpxData d) {
 		super((String) d.attr.get("name"));
-		data = d;		
+		data = d;
+		me = this;
 	}
 
@@ -149,5 +151,5 @@
 								namedTrackPoints.waypoints.add(point);
 
-	            MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", name), associatedFile);
+	            MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", name), associatedFile, me);
 	            if (ml.data.size() > 0) {
 	            	Main.main.addLayer(ml);
@@ -499,10 +501,10 @@
 	    WayPoint prevPoint = null;
 
-	    MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Sampled audio markers from {0}", name), associatedFile);
+	    MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Sampled audio markers from {0}", name), associatedFile, me);
 	    
 		for (GpxTrack track : data.tracks) {
 			for (Collection<WayPoint> seg : track.trackSegs) {
 				for (WayPoint point : seg) {
-					double time = point.time();
+					double time = point.time;
 					if (firstTime < 0.0)
 						firstTime = time;
@@ -521,5 +523,5 @@
 						else
 							markerName = String.format("%d:%02d:%02d", wholeSeconds / 3600, (wholeSeconds % 3600)/60, wholeSeconds % 60);
-						AudioMarker am = AudioMarker.create(point.latlon, markerName, uri, offset);
+						AudioMarker am = AudioMarker.create(point.latlon, markerName, uri, ml, time, offset);
 						ml.data.add(am);
 						prevPoint = point;
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java	(revision 553)
@@ -4,18 +4,24 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.io.IOException;
 import java.net.URL;
 
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.DataLine;
-import javax.sound.sampled.SourceDataLine;
+import javax.swing.Icon;
 import javax.swing.JOptionPane;
+import javax.swing.Timer;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.tools.AudioPlayer;
+import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.gui.MapView;
+
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
@@ -27,15 +33,15 @@
 public class AudioMarker extends ButtonMarker {
 
-	private URL audioUrl;
-	private double syncOffset;
+	private URL audioUrl;	
 	private static AudioMarker recentlyPlayedMarker = null;
-
+	public  double syncOffset;
+	
 	/**
 	 * Verifies the parameter whether a new AudioMarker can be created and return
 	 * one or return <code>null</code>.
 	 */
-	public static AudioMarker create(LatLon ll, String text, String url, double offset) {
+	public static AudioMarker create(LatLon ll, String text, String url, MarkerLayer parentLayer, double time, double offset) {
 		try {
-			return new AudioMarker(ll, text, new URL(url), offset);
+			return new AudioMarker(ll, text, new URL(url), parentLayer, time, offset);
 		} catch (Exception ex) {
 			return null;
@@ -43,6 +49,6 @@
 	}
 
-	private AudioMarker(LatLon ll, String text, URL audioUrl, double offset) {
-		super(ll, text, "speech.png", offset);
+	private AudioMarker(LatLon ll, String text, URL audioUrl, MarkerLayer parentLayer, double time, double offset) {
+		super(ll, text, "speech.png", parentLayer, time, offset);
 		this.audioUrl = audioUrl;
 		this.syncOffset = 0.0;
@@ -60,5 +66,5 @@
 		return audioUrl;
 	}
-	
+		
 	/**
 	 * Starts playing the audio associated with the marker: used in response to pressing
@@ -68,4 +74,9 @@
 	public void play() {
 		try {
+			// first enable tracing the audio along the track
+			if (Main.pref.getBoolean("marker.traceaudio") && parentLayer != null) {
+				parentLayer.traceAudio();
+			}
+
 			AudioPlayer.play(audioUrl, offset + syncOffset);
 			recentlyPlayedMarker = this;
@@ -74,5 +85,5 @@
 		}
 	}
-	
+
 	public void adjustOffset(double adjustment) {
 		syncOffset = adjustment; // added to offset may turn out negative, but that's ok
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java	(revision 553)
@@ -25,12 +25,13 @@
 
 	private Rectangle buttonRectangle;
+	protected Graphics graphicsContext = null;
 	
-	public ButtonMarker(LatLon ll, String buttonImage, double offset) {
-		super(ll, null, buttonImage, offset);
+	public ButtonMarker(LatLon ll, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
+		super(ll, null, buttonImage, parentLayer, time, offset);
 		buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
 	}
 	
-	public ButtonMarker(LatLon ll, String text, String buttonImage, double offset) {
-		super(ll, text, buttonImage, offset);
+	public ButtonMarker(LatLon ll, String text, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
+		super(ll, text, buttonImage, parentLayer, time, offset);
 		buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
 	}
@@ -43,4 +44,5 @@
 	
 	@Override public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
+		graphicsContext = g;
 		Point screen = mv.getPoint(eastNorth);
 		buttonRectangle.setLocation(screen.x+4, screen.y+2);
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java	(revision 553)
@@ -22,4 +22,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.gui.layer.Layer;
 
 /**
@@ -34,7 +35,7 @@
 	public URL imageUrl;
 
-	public static ImageMarker create(LatLon ll, String url, double offset) {
+	public static ImageMarker create(LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
 		try {
-			return new ImageMarker(ll, new URL(url), offset);
+			return new ImageMarker(ll, new URL(url), parentLayer, time, offset);
 		} catch (Exception ex) {
 			return null;
@@ -42,6 +43,6 @@
 	}
 
-	private ImageMarker(LatLon ll, URL imageUrl, double offset) {
-		super(ll, "photo.png", offset);
+	private ImageMarker(LatLon ll, URL imageUrl, MarkerLayer parentLayer, double time, double offset) {
+		super(ll, "photo.png", parentLayer, time, offset);
 		this.imageUrl = imageUrl;
 	}
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 553)
@@ -22,4 +22,5 @@
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -64,4 +65,6 @@
 	public final String text;
 	public final Icon symbol;
+	public final MarkerLayer parentLayer;
+	public double time; /* avbsolute time of marker since epocj */
 	public double offset; /* time offset in seconds from the gpx point from which it was derived,
 							 may be adjusted later to sync with other data, so not final */
@@ -78,8 +81,8 @@
 		Marker.markerProducers.add(new MarkerProducers() {
 			public Marker createMarker(WayPoint wpt, File relativePath) {
-				return createMarker(wpt, relativePath, 0.0);
+				return createMarker(wpt, relativePath, null, 0.0, 0.0);
 			}
 			
-			public Marker createMarker(WayPoint wpt, File relativePath, double offset) {
+			public Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
 				String uri = null;
 				// cheapest way to check whether "link" object exists and is a non-empty
@@ -104,11 +107,11 @@
                 
                 if (uri == null)
-                    return new Marker(wpt.latlon, name_desc, wpt.getString("symbol"), offset);
+                    return new Marker(wpt.latlon, name_desc, wpt.getString("symbol"), parentLayer, time, offset);
                 else if (uri.endsWith(".wav"))
-                    return AudioMarker.create(wpt.latlon, name_desc, uri, offset);
+                    return AudioMarker.create(wpt.latlon, name_desc, uri, parentLayer, time, offset);
                 else if (uri.endsWith(".png") || uri.endsWith(".jpg") || uri.endsWith(".jpeg") || uri.endsWith(".gif"))
-					return ImageMarker.create(wpt.latlon, uri, offset);
+					return ImageMarker.create(wpt.latlon, uri, parentLayer, time, offset);
 				else
-					return WebMarker.create(wpt.latlon, uri, offset);
+					return WebMarker.create(wpt.latlon, uri, parentLayer, time, offset);
 			}
 
@@ -124,8 +127,9 @@
 	}
 
-	public Marker(LatLon ll, String text, String iconName, double offset) {
+	public Marker(LatLon ll, String text, String iconName, MarkerLayer parentLayer, double time, double offset) {
 		eastNorth = Main.proj.latlon2eastNorth(ll); 
 		this.text = text;
 		this.offset = offset;
+		this.time = time;
 		Icon symbol = ImageProvider.getIfAvailable("markers",iconName);
 		if (symbol == null)
@@ -134,4 +138,5 @@
 			symbol = ImageProvider.getIfAvailable("nodes",iconName);
 		this.symbol = symbol;
+		this.parentLayer = parentLayer;
 	}
 
@@ -187,7 +192,7 @@
 	 * @return a new Marker object
 	 */
-	public static Marker createMarker(WayPoint wpt, File relativePath, double offset) {
+	public static Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
 		for (MarkerProducers maker : Marker.markerProducers) {
-			Marker marker = maker.createMarker(wpt, relativePath, offset);
+			Marker marker = maker.createMarker(wpt, relativePath, parentLayer, time, offset);
 			if (marker != null)
 				return marker;
@@ -207,5 +212,5 @@
 	
 	public AudioMarker audioMarkerFromMarker(String uri) {
-		AudioMarker audioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(this.eastNorth), this.text, uri, this.offset);
+		AudioMarker audioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(this.eastNorth), this.text, uri, this.parentLayer, this.time, this.offset);
 		return audioMarker;
 	}
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 553)
@@ -9,4 +9,5 @@
 import java.awt.Graphics;
 import java.awt.Point;
+import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -26,9 +27,13 @@
 import javax.swing.JSeparator;
 import javax.swing.SwingUtilities;
+import javax.swing.Timer;
 import javax.swing.filechooser.FileFilter;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.RenameLayerAction;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
@@ -37,4 +42,5 @@
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.markerlayer.AudioMarker;
 import org.openstreetmap.josm.tools.ColorHelper;
@@ -60,18 +66,26 @@
 	public final Collection<Marker> data;
 	private boolean mousePressed = false;
-	
-	public MarkerLayer(GpxData indata, String name, File associatedFile) {
+	public GpxLayer fromLayer = null;
+	private Rectangle audioTracer = null;
+	private Icon audioTracerIcon = null;
+	private EastNorth audioTracerPosition = null;
+	private static Timer timer = null;
+	private static double audioAnimationInterval = 0.0; // seconds
+	private static double previousTime = -1.0;
+
+	public MarkerLayer(GpxData indata, String name, File associatedFile, GpxLayer fromLayer) {
 		
 		super(name);
 		this.associatedFile = associatedFile;
 		this.data = new ArrayList<Marker>();
+		this.fromLayer = fromLayer;
 		double firstTime = -1.0;
 
 		for (WayPoint wpt : indata.waypoints) {
 			/* calculate time differences in waypoints */
-			double time = wpt.time();
+			double time = wpt.time;
 			if (firstTime < 0)
 				firstTime = time;
-            Marker m = Marker.createMarker(wpt, indata.storageFile, time - firstTime);
+            Marker m = Marker.createMarker(wpt, indata.storageFile, this, time, time - firstTime);
             if (m != null)
             	data.add(m);
@@ -147,4 +161,74 @@
 			}
 		}
+
+		if (audioTracer != null) {
+			Point screen = Main.map.mapView.getPoint(audioTracerPosition);
+			audioTracer.setLocation(screen.x, screen.y);
+			audioTracerIcon.paintIcon(Main.map.mapView, g, screen.x, screen.y);
+		}
+	}
+
+	protected void traceAudio() {
+		if (timer == null) {
+			audioAnimationInterval = Double.parseDouble(Main.pref.get("marker.audioanimationinterval", "1")); //milliseconds
+			timer = new Timer((int)(audioAnimationInterval * 1000.0), new ActionListener() {
+				public void actionPerformed(ActionEvent e) {
+					timerAction();
+				}
+			});
+			timer.start();
+		}
+	}
+	
+	/**
+	 * callback for AudioPlayer when position changes 
+	 * @param position seconds into the audio stream
+	 */
+	public void timerAction() {
+		AudioMarker recentlyPlayedMarker = AudioMarker.recentlyPlayedMarker();
+		if (recentlyPlayedMarker == null)
+			return;
+		double audioTime = recentlyPlayedMarker.time + 
+			AudioPlayer.position() - 
+			recentlyPlayedMarker.offset -
+			recentlyPlayedMarker.syncOffset;
+		if (Math.abs(audioTime- previousTime) < audioAnimationInterval)
+			return;
+		if (fromLayer == null)
+			return;
+		/* find the pair of track points for this position (adjusted by the syncOffset)
+		 * and interpolate between them 
+		 */
+		WayPoint w1 = null;
+		WayPoint w2 = null;
+
+		for (GpxTrack track : fromLayer.data.tracks) {
+			for (Collection<WayPoint> trackseg : track.trackSegs) {
+				for (Iterator<WayPoint> it = trackseg.iterator(); it.hasNext();) {
+					WayPoint w = it.next();
+					if (audioTime < w.time) {
+						w2 = w;
+						break;
+					}
+					w1 = w;
+				}
+				if (w2 != null) break;
+			}
+			if (w2 != null) break;
+		}
+		
+		if (w1 == null)
+			return;
+		audioTracerPosition = w2 == null ? 
+			w1.eastNorth : 
+			w1.eastNorth.interpolate(w2.eastNorth, 
+					(audioTime - w1.time)/(w2.time - w1.time));
+		
+		if (audioTracer == null) {
+			audioTracerIcon = ImageProvider.getIfAvailable("markers",Main.pref.get("marker.audiotracericon", "audio-tracer"));
+			audioTracer = new Rectangle(0, 0, audioTracerIcon.getIconWidth(), audioTracerIcon.getIconHeight());			
+		}
+		previousTime = audioTime;
+		Main.map.mapView.repaint();
 	}
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerProducers.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerProducers.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerProducers.java	(revision 553)
@@ -7,4 +7,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.gui.layer.Layer;
 
 /**
@@ -27,4 +28,4 @@
 	 * @return A Marker object, or <code>null</code>.
 	 */
-	public Marker createMarker(WayPoint wp, File relativePath, double offset);
+	public Marker createMarker(WayPoint wp, File relativePath, MarkerLayer parentLayer, double time, double offset);
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java	(revision 553)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.tools.OpenBrowser;
+import org.openstreetmap.josm.gui.layer.Layer;
 
 /**
@@ -23,7 +24,7 @@
 	public URL webUrl;
 
-	public static WebMarker create (LatLon ll, String url, double offset) {
+	public static WebMarker create (LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
 		try {
-			return new WebMarker(ll, new URL(url), offset);
+			return new WebMarker(ll, new URL(url), parentLayer, time, offset);
 		} catch (Exception ex) {
 			return null;
@@ -31,6 +32,6 @@
 	}
 
-	private WebMarker(LatLon ll, URL webUrl, double offset) {
-		super(ll, "web.png", offset);
+	private WebMarker(LatLon ll, URL webUrl, MarkerLayer parentLayer, double time, double offset) {
+		super(ll, "web.png", parentLayer, time, offset);
 		this.webUrl = webUrl;
 	}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 553)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 553)
@@ -0,0 +1,122 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.preferences;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.GBC;
+
+/*
+ * marker.audiosampleminsecs
+ * marker.audiosampleminmetres
+ * marker.buttonlabels
+ * markers.namedtrackpoints
+ * audio.forwardbackamount
+ * audio.leadin
+ * audio.menuinvisible
+ * marker.audiotraceVisible
+ * audio.toolbar ??
+ */
+
+public class AudioPreference implements PreferenceSetting {
+	private JCheckBox audioMenuVisible = new JCheckBox(tr("Display the Audio menu."));
+	/*
+	private JCheckBox audioToolbarVisible = new JCheckBox(tr("Display Audio control buttons on toolbar."));
+	*/
+	private JCheckBox markerButtonLabels = new JCheckBox(tr("Label audio (and image and web) markers."));
+	private JCheckBox markerAudioTraceVisible = new JCheckBox(tr("Display live audio trace."));
+	private JCheckBox markersNamedTrackpoints = new JCheckBox(tr("Create audio markers from named trackpoints."));
+
+	private JTextField audioSampleMinSecs = new JTextField(8);
+	private JTextField audioSampleMinMetres = new JTextField(8);
+	private JTextField audioLeadIn = new JTextField(8);
+	private JTextField audioForwardBackAmount = new JTextField(8);
+
+	public void addGui(PreferenceDialog gui) {
+		// audioMenuVisible
+		audioMenuVisible.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				if (!audioMenuVisible.isSelected())
+					audioMenuVisible.setSelected(false);
+				audioMenuVisible.setEnabled(audioMenuVisible.isSelected());
+			}
+		});
+		audioMenuVisible.setSelected(! Main.pref.getBoolean("audio.menuinvisible"));
+		audioMenuVisible.setToolTipText(tr("Show or hide the audio menu entry on the main menu bar."));
+		gui.audio.add(audioMenuVisible, GBC.eol().insets(0,0,0,0));
+
+		// audioTraceVisible
+		markerAudioTraceVisible.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				if (!markerAudioTraceVisible.isSelected())
+					markerAudioTraceVisible.setSelected(false);
+				markerAudioTraceVisible.setEnabled(markerAudioTraceVisible.isSelected());
+			}
+		});
+		markerAudioTraceVisible.setSelected(Main.pref.getBoolean("marker.traceaudio"));
+		markerAudioTraceVisible.setToolTipText(tr("Display a moving icon representing the point on the synchronized track where the audio currently playing was recorded."));
+		gui.audio.add(markerAudioTraceVisible, GBC.eol().insets(0,0,0,0));
+		
+		// buttonLabels
+		markerButtonLabels.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				if (!markerButtonLabels.isSelected())
+					markerButtonLabels.setSelected(false);
+				markerButtonLabels.setEnabled(markerButtonLabels.isSelected());
+			}
+		});
+		markerButtonLabels.setSelected(Main.pref.getBoolean("marker.buttonlabels"));
+		markerButtonLabels.setToolTipText(tr("Put text labels against audio (and image and web) markers as well as their button icons."));
+		gui.audio.add(markerButtonLabels, GBC.eol().insets(0,0,0,0));
+		
+		// markersNamedTrackpoints
+		markersNamedTrackpoints.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				if (!markersNamedTrackpoints.isSelected())
+					markersNamedTrackpoints.setSelected(false);
+				markersNamedTrackpoints.setEnabled(markersNamedTrackpoints.isSelected());
+			}
+		});
+		markersNamedTrackpoints.setSelected(Main.pref.getBoolean("markers.namedtrackpoints"));
+		markersNamedTrackpoints.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
+		gui.audio.add(markersNamedTrackpoints, GBC.eol().insets(0,0,0,0));
+		
+		audioSampleMinSecs.setText(Main.pref.get("marker.audiosampleminsecs", "15"));
+		audioSampleMinSecs.setToolTipText(tr("Minimum time in seconds between audio samples when creating sampled audio markers from waypoints"));
+		gui.audio.add(new JLabel(tr("Min audio marker sample rate (seconds)")), GBC.std());
+		gui.audio.add(audioSampleMinSecs, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+		audioSampleMinMetres.setText(Main.pref.get("marker.audiosampleminmetres", "75"));
+		audioSampleMinMetres.setToolTipText(tr("Minimum distance in metres between audio samples when creating sampled audio markers from waypoints"));
+		gui.audio.add(new JLabel(tr("Min audio marker sample rate (metres)")), GBC.std());
+		gui.audio.add(audioSampleMinMetres, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+		audioForwardBackAmount.setText(Main.pref.get("audio.forwardbackamount", "10"));
+		audioForwardBackAmount.setToolTipText(tr("The number of seconds to jump forward or back when the relevant button is pressed"));
+		gui.audio.add(new JLabel(tr("Forward/back time (seconds)")), GBC.std());
+		gui.audio.add(audioForwardBackAmount, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+
+		audioLeadIn.setText(Main.pref.get("audio.leadin", "1"));
+		audioLeadIn.setToolTipText(tr("Playback starts this number of seconds before (or after, if negative) the audio track position requested"));
+		gui.audio.add(new JLabel(tr("Lead-in time (seconds)")), GBC.std());
+		gui.audio.add(audioLeadIn, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
+	}
+
+	public void ok() {
+		Main.pref.put("audio.menuinvisible", ! audioMenuVisible.isSelected());
+		Main.pref.put("marker.traceaudio", markerAudioTraceVisible.isSelected());
+		Main.pref.put("marker.buttonlabels", markerButtonLabels.isSelected());
+		Main.pref.put("markers.namedtrackpoints", markersNamedTrackpoints.isSelected());
+		Main.pref.put("marker.audiosampleminsecs", audioSampleMinSecs.getText());		
+		Main.pref.put("marker.audiosampleminmetres", audioSampleMinMetres.getText());		
+		Main.pref.put("audio.forwardbackamount", audioForwardBackAmount.getText());		
+		Main.pref.put("audio.leadin", audioLeadIn.getText());		
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 553)
@@ -40,5 +40,6 @@
 	public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."));
 	public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
-
+	public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
+	
 	/**
 	 * Construct a JPanel for the preference settings. Layout is GridBagLayout
@@ -109,5 +110,6 @@
 		settings.add(new PluginPreference());
 		settings.add(Main.toolbar);
-
+		settings.add(new AudioPreference());
+		
 		for (PluginProxy plugin : Main.plugins) {
 			PreferenceSetting p = plugin.getPreferenceSetting();
Index: trunk/src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 553)
@@ -234,7 +234,9 @@
 				} else if (qName.equals("rtept")) {
 					currentState = states.pop();
+					currentWayPoint.setTime();
 					currentRoute.routePoints.add(currentWayPoint);
 				} else if (qName.equals("trkpt")) {
 					currentState = states.pop();
+					currentWayPoint.setTime();
 					currentTrackSeg.add(currentWayPoint);
 					if (Main.pref.getBoolean("marker.namedtrackpoints") && 
@@ -246,4 +248,5 @@
 				} else if (qName.equals("wpt")) {
 					currentState = states.pop();
+					currentWayPoint.setTime();
 					currentData.waypoints.add(currentWayPoint);
 				}
Index: trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java	(revision 552)
+++ trunk/src/org/openstreetmap/josm/tools/AudioPlayer.java	(revision 553)
@@ -35,5 +35,5 @@
 	private double position; // seconds
 	private double bytesPerSecond; 
-	
+
 	/**
 	 * Passes information from the control thread to the playing thread 
