Mercurial > hg > beatroot
changeset 1:4de8d7f01bd4
* Import BeatRoot v0.5.6
author | Chris Cannam |
---|---|
date | Fri, 08 Oct 2010 16:09:10 +0100 |
parents | c7e0e3007677 |
children | 4c3f5bc01c97 |
files | at/ofai/music/beatroot/BeatRoot.java at/ofai/music/beatroot/BeatTrackDisplay.java at/ofai/music/beatroot/GUI.java |
diffstat | 3 files changed, 69 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/at/ofai/music/beatroot/BeatRoot.java Fri Oct 08 16:08:48 2010 +0100 +++ b/at/ofai/music/beatroot/BeatRoot.java Fri Oct 08 16:09:10 2010 +0100 @@ -134,6 +134,8 @@ * <LI><I><B>-l</B> lowThreshold</I> Spectrogram energy threshold corresponding * to minimum value in colour map</LI> * <LI><I><B>-o</B> outputFile</I> Save output to this file (implies <I><B>-b</B></I>)</LI> + * <LI><I><B>-O</B> Output the times of onsets, not beats, and exit (use -o + * flag to specify the output file; implies batch mode)</LI> * <LI><I><B>-p</B></I> Play audio with beats as soon as processing is completed</LI> * <LI><I><B>-q</B></I> Suppress output of warnings (TODO) </LI> * <LI><I><B>-s</B> audioScaleFactor</I> Constant for scaling amplitude envelope display</LI> @@ -142,6 +144,7 @@ * <LI><I><B>-w</B></I> live input (not used)</LI> * <LI><I><B>-c</B></I> cursor is always at centre; data scrolls past it</LI> * <LI><I><B>-e</B> allowedError</I> allowed error in beat position for evaluation</LI> + * <LI><I><B>-E</B> allowedRelativeError</I> allowed relative error (0-1) in beat position for evaluation</LI> * </BL> */ public void processArgs(String[] args) { @@ -169,6 +172,14 @@ break; case 'e': BeatTrackDisplay.allowedError = Double.parseDouble(args[++i]); + BeatTrackDisplay.useRelativeError = false; + break; + case 'E': + BeatTrackDisplay.allowedError = Double.parseDouble(args[++i]); + BeatTrackDisplay.useRelativeError = true; + break; + case 'P': + BeatTrackDisplay.usePScore = true; break; case 'h': GUI.DEFAULT_HIGH_THRESHOLD = Double.parseDouble(args[++i]); @@ -265,8 +276,17 @@ audioProcessor.setInputFile(audioIn); audioProcessor.processFile(); if (onsetOnly && (textOutputFile != null)) { - audioProcessor.onsetList.writeBinary(textOutputFile); - continue; + if (textOutputFile.endsWith(".obj")) + audioProcessor.onsetList.writeBinary(textOutputFile); + else try { + audioProcessor.onsetList.writeBeatsAsText(textOutputFile); + } catch (Exception e) { + System.err.println("Can't write onset file\n" + e); + } + if (argsFile != null) + continue; + else + break; } } else if (beatsIn == null) { System.exit(0);
--- a/at/ofai/music/beatroot/BeatTrackDisplay.java Fri Oct 08 16:08:48 2010 +0100 +++ b/at/ofai/music/beatroot/BeatTrackDisplay.java Fri Oct 08 16:09:10 2010 +0100 @@ -30,6 +30,7 @@ import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; +import java.util.Arrays; import java.util.ListIterator; import javax.swing.JPanel; @@ -281,6 +282,14 @@ */ public static double allowedError = 0.1; + /** For evaluation of beat tracking results, indicates whether <code>allowedError</code> + * is interpreted as absolute (in seconds) or relative (0-1). + */ + public static boolean useRelativeError = false; + + /** For evaluation, select whether to use the P-score or T-score */ + public static boolean usePScore = false; + /** mode for scrolling the display: * if true the cursor remains centred on the screen and the data scrolls; * if false the cursor moves and the data is changed just before @@ -475,7 +484,7 @@ /** Sets the length of audio that is visible at any one time (i.e. zoom factor). * @param msec Length in milliseconds - */ + */ synchronized public void setVisibleAmount(int msec) { visibleTimeLength = (double)msec / 1000.0; if (visibleTimeStart + visibleTimeLength > maximumTime) @@ -1144,7 +1153,7 @@ /** Constant representing an unknown relationship between metrical levels */ protected static final double UNKNOWN = -1.0; - /** Finds the mean tempo from an array of beat times + /** Finds the mean tempo (as inter-beat interval) from an array of beat times * @param d An array of beat times * @return The average inter-beat interval */ @@ -1154,6 +1163,23 @@ return (d[d.length - 1] - d[0]) / (d.length - 1); } // getAverageIBI() + /** Finds the median tempo (as inter-beat interval) from an array of beat times + * @param d An array of beat times + * @return The median inter-beat interval + */ + public static double getMedianIBI(double[] d) { + if ((d == null) || (d.length < 2)) + return -1.0; + double[] ibi = new double[d.length-1]; + for (int i = 1; i < d.length; i++) + ibi[i-1] = d[i] - d[i-1]; + Arrays.sort(ibi); + if (ibi.length % 2 == 0) + return (ibi[ibi.length / 2] + ibi[ibi.length / 2 - 1]) / 2; + else + return ibi[ibi.length / 2]; + } // getAverageIBI() + /** Estimates the metrical relationship between two beat sequences. * @param beats The system's beat times * @param correct The annotated beat times @@ -1234,13 +1260,16 @@ int ok = 0; int extra = 0; double metricalLevel = getRhythmicLevel(beatsArr, correct); + double errorWindow = allowedError; + if (useRelativeError) + errorWindow *= getMedianIBI(correct); // double[] revBeats = makeRealBeatList(correctBeats, metricalLevel, true); int b = 0; // index of beats to be evaluated int c = 0; // index of correct (annotated) beats for ( ; b < beatsArr.length && (beatsArr[b] < correct[c]); b++) extra++; // skip any "beats" before music starts while ((c < correct.length) && (b < beatsArr.length)) { - if (Math.abs(beatsArr[b] - correct[c]) < allowedError) { + if (Math.abs(beatsArr[b] - correct[c]) < errorWindow) { ok++; b++; c++; @@ -1260,9 +1289,15 @@ fp++; b++; } - System.out.printf("%4.2f %5.3f %5.3f", metricalLevel, getAverageIBI(correct), getAverageIBI(beatsArr)); - System.out.printf(" ok: " + ok + " f+: " + fp + " f-: " + fn + + if (usePScore) { + System.out.printf("%4.2f %5.3f %5.3f", metricalLevel, getMedianIBI(correct), getMedianIBI(beatsArr)); + System.out.printf(" ok: " + ok + " f+: " + fp + " f-: " + fn + + " Score: %5.1f\n", (double)(ok*100) / (double)(Math.max(fp, fn) + ok)); + } else { + System.out.printf("%4.2f %5.3f %5.3f", metricalLevel, getAverageIBI(correct), getAverageIBI(beatsArr)); + System.out.printf(" ok: " + ok + " f+: " + fp + " f-: " + fn + " Score: %5.1f\n", (double)(ok*100) / (double)(fp+fn+ok)); + } if (ok + fp + extra != beatsArr.length) System.err.println("Beat count wrong " + extra + " " + beatsArr.length + " " + correct.length); } // evaluate()
--- a/at/ofai/music/beatroot/GUI.java Fri Oct 08 16:08:48 2010 +0100 +++ b/at/ofai/music/beatroot/GUI.java Fri Oct 08 16:09:10 2010 +0100 @@ -95,7 +95,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.5"; + public static final String version = "0.5.6"; /** Strings displayed on menus and buttons */ public static final String LOAD_AUDIO = "Load Audio Data"; @@ -339,7 +339,12 @@ public void loadBeatData(String fileName) { if (fileName != null) { try { - beats = EventList.readBeatTrackFile(fileName); + if (fileName.endsWith(".tmf")) + beats = EventList.readBeatTrackFile(fileName); + else if (fileName.endsWith(".lbl")) + beats = EventList.readLabelFile(fileName); + else // if (fileName.endsWith(".txt")) + beats = EventList.readBeatsAsText(fileName); setBeatData(beats); } catch (Exception e) { System.err.println("Error loading beat data: " + e);