changeset 4:ee8c69ea3247

* Import BeatRoot v0.5.8
author Chris Cannam
date Fri, 30 Sep 2011 15:21:26 +0100
parents 18ffb64cde0d
children bcb4c9697967
files META-INF/MANIFEST.MF at/ofai/music/beatroot/Agent.java at/ofai/music/beatroot/AudioFile.java at/ofai/music/beatroot/AudioProcessor.java at/ofai/music/beatroot/BeatRoot.java at/ofai/music/beatroot/BeatTrackDisplay.java at/ofai/music/beatroot/Chooser.java at/ofai/music/beatroot/ControlPanel.java at/ofai/music/beatroot/EventProcessor.java at/ofai/music/beatroot/GUI.java at/ofai/music/beatroot/OnsetParameterListener.java gpl.txt
diffstat 12 files changed, 914 insertions(+), 233 deletions(-) [+]
line wrap: on
line diff
--- a/META-INF/MANIFEST.MF	Fri Oct 08 16:14:43 2010 +0100
+++ b/META-INF/MANIFEST.MF	Fri Sep 30 15:21:26 2011 +0100
@@ -1,4 +1,3 @@
 Manifest-Version: 1.0
-Created-By: 1.5.0 (Sun Microsystems Inc.)
 Main-Class: at.ofai.music.beatroot.BeatRoot
 
--- a/at/ofai/music/beatroot/Agent.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/Agent.java	Fri Sep 30 15:21:26 2011 +0100
@@ -20,9 +20,10 @@
 package at.ofai.music.beatroot;
 
 import java.util.ListIterator;
+
+import at.ofai.music.audio.Util;
 import at.ofai.music.util.Event;
 import at.ofai.music.util.EventList;
-import at.ofai.music.audio.Util;
 
 /** Agent is the central class for beat tracking.
  *  Each Agent object has a tempo hypothesis, a history of tracked beats, and
--- a/at/ofai/music/beatroot/AudioFile.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/AudioFile.java	Fri Sep 30 15:21:26 2011 +0100
@@ -80,9 +80,9 @@
 			channels = format.getChannels();
 			length = audioIn.getFrameLength() * frameSize;
 		} catch (java.io.IOException e) {	// includes FileNotFound
-			e.printStackTrace();
+			System.err.println("File not found."); //e.printStackTrace();
 		} catch (UnsupportedAudioFileException e) {
-			e.printStackTrace();
+			System.err.println("File not supported."); //e.printStackTrace();
 		}
 	} // constructor
 
--- a/at/ofai/music/beatroot/AudioProcessor.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/AudioProcessor.java	Fri Sep 30 15:21:26 2011 +0100
@@ -164,6 +164,9 @@
 	/** The estimated onset times and their saliences. */	
 	protected EventList onsetList;
 
+	/** The y-coordinates of the onsets for plotting. Only used if doOnsetPlot is true */
+	protected double[] y2Onsets;
+	
 	/** GUI component which shows progress of audio processing. */
 	protected ProgressIndicator progressCallback;
 
@@ -606,18 +609,61 @@
 //		Peaks.getSlope(energy, hop, 15, slope);
 //		LinkedList<Integer> peaks = Peaks.findPeaks(slope, (int)Math.round(0.06 / hop), 10);
 		
-		double hop = hopTime;
+//		double hop = hopTime;
+//		Peaks.normalise(spectralFlux);
+//		LinkedList<Integer> peaks = Peaks.findPeaks(spectralFlux, (int)Math.round(0.06 / hop), 0.35, 0.84, true);
+//		onsets = new double[peaks.size()];
+//		double[] y2 = new double[onsets.length];
+//		Iterator<Integer> it = peaks.iterator();
+//		onsetList = new EventList();
+//		double minSalience = Peaks.min(spectralFlux);
+//		for (int i = 0; i < onsets.length; i++) {
+//			int index = it.next();
+//			onsets[i] = index * hop;
+//			y2[i] = spectralFlux[index];
+//			Event e = BeatTrackDisplay.newBeat(onsets[i], 0);
+////			if (debug)
+////				System.err.printf("Onset: %8.3f  %8.3f  %8.3f\n",
+////						onsets[i], energy[index], slope[index]);
+////			e.salience = slope[index];	// or combination of energy + slope??
+//			// Note that salience must be non-negative or the beat tracking system fails!
+//			e.salience = spectralFlux[index] - minSalience;
+//			onsetList.add(e);
+//		}
+		double p1 = 0.35;
+		double p2 = 0.84;
+		
 		Peaks.normalise(spectralFlux);
