# MP3 SPI



## Killi138 (20. Feb 2008)

Hi Leute,

ich hab mir eine Klasse geschrieben, die mir MP3-Dateien abspielen kann (mit Hilfe von MP3 SPI).
MP3 SPI unterstützt scheinbar auch einen Live Equalizer, siehe in der Doku: http://www.javazoom.net/mp3spi/documents.html 

Allerdings zeigt mir mein Code immer nur 0.0 an - für jeden Wert des Equalizers...wieso? Ich lese ihn doch jedesmal neu ein...oder ist gerade das der Fehler?

Ich weiß nicht wo ich weiter suchen soll..



```
import java.io.*;
import javax.sound.sampled.*;
import java.util.Map;

public class JLayerPlayer {

	public static void main(String[] args) {
		  testPlay("C:/Overhaulin-Gasoline.mp3");
	}

    public static void testPlay(String filename)
    {
            try {
                File file = new File(filename);
                AudioInputStream in= AudioSystem.getAudioInputStream(file);
                AudioInputStream din = null;
                AudioFormat baseFormat = in.getFormat();
                AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                                            baseFormat.getSampleRate(),
                                                            16,
                                                            baseFormat.getChannels(),
                                                            baseFormat.getChannels() * 2,
                                                            baseFormat.getSampleRate(),
                                                            false);
                din = AudioSystem.getAudioInputStream(decodedFormat, in);
                // Play now.
                rawplay(decodedFormat, din);
                in.close();
            } catch (Exception e)
            {
                    //Handle exception.
            }
    }

    private static void rawplay(AudioFormat targetFormat, AudioInputStream din) throws IOException, LineUnavailableException
    {
            byte[] data = new byte[4096];
            SourceDataLine line = getLine(targetFormat);
            if (line != null)
            {
               // Start
               line.start();
               int nBytesRead = 0, nBytesWritten = 0;
               while (nBytesRead != -1)
               {
                     nBytesRead = din.read(data, 0, data.length);
                     // DecodedMpegAudioInputStream properties
                     if (din instanceof javazoom.spi.PropertiesContainer)
                     {
                        Map properties = ((javazoom.spi.PropertiesContainer) din).properties();
                        float[] equalizer = (float[]) properties.get("mp3.equalizer");
                        equalizer[0] = (float)0.5;
                        equalizer[31] = (float)0.25;

                        String eq = "";
                        for(int i=0;i<equalizer.length;i++) {
                            eq = eq + equalizer[i] + "   ";
                        }
                        System.out.println("Equal: " + eq);
                     }
                     if (nBytesRead != -1) nBytesWritten = line.write(data, 0, nBytesRead);
               }
               // Stop
               line.drain();
               line.stop();
               line.close();
               din.close();
            }
    }

    private static SourceDataLine getLine(AudioFormat audioFormat) throws LineUnavailableException
    {
            SourceDataLine res = null;
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
            res = (SourceDataLine) AudioSystem.getLine(info);
            res.open(audioFormat);
            return res;
    }

}
```


----------



## Killi138 (22. Feb 2008)

Wer hierzu eine Antwort braucht, ich habs soeben geschafft!

Man braucht dazu die Libs 
- kj_dsp.jar
- ldlib.jar
- ldsa.jar
- tritonus_share.jar
von diesem Paket hier: http://www.lightdev.com/page/74.htm 

Und die Lib
- mp3plugin.jar
von MP3SPI: http://www.javazoom.net/mp3spi/sources.html



Hier der Code:

Klasse Equalizer

