Index: trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 812)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java	(revision 813)
@@ -206,4 +206,6 @@
 	private Collection<OsmPrimitive> getNearestCollectionVirtual(Point p) {
 		MapView c = Main.map.mapView;
+		int snapDistance = Main.pref.getInteger("mappaint.node.virtual-snap-distance", 8);
+		snapDistance *= snapDistance;
 		OsmPrimitive osm = c.getNearestNode(p);
 		if (osm == null)
@@ -220,8 +222,8 @@
 					int xd = p2.x-p1.x; if(xd < 0) xd = -xd;
 					int yd = p2.y-p1.y; if(yd < 0) yd = -yd;
-					if(xd+yd > Main.pref.getInteger("mappaint.node.virtual-space", 50))
+					if(xd+yd > Main.pref.getInteger("mappaint.node.virtual-space", 70))
 					{
 						Point pc = new Point((p1.x+p2.x)/2, (p1.y+p2.y)/2);
-						if(p.distanceSq(pc) < Main.map.mapView.snapDistance)
+						if(p.distanceSq(pc) < snapDistance)
 						{
 							Collection<Command> cmds = new LinkedList<Command>();
Index: trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 812)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 813)
@@ -35,14 +35,36 @@
 	 * Convert the time stamp of the waypoint into seconds from the epoch
 	 */
-	public void setTime () {
+	public void setTime() {
 		if (! attr.containsKey("time")) {
-			time = 0.0;
 			return;
 		}
 		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 */) {
-			time = 0.0;
-		} else {
+		if (d != null /* parsing ok */) {
+			time = d.getTime() / 1000.0; /* ms => seconds */
+		}
+	}
+
+	/**
+	 * Convert a time stamp of the waypoint from the <cmt> or <desc> field 
+	 * into seconds from the epoch. Handles the date format as it is used by 
+	 * Garmin handhelds. Does not overwrite an existing timestamp (!= 0.0).
+	 * A value of <time> fields overwrites values set with by method.
+	 * Does nothing if specified key does not exist or text cannot be parsed.
+	 * 
+	 * @param key The key that contains the text to convert.
+	 */
+	public void setGarminCommentTime(String key) {
+		// do not overwrite time if already set
+		if (time != 0.0) {
+			return;
+		}
+		if (! attr.containsKey(key)) {
+			return;
+		}
+		// example date format "18-AUG-08 13:33:03"
+		SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); // Garmin wpts have no timezone
+		Date d = f.parse(attr.get(key).toString(), new ParsePosition(0));
+		if (d != null /* parsing OK */) {
 			time = d.getTime() / 1000.0; /* ms => seconds */
 		}
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 812)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 813)
@@ -108,5 +108,5 @@
 		fillUnselectedNode = Main.pref.getBoolean("mappaint.node.fill-unselected", false);
 		virtualNodeSize = virtual ? Main.pref.getInteger("mappaint.node.virtual-size", 4) / 2 : 0;
-		virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 50);
+		virtualNodeSpace = Main.pref.getInteger("mappaint.node.virtual-space", 70);
 
 		((Graphics2D)g)
Index: trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 812)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 813)
@@ -81,5 +81,5 @@
 	private Color computeCacheColorUsed;
 	private boolean computeCacheColored;
-	
+
 	public GpxLayer(GpxData d) {
 		super((String) d.attr.get("name"));
@@ -162,11 +162,11 @@
 					for (Collection<WayPoint> seg : track.trackSegs)
 						for (WayPoint point : seg)
-							if (point.attr.containsKey("name") || point.attr.containsKey("desc")) 
+							if (point.attr.containsKey("name") || point.attr.containsKey("desc"))
 								namedTrackPoints.waypoints.add(point);
 
-	            MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", name), associatedFile, me);
-	            if (ml.data.size() > 0) {
-	            	Main.main.addLayer(ml);
-	            }
+				MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", name), associatedFile, me);
+				if (ml.data.size() > 0) {
+					Main.main.addLayer(ml);
+				}
 			}
 		});