-		LinkedList<Integer> peaks = Peaks.findPeaks(spectralFlux, (int)Math.round(0.06 / hop), 0.35, 0.84, true);
+		findOnsets(p1, p2);
+		
+		if (progressCallback != null)
+			progressCallback.setFraction(1.0);
+		if (doOnsetPlot) {
+			double[] x1 = new double[spectralFlux.length];
+			for (int i = 0; i < x1.length; i++)
+				x1[i] = i * hopTime;
+			plot.addPlot(x1, spectralFlux, Color.red, 4);
+			plot.addPlot(onsets, y2Onsets, Color.green, 3);
+			plot.setTitle("Spectral flux and onsets");
+			plot.fitAxes();
+		}
+		if (debug) {
+			System.err.printf("Onsets: %d\nContinue? ", onsets.length);
+			readLine();
+		}
+	} // processFile()
+	
+	public void findOnsets(double p1, double p2){
+		LinkedList<Integer> peaks = Peaks.findPeaks(spectralFlux, (int)Math.round(0.06 / hopTime), p1, p2, true);
 		onsets = new double[peaks.size()];
-		double[] y2 = new double[onsets.length];
+		y2Onsets = new double[onsets.length];
 		Iterator<Integer> it = peaks.iterator();
 		onsetList = new EventList();
 		double minSalience = Peaks.min(spectralFlux);
 		for (int i = 0; i < onsets.length; i++) {
 			int index = it.next();
-			onsets[i] = index * hop;
-			y2[i] = spectralFlux[index];
+			onsets[i] = index * hopTime;
+			y2Onsets[i] = spectralFlux[index];
 			Event e = BeatTrackDisplay.newBeat(onsets[i], 0);
 //			if (debug)
 //				System.err.printf("Onset: %8.3f  %8.3f  %8.3f\n",
@@ -627,23 +673,7 @@
 			e.salience = spectralFlux[index] - minSalience;
 			onsetList.add(e);
 		}
-		if (progressCallback != null)
-			progressCallback.setFraction(1.0);
-		if (doOnsetPlot) {
-			double[] x1 = new double[spectralFlux.length];
-			for (int i = 0; i < x1.length; i++)
-				x1[i] = i * hopTime;
-			plot.addPlot(x1, spectralFlux, Color.red, 4);
-			plot.addPlot(onsets, y2, Color.green, 3);
-			plot.setTitle("Spectral flux and onsets");
-			plot.fitAxes();
-		}
-		if (debug) {
-			System.err.printf("Onsets: %d\nContinue? ", onsets.length);
-			readLine();
-		}
-	} // processFile()
-
+	}
 	/** Reads a text file containing a list of whitespace-separated feature values.
 	 *  Created for paper submitted to ICASSP'07.
 	 *  @param fileName File containing the data
--- a/at/ofai/music/beatroot/BeatRoot.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/BeatRoot.java	Fri Sep 30 15:21:26 2011 +0100
@@ -398,7 +398,7 @@
 				"this operation may result in loss of data :)\n" + 
 				"Do you really want to quit?", "Just checking ...",
 				JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
-			System.exit(0);
+				System.exit(0);
 	} // quit()
 
 	/** Print a warning message.
--- a/at/ofai/music/beatroot/BeatTrackDisplay.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/BeatTrackDisplay.java	Fri Sep 30 15:21:26 2011 +0100
@@ -1,20 +1,20 @@
 /*  BeatRoot: An interactive beat tracking system
-    Copyright (C) 2001, 2006 by Simon Dixon
+   Copyright (C) 2001, 2006 by Simon Dixon
 
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License along
-    with this program (the file gpl.txt); if not, download it from
+   You should have received a copy of the GNU General Public License along
+   with this program (the file gpl.txt); if not, download it from
 	http://www.gnu.org/licenses/gpl.txt or write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 package at.ofai.music.beatroot;
@@ -29,7 +29,6 @@
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.awt.image.BufferedImage;
-
 import java.util.Arrays;
 import java.util.ListIterator;
 
@@ -40,9 +39,9 @@
 import at.ofai.music.util.EventList;
 
 /** Main panel of BeatRoot's GUI, which displays the audio and beat data
- *  and allows editing, scrolling, selecting, etc
- *  @author Simon Dixon
- */
+*  and allows editing, scrolling, selecting, etc
+*  @author Simon Dixon
+*/
 public class BeatTrackDisplay
 			 extends JPanel
 			 implements MouseListener, MouseMotionListener {
@@ -54,6 +53,7 @@
 	protected GUI gui;
 	
 	/** width in pixels of this panel */
+	protected final int defaultXSize = 1000;
 	protected int xSize;
 	
 	/** height in pixels of this panel */
@@ -136,93 +136,93 @@
 	
 	/** colour map used in the spectrogram */
 	public static final Color[] colour = {
-            new Color( 11,  0,  0),
-            new Color( 21,  0,  0),
-            new Color( 32,  0,  0),
-            new Color( 43,  0,  0),
-            new Color( 53,  0,  0),
-            new Color( 64,  0,  0),
-            new Color( 74,  0,  0),
-            new Color( 85,  0,  0),
-            new Color( 96,  0,  0),
-            new Color(106,  0,  0),
-            new Color(117,  0,  0),
-            new Color(128,  0,  0),
-            new Color(138,  0,  0),
-            new Color(149,  0,  0),
-            new Color(159,  0,  0),
-            new Color(170,  0,  0),
-            new Color(181,  0,  0),
-            new Color(191,  0,  0),
-            new Color(202,  0,  0),
-            new Color(212,  0,  0),
-            new Color(223,  0,  0),
-            new Color(234,  0,  0),
-            new Color(244,  0,  0),
-            new Color(255,  0,  0),
-            new Color(255, 11,  0),
-            new Color(255, 21,  0),
-            new Color(255, 32,  0),
-            new Color(255, 43,  0),
-            new Color(255, 53,  0),
-            new Color(255, 64,  0),
-            new Color(255, 74,  0),
-            new Color(255, 85,  0),
-            new Color(255, 96,  0),
-            new Color(255,106,  0),
-            new Color(255,117,  0),
-            new Color(255,128,  0),
-            new Color(255,138,  0),
-            new Color(255,149,  0),
-            new Color(255,159,  0),
-            new Color(255,170,  0),
-            new Color(255,181,  0),
-            new Color(255,191,  0),
-            new Color(255,202,  0),
-            new Color(255,212,  0),
-            new Color(255,223,  0),
-            new Color(255,234,  0),
-            new Color(255,244,  0),
-            new Color(255,255,  0),
-            new Color(255,255, 16),
-            new Color(255,255, 32),
-            new Color(255,255, 48),
-            new Color(255,255, 64),
-            new Color(255,255, 80),
-            new Color(255,255, 96),
-            new Color(255,255,112),
-            new Color(255,255,128),
-            new Color(255,255,143),
-            new Color(255,255,159),
-            new Color(255,255,175),
-            new Color(255,255,191),
-            new Color(255,255,207),
-            new Color(255,255,223),
-            new Color(255,255,239),
-            new Color(255,255,255)};
+           new Color( 11,  0,  0),
+           new Color( 21,  0,  0),
+           new Color( 32,  0,  0),
+           new Color( 43,  0,  0),
+           new Color( 53,  0,  0),
+           new Color( 64,  0,  0),
+           new Color( 74,  0,  0),
+           new Color( 85,  0,  0),
+           new Color( 96,  0,  0),
+           new Color(106,  0,  0),
+           new Color(117,  0,  0),
+           new Color(128,  0,  0),
+           new Color(138,  0,  0),
+           new Color(149,  0,  0),
+           new Color(159,  0,  0),
+           new Color(170,  0,  0),
+           new Color(181,  0,  0),
+           new Color(191,  0,  0),
+           new Color(202,  0,  0),
+           new Color(212,  0,  0),
+           new Color(223,  0,  0),
+           new Color(234,  0,  0),
+           new Color(244,  0,  0),
+           new Color(255,  0,  0),
+           new Color(255, 11,  0),
+           new Color(255, 21,  0),
+           new Color(255, 32,  0),
+           new Color(255, 43,  0),
+           new Color(255, 53,  0),
+           new Color(255, 64,  0),
+           new Color(255, 74,  0),
+           new Color(255, 85,  0),
+           new Color(255, 96,  0),
+           new Color(255,106,  0),
+           new Color(255,117,  0),
+           new Color(255,128,  0),
+           new Color(255,138,  0),
+           new Color(255,149,  0),
+           new Color(255,159,  0),
+           new Color(255,170,  0),
+           new Color(255,181,  0),
+           new Color(255,191,  0),
+           new Color(255,202,  0),
+           new Color(255,212,  0),
+           new Color(255,223,  0),
+           new Color(255,234,  0),
+           new Color(255,244,  0),
+           new Color(255,255,  0),
+           new Color(255,255, 16),
+           new Color(255,255, 32),
+           new Color(255,255, 48),
+           new Color(255,255, 64),
+           new Color(255,255, 80),
+           new Color(255,255, 96),
+           new Color(255,255,112),
+           new Color(255,255,128),
+           new Color(255,255,143),
+           new Color(255,255,159),
+           new Color(255,255,175),
+           new Color(255,255,191),
+           new Color(255,255,207),
+           new Color(255,255,223),
+           new Color(255,255,239),
+           new Color(255,255,255)};
 	
 	/** the colour of the amplitude envelope */