```
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.sound.sampled.*;
import java.util.Map;
import kj.dsp.KJDigitalSignalProcessingAudioDataConsumer;
import com.lightdev.lib.audio.Player;
import com.lightdev.lib.audio.PlayerListener;
import java.awt.Graphics;
import java.net.URL;
import java.net.MalformedURLException;
import java.security.CodeSource;
import java.security.ProtectionDomain;


public class Equalizer implements PlayerListener {
    private SpectrumAnalyzer analyzer;
    private KJDigitalSignalProcessingAudioDataConsumer synchronizer;
    private Player player;
    public final String ACTION_PLAY_ITEM = "playItem";
    private int width = 573;
    private int height = 320;
    private int analyzer_width = 450;
    private int analyzer_height = 200;

    public static void main(String s[]) {
        Equalizer obj=new Equalizer();
	}

    public Color convertToColor(String s)
  {
          int hex[];
          String h="0123456789abcdef";
          Color c;
          hex=new int[6];
          if ((s!=null)&&(s.length()==7))
          {
                  for (int i=0;i<6;i++)
                          for (int j=0;j<16;j++)
                                  if (Character.toLowerCase(s.charAt(i+1))==h.charAt(j))
                                          hex[i]=j;
                  c=new Color(hex[0]*16+hex[1],hex[2]*16+hex[3],hex[4]*16+hex[5]);
          }
          else
                  c=Color.lightGray;
          return c;
  }


	public Equalizer() {
		JFrame frame = new JFrame("Equalizer / Spectrum Analyzer");
		// Add a window listner for close button
		frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
        frame.setLayout(null);
        frame.setPreferredSize(new Dimension(width,height));
        frame.getContentPane().setBackground(convertToColor("#1A79CD"));

		// create an instance of KJDigitalSignalProcessingAudioDataConsumer
        synchronizer =  new KJDigitalSignalProcessingAudioDataConsumer(4096, 10);

        // create a spectrum analyzer
        analyzer = new SpectrumAnalyzer(10, 12);
        analyzer.setSize(analyzer_width, analyzer_height);
        analyzer.setLocation(61, 61);
        analyzer.setVisible(true);
        synchronizer.add(analyzer);


		frame.add(analyzer);

		frame.pack();
		frame.setVisible(true);


        startToPlay("C:/Hed - Crazy life.mp3");
	}


  public void setPlayer(Player playerNew) {
    if(player != null) {
      player.removePlayerListener(this);
      player.removePlayerListener(analyzer);
    }
    player = playerNew;
    player.addPlayerListener(this);
    player.addPlayerListener(analyzer);
  }
  public Player getPlayer() {
    return player;
  }


  /**
   * updates the application state according to the current play status, i.e. updating
   * ui elements and internal control values accordingly
   *
   * @param p Player
   * @param fromStatus int
   * @param toStatus int
   */

  public void stateChanged(Player p, int fromStatus, int toStatus) {
    switch(toStatus) {
      case Player.PLAYING:
        synchronizer.start(player.getSourceDataLine());

        if(fromStatus == Player.READY) { // started initially
          /*System.out.println("   bytePerFrame=" + p.getSizeBytes() / p.getFrameCount() +
                             ", bytePerSec=" + p.getFrameRate() * p.getSizeBytes() / p.getFrameCount() +
                             ", sampleSizeInBits=" + p.getSampleSizeInBits() +
                             ", channels=" + p.getChannels() +
                             ",\r\n" +
                             "   frame size=" + p.getFrameSize() +
                             ", sample rate=" + p.getSampleRate() +
                             ", frame rate=" + p.getAudioFrameRate() +
                             ", isbigendian=" + p.isBigEndian());*/

        }
        else if(fromStatus == Player.PAUSED) { // resumed from pause
          //setPlayPauseAction(true);
        }
        break;
    }
  }


  public void decoded(Player p, byte[] buf, int byteCount) {
    p.write(buf, buf.length);
    synchronizer.writeAudioData(buf);
  }

  public void exception(Player p, Exception ex) {
    ex.printStackTrace();
  }

  public void progress(Player p, long progressValue) {
    /*if(!userMovesSlider) {
      songSlider.setValue( (int) (progressValue / 1000l + sliderOffset));
    } */
  }

  public void startToPlay(String filename) {
    File file = new File(filename);

    if(player != null && player.isPaused()) {
      player.resumePlay();
    }
    else {
      player = new Player();
      setPlayer(player);
      player.setVolume((float)100.0, (float)50.0);
      player.startPlay(file);
    }
  }





  /**
     * Given a Class object, attempts to find its .class location [returns null
     * if no such definition can be found]. Use for testing/debugging only.
     *
     * @return URL that points to the class definition [null if not found].
     */
    public static URL getClassLocation (final Class cls)
    {
        if (cls == null) throw new IllegalArgumentException ("null input: cls");

        URL result = null;
        final String clsAsResource = cls.getName ().replace ('.', '/').concat (".class");

        final ProtectionDomain pd = cls.getProtectionDomain ();
        // java.lang.Class contract does not specify if 'pd' can ever be null;
        // it is not the case for Sun's implementations, but guard against null
        // just in case:
        if (pd != null)
        {
            final CodeSource cs = pd.getCodeSource ();
            // 'cs' can be null depending on the classloader behavior:
            if (cs != null) result = cs.getLocation ();

            if (result != null)
            {
                // Convert a code source location into a full class file location
                // for some common cases:
                if ("file".equals (result.getProtocol ()))
                {
                    try
                    {
                        if (result.toExternalForm ().endsWith (".jar") ||
                            result.toExternalForm ().endsWith (".zip"))
                            result = new URL ("jar:".concat (result.toExternalForm ())
                                .concat("!/").concat (clsAsResource));
                        else if (new File (result.getFile ()).isDirectory ())
                            result = new URL (result, clsAsResource);
                    }
                    catch (MalformedURLException ignore) {}
                }
            }
        }

        if (result == null)
        {
            // Try to find 'cls' definition as a resource; this is not
            // documented to be legal, but Sun's implementations seem to allow this:
            final ClassLoader clsLoader = cls.getClassLoader ();

            result = clsLoader != null ?
                clsLoader.getResource (clsAsResource) :
                ClassLoader.getSystemResource (clsAsResource);
        }

        return result;
    }
}
```