@@ -191,15 +191,14 @@
 				if(fc.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION) {
 					if (!fc.getCurrentDirectory().getAbsolutePath().equals(dir))
-						Main.pref.put("markers.lastaudiodirectory", fc
-								.getCurrentDirectory().getAbsolutePath());
-					
-					// FIXME: properly support multi-selection here. 
+						Main.pref.put("markers.lastaudiodirectory", fc.getCurrentDirectory().getAbsolutePath());
+
+					// FIXME: properly support multi-selection here.
 					// Calling importAudio several times just creates N maker layers, which
 					// is sub-optimal.
 					File sel[] = fc.getSelectedFiles();
 					if(sel != null)
-						for (int i = 0; i < sel.length; i++) 
+						for (int i = 0; i < sel.length; i++)
 							importAudio(sel[i]);
-					
+
 					Main.map.repaint();
 				}
@@ -256,20 +255,20 @@
 				new JMenuItem(new LayerListPopup.InfoAction(this))};
 		return new Component[] {
-				new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
-				new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
-				new JSeparator(),
-				new JMenuItem(new SaveAction(this)),
-				new JMenuItem(new SaveAsAction(this)),
-				// new JMenuItem(new UploadTraceAction()),
-				color,
-				line,
-				tagimage,
-				importAudio,
-				markersFromNamedTrackpoints,
-				new JMenuItem(new ConvertToDataLayerAction()),
-				new JSeparator(),
-				new JMenuItem(new RenameLayerAction(associatedFile, this)),
-				new JSeparator(),
-				new JMenuItem(new LayerListPopup.InfoAction(this))};
+			new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
+			new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
+			new JSeparator(),
+			new JMenuItem(new SaveAction(this)),
+			new JMenuItem(new SaveAsAction(this)),
+			// new JMenuItem(new UploadTraceAction()),
+			color,
+			line,
+			tagimage,
+			importAudio,
+			markersFromNamedTrackpoints,
+			new JMenuItem(new ConvertToDataLayerAction()),
+			new JSeparator(),
+			new JMenuItem(new RenameLayerAction(associatedFile, this)),
+			new JSeparator(),
+			new JMenuItem(new LayerListPopup.InfoAction(this))};
 	}
 
@@ -278,50 +277,46 @@
 
 		info.append(trn("{0} track, ", "{0} tracks, ",
-				data.tracks.size(), data.tracks.size()))
-			.append(trn("{0} route, ", "{0} routes, ",
-				data.routes.size(), data.routes.size()))
-			.append(trn("{0} waypoint", "{0} waypoints",
-				data.waypoints.size(), data.waypoints.size()))
-			.append("<br>");
+		data.tracks.size(), data.tracks.size())).append(trn("{0} route, ", "{0} routes, ",
+		data.routes.size(), data.routes.size())).append(trn("{0} waypoint", "{0} waypoints",
+		data.waypoints.size(), data.waypoints.size())).append("<br>");
 
 		if (data.attr.containsKey("name"))
-			info.append(tr("Name: {0}", data.attr.get("name")))
-				.append("<br>");
+			info.append(tr("Name: {0}", data.attr.get("name"))).append("<br>");
 
 		if (data.attr.containsKey("desc"))