-    static Color AUDIO_COLOUR = new Color(100,20,120);
-    
-    /** the colour of the MIDI piano roll */
-    static Color MIDI_COLOUR = Color.BLUE;
-    
-    /** the colour of the onset markers on the amplitude envelope */
-    static Color ONSET_COLOUR = Color.GREEN;
-    
-    /** the colour of the lines marking the beats */
-    static Color BEAT_COLOUR = Color.BLACK;
-    
-    /** the colour of the text (for IBIs and axes) */
-    static Color TEXT_COLOUR = Color.BLACK;
-    
-    /** the background colour of a selected region */
-    static Color SELECTION_COLOUR = new Color(240,200,200);
-    
+   static Color AUDIO_COLOUR = new Color(100,20,120);
+
+   /** the colour of the MIDI piano roll */
+   static Color MIDI_COLOUR = Color.BLUE;
+
+   /** the colour of the onset markers on the amplitude envelope */
+   static Color ONSET_COLOUR = Color.GREEN;
+
+   /** the colour of the lines marking the beats */
+   static Color BEAT_COLOUR = Color.BLACK;
+
+   /** the colour of the text (for IBIs and axes) */
+   static Color TEXT_COLOUR = Color.BLACK;
+
+   /** the background colour of a selected region */
+   static Color SELECTION_COLOUR = new Color(240,200,200);
+
 	/** the threshold below which the minimum colour is used in the spectrogram */
-    double loThreshold;
+   double loThreshold;
 
-    /** the threshold above which the maximum colour is used in the spectrogram */
+   /** the threshold above which the maximum colour is used in the spectrogram */
 	double hiThreshold;
 	
 	/** the ratio of hop size to frame size (for aligning the spectrogram with the audio) */
@@ -310,7 +310,7 @@
 		midiMin = 21;
 		midiMax = 108;
 		onsetList = null;
-		onsets = new double[0];
+		onsets = new double[0]; 
 		offsets = new double[0];
 		pitches = new int[0];
 		beats = b;
@@ -321,6 +321,7 @@
 		// setBorder(BorderFactory.createLineBorder(Color.black));
 		addMouseListener(this);
 		addMouseMotionListener(this);
+		xSize = -1;
 		init(true);
 	} // BeatTrackDisplay constructor
 
@@ -328,16 +329,16 @@
 	 * @param c The energy value
 	 * @return The corresponding colour for this energy value
 	 */
-    Color getColour(double c) {
-    	int max = colour.length - 1;
-        int index = (int)(max - (c - loThreshold) *
+   Color getColour(double c) {
+   	int max = colour.length - 1;
+       int index = (int)(max - (c - loThreshold) *
 							max / (hiThreshold - loThreshold));
-        return colour[index < 0? 0: (index > max? max: index)];
-    } // getColour()
+       return colour[index < 0? 0: (index > max? max: index)];
+   } // getColour()
 
-    /** Initialises the panel after new data is loaded or preferences are changed.
-     *  @param resetSelection Indicates whether the selected region should be cleared
-     */
+   /** Initialises the panel after new data is loaded or preferences are changed.
+    *  @param resetSelection Indicates whether the selected region should be cleared
+    */
 	synchronized public void init(boolean resetSelection) {
 		selectedBeat = null;
 		scrollDirection = 0;
@@ -376,7 +377,8 @@
 			yMid = yTop + 352;
 			yBottom = yMid + 150;
 			ySize = yBottom + 20;
-			xSize = 1000;
+			if (xSize == -1)
+				xSize = defaultXSize;
 			setPreferredSize(new Dimension(xSize, ySize));
 		}
 		x0 = xSize;
@@ -511,6 +513,13 @@
 	/** Renders the panel.
 	 *  @param g The Graphics object for painting on this panel. */
 	synchronized public void paint(Graphics g) {
+		//xSize = gui.getWidth();
+		//System.out.println("xSize repainted: now="+xSize);
+		/*if (xSize != getWidth()) {
+			xSize = getWidth();
+			System.out.println("xSize changed: now="+xSize);
+			init(false);
+		}*/
 		if (scrollDirection != 0) {
 			gui.scroll(scrollDirection);
 		}
@@ -527,11 +536,11 @@
 
 	/** Clears the background image to white */
 	protected void clearImage() {
-        if (gImage != null) {
-            gImage.setColor(Color.white);
-            gImage.fillRect(0, 0, xSize, ySize);
-        }
-    } // clearImage()
+       if (gImage != null) {
+           gImage.setColor(Color.white);
+           gImage.fillRect(0, 0, xSize, ySize);
+       }
+   } // clearImage()
 	
 	/** Updates the background image, after creating it if necessary */
 	synchronized protected void repaintImage() {
@@ -631,9 +640,22 @@
 				g.drawLine(position, yBottom-5, position, yBottom+5);
 			}
 		}