Klasse LevelMeter (wurde von mir angepasst - die Höhe des Ausschlags bei größeren Diagrammen verbessert und zusätzlich noch eingeführt, dass der Peak (der höchste Ausschlag eines Balkens) kurzzeitig stehen bleibt):

```
/*
 * Light Development Spectrum Analyzer Component
 * Copyright (C) 2003-2005 Ulrich Hilger
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */


import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.image.BufferedImage;

/**
 * a user interface component to show an amplitude value
 *
 * @author Ulrich Hilger
 * @author Light Development
 * @author [url="http://www.lightdev.com"]http://www.lightdev.com[/url]
 * @author [email="info@lightdev.com"]info@lightdev.com[/email]
 * @author published under the terms and conditions of the
 *      GNU General Public License,
 *      for details see file license.txt in the distribution
 *      package of this software
 *
 * @version 1, January 20, 2005
 */

public class LevelMeter {

  /**
   * constructor
   * @param bi BufferedImage  the offscreen image to use for painting
   * @param index int  index inside a group of level meters
   * @param width int  width of this level meter
   * @param height int  height of this level meter
   * @param min int  minimum value to display by this level meter
   * @param max int  maximum value to display by this level meter
   */
  public LevelMeter(BufferedImage bi, int index, int width, int height, int min,
                    int max) {
    this.bi = bi;
    this.index = index;

    setSize(width, height);

    this.min = min;
    this.max = max;
    sideMargin = barGap / 2;
  }

  /**
   * set the size of this component
   * @param width int  the width
   * @param height int  the height
   */
  public void setSize(int width, int height) {
    if(width > 0 && height > 0) {
      this.outerWidth = width;
      this.meterHeight = height;
      meterWidth = outerWidth - barGap;
    }
  }

  public double getRealValue(double value) {
         value = value * 4;
         return value;
  }

  /**
   * repaint this component
   * @param value double  the decibel value to display
   */
  private void repaintMeter(double value) {
    if(value > min && value < max) {
      value = getRealValue(value);
      double oldValue = meterValue;
      if (oldValue != value) {
        meterValue = value;
        if(bi != null) {
          Graphics2D g2 = bi.createGraphics();
          if (oldValue < value) {
            increaseMeter(g2, value);
          }
          else {
            reduceMeter(g2, value);
          }
          showPeek(g2);
          g2.dispose();
        }
      }
    }
  }

  /**
   * set the decibel value this component should display
   * @param value double  the decibel value to display
   */
  public void setValue(double value) {
      // Neuer Peek?
      if (getRealValue(value) > peek && getRealValue(value) > (meterHeight / 2)) {
         peek = getRealValue(value);
         peek_wait = 0;
         peek_cnt = 0;
      }
    repaintMeter(value);

  }

  /**
   * set the width of this component
   * @param width int  the width
   */
  public void setWidth(int width) {
    this.outerWidth = width;
  }

  /**
   * paint this level meter without showing a value
   */
  public void paintInitially() {
    Graphics2D g2 = bi.createGraphics();

    g2.setColor(convertToColor("#1FA4E9"));
    int x = outerWidth * index;
    int y = meterHeight;
    while (y >= 0) {
      g2.drawLine(x + sideMargin, y, x + meterWidth, y);
      y -= barSegmentStep;
    }
    x += outerWidth;
    meterPosY = meterHeight;
    g2.dispose();
  }


  public void paintAfterPeek(Graphics2D g2) {
    if (peek > 5) {
       g2.setColor(convertToColor("#1FA4E9"));
       int x = outerWidth * index;
       int y = 0;
       if (y % 2 != 0) y -= 1;
       while (y < ((int)(meterHeight - peek))) {
          g2.drawLine(x + sideMargin, y, x + meterWidth, y);
          y += barSegmentStep;
       }
       x += outerWidth;
    }
  }


  /**
   * set the offscreen image this component should draw to
   * @param bi BufferedImage  the offscreen image to draw to
   */
  public void setOffscreenImage(BufferedImage bi) {
    this.bi = bi;
  }

  /**
   * increase the level meter to accommodate a new decibel value
   * @param g2 Graphics2D  the graphics context to paint to
   * @param newValue double  the new (higher) decibel value to display
   */
  private void increaseMeter(Graphics2D g2, double newValue) {
    int x = outerWidth * index;
    int valueY = meterHeight - (int) newValue;
    int y = meterPosY;
    g2.setColor(Color.WHITE);
    while(y > valueY) {
      g2.drawLine(x + sideMargin, y, x + meterWidth, y);
      meterPosY = y;
      y -= barSegmentStep;
    }
  }

  private void showPeek(Graphics2D g2) {
    if (peek > 0) {
       int x = outerWidth * index;
       int valueY = meterHeight - (int) peek;
       if (valueY % 2 != 0)
          valueY += 1;
       g2.setColor(Color.WHITE);
       g2.drawLine(x + sideMargin, valueY, x + meterWidth, valueY);

       //if (peek_cnt % 2 == 0)
          //peek -= barSegmentStep;
       peek_cnt++;
       if (peek_cnt >= 25) {
          peek_wait = 0;
          peek = 0;
       }
       paintAfterPeek(g2);
    }
  }


  /**
   * reduce the level meter to accommodate a new decibel value
   * @param g2 Graphics2D  the graphics context to paint to
   * @param newValue double  the new (lower) decible value to display
   */
  private void reduceMeter(Graphics2D g2, double newValue) {
    int x = outerWidth * index;
    int valueY = meterHeight - (int) newValue;
    int y = meterPosY;

    g2.setColor(convertToColor("#1FA4E9"));
    while(y < valueY) {
      g2.drawLine(x + sideMargin, y, x + meterWidth, y);
      meterPosY = y;
      y += barSegmentStep;
    }
  }

  public Color convertToColor(String s)
  {
          int hex[];
          String h="0123456789abcdef";
          Color c;
          hex=new int[6];
          if ((s!=null)&&(s.length()==7))
          {
                  for (int i=0;i<6;i++)
                          for (int j=0;j<16;j++)
                                  if (Character.toLowerCase(s.charAt(i+1))==h.charAt(j))
                                          hex[i]=j;
                  c=new Color(hex[0]*16+hex[1],hex[2]*16+hex[3],hex[4]*16+hex[5]);
          }
          else
                  c=Color.lightGray;
          return c;
  }

  private BufferedImage bi;

  /** room between level meters in pixels */
  private int barGap = 2;
  /** room between segments of this level meter in pixels */
  private int barSegmentStep = 2;
  /** the decibel value this level meter currently displays */
  private double meterValue;
  /** ***************************************************** */
  private double peek = 0;
  private int peek_wait = 0;
  private int peek_cnt = 0;
  /** the Y position of the current meter value */
  private int meterPosY;
  /** width of a level meter in pixels including the room between two level meters */
  private int outerWidth;
  /** margin width in pixels at each side of a level meter */
  private int sideMargin;
  /**
   * width in pixels of a level meter without the room between two
   * level meters (the width of segments of a level meter)
   */
  private int meterWidth;
  /** height in pixels */
  private int meterHeight;
  /** minimum value */
  private int min;
  /** maximum value */
  private int max;
  /** index of this meter in a range of meters */
  private int index;

  //double paintValue;
}
```