-			info.append(tr("Description: {0}", data.attr.get("desc")))
-				.append("<br>");
-
-                if(data.tracks.size() > 0){
-                    boolean first = true;
-                    WayPoint earliest = null, latest = null;
-
-                    for(GpxTrack trk: data.tracks){
-                        for(Collection<WayPoint> seg:trk.trackSegs){
-                            for(WayPoint pnt:seg){
-                                if(first){
-                                    latest = earliest = pnt;
-                                    first = false;
-                                }else{
-                                    if(pnt.compareTo(earliest) < 0){
-                                        earliest = pnt;
-                                    }else{
-                                        latest = pnt;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    if(earliest != null && latest != null){
-                        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
-                        info.append(tr("Timespan: ") + df.format(new Date((long)(earliest.time * 1000))) + " - " + df.format(new Date((long)(latest.time * 1000))));
-                        int diff = (int)(latest.time - earliest.time);
-                        info.append(" (" + (diff / 3600) + ":" + ((diff % 3600)/60) + ")");
-                        info.append("<br>");
-                    }
-                }
-                info.append(tr("Length: ") + new DecimalFormat("#0.00").format(data.length() / 1000) + "km");
-                info.append("<br>");
-                
+			info.append(tr("Description: {0}", data.attr.get("desc"))).append("<br>");
+
+		if(data.tracks.size() > 0){
+			boolean first = true;
+			WayPoint earliest = null, latest = null;
+
+			for(GpxTrack trk: data.tracks){
+				for(Collection<WayPoint> seg:trk.trackSegs){
+					for(WayPoint pnt:seg){
+						if(first){
+							latest = earliest = pnt;
+							first = false;
+						}else{
+							if(pnt.compareTo(earliest) < 0){
+								earliest = pnt;
+							}else{
+								latest = pnt;
+							}
+						}
+					}
+				}
+			}
+			if(earliest != null && latest != null){
+				DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
+				info.append(tr("Timespan: ") + df.format(new Date((long)(earliest.time * 1000))) + " - "
+				+ df.format(new Date((long)(latest.time * 1000))));
+				int diff = (int)(latest.time - earliest.time);
+				info.append(" (" + (diff / 3600) + ":" + ((diff % 3600)/60) + ")");
+				info.append("<br>");
+			}
+		}
+		info.append(tr("Length: ") + new DecimalFormat("#0.00").format(data.length() / 1000) + "km");
+		info.append("<br>");
+
 		return info.append("</html>").toString();
 	}
@@ -389,7 +384,7 @@
 		 ****************************************************************/
 		if (computeCacheInSync && ((computeCacheMaxLineLengthUsed != maxLineLength) ||
-		                           (!neutralColor.equals(computeCacheColorUsed)) ||
-		                           (computeCacheColored != colored))) {
-//			System.out.println("(re-)computing gpx line styles, reason: CCIS=" + computeCacheInSync + " CCMLLU=" + (computeCacheMaxLineLengthUsed != maxLineLength) + " CCCU=" +  (!neutralColor.equals(computeCacheColorUsed)) + " CCC=" + (computeCacheColored != colored));
+								   (!neutralColor.equals(computeCacheColorUsed)) ||
+								   (computeCacheColored != colored))) {
+//          System.out.println("(re-)computing gpx line styles, reason: CCIS=" + computeCacheInSync + " CCMLLU=" + (computeCacheMaxLineLengthUsed != maxLineLength) + " CCCU=" +  (!neutralColor.equals(computeCacheColorUsed)) + " CCC=" + (computeCacheColored != colored));
 			computeCacheMaxLineLengthUsed = maxLineLength;
 			computeCacheInSync = false;
@@ -440,5 +435,5 @@
 			computeCacheInSync = true;
 		}
-						
+
 		/****************************************************************
 		 ********** STEP 3a - DRAW LINES ********************************
@@ -453,7 +448,8 @@
 					Point screen = mv.getPoint(trkPnt.eastNorth);
 						if (trkPnt.drawLine) {
-							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) { // skip points that are on the same screenposition
+							// skip points that are on the same screenposition
+							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) {
 								g.setColor(trkPnt.speedLineColor);
-                                                g.drawLine(old.x, old.y, screen.x, screen.y);
+								g.drawLine(old.x, old.y, screen.x, screen.y);
 							}
 						}
@@ -476,12 +472,15 @@
 						if (trkPnt.drawLine) {
 							Point screen = mv.getPoint(trkPnt.eastNorth);
-							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) { // skip points that are on the same screenposition
+							// skip points that are on the same screenposition
+							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) {
 								g.setColor(trkPnt.speedLineColor);
-                                                    double t = Math.atan2(screen.y-old.y, screen.x-old.x) + Math.PI;
-                                                    g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t-PHI)), (int)(screen.y + 10*Math.sin(t-PHI)));
-                                                    g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t+PHI)), (int)(screen.y + 10*Math.sin(t+PHI)));
-                                                }
+								double t = Math.atan2(screen.y-old.y, screen.x-old.x) + Math.PI;
+								g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t-PHI)), (int)(screen.y
+								+ 10*Math.sin(t-PHI)));
+								g.drawLine(screen.x,screen.y, (int)(screen.x + 10*Math.cos(t+PHI)), (int)(screen.y
+								+ 10*Math.sin(t+PHI)));
+							}
 							old = screen;
-							}
+						}
 					} // end for trkpnt
 				} // end for segment
@@ -501,11 +500,12 @@
 						if (trkPnt.drawLine) {
 							Point screen = mv.getPoint(trkPnt.eastNorth);
-							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) { // skip points that are on the same screenposition
+							// skip points that are on the same screenposition
+							if (old != null && ((old.x != screen.x) || (old.y != screen.y))) {
 								g.setColor(trkPnt.speedLineColor);
 								g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][0], screen.y + dir[trkPnt.dir][1]);
 								g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][2], screen.y + dir[trkPnt.dir][3]);
-						}
+							}
 							old = screen;
-                                            }
+						}
 					} // end for trkpnt
 				} // end for segment
@@ -566,7 +566,6 @@
 		} // end if large
 
-	Long duration = System.currentTimeMillis() - startTime;
-	//System.out.println(duration);
-
+		//Long duration = System.currentTimeMillis() - startTime;
+		//System.out.println(duration);
 	} // end paint
 
@@ -634,6 +633,5 @@
 				try {
 					String version = Main.pref.get("osm-server.version", "0.5");
-					URL url = new URL(Main.pref.get("osm-server.url") +
-							"/" + version + "/gpx/create");
+					URL url = new URL(Main.pref.get("osm-server.url") + "/" + version + "/gpx/create");
 
 					// create a boundary string
@@ -641,12 +639,10 @@
 					URLConnection urlConn = MultiPartFormOutputStream.createConnection(url);
 					urlConn.setRequestProperty("Accept", "*/*");
-					urlConn.setRequestProperty("Content-Type", 
-							MultiPartFormOutputStream.getContentType(boundary));
+					urlConn.setRequestProperty("Content-Type", MultiPartFormOutputStream.getContentType(boundary));
 					// set some other request headers...
 					urlConn.setRequestProperty("Connection", "Keep-Alive");
 					urlConn.setRequestProperty("Cache-Control", "no-cache");
 					// no need to connect cuz getOutputStream() does it
-					MultiPartFormOutputStream out = 
-						new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
+					MultiPartFormOutputStream out = new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
 					out.writeField("description", description.getText());
 					out.writeField("tags", tags.getText());
@@ -655,5 +651,5 @@
 					// out.writeFile("gpx_file", "text/xml", associatedFile);
 					// can also write bytes directly
-					// out.writeFile("myFile", "text/plain", "C:\\test.txt", 
+					// out.writeFile("myFile", "text/plain", "C:\\test.txt",
 					// "This is some file text.".getBytes("ASCII"));
 					File tmp = File.createTempFile("josm", "tmp.gpx");
@@ -667,6 +663,5 @@
 					tmp.delete();
 					// read response from server
-					BufferedReader in = new BufferedReader(
-							new InputStreamReader(urlConn.getInputStream()));
+					BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
 					String line = "";
 					while((line = in.readLine()) != null) {
@@ -676,5 +671,5 @@
 
 					//TODO check response
-					/*					int retCode = urlConn.getResponseCode();
+					/*                  int retCode = urlConn.getResponseCode();
 					System.out.println("got return: " + retCode);
 					String retMsg = urlConn.getResponseMessage();
@@ -695,9 +690,9 @@
 				} catch (Exception ex) {
 					//if (cancel)
-					//	return; // assume cancel
+					//  return; // assume cancel
 					if (ex instanceof RuntimeException)
 						throw (RuntimeException)ex;
 					throw new RuntimeException(ex.getMessage(), ex);
-				}	
+				}
 			}
 		}
@@ -736,7 +731,7 @@
 		}
 	}
-	
+
 	/**
-	 * Makes a new marker layer derived from this GpxLayer containing at least one 
+	 * Makes a new marker layer derived from this GpxLayer containing at least one
 	 * audio marker which the given audio file is associated with.
 	 * Markers are derived from the following
@@ -749,113 +744,114 @@
 	private void importAudio(File wavFile) {
 		String uri = "file:".concat(wavFile.getAbsolutePath());
-	    MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", name), associatedFile, me);
-	    
-	    Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
-	    boolean timedMarkersOmitted = false;
-	    boolean untimedMarkersOmitted = false;
-	    
-	    // determine time of first point in track
-	    double firstTime = -1.0;
-    	if (data.tracks != null && ! data.tracks.isEmpty()) {
-    		for (GpxTrack track : data.tracks) {
-    			if (track.trackSegs == null) continue;
-    			for (Collection<WayPoint> seg : track.trackSegs) {
-    				for (WayPoint w : seg) {
-    					firstTime = w.time;
-    					break;
-    				}
-        			if (firstTime >= 0.0) break;
-    			}
-    			if (firstTime >= 0.0) break;
-    		}
-    	}
-    	if (firstTime < 0.0) {
+		MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", name), associatedFile, me);
+
+		Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
+		boolean timedMarkersOmitted = false;
+		boolean untimedMarkersOmitted = false;
+		double snapDistance = Main.pref.getDouble("marker.audiofromuntimedwaypoints.distance", 1.0e-3); /* about 25m */
+
+		// determine time of first point in track
+		double firstTime = -1.0;
+		if (data.tracks != null && ! data.tracks.isEmpty()) {
+			for (GpxTrack track : data.tracks) {
+				if (track.trackSegs == null) continue;
+				for (Collection<WayPoint> seg : track.trackSegs) {
+					for (WayPoint w : seg) {
+						firstTime = w.time;
+						break;
+					}
+					if (firstTime >= 0.0) break;
+				}
+				if (firstTime >= 0.0) break;
+			}
+		}
+		if (firstTime < 0.0) {
 			JOptionPane.showMessageDialog(Main.parent, tr("No GPX track available in layer to associate audio with."));
 			return;
-    	}
-	    
-	    // (a) try explicit timestamped waypoints - unless suppressed
-	    if (Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true) && 
-	    	data.waypoints != null && ! data.waypoints.isEmpty())
-	    {
-	    	for (WayPoint w : data.waypoints) {
-	    		if (w.time > firstTime) {
-	    			waypoints.add(w);
-	    		} else if (w.time > 0.0) {
-	    			timedMarkersOmitted = true;
-	    		}
-	    	}
-	    }
-
-	    // (b) try explicit waypoints without timestamps - unless suppressed
-	    if (Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true) && 
-	    	data.waypoints != null && ! data.waypoints.isEmpty())
-	    {
-	    	for (WayPoint w : data.waypoints) {
-	    		if (waypoints.contains(w)) { continue; }
-    			WayPoint wNear = nearestPointOnTrack(w.eastNorth, 10.0e-7 /* about 25m */);
-    			if (wNear != null) {
-    				WayPoint wc = new WayPoint(w.latlon);
-    				wc.time = wNear.time;
-    				if (w.attr.containsKey("name")) wc.attr.put("name", w.getString("name"));
-    				waypoints.add(wc);
-    			} else {
-    				untimedMarkersOmitted = true;
-    			}
-	    	}
-	    }
-	    
-	    // (c) use explicitly named track points, again unless suppressed
-	    if ((Main.pref.getBoolean("marker.audiofromnamedtrackpoints", Main.pref.getBoolean("marker.namedtrackpoints") /* old name */)) && 
-	    	data.tracks != null && ! data.tracks.isEmpty())
-	    {
-	    	for (GpxTrack track : data.tracks) {
-	    		if (track.trackSegs == null) continue;
-	    		for (Collection<WayPoint> seg : track.trackSegs) {
-	    			for (WayPoint w : seg) {
-	    				if (w.attr.containsKey("name") || w.attr.containsKey("desc")) {
-	    					waypoints.add(w);
-	    				}
-	    			}
-	    		}
-	    	}
-	    }
-
-	    // (d) analyse audio for spoken markers here, in due course
-	    
-	    // (e) simply add a single marker at the start of the track
-	    if ((Main.pref.getBoolean("marker.audiofromstart") || waypoints.isEmpty()) &&
-	    	data.tracks != null && ! data.tracks.isEmpty())
+		}
+
+		// (a) try explicit timestamped waypoints - unless suppressed
+		if (Main.pref.getBoolean("marker.audiofromexplicitwaypoints", true) &&
+			data.waypoints != null && ! data.waypoints.isEmpty())
 		{
-	    	boolean gotOne = false;
-	    	for (GpxTrack track : data.tracks) {
-	    		if (track.trackSegs == null) continue;
-	    		for (Collection<WayPoint> seg : track.trackSegs) {
-	    			for (WayPoint w : seg) {
-	    				WayPoint wStart = new WayPoint(w.latlon);
-	    				wStart.attr.put("name", "start");
-	    				wStart.time = w.time;
-	    				waypoints.add(wStart);
-	    				gotOne = true;
-	    				break;
-	    			}
-	    			if (gotOne) break;
-	    		}
-	    		if (gotOne) break;
-	    	}
-		}
-
-	    /* we must have got at least one waypoint now */
-	    
-	    Collections.sort((ArrayList<WayPoint>) waypoints, new Comparator<WayPoint>() {
-	    	public int compare(WayPoint a, WayPoint b) {
-	    		return a.time <= b.time ? -1 : 1;
-	    	}
-	    });
-
-	    firstTime = -1.0; /* this time of the first waypoint, not first trackpoint */
-	    for (WayPoint w : waypoints) {
-	    	if (firstTime < 0.0) firstTime = w.time;
-	    	double offset = w.time - firstTime;
+			for (WayPoint w : data.waypoints) {
+				if (w.time > firstTime) {
+					waypoints.add(w);
+				} else if (w.time > 0.0) {
+					timedMarkersOmitted = true;
+				}
+			}
+		}
+
+		// (b) try explicit waypoints without timestamps - unless suppressed
+		if (Main.pref.getBoolean("marker.audiofromuntimedwaypoints", true) &&
+			data.waypoints != null && ! data.waypoints.isEmpty())
+		{
+			for (WayPoint w : data.waypoints) {
+				if (waypoints.contains(w)) { continue; }
+				WayPoint wNear = nearestPointOnTrack(w.eastNorth, snapDistance);
+				if (wNear != null) {
+					WayPoint wc = new WayPoint(w.latlon);
+					wc.time = wNear.time;
+					if (w.attr.containsKey("name")) wc.attr.put("name", w.getString("name"));
+					waypoints.add(wc);
+				} else {
+					untimedMarkersOmitted = true;
+				}
+			}
+		}
+
+		// (c) use explicitly named track points, again unless suppressed
+		if ((Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false)) &&
+			data.tracks != null && ! data.tracks.isEmpty())
+		{
+			for (GpxTrack track : data.tracks) {
+				if (track.trackSegs == null) continue;
+				for (Collection<WayPoint> seg : track.trackSegs) {
+					for (WayPoint w : seg) {
+						if (w.attr.containsKey("name") || w.attr.containsKey("desc")) {
+							waypoints.add(w);
+						}
+					}
+				}
+			}
+		}
+
+		// (d) analyse audio for spoken markers here, in due course
+
+		// (e) simply add a single marker at the start of the track
+		if ((Main.pref.getBoolean("marker.audiofromstart") || waypoints.isEmpty()) &&
+			data.tracks != null && ! data.tracks.isEmpty())
+		{
+			boolean gotOne = false;
+			for (GpxTrack track : data.tracks) {
+				if (track.trackSegs == null) continue;
+				for (Collection<WayPoint> seg : track.trackSegs) {
+					for (WayPoint w : seg) {
+						WayPoint wStart = new WayPoint(w.latlon);
+						wStart.attr.put("name", "start");
+						wStart.time = w.time;
+						waypoints.add(wStart);
+						gotOne = true;
+						break;
+					}
+					if (gotOne) break;
+				}
+				if (gotOne) break;
+			}
+		}
+
+		/* we must have got at least one waypoint now */
+
+		Collections.sort((ArrayList<WayPoint>) waypoints, new Comparator<WayPoint>() {
+			public int compare(WayPoint a, WayPoint b) {
+				return a.time <= b.time ? -1 : 1;
+			}
+		});
+
+		firstTime = -1.0; /* this time of the first waypoint, not first trackpoint */
+		for (WayPoint w : waypoints) {
+			if (firstTime < 0.0) firstTime = w.time;
+			double offset = w.time - firstTime;
 			String name;
 			if (w.attr.containsKey("name"))
@@ -865,60 +861,62 @@
 			else
 				name = AudioMarker.inventName(offset);
-			AudioMarker am = AudioMarker.create(w.latlon, 
+			AudioMarker am = AudioMarker.create(w.latlon,
 					name, uri, ml, w.time, offset);
-			ml.data.add(am);	    			    	
-	    }
-	    Main.main.addLayer(ml);
-	    
-	    if (timedMarkersOmitted) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Some waypoints with timestamps from before the start of the track were omitted."));
-	    }
-	    if (untimedMarkersOmitted) {
-			JOptionPane.showMessageDialog(Main.parent, tr("Some waypoints which were too far from the track to sensibly estimate their time were omitted."));
-	    }
+			ml.data.add(am);
+		}
+		Main.main.addLayer(ml);
+
+		if (timedMarkersOmitted) {
+			JOptionPane.showMessageDialog(Main.parent,
+			tr("Some waypoints with timestamps from before the start of the track were omitted."));
+		}
+		if (untimedMarkersOmitted) {
+			JOptionPane.showMessageDialog(Main.parent,
+			tr("Some waypoints which were too far from the track to sensibly estimate their time were omitted."));
+		}
 	}
 
 	/**
-	 * Makes a WayPoint at the projection of point P onto the track providing P is 
-	 * less than tolerance away from the track 
+	 * Makes a WayPoint at the projection of point P onto the track providing P is
+	 * less than tolerance away from the track
 
 	 * @param P : the point to determine the projection for
 	 * @param tolerance : must be no further than this from the track
-	 * @return the closest point on the track to P, which may be the 
-	 * first or last point if off the end of a segment, or may be null if 
+	 * @return the closest point on the track to P, which may be the
+	 * first or last point if off the end of a segment, or may be null if
 	 * nothing close enough
 	 */
 	public WayPoint nearestPointOnTrack(EastNorth P, double tolerance) {
 		/*
-		 * assume the coordinates of P are xp,yp, and those of a section of track 
+		 * assume the coordinates of P are xp,yp, and those of a section of track
 		 * between two trackpoints are R=xr,yr and S=xs,ys. Let N be the projected point.
-		 * 
+		 *
 		 * The equation of RS is Ax + By + C = 0 where
 		 * A = ys - yr
 		 * B = xr - xs
 		 * C = - Axr - Byr
-		 * 
+		 *
 		 * Also, note that the distance RS^2 is A^2 + B^2
-		 * 
+		 *
 		 * If RS^2 == 0.0 ignore the degenerate section of track
-		 * 
+		 *
 		 * PN^2 = (Axp + Byp + C)^2 / RS^2
 		 * that is the distance from P to the line
-		 * 
-		 * so if PN^2 is less than PNmin^2 (initialized to tolerance) we can reject 
+		 *
+		 * so if PN^2 is less than PNmin^2 (initialized to tolerance) we can reject
 		 * the line; otherwise...
 		 * determine if the projected poijnt lies within the bounds of the line:
 		 * PR^2 - PN^2 <= RS^2 and PS^2 - PN^2 <= RS^2
-		 * 
+		 *
 		 * where PR^2 = (xp - xr)^2 + (yp-yr)^2
 		 * and   PS^2 = (xp - xs)^2 + (yp-ys)^2
-		 * 
+		 *
 		 * If so, calculate N as
 		 * xn = xr + (RN/RS) B
 		 * yn = y1 + (RN/RS) A
-		 * 
+		 *
 		 * where RN = sqrt(PR^2 - PN^2)
 		 */
-		
+
 		double PNminsq = tolerance * tolerance;
 		EastNorth bestEN = null;
@@ -929,5 +927,5 @@
 		if (data.tracks == null) return null;
 		for (GpxTrack track : data.tracks) {
-			if (track.trackSegs == null) continue;			
+			if (track.trackSegs == null) continue;
 			for (Collection<WayPoint> seg : track.trackSegs) {
 				WayPoint R = null;
@@ -988,5 +986,4 @@
 						bestTime = R.time;
 					}
-					
 				}
 			}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 812)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java	(revision 813)