+		g.drawString("["+beats.size()+" beats]", 5, this.yTop+10); // WG: added to show number of beats
+		if (gui.audioPlayer.currentFile!=null) {  // WG: added to show length of audio file
+			String label = Double.toString(gui.audioPlayer.currentFile.length / 
+					gui.audioPlayer.currentFile.frameRate / gui.audioPlayer.currentFile.frameSize);
+			int position = label.indexOf('.');
+			if (position < 0) {
+				position = label.length();
+				label += ".";
+			}
+			label += "000";
+			label = label.substring(0, position + (tickGap < 0.5 ? 3 : 2));
+			g.drawString(label, xSize-metrics.stringWidth(label)-2, this.ySize-5);
+		}
 	} // paintAxes()
 
-	/** Paints the beats and inter-baet intervals
+	/** Paints the beats and inter-beat intervals
 	 *  @param g The Graphics object to paint to
 	 */
 	synchronized protected void paintBeats(Graphics g) {
@@ -970,6 +992,26 @@
 				selectedBeat = null;
 		}
 	} // selectBeat()
+	
+	/** Finds the nearest detected onset time location to a given x-coordinate.
+	 * @param x The x-coordinate (e.g. of a mouse-click) near shich a beat is sought
+	 * @return The onset time (s) of the nearest detected onset.
+	 * inserted by WG, 7 Aug 2009
+	 */
+	synchronized public double selectOnset(int x) {
+		if (onsets.length == 0)
+			return -1.0;
+		int i = 0;
+		while (i < onsets.length-1 && timeToLocation(onsets[i]) <= x){
+			i++;
+		}
+		if (i == 0)
+			return onsets[i];
+		if (Math.abs(timeToLocation(onsets[i])-x) <= Math.abs(x-timeToLocation(onsets[i-1])))
+			return onsets[i];
+		else
+			return onsets[i-1];
+	} // selectOnset()
 
 	/** Creates a new Event object representing a beat.
 	 *  @param time The time of the beat in seconds
@@ -991,6 +1033,10 @@
 			System.err.printf("Add at: %5.3f\n", time);
 	} // addBeatNow()
 
+	//public void addBeatCurrentTime() {
+	//	beatPtr.add(newBeat())
+	//}
+	
 	/** Adds a beat at the given time.
 	 *  @param time Time in seconds of the new beat
 	 */
@@ -1204,18 +1250,18 @@
 	        roundedRatio = 1.5;
 	    else if ((0.9 < ratio) && (ratio < 1.3))
 	        roundedRatio = 1.0;