Klasse SpectrumAnalyzer (wurde nur wegen der Hintergrundfarbe angepasst):

```
/*
 * Light Development Spectrum Analyzer Component
 * Copyright (C) 2003-2005 Ulrich Hilger
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */


import java.awt.Graphics;
import com.lightdev.lib.audio.PlayerListener;
import com.lightdev.lib.audio.Player;
import java.awt.Canvas;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.Dimension;
import kj.dsp.KJDigitalSignalProcessor;
import kj.dsp.KJFFT;
import java.awt.Color;

/**
 * A user interface component to display the sound pressure for a range of frequencies
 * over time as produced by an audio data stream.
 *
 * 

This is the second version of the spectrum analyzer component. It has significantly
 * improved performance with the help of the KJ signal processor package by Kris
 * Fudalewski. KJ signal processor synchronizes processed bytes with the audio output.</p>
 *
 * @author Ulrich Hilger
 * @author Light Development
 * @author [url="http://www.lightdev.com"]http://www.lightdev.com[/url]
 * @author [email="info@lightdev.com"]info@lightdev.com[/email]
 * @author KJ signal processor by Kris Fudalewski at [url="http://sirk.sytes.net/"]http://sirk.sytes.net/[/url]
 * @author published under the terms and conditions of the
 *      GNU General Public License,
 *      for details see file license.txt in the distribution
 *      package of this software
 *
 * @version 2, January 20, 2005
 */

public class SpectrumAnalyzer extends Canvas implements PlayerListener, KJDigitalSignalProcessor
{

  /**
   * constructor
   *
   * @param freqCount int  number of level meters to show for one channel (i.e. number of
   * frequencies to measure amplitudes for)
   * @param expFftSize int  the power of two to use to set the size of a fast fourier transform.
   * When expFftSize is 8 for instance the fft will be of size 2^8 = 256,
   * i.e. the fft will transform 256 values of the amplitude/time domain to
   * 128 values of the amplitude/frequency domain.
   */
  public SpectrumAnalyzer(int freqCount, int expFftSize)
  {
    super();
    this.frequencyCount = freqCount;
    initComponent(expFftSize);
  }

  /**
   * initialze some vital values of this component upon creation
   * @param expFftSize int  the size of a fast fourier transform expressed as a power of two
   */
  private void initComponent(int expFftSize) {
    fftSize = 1 << expFftSize;
    fftResultSize = fftSize / 2;
    fBandIx = new int[frequencyCount];
    meters = new LevelMeter[frequencyCount];
    createMeters();
    fft = new KJFFT(fftSize);
    lastY = new float[frequencyCount];
  }

  /* ------------------------ paint part start --------------------------- */

  /**
   * paint this component to the screen
   */
  private void paintScreen()
  {
    initOffscreenImage(getWidth(), getHeight());
    Graphics g = getGraphics();
    if ( (g != null) && (bi != null)) {
      g.drawImage(bi, 0, 0, null);
      g.dispose();
    }
  }


  public Color convertToColor(String s)
  {
          int hex[];
          String h="0123456789abcdef";
          Color c;
          hex=new int[6];
          if ((s!=null)&&(s.length()==7))
          {
                  for (int i=0;i<6;i++)
                          for (int j=0;j<16;j++)
                                  if (Character.toLowerCase(s.charAt(i+1))==h.charAt(j))
                                          hex[i]=j;
                  c=new Color(hex[0]*16+hex[1],hex[2]*16+hex[3],hex[4]*16+hex[5]);
          }
          else
                  c=Color.lightGray;
          return c;
  }


  /**
   * initialize the image that is used by this component for
   * offscreen in-memory painting
   * @param w int  the width of the offscreen image
   * @param h int  the height of the offscreen image
   */
  private void initOffscreenImage(int w, int h) {
    if (firstTime && w > 0 && h > 0) {
      bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
      Graphics2D g2 = bi.createGraphics();
      //g2.setColor(getBackground());
      g2.setColor(convertToColor("#1A79CD"));
      g2.fillRect(0, 0, w, h);
      createMeters();
      paintMetersInitially();
      g2.dispose();
      firstTime = false;
    }
  }

  /**
   * Paints this component.
   *
   * @param g the graphics context to use for painting
   */
  public void paint(Graphics g) {
    paintScreen();
  }

  /**
   * draw level meters as they appear before values are displayed
   */
  private void paintMetersInitially() {
    for(int i = 0; i < frequencyCount; i++) {
      meters[i].paintInitially();
    }
  }

  /**
   * set the size of this component
   * @param d Dimension  the new size
   */
  public void setSize(Dimension d) {
    setSize(d.width, d.height);
  }

  /**
   * set the size of this component
   * @param w int  the width
   * @param h int  the height
   */
  public void setSize(int w, int h) {
    if(w > 0 && h > 0) {
      super.setSize(w, h);
      if (myWidth != w || myHeight != h) {
        //System.out.println("setSize w=" + w + ", h=" + h);
        myWidth = w;
        myHeight = h;
        firstTime = true;
        initOffscreenImage(w, h);
      }
    }
  }

  /**
   * create an array of level meters suitable to display amplitude values
   * of this spectrum analyzer
   */
  private void createMeters() {
    int mWidth = getWidth() / frequencyCount;
    int mHeight = getHeight();
    for(int i = 0; i < frequencyCount; i++) {
      meters[i] = new LevelMeter(bi, i, mWidth, mHeight, minAmp, maxAmp);
    }
  }

  /**
   * find out which frequencies belong to which band (i.e. level meter)
   * based on the hearable audio spectrum and the number of meters
   */
  private void initFrequencyBandIndices() {
    double factor = Math.pow(
      16000 / 20, (double) ((double) 1 / (
        (double) ((double) frequencyCount - (double) 1)))) ;
    int fMin = 0;
    for(int i = 0; i < frequencyCount; i++) {
      int groupMin = (int) (20 * Math.pow(factor, i));
      for(int f = fMin; f < frequencies.length; f++) {
        if(frequencies[f] >= groupMin) {
          fBandIx[i] = f;
          //System.out.println("frequencies[" + f+ "]=" + frequencies[f] +
            //                 ", fBandIx[" + i + "]=" + fBandIx[i]);
          fMin = f;
          break;
        }
      }
    }
  }

  /* ------------------------ paint part end ----------------------------- */

  /* ---------------------- player listener implementation start -------------- */

  /**
   * take stateChanged messages from the audio player as a trigger to
   * start and stop the spectrum analyzer
   *
   * @param p Player the player whose status changed
   * @param fromStatus int the status changed from
   * @param toStatus int the status changed to
   */
  public void stateChanged(Player p, int fromStatus, int toStatus) {
    switch (toStatus) {
      case Player.PLAYING:
        frequencies = new int[fftResultSize];
        for (int i = 0; i < fftResultSize; i++) {
          frequencies[i] = (int) (i * p.getSampleRate() / fftSize);
        }
        initFrequencyBandIndices();
        break;

      case Player.STOPPED_EOM:
        suspend();
        break;
      case Player.STOPPED_PLAY:
        suspend();
        break;
      case Player.PAUSED:
        suspend();
        break;
    }
  }

  /**
   * reset display
   */
  private void suspend() {
    paintMetersInitially();
    paintScreen();
  }

  /**
   * unused here
   * @param p Player the player that fired the event
   * @param progressValue long the microseconds played so far
   */
  public void progress(Player p, long progressValue) {
  }

  /**
   * unused here
   * @param p Player the player that fired the event
   * @param ex Exception the exception that occurred
   */
  public void exception(Player p, Exception ex) {
  }

  /**
   * unused here
   * @param p Player the player that fired the event
   * @param buf byte[] the decoded bytes
   * @param byteCount int the number of bytes in buf
   */
  public void decoded(Player p, byte[] buf, int byteCount) {
  }

  /* ---------------------- player listener implementation end -------------- */

  /* ---------------------- KJDigitalSignalProcessor implementation start ------------- */

  /**
   * process a range of samples received from the KJ signal processor, i.e. repaint
   * level meters
   * @param samples float[]  the samples to process
   */
  public void process( float[] samples ) {
    float resultValues[] = fft.calculate(samples);
    int k = frequencyCount;
    int amplitudeIndex = 0;
    int meterIndex = 0;
    while(meterIndex < frequencyCount) {
      float y = 0f;
      while(amplitudeIndex < fBandIx[meterIndex]) {
        y += resultValues[amplitudeIndex++];
      }
      y = y * 32f * (float) Math.log(k);
      if(y > 48f) {
        y = 48f;
      }
      if(y > lastY[meterIndex]) {
        lastY[meterIndex] = y;
      }
      else {
        lastY[meterIndex] -= 2f;
        if(lastY[meterIndex] < 0f) {
          lastY[meterIndex] = 0f;
        }
        y = lastY[meterIndex];
      }
      meters[meterIndex++].setValue(y);
      --k;
    }
    paintScreen();
  }

  /* ---------------------- KJDigitalSignalProcessor implementation end --------------- */

  /* ---------------------- class fields start -------------- */

  /** the value painted last */
  private float[] lastY;
  /** the BufferedImage of this SpectrumAnalyzer */
  private BufferedImage bi;
  /** indicates whether or not a paint process runs for the first time */
  private boolean firstTime = true;
  /** the level meters of this SpectrumAnalyzer */
  private LevelMeter[] meters;
  /** the frequencies (Hz) of the results of one fast fourier transform in the current fft size */
  private int[] frequencies;
  /** indices of result per frequency band */
  private int[] fBandIx;
  /**
   * number of level meters to show for one channel (i.e. number of
   * frequencies to measure amplitudes for)
   */
  private int frequencyCount;
  /** the minimum amplitude (db) to show in level meters */
  private int minAmp = 0;
  /** the maximum amplitude (db) to show in level meters */
  private int maxAmp = 150;
  /** the number of values to transform in a fast fourier transform (fft) */
  private int fftSize;
  /** the number of results produced by a fast fourer transform (fft) */
  private int fftResultSize;
  /** the object to use to do fast fourier transforms */
  private KJFFT fft;
  /** this component's width */
  private int myWidth = 0;
  /** this component's height */
  private int myHeight = 0;

  /* ---------------------- class fields end -------------- */

}
```


Aussehen sollte das Ganze dann in etwa so:






[/img]


----------