@@ -120,5 +120,5 @@
 			}
 		});
-		audioMarkersFromNamedTrackpoints.setSelected(Main.pref.getBoolean("marker.audiofromnamedtrackpoints", Main.pref.getBoolean("marker.namedtrackpoints")));
+		audioMarkersFromNamedTrackpoints.setSelected(Main.pref.getBoolean("marker.audiofromnamedtrackpoints", false));
 		audioMarkersFromNamedTrackpoints.setToolTipText(tr("Automatically create audio markers from trackpoints (rather than explicit waypoints) with names or descriptions."));
 		gui.audio.add(audioMarkersFromNamedTrackpoints, GBC.eol().insets(10,0,0,0));
Index: trunk/src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 812)
+++ trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 813)
@@ -224,12 +224,14 @@
 				break;
 			case wpt:
-				if (qName.equals("ele") || qName.equals("desc")
-						|| qName.equals("magvar") || qName.equals("geoidheight")
-						|| qName.equals("name")	|| qName.equals("sym") 
-						|| qName.equals("cmt") || qName.equals("type")) {
+				if (qName.equals("ele") || qName.equals("magvar")
+						|| qName.equals("geoidheight") || qName.equals("name")
+						|| qName.equals("sym") || qName.equals("type")) {
 					currentWayPoint.attr.put(qName, accumulator.toString());
 				} else if (qName.equals("time")) {
 					currentWayPoint.attr.put(qName, accumulator.toString());
 					currentWayPoint.setTime();					
+				} else if (qName.equals("cmt") || qName.equals("desc")) {
+					currentWayPoint.attr.put(qName, accumulator.toString());
+					currentWayPoint.setGarminCommentTime(qName);					
 				} else if (qName.equals("rtept")) {
 					currentState = states.pop();