-        else if ((1.35 < ratio) && (ratio < 1.6))
-            roundedRatio = 2.0/3.0;
-        else if ((1.8 < ratio) && (ratio < 2.5))
-            roundedRatio = 0.5;
-        else if ((2.7 < ratio) && (ratio < 3.5))
-            roundedRatio = 1.0/3.0;
-        else if ((3.6 < ratio) && (ratio < 4.6))
-            roundedRatio = 0.25;
-        else if ((7.6 < ratio) && (ratio < 8.6))
-            roundedRatio = 0.125;
-        return roundedRatio;
-    } // getRhythmicLevel()
+       else if ((1.35 < ratio) && (ratio < 1.6))
+           roundedRatio = 2.0/3.0;
+       else if ((1.8 < ratio) && (ratio < 2.5))
+           roundedRatio = 0.5;
+       else if ((2.7 < ratio) && (ratio < 3.5))
+           roundedRatio = 1.0/3.0;
+       else if ((3.6 < ratio) && (ratio < 4.6))
+           roundedRatio = 0.25;
+       else if ((7.6 < ratio) && (ratio < 8.6))
+           roundedRatio = 0.125;
+       return roundedRatio;
+   } // getRhythmicLevel()
 
 	/** Evaluates a beat tracking solution against an annotation of the data.
 	 *  @param beatsFile The file name of the annotation data
@@ -1281,7 +1327,7 @@
 	            c++;
 	        }
 	    }
-        fn += correct.length - c;
+       fn += correct.length - c;
 	    while (b < beatsArr.length) {
 	        if (correct[correct.length - 1] < beatsArr[b])
 	            extra++;
@@ -1326,38 +1372,59 @@
 		synchronized(this) {
 			int x = e.getX();
 			int y = e.getY();
-			if ((y > 0) && (y < yTop)) {
-				if (!gui.audioPlayer.playing) {
-					currentTime = locationToTime(x);
-					gui.skipTo(currentTime);
-					scrollTo(currentTime, false);
+			if (e.isControlDown()) { // WG added CTRL + Left Mouse shifts beats along detected onsets
+				if ((y >= yTop) && (y < yBottom) && // all clicks in the spectrogram
+						SwingUtilities.isLeftMouseButton(e)) { // Left Button
+					selectBeat(x, 10); 
+					if (selectedBeat != null)
+						//selectedBeatTime = selectedBeat.keyDown;
+						selectedBeatTime = selectOnset(x);
+				} else if ((y >= yTop) && (y < yBottom)) { // all clicks in the spectrogram
+					if (SwingUtilities.isRightMouseButton(e)) { // WG changed from Middle to Right
+						addBeat(locationToTime(x));
+						beatPtr.previous();
+						selectedBeat = beatPtr.next();
+						selectedBeatTime = -1;
+					} else {
+						selectBeat(x, 10);
+						if (selectedBeat != null)
+							selectedBeatTime = selectedBeat.keyDown;
+					}
 				}
-			} else if ((y >= yTop) && (y < yBottom)) {
-				if (SwingUtilities.isMiddleMouseButton(e)) {
-					addBeat(locationToTime(x));
-					beatPtr.previous();
-					selectedBeat = beatPtr.next();
-					selectedBeatTime = -1;
-				} else {
-					selectBeat(x, 5);
-					if (selectedBeat != null)
-						selectedBeatTime = selectedBeat.keyDown;
+			} else {
+				if ((y > 0) && (y < yTop)) {
+					if (!gui.audioPlayer.playing) {
+						currentTime = locationToTime(x);
+						gui.skipTo(currentTime);
+						scrollTo(currentTime, false);
+					}
+				} else if ((y >= yTop) && (y < yBottom)) { // all clicks in the spectrogram
+					if (SwingUtilities.isRightMouseButton(e)) { // WG changed from Middle to Right
+						addBeat(locationToTime(x));
+						beatPtr.previous();
+						selectedBeat = beatPtr.next();
+						selectedBeatTime = -1;
+					} else {
+						selectBeat(x, 10);
+						if (selectedBeat != null)
+							selectedBeatTime = selectedBeat.keyDown;
+					}
+				} else if ((y >= yBottom) && (y < ySize)) {
+					if (SwingUtilities.isLeftMouseButton(e)) {
+						regionSelected = true;
+						if (e.isShiftDown() && (startSelection >= 0)) 
+							endSelection = locationToTime(x);
+						else {
+							startSelection = locationToTime(x);
+							endSelection = -1.0;
+						}
+					} else {
+						regionSelected = false;
+						startSelection = endSelection = -1.0;
+						repaintImage();
+					}
 				}
-			} else if ((y >= yBottom) && (y < ySize)) {
-				if (SwingUtilities.isLeftMouseButton(e)) {
-					regionSelected = true;
-					if (e.isShiftDown() && (startSelection >= 0))
-						endSelection = locationToTime(x);
-					else {
-						startSelection = locationToTime(x);
-						endSelection = -1.0;
-					}
-				} else {
-					regionSelected = false;
-					startSelection = endSelection = -1.0;
-					repaintImage();
-				}
-			}
+			} 
 			repaint();
 		}
 	} // mousePressed()
@@ -1370,9 +1437,14 @@
 			int x = e.getX();
 			int y = e.getY();
 			if ((selectedBeat != null) && (x >= 0) && (x <= xSize) &&
-										(y >= 0) && (y <= ySize)) {
-				if (!SwingUtilities.isRightMouseButton(e)) {
-					selectedBeat.keyDown = locationToTime(x);
+					(y >= 0) && (y <= ySize)) {
+				if (!SwingUtilities.isMiddleMouseButton(e)) { 
+					if (e.isControlDown()) {
+						selectedBeat.keyDown = selectOnset(x);
+
+					} else {
+						selectedBeat.keyDown = locationToTime(x);
+					}
 					reorderBeats();
 				}
 			} else if (regionSelected) {
@@ -1383,7 +1455,7 @@
 						scrollDirection = 1;
 					else
 						scrollDirection = 0;
-					if (Math.abs(timeToLocation(startSelection) - x) == 0)
+					if (Math.abs(timeToLocation(startSelection) - x) <= 15) // WG changed from '==0' to '<=15'; to avoid region selection, when all to end selection was desired! Aug 2009
 						endSelection = -1;
 					else
 						endSelection = locationToTime(x);
@@ -1400,9 +1472,9 @@
 		if (selectedBeat != null) {
 			if (SwingUtilities.isLeftMouseButton(e)) // move
 				EditAction.add(selectedBeatTime, selectedBeat.keyDown);
-			else if (SwingUtilities.isMiddleMouseButton(e)) // add
+			else if (SwingUtilities.isRightMouseButton(e)) // add // WG changed from Middle to Right
 				EditAction.add(-1, selectedBeat.keyDown);
-			else {								// right button, delete
+			else if (SwingUtilities.isMiddleMouseButton(e)) { // right button, delete
 				beatPtr.remove();
 				EditAction.add(selectedBeatTime, -1);
 			}
@@ -1501,5 +1573,24 @@
 		tInc = inc;
 		overlap = lap;
 	} // setSpectro()
+	
+	/**
+	 * WG: To resize the panel in the x dimension.
+	 */
+	public void resizeX() {
+		setPreferredSize(new Dimension(xSize,ySize));
+	}
 
-} // class BeatTrackDisplay
+	public double getCurrentTime() {
+		return currentTime;
+	}
+
+	public void setCurrentTime(double currentTime) {
+		this.currentTime = currentTime;
+	}
+	
+	public void setOnsetDetectionParam(double param1,double param2) {
+		gui.setOnsetDetectionParameter(param1,param2);
+	}
+
+} // class BeatTrackDisplay
\ No newline at end of file
--- a/at/ofai/music/beatroot/Chooser.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/Chooser.java	Fri Sep 30 15:21:26 2011 +0100
@@ -19,17 +19,22 @@
 
 package at.ofai.music.beatroot;
 
