package com.jdriven.xmastree;


import javax.sound.sampled.*;

public class Volume implements Runnable {

    private double current;
    private boolean cont;
    private Averages averages = new Averages(60);

    @Override
    public void run() {
        AudioFormat format = new AudioFormat(44100, 16, 2, true, true);

        DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format);
        DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format);

        try {
            TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo);
            targetLine.open(format);
            targetLine.start();

            SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo);
            sourceLine.open(format);
            sourceLine.start();

            int numBytesRead;
            byte[] targetData = new byte[targetLine.getBufferSize() / 5];

            double min = Double.MAX_VALUE;
            double max = Double.MIN_VALUE;
            cont = true;
            while (cont) {
                numBytesRead = targetLine.read(targetData, 0, targetData.length);

                if (numBytesRead == -1)	break;

                double rms = calculateRMSLevel(targetData);


                min = Math.min(min, rms);
                max = Math.max(max, rms);

                double calculated = (rms - min);

                current = calculated / (max - min);
                if(max - min < 5.0) {
                    current = 0.0;
                }
                max -= 0.1;
                Thread.sleep(20);
            }
        }
        catch (Exception e) {
            System.err.println(e);
        }
    }

    public SoundValues get() {
        return new SoundValues(current);
    }

    public void stop() {
        cont = false;
    }

    protected static double calculateRMSLevel(byte[] audioData) { // audioData might be buffered data read from a data line
        long lSum = 0;
        for(int i=0; i<audioData.length; i++)
            lSum = lSum + audioData[i];

        double dAvg = lSum / audioData.length;

        double sumMeanSquare = 0d;
        for(int j=0; j<audioData.length; j++)
            sumMeanSquare = sumMeanSquare + Math.pow(audioData[j] - dAvg, 2d);

        double averageMeanSquare = sumMeanSquare / audioData.length;
        return (Math.pow(averageMeanSquare,0.5d) + 0.5);
    }

    public static class SoundValues {
        public final double current;

        public SoundValues(double current) {
            this.current = current;
        }
    }
}

@@ -99,16 +99,76 @@
 able %7B%0A%0A
+    private static final double DEFAULT_DELTA_CUTOFF = 5.0;%0A
     priv
@@ -209,24 +209,57 @@
 olean cont;%0A
+    private double deltaCutoff;%0A%0A
     private 
@@ -293,24 +293,185 @@
 rages(60);%0A%0A
+    public Volume() %7B%0A        deltaCutoff = System.getProperty(%22delta%22) != null ? Double.parseDouble(System.getProperty(%22delta%22)) : DEFAULT_DELTA_CUTOFF;%0A    %7D%0A%0A
     @Overrid
@@ -1589,24 +1589,186 @@
 max, rms);%0A%0A
+                double delta = max - min;%0A%0A                System.out.printf(%22%255.2f %7C %255.2f %7C %255.2f %7C %255.2f %7C %25s%5Cn%22, rms, min, max, delta, delta %3C deltaCutoff);%0A%0A
             
@@ -1804,16 +1804,16 @@
 - min);%0A
-
 %0A       
@@ -1857,16 +1857,18 @@
 - min);%0A
+%0A%0A
         
@@ -1882,23 +1882,27 @@
  if(
-max - min %3C 5.0
+delta %3C deltaCutoff
 ) %7B%0A
@@ -1946,32 +1946,32 @@
               %7D%0A
-
                 
@@ -1976,16 +1976,57 @@
   max -=
+ (delta / 25.0);%0A                //max -=
  0.1;%0A  

Debug output