[ronw_2006-07-12
ronw@ee.columbia.edu**20060712183526
 
 Bugs fixed:
  - fixed the off by one error in display composed features where the
    first chunk was sometimes displayed at the end
  - In MEAPsoftGUI if featFile == null (i.e. if feature extractor is
    disabled), the composer will automatically use the segment file
    instead.  So there is no need to enable feature extractors when
    using a composer that doesn't use features.
  - some code and GUI clean up
 
 New features:
  - Added support for feature weights and normalization. SortComposer
    and NNComposer now use normalized/weighted features.
  - Added a segment density slider to SegmenterPanel.  The range of
    values used might need some tweaking.
 
] {
hunk ./Makefile 30
-all: classes jar
+all: jar
hunk ./Makefile 46
-jar:
+jar: classes
hunk ./Makefile 67
+	chmod 755 $(PACKAGENAME)-$(VERSION)/$(BINDIR)/runme.*;      \
hunk ./examples/make_psycho_stairway.sh 15
-$JAVA $PFX.FeatExtractor -f TimeFreqCentroid -f AvgMelSpec mashup_stairway.feat mashup_psycho_killer.feat
+$JAVA $PFX.FeatExtractor -f TimeCentroid -f AvgMelSpec mashup_stairway.feat mashup_psycho_killer.feat
hunk ./examples/reorder_stairway.sh 12
-$JAVA $PFX.FeatExtractor -f AvgChunkPower -f AvgSpecCentroid -f AvgSpecFlatness -o stairway.feat stairway.segments
+$JAVA $PFX.FeatExtractor -f AvgSpecCentroid -f AvgSpecFlatness -o stairway.feat stairway.segments
hunk ./src/com/meapsoft/EDLFile.java 131
+    public double[][] getFeatures()
+    {
+        return getFeatures(null);
+    }
+
+    /**
+     * Get the matrix of features associated with each chunk in this
+     * EDLFile
+     */
hunk ./src/com/meapsoft/EDLFile.java 147
-        // the above call destroys the Heap property in chunks, need to fix it here.
-        ((MaxHeap)chunks).rebuildHeap();
+        // the above call destroys the Heap property in chunks, need
+        // to fix it here.
+        if(!((Heap)chunks).isHeap())
+            ((MaxHeap)chunks).rebuildHeap();
hunk ./src/com/meapsoft/FeatChunk.java 97
+     * Set feature dimension idx to the given feature value.
+     */
+    public void setFeature(int idx, double f)
+    {
+        features.set(idx, new Double(f));
+    }
+
+    /**
hunk ./src/com/meapsoft/FeatExtractor.java 29
+import java.util.ListIterator;
hunk ./src/com/meapsoft/FeatExtractor.java 47
-    FeatFile[] featFiles;
-    FeatFile outFile = null;
+    private FeatFile[] featFiles;
+    private FeatFile outFile = null;
hunk ./src/com/meapsoft/FeatExtractor.java 51
-    Vector featExts;
+    private Vector featExts;
+    // and their associated weights
+    private Vector featExtWeights;
hunk ./src/com/meapsoft/FeatExtractor.java 55
-    String feat_names = "";
+    private String feat_names = "";
hunk ./src/com/meapsoft/FeatExtractor.java 184
-        //file.featureDescriptions.add("");
hunk ./src/com/meapsoft/FeatExtractor.java 223
-            Iterator i = featExts.listIterator();
+            ListIterator i = featExts.listIterator();
hunk ./src/com/meapsoft/FeatExtractor.java 235
+                    
+                    if(featExtWeights != null)
+                    {
+                        int idx = i.nextIndex()-1;
+                        if(idx < featExtWeights.size())
+                            featString = featExtWeights.get(idx)+"*"+featString;
+                    }
+
hunk ./src/com/meapsoft/FeatExtractor.java 311
+    /**
+     * Set weights associated with the different FeatureExtractors
+     * used by this object.
+     */
+    public void setFeatureExtractorWeights(Vector v)
+    {
+        featExtWeights = v;
+    }
hunk ./src/com/meapsoft/FeatFile.java 103
-        
+
hunk ./src/com/meapsoft/FeatFile.java 105
+    }
+
+    /**
+     * Normalize the features contained in this file such that the
+     * feature dimensions corresponding to the outputs of each
+     * FeatureExtractor are normalized independently to lie between 0
+     * and 1.  
+     *
+     * I.e. if this featfile contains outputs of both AvgMelSpec (dim
+     * 0-39) and AvgChroma (dim 40-51), dimensions 0-39 will be
+     * normalized independently of dimensions 40-51 and vice versa.
+     */
+    public void normalizeFeatures()
+    {
+        // operate on each feature type separately
+        int startDim = 0;
+        for(int featType = 0; featType < featureDescriptions.size(); featType++)
+        {
+            int numDim = Integer.parseInt(
+                ((String)featureDescriptions.get(featType)).split("[()]" )[1]);
+
+            int[] featDim = new int[numDim];
+            for(int x = 0; x < numDim; x++)
+                featDim[x] = startDim + x;
+
+            // find the max and min values in these dimensions
+            double[][] feat = getFeatures(featDim);
+            double minFeat = DSP.min(DSP.min(feat));
+            double maxFeat = DSP.max(DSP.max(feat));
+
+            for(int x = 0; x < chunks.size(); x++)
+            {
+                FeatChunk c = (FeatChunk)chunks.get(x);
+
+                double[] currFeat = c.getFeatures(featDim);
+
+                for(int d = 0; d < featDim.length; d++)
+                    c.setFeature(featDim[d], 
+                                 (currFeat[d]-minFeat)/(maxFeat-minFeat));
+            }
+
+            startDim += numDim;
+        }
+    }
+
+    /**
+     * Apply weights (as listed in the "# Features: x.x*FeatureExtractor(ndim)" line )
+     * to the features contained in this file.
+     */
+    public void applyFeatureWeights()
+    {
+        // operate on each feature type separately
+        int startDim = 0;
+        for(int featType = 0; featType < featureDescriptions.size(); featType++)
+        {
+            int numDim = Integer.parseInt(
+                ((String)featureDescriptions.get(featType)).split("[()]")[1]);
+
+            double weight = 1.0;
+            try
+            {
+                weight = Double.parseDouble(
+                    ((String)featureDescriptions.get(featType)).split("[*]")[0]);
+            }
+            catch(NumberFormatException e)
+            {
+                // the featureDescription does not contain a weight
+                continue;
+            }
+
+            int[] featDim = new int[numDim];
+            for(int x = 0; x < numDim; x++)
+                featDim[x] = startDim + x;
+
+            for(int x = 0; x < chunks.size(); x++)
+            {
+                FeatChunk c = (FeatChunk)chunks.get(x);
+
+                double[] currFeat = c.getFeatures(featDim);
+
+                for(int d = 0; d < featDim.length; d++)
+                    c.setFeature(featDim[d], weight*currFeat[d]);
+            }
+
+            startDim += numDim;
+        }
hunk ./src/com/meapsoft/Heap.java 189
-        for(int i = (int)(size()/2)+1; i >= 0; i--)
+        for(int i = (int)(size()/2); i >= 0; i--)
hunk ./src/com/meapsoft/Heap.java 199
-     * sorted order.  This is not stable.
+     * sorted order.  This is not a stable sort.
hunk ./src/com/meapsoft/Heap.java 274
+    }
+
+    /**
+     * Do the contents of this object currently obey the heap
+     * property?
+     */
+    public boolean isHeap()
+    {
+        return isHeap;
hunk ./src/com/meapsoft/MEAPUtil.java 58
-	public static final String version = "rc7";
+    public static final String version = "rc7";
hunk ./src/com/meapsoft/MinHeap.java 84
-     * This is not stable.
+     * This is not a stable sort.
hunk ./src/com/meapsoft/composers/SortComposer.java 180
+        featFile = (FeatFile)featFile.clone();
+        featFile.normalizeFeatures();
+        featFile.applyFeatureWeights();
+
hunk ./src/com/meapsoft/composers/SortComposer.java 224
-            
+
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 29
+import java.text.*;
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 49
+    Vector featureWeightFields;
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 81
-		featureCheckBoxes = new Vector();
+		featureCheckBoxes = new Vector(classNames.size());
+        featureWeightFields = new Vector(classNames.size());
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 108
-		
+
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 116
-		BoxLayout sfp = new BoxLayout(selectFeaturesPanel, BoxLayout.Y_AXIS);
-		selectFeaturesPanel.setLayout(sfp);
-		
-		Vector selectFeaturesPanels = new Vector();
+		//BoxLayout sfp = new BoxLayout(selectFeaturesPanel, BoxLayout.Y_AXIS);
+        //selectFeaturesPanel.setLayout(sfp);
+
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 120
+        selectFeaturesPanel.setLayout(new GridLayout((int)(numFeatures/4.0 + 1), 4));
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 122
+		Vector selectFeaturesPanels = new Vector();
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 129
-			selectFeaturesPanel.add(panel);
+			//selectFeaturesPanel.add(panel);
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 143
-			
-			int whichPanel = i/4;
-			
-			JPanel panel = (JPanel)selectFeaturesPanels.elementAt(whichPanel);
-			panel.add(cb);
+            cb.setActionCommand("enableFeatExt"+i);
+            cb.addActionListener(this);
+
+            JFormattedTextField tf = new JFormattedTextField(NumberFormat.getNumberInstance());
+            tf.setValue(new Double(1.0));
+            tf.setColumns(2);
+            tf.setBackground(c);
+            tf.setEnabled(false);
+            featureWeightFields.add(tf);
+
+			//int whichPanel = i/4;
+            //JPanel panel = (JPanel)selectFeaturesPanels.elementAt(whichPanel);
+            JPanel panel = new JPanel();
+            panel.setBackground(c);
+            panel.add(cb);
+			panel.add(tf);
+
+            selectFeaturesPanel.add(panel);
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 163
+            {
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 165
+				tf.setEnabled(true);
+            }
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 241
+        }
+        else if(command.startsWith("enableFeatExt"))
+        {
+            int i = Integer.parseInt(command.substring("enableFeatExt".length()));
+
+            ((JTextField)featureWeightFields.get(i)).setEnabled(
+                ((JCheckBox)featureCheckBoxes.get(i)).isSelected());
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 254
+        {
+            // not all composers need features, so by default set the
+            // featFile to be the empty segmentFile
+            if(featFile == null)
+                featFile = segmentFile;
+
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 261
+        }
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 264
+        Vector featWeights = new Vector();
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 268
-			
+
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 272
+                {
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 275
+                    featWeights.add(((JFormattedTextField)featureWeightFields.elementAt(i)).getValue());
+                }
hunk ./src/com/meapsoft/gui/FeatExtractorPanel.java 288
+        featExtractor.setFeatureExtractorWeights(featWeights);
hunk ./src/com/meapsoft/gui/MEAPsoftGUI.java 396
+
+        //if(message.length() > 70)
+        //    message = message.substring(0, 70);
hunk ./src/com/meapsoft/gui/MEAPsoftGUI.java 400
-		final JOptionPane optionPane = new JOptionPane(
-						message, //.substring(0, 70),
-						JOptionPane.QUESTION_MESSAGE);
+		final JOptionPane optionPane = 
+            new JOptionPane(message, JOptionPane.QUESTION_MESSAGE);
hunk ./src/com/meapsoft/gui/MEAPsoftGUI.java 403
-		final JDialog dialog = new JDialog(jframe, 
-									 "Exception!",
-									 true);
+		final JDialog dialog = new JDialog(jframe, "Exception!", true);
hunk ./src/com/meapsoft/gui/MEAPsoftGUI.java 405
-		dialog.setDefaultCloseOperation(
-			JDialog.DO_NOTHING_ON_CLOSE);
+		dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
hunk ./src/com/meapsoft/gui/MEAPsoftGUIPanel.java 49
-    //protected String = inputSoundFileNa
hunk ./src/com/meapsoft/gui/PreferencesPanel.java 108
-		String aboutText = "MEAPsoft was created by the participants in the\n" +
			"Music Engineering Art Project at Columbia University.\n\n" +
			"For more information, please see:\n" +
			"http://music.columbia.edu/cmc/meap\n" +
			"\n" +
			"Sponsored by:\n" + 
-			"The Academic Quality Fund\n" + 
-			"LabROSA: http://labrosa.ee.columbia.edu \n" +
			"The Computer Music Center: http://music.columbia.edu/cmc \n" +
			"\n" +
-			"Developed and written by:\n" +
			"Victor Adan, John Arroyo, Johanna Devaney, Dan Ellis,\n" +
			"Dan Iglesia, Mike Mandel, Graham Poliner, Douglas Repetto,\n" +
			"Jeff Snyder, Ron Weiss";
-		
+		String aboutText = 
+            "MEAPsoft was created by the participants in the " + 
+            "Music Engineering Art Project at Columbia University.\n" +
+            "\n" +
+            "For more information, please see:\n" +
+            "http://music.columbia.edu/cmc/meap\n" +
+            "\n" +
+            "Sponsored by:\n" + 
+            "The Academic Quality Fund\n" + 
+            "LabROSA: http://labrosa.ee.columbia.edu \n" +
+            "The Computer Music Center: http://music.columbia.edu/cmc \n" +
+            "\n" +
+            "Development by:\n" +
+            "Ron Weiss, Douglas Repetto, Mike Mandel, Dan Ellis, Victor Adan, Jeff Snyder\n" +
+            "\n" +
+            "Additional contributions by:\n" +
+            "John Arroyo, Johanna Devaney, Dan Iglesia, Graham Poliner\n\n" +
+            "MEAPsoft Version " + MEAPUtil.version;
+
hunk ./src/com/meapsoft/gui/PreferencesPanel.java 129
-		aboutPanel.add(aboutTextArea);
+        aboutTextArea.setColumns(50);
+		aboutTextArea.setLineWrap(true);
+		aboutTextArea.setWrapStyleWord(true);
+        aboutPanel.add(aboutTextArea);
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 51
+    JSlider densitySlider;
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 144
-		eventPanel = new JPanel();
+		eventPanel = new JPanel(new GridLayout(2,2));
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 148
-		thresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 12, 1);
+		thresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 20, 1);
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 150
-		thresholdSlider.setValue(6);
+		thresholdSlider.setValue(10);
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 153
-		labelTable.put( new Integer(12), new JLabel("high") );
+		labelTable.put( new Integer(20), new JLabel("high") );
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 156
-		thresholdSlider.setMajorTickSpacing(1);
+		thresholdSlider.setMajorTickSpacing(2);
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 159
+        
+        JLabel densityLabel = new JLabel("segment density: ");
+        eventPanel.add(densityLabel);
+        densitySlider = new JSlider(JSlider.HORIZONTAL, 0, 20, 1);
+        densitySlider.setBackground(c);
+        densitySlider.setValue(15);
+        densitySlider.setMajorTickSpacing(2);
+        densitySlider.setPaintTicks(true);
+		densitySlider.setLabelTable(labelTable);
+		densitySlider.setPaintLabels(true);
+        eventPanel.add(densitySlider);
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 262
+        // for event detector:
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 264
-        double thresh = 3.0-thresholdSlider.getValue()/4.0;
+        double thresh = 3.0-thresholdSlider.getValue()/6.666;
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 266
-        double smtime = 0.25*(thresh)/3;
+        //double smtime = 0.25*(thresh)/3;
+        // want value between 1 and 0
+        double smtime = (20.0-densitySlider.getValue())/20.0;
+        //System.out.print("smtime = "+smtime+"... "); 
+
+        // for beat detector:
hunk ./src/com/meapsoft/gui/SegmenterPanel.java 314
+
+        //System.out.println("found "+segmentFile.chunks.size()+" chunks.");
}