+import java.io.File;
+
 import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileSystemView;
 
 /** An extension of the Swing file chooser for specific file types. */
 public class Chooser extends JFileChooser {
 	
 	static final long serialVersionUID = 0;	// avoid compiler warning
+	
+	File file = null;
 
 	/** Constructor for BeatRoot's file chooser */
 	public Chooser() {
-		super(".");
+		super(FileSystemView.getFileSystemView().getHomeDirectory()); // WG changed from super(".")
 		addChoosableFileFilter(getAcceptAllFileFilter());
 	} // constructor
 
@@ -41,9 +46,19 @@
 	public String getInputName(FileFilters ff) {
 		String pathName = null;
 		addChoosableFileFilter(ff);
+		if (file != null) {
+			pathName = file.getAbsolutePath();
+			int index = pathName.lastIndexOf(".");
+			if (index > 0)
+				pathName = pathName.substring(0, index);
+			file = new File(pathName + ff.suffix);
+			setSelectedFile(file);
+		}
 		if (showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
-			if (getSelectedFile().exists())
+			if (getSelectedFile().exists()) {
+				file = getSelectedFile();
 				pathName = getSelectedFile().getAbsolutePath();
+			}
 		}
 		removeChoosableFileFilter(ff);
 		return pathName;
@@ -76,13 +91,27 @@
 	public String getOutputName(FileFilters ff) {
 		String pathName = null;
 		addChoosableFileFilter(ff);
+		if (file != null) {
+			pathName = file.getAbsolutePath();
+			int index = pathName.lastIndexOf(".");
+			if (index > 0)
+				pathName = pathName.substring(0, index);
+			file = new File(pathName + ff.suffix);
+			setSelectedFile(file);
+		}
 		if (showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
 			if (!getSelectedFile().exists() || (
 						JOptionPane.showConfirmDialog(null,
 						"File " + getSelectedFile().getAbsolutePath() +
 						" exists.\nDo you want to replace it?", "Are you sure?",
-						JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
+						JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)) {
 				pathName = getSelectedFile().getAbsolutePath();
+				int index = pathName.lastIndexOf(".");
+				if (index > 0)
+					pathName = pathName.substring(0, index);
+				file = new File(pathName + ((FileFilters)getFileFilter()).suffix);
+				pathName = file.getAbsolutePath();
+			}
 		}
 		removeChoosableFileFilter(ff);
 		return pathName;
@@ -97,10 +126,18 @@
 	/** Opens a dialog to get a file name for saving beat information.
 	 *  @return The file name for saving beat information */
 	public String getBeatOutName() {
-		//addChoosableFileFilter(FileFilters.tmfFileFilter);
 		addChoosableFileFilter(FileFilters.textFileFilter);
 		addChoosableFileFilter(FileFilters.csvFileFilter);
 		String oName = getOutputName(FileFilters.tmfFileFilter);
+		/*if (getFileFilter()==FileFilters.textFileFilter &&
+				!oName.endsWith(".txt"))
+			oName = oName + ".txt";
+		if (getFileFilter()==FileFilters.tmfFileFilter &&
+				!oName.endsWith(".tmf"))
+			oName = oName + ".tmf";
+		if (getFileFilter()==FileFilters.csvFileFilter &&
+				!oName.endsWith(".csv"))
+			oName = oName + ".csv";*/
 		removeChoosableFileFilter(FileFilters.textFileFilter);
 		removeChoosableFileFilter(FileFilters.csvFileFilter);
 		return oName;
--- a/at/ofai/music/beatroot/ControlPanel.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/ControlPanel.java	Fri Sep 30 15:21:26 2011 +0100
@@ -15,13 +15,14 @@
     with this program (the file gpl.txt); if not, download it from
 	http://www.gnu.org/licenses/gpl.txt or write to the Free Software Foundation, Inc.,
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
+ */
 
 package at.ofai.music.beatroot;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
+import java.awt.FlowLayout;
 import java.awt.GridLayout;
 import java.awt.event.ActionListener;
 import javax.swing.BorderFactory;
@@ -31,29 +32,40 @@
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JScrollBar;
+import javax.swing.JSlider;
 import javax.swing.JTextField;
 
 /** The panel at the bottom of BeatRoot's GUI containing the buttons */
 class ControlPanel extends JPanel {
-	
-	static final long serialVersionUID = 0;	// avoid compiler warning
-	
+
+	static final long serialVersionUID = 0; // avoid compiler warning
+
 	/** The listener object which handles key, button and menu events */
 	EventProcessor jobq;
 
 	/** For layout of the grid of buttons (i.e. not including the zoom buttons) */
 	class ButtonPanel extends JPanel {
-		static final long serialVersionUID = 0;	// avoid compiler warning
-		/** Constructor:
-		 * @param r Number of rows of buttons
-		 * @param c NUmber of columns of buttons
+		static final long serialVersionUID = 0; // avoid compiler warning
+
+		/**
+		 * Constructor:
+		 * 
+		 * @param r
+		 *            Number of rows of buttons
+		 * @param c
+		 *            NUmber of columns of buttons
 		 */
 		public ButtonPanel(int r, int c) {
-			super(new GridLayout(r,c));
+			super(new GridLayout(r, c));
 		} // constructor
-		/** Adds a button to this panel. 
-		 * @param s  The text on the button
-		 * @param al The event handler for when the button is pressed 
+
+		/**
+		 * Adds a button to this panel.
+		 * 
+		 * @param s
+		 *            The text on the button
+		 * @param al
+		 *            The event handler for when the button is pressed
 		 */
 		public void addButton(String s, ActionListener al) {
 			JButton b = new JButton(s);
@@ -62,37 +74,69 @@
 		} // addButton()
 	} // inner class ButtonPanel
 
-	/** Constructor:
-	 * @param displayPanel The main panel of BeatRoot's GUI
-	 * @param scroller     The scrollbar on BeatRoot's GUI
-	 * @param args Not used - was used for a file name in BeatRoot 0.4 for experiments
-	 *             reported in Dixon, Goebl and Cambouropoulos, Music Perception, 2006 
-	 * @param j The object which handles button, key and menu events
+	/**
+	 * Constructor:
+	 * 
+	 * @param displayPanel
+	 *            The main panel of BeatRoot's GUI
+	 * @param scroller
+	 *            The scrollbar on BeatRoot's GUI
+	 * @param args
+	 *            Not used - was used for a file name in BeatRoot 0.4 for
+	 *            experiments reported in Dixon, Goebl and Cambouropoulos, Music
+	 *            Perception, 2006
+	 * @param j
+	 *            The object which handles button, key and menu events
 	 */
 	public ControlPanel(BeatTrackDisplay displayPanel, JScrollBar scroller,
-						String args, EventProcessor j) {
+			String args, EventProcessor j) {
 		setPreferredSize(new Dimension(1000, 100));
 		setLayout(new BorderLayout());
 		setBorder(BorderFactory.createLineBorder(Color.black, 5));
 
-		JLabel fileName = new JLabel(); // "File: <none>");
+		//JLabel fileName = new JLabel(); // "File: <none>");
 		JTextField argumentField = new JTextField(24);
 		jobq = j;
 
 		ButtonPanel buttonPanel;
-		if ((args != null) && args.endsWith(".tmf")) {	// never happens
-			buttonPanel = new ButtonPanel(3,2);
+		if ((args != null) && args.endsWith(".tmf")) { // never happens
+			buttonPanel = new ButtonPanel(3, 2);
 			buttonPanel.addButton("New", jobq);
 			buttonPanel.addButton(GUI.PLAY, jobq);
 			buttonPanel.addButton(GUI.CLEAR_BEATS, jobq);
 			buttonPanel.addButton(GUI.STOP, jobq);
 			buttonPanel.addButton(GUI.SAVE_BEATS, jobq);
-		} else {										// always happens
+		} else { // always happens
 			Box optionsBox = new Box(BoxLayout.X_AXIS);
 			optionsBox.add(new JLabel("Options: "));
 			optionsBox.add(argumentField);
 
-			JPanel viewPanel = new JPanel(new GridLayout(1,3));
+			int upperInitValue = 34;
+			int lowerInitValue = 84;
+			JTextField upperParamText = new JTextField(Integer.toString(upperInitValue),4);
+			upperParamText.setEditable(false);
+			JTextField lowerParamText = new JTextField(Integer.toString(lowerInitValue),4);
+			lowerParamText.setEditable(false);
+			OnsetParameterListener onsetParameterListener = new OnsetParameterListener(
+					displayPanel, upperInitValue, lowerInitValue,
+					upperParamText, lowerParamText);
+
+			JSlider upperParamSlider = new JSlider(0, 100, upperInitValue);
+			upperParamSlider.addChangeListener(onsetParameterListener);
+			upperParamSlider.setName("upperSlider");
+
+			JSlider lowerParamSlider = new JSlider(0, 100, lowerInitValue);
+			lowerParamSlider.addChangeListener(onsetParameterListener);
+			lowerParamSlider.setName("lowerSlider");
+			
+			
+			JPanel upperParamBox = new JPanel();
+			upperParamBox.add(upperParamSlider);
+			upperParamBox.add(upperParamText);
+			JPanel lowerParamBox = new JPanel(new FlowLayout());
+			lowerParamBox.add(lowerParamSlider);
+			lowerParamBox.add(lowerParamText);
+			JPanel viewPanel = new JPanel(new GridLayout(1, 3));
 			JLabel viewLabel = new JLabel("View range (s): ");
 			JButton dec = new JButton("-");
 			JTextField zoomField = new JTextField(5);
@@ -102,19 +146,22 @@
 			viewPanel.add(dec);
 			viewPanel.add(zoomField);
 			viewPanel.add(inc);
-			ZoomListener viewListener = new ZoomListener(displayPanel, scroller,
-															zoomField);
+			ZoomListener viewListener = new ZoomListener(displayPanel,
+					scroller, zoomField);
 			inc.addActionListener(viewListener);
 			zoomField.addActionListener(viewListener);
 			dec.addActionListener(viewListener);
 
-			JPanel fileAndOptions = new JPanel(new GridLayout(3,1));
-			fileAndOptions.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
-			fileAndOptions.add(fileName);
+			JPanel fileAndOptions = new JPanel(new GridLayout(4, 1));
+			fileAndOptions.setBorder(BorderFactory
+					.createEmptyBorder(0, 5, 0, 0));
+			//fileAndOptions.add(fileName);
+			fileAndOptions.add(upperParamBox);
+			fileAndOptions.add(lowerParamBox);
 			fileAndOptions.add(optionsBox);
 			fileAndOptions.add(viewPanel);
 			add(fileAndOptions, BorderLayout.WEST);
-			buttonPanel = new ButtonPanel(3,4);
+			buttonPanel = new ButtonPanel(3, 4);
 			buttonPanel.addButton(GUI.LOAD_AUDIO, jobq);
 			buttonPanel.addButton(GUI.BEAT_TRACK, jobq);
 			buttonPanel.addButton(GUI.SAVE_BEATS, jobq);
--- a/at/ofai/music/beatroot/EventProcessor.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/EventProcessor.java	Fri Sep 30 15:21:26 2011 +0100
@@ -125,12 +125,12 @@
 				audioPlayer.stop(false);
 				gui.displayPanel.toggleAnnotateMode();
 				break;
-			case KeyEvent.VK_LEFT:
+			/*case KeyEvent.VK_LEFT:
 				gui.displayPanel.selectPreviousBeat();
 				break;
 			case KeyEvent.VK_RIGHT:
 				gui.displayPanel.selectNextBeat();
-				break;
+				break;*/
 			case KeyEvent.VK_HOME:
 				gui.displayPanel.selectFirstBeat();
 				break;
@@ -172,13 +172,52 @@
 					System.err.print(System.nanoTime() / 1000000 % 100000);
 				gui.displayPanel.addBeatNow();
 				break;
+			case KeyEvent.VK_V:
+				gui.displayPanel.addBeat(gui.displayPanel.getCurrentTime());
+				break;
 			case KeyEvent.VK_P:
 				audioPlayer.play();
 				break;
 			case KeyEvent.VK_S:
 				audioPlayer.stop();
 				break;
+			case KeyEvent.VK_SPACE: // WG. inserted (4 Aug 2009)
+				if (audioPlayer.playing)
+					audioPlayer.stop();
+				else
+					audioPlayer.play();
+				break;
+			case KeyEvent.VK_B: // WG. inserted (4 Aug 2009)
+				gui.displayPanel.beatTrack();
+				break;
+			case KeyEvent.VK_Z: // WG. inserted (5 Aug 2009)
+				gui.displayPanel.clearBeats();
+				break;
+			case KeyEvent.VK_RIGHT:
+				gui.scroll(.025);
+				break;
+			case KeyEvent.VK_LEFT:
+				gui.scroll(-.025);
+				break;
 			} // switch
+		} else if (modifiers == KeyEvent.CTRL_MASK) {
+			switch (keyCode) {
+			case KeyEvent.VK_RIGHT:
+				gui.scroll(.1);
+				break;
+			case KeyEvent.VK_LEFT:
+				gui.scroll(-.1);
+				break;
+			} // switch
+		} else if (modifiers == KeyEvent.ALT_MASK) {
+			switch (keyCode) {
+			case KeyEvent.VK_RIGHT:
+				gui.scroll(.005);
+				break;
+			case KeyEvent.VK_LEFT:
+				gui.scroll(-.005);
+				break;
+			} // switch			
 		}
 	} // keyPressed()
 	
--- a/at/ofai/music/beatroot/GUI.java	Fri Oct 08 16:14:43 2010 +0100
+++ b/at/ofai/music/beatroot/GUI.java	Fri Sep 30 15:21:26 2011 +0100
@@ -74,6 +74,7 @@
 	
 	/** The scroller for showing or changing the position of the viewport relative to the whole audio file */
 	protected JScrollBar scroller;
+	protected int scrollBarWidth = 1000; // pixel
 	
 	/** An intermediate level panel containing the displayPanel and scroller */
 	protected JPanel scrollPane;
@@ -95,7 +96,7 @@
 	
 	/** Version number of program - displayed as part of window title.
 	 *  DO NOT EDIT: This line is also used in creating the file name of the jar file. */
-	public static final String version = "0.5.7";
+	public static final String version = "0.5.6";
 	
 	/** Strings displayed on menus and buttons */
 	public static final String LOAD_AUDIO = "Load Audio Data";
@@ -192,6 +193,7 @@
 		displayPanel = new BeatTrackDisplay(this, beats);
 		displayPanel.addKeyListener(listener);
 		displayPanel.setBeats(beats);
+		//displayPanel.addPropertyChangeListener(arg0)
 		EditAction.setDisplay(displayPanel);
 		
 		scroller = new JScrollBar();
@@ -202,9 +204,11 @@
 		scroller.setUnitIncrement(100);
 		scroller.setBlockIncrement(400);
 		scroller.setOrientation(Adjustable.HORIZONTAL);
-		scroller.setPreferredSize(new Dimension(1000, 17));
+		scroller.setPreferredSize(new Dimension(scrollBarWidth, 17));
+		
 		scrollPane = new JPanel();
-		scrollPane.setPreferredSize(new Dimension(1010, displayPanel.ySize+17+10));
+		scrollPane.setLayout(new BorderLayout());
+		scrollPane.setPreferredSize(new Dimension(scrollBarWidth+10, displayPanel.ySize+17+10));
 		scrollPane.setBackground(Color.black);
 		scrollPane.add(displayPanel, BorderLayout.CENTER);
 		scrollPane.add(scroller, BorderLayout.SOUTH);
@@ -304,8 +308,8 @@
 	protected JMenu makeBeatTrackMenu() {
 		JMenu menu = new JMenu("BeatTrack");
 		menu.setMnemonic(KeyEvent.VK_T);
-		menu.add(makeMenuItem(BEAT_TRACK, KeyEvent.VK_T, 0, false));
-		menu.add(makeMenuItem(CLEAR_BEATS, KeyEvent.VK_C, 0, false));
+		menu.add(makeMenuItem(BEAT_TRACK, KeyEvent.VK_B, KeyEvent.VK_B, false));
+		menu.add(makeMenuItem(CLEAR_BEATS, KeyEvent.VK_Z, KeyEvent.VK_Z, false));
 		menu.add(makeMenuItem(MARK_METRICAL_LEVEL, KeyEvent.VK_M, KeyEvent.VK_M, false));
 		menu.add(makeMenuItem(CLEAR_METRICAL_LEVELS, KeyEvent.VK_L, 0, false));
 		return menu;
@@ -353,6 +357,7 @@
 	} // loadBeatData()
 
 	/** Saves beat data to a file chosen by a file save dialog. */
+	// TODO Check for the correct extension of exported file names
 	public void saveBeatData() {
 		try {
 			beats.writeBeatTrackFile(chooser.getBeatOutName());
@@ -460,6 +465,16 @@
 	public void scroll(int dir) {
 		scroller.setValue(scroller.getValue() + dir * scroller.getUnitIncrement());
 	} // scroll()
+	
+	/** Scroll the display by a given amount in seconds. Used for keyboard input 
+	 * @param incr amount of shift in seconds (positive to the right, vice versa)
+	 * inserted by WG, Aug 2009.
+	 */
+	public void scroll(double incr) {
+		displayPanel.setCurrentTime(displayPanel.getCurrentTime() + incr);
+		skipTo(displayPanel.getCurrentTime());
+		displayPanel.scrollTo(displayPanel.getCurrentTime(), false);
+	}
 
 	/** Copies default values into preferences dialog. */
 	public void setPreferences() {
@@ -521,4 +536,12 @@
 		return percussionSounds.getString(PERCUSSION_STRINGS[level][0]);
 	} // getPercussionSound()
 	
+	public void setOnsetDetectionParameter(double param1,double param2) {
+		if (audioProcessor.audioFileName != null) {
+			audioProcessor.findOnsets(param1, param2);
+			audioProcessor.setDisplay(displayPanel); // after processing
+			updateDisplay(false);
+		}
+	} // setOnsetDetectionParameter()
+	
 } // class GUI
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/at/ofai/music/beatroot/OnsetParameterListener.java	Fri Sep 30 15:21:26 2011 +0100
@@ -0,0 +1,75 @@
+/*  BeatRoot: An interactive beat tracking system
+    Copyright (C) 2001, 2006 by Simon Dixon
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program (the file gpl.txt); if not, download it from
+	http://www.gnu.org/licenses/gpl.txt or write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package at.ofai.music.beatroot;
+
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * A listener class for onset parameter slider, which notifies the GUI's main
+ * panel when the scrollbar is moved.
+ * 
+ * @author Sebastian Flossmann
+ */
+class OnsetParameterListener implements ChangeListener {
+	BeatTrackDisplay display;
+	/* The current value of the upper slider */
+	int p1;
+	
+	/* The current value of the lower slider */
+	int p2;
+	
+	/* The Textfield showing the current value of the upper slider */
+	JTextField text1;
+	
+	/* The Textfield showing the current value of the lower slider */
+	JTextField text2;
+
+	public OnsetParameterListener(BeatTrackDisplay btd, int upper, int lower, JTextField upperText, JTextField lowerText){
+		display = btd;
+		p1 = upper;
+		p2 = lower;
+		text1 = upperText;
+		text2 = lowerText;
+	}
+
+	public void stateChanged(ChangeEvent e) {
+		JSlider slider = (JSlider) e.getSource();
+		if (slider.getName() == "upperSlider") {
+			p1 = slider.getValue();
+//			if (p1 >= p2) {
+//				p1 = p2;
+//				slider.setValue(p2);
+//			}
+			text1.setText(Integer.toString(p1));
+		} else {
+			p2 = slider.getValue();
+//			if (p2 <= p1) {
+//				p2 = p1;
+//				slider.setValue(p1);
+//			}
+			text2.setText(Integer.toString(p2));
+		}
+		display.setOnsetDetectionParam(p1/100.0, p2/100.0);
+	} // stateChanged()
+
+} // class OnsetParameterListener
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpl.txt	Fri Sep 30 15:21:26 2011 +0100
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.