📄 spectrumtimeanalyzer.java
字号:
package MP3;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JPanel;
import kj.dsp.KJDigitalSignalProcessingAudioDataConsumer;
import kj.dsp.KJDigitalSignalProcessor;
import kj.dsp.KJFFT;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This class implements interface KJDigitalSignalProcessor in order to be registered with the
* KJDigitalSignalProcessingAudioDataConsumer class .The class is designed to draw peaks
* when the player is playing a song.The code is made reference to other mp3 player.
*
*
*/
public class SpectrumTimeAnalyzer extends JPanel implements KJDigitalSignalProcessor
{
private static Log log = LogFactory.getLog(SpectrumTimeAnalyzer.class);
public static final int DISPLAY_MODE_SCOPE = 0;
public static final int DISPLAY_MODE_SPECTRUM_ANALYSER = 1;
public static final int DISPLAY_MODE_OFF = 2;
public static final int DEFAULT_WIDTH = 256;
public static final int DEFAULT_HEIGHT = 128;
public static final int DEFAULT_FPS = 50;
public static final int DEFAULT_SPECTRUM_ANALYSER_FFT_SAMPLE_SIZE = 512;
public static final int DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT = 19;
public static final float DEFAULT_SPECTRUM_ANALYSER_DECAY = 0.05f;
public static final int DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY = 20;
public static final float DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO = 0.4f;
public static final float DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE = 0.1f;
public static final float MIN_SPECTRUM_ANALYSER_DECAY = 0.02f;
public static final float MAX_SPECTRUM_ANALYSER_DECAY = 0.08f;
public static final Color DEFAULT_SCOPE_COLOR = new Color(255, 128, 192);
public static final float DEFAULT_VU_METER_DECAY = 0.02f;
private Image bi;
private int displayMode = DISPLAY_MODE_SPECTRUM_ANALYSER;
private Color scopeColor = DEFAULT_SCOPE_COLOR;
private Color[] spectrumAnalyserColors = getDefaultSpectrumAnalyserColors();
private KJDigitalSignalProcessingAudioDataConsumer dsp = null;
private boolean dspStarted = false;
private Color peakColor = null;
private int[] peaks = new int[DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT];
private int[] peaksDelay = new int[DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT];
private int peakDelay = DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY;
private boolean peaksEnabled = true;
private int barOffset = 1;
private int width;
private int height;
private int height_2;
// -- Spectrum analyser variables.
private KJFFT fft;
private float[] old_FFT;
private int saFFTSampleSize;
private int saBands;
private float saColorScale;
private float saMultiplier;
private float saDecay = DEFAULT_SPECTRUM_ANALYSER_DECAY;
private SourceDataLine m_line = null;
// -- VU Meter
private float oldLeft;
private float oldRight;
private float vuDecay = DEFAULT_VU_METER_DECAY;
private float vuColorScale;
// -- FPS calulations.
private long lfu = 0;
private int fc = 0;
private int fps = DEFAULT_FPS;
private boolean showFPS = false;
// private Runnable PAINT_SYNCHRONIZER = new AWTPaintSynchronizer();
public SpectrumTimeAnalyzer()
{
setOpaque(false);
initialize();
}
/**
* Method to see if the peaks can be displayed.
*
* @return Returns whether the peaks is enabled or not.
*/
public boolean isPeaksEnabled()
{
return peaksEnabled;
}
/**
* Method to set peaks' state.
*
* @param peaksEnabled
* the state of peaks
*/
public void setPeaksEnabled(boolean peaksEnabled)
{
this.peaksEnabled = peaksEnabled;
}
/**
* Method to get the value of FPS.
*
* @return Returns the FPS
*/
public int getFps()
{
return fps;
}
/**
* Method to set the value of FPS
*
* @param fps
*/
public void setFps(int fps) //设置每秒的帧数
{
this.fps = fps;
}
/**
* Method to start DSP when a song is playing.
* @param line
*/
public void startDSP(SourceDataLine line)
{
if (displayMode == DISPLAY_MODE_OFF) return;
if (line != null) m_line = line;
if (dsp == null)
{
dsp = new KJDigitalSignalProcessingAudioDataConsumer(2048, fps);
dsp.add(this);
}
if ((dsp != null) && (m_line != null))
{
if (dspStarted == true)
{
stopDSP();
}
dsp.start(m_line);
dspStarted = true;
log.debug("DSP started");
}
}
/**
* Method to stop DSP when no song is playing.
*/
public void stopDSP()
{
if (dsp != null)
{
dsp.stop();
dspStarted = false;
log.debug("DSP stopped");
}
}
/**
* Method to close DSP when there is no need to use it.
*/
public void closeDSP()
{
if (dsp != null)
{
stopDSP();
dsp = null;
log.debug("DSP closed");
}
}
/**
* Menthod to setup DSP.
* @param line
*/
public void setupDSP(SourceDataLine line)
{
if (dsp != null)
{
int channels = line.getFormat().getChannels();
if (channels == 1) dsp.setChannelMode(KJDigitalSignalProcessingAudioDataConsumer.CHANNEL_MODE_MONO);
else dsp.setChannelMode(KJDigitalSignalProcessingAudioDataConsumer.CHANNEL_MODE_STEREO);
int bits = line.getFormat().getSampleSizeInBits();
if (bits == 8) dsp.setSampleType(KJDigitalSignalProcessingAudioDataConsumer.SAMPLE_TYPE_EIGHT_BIT);
else dsp.setSampleType(KJDigitalSignalProcessingAudioDataConsumer.SAMPLE_TYPE_SIXTEEN_BIT);
}
}
/**
* Method to write PCM data to DSP.
* @param pcmdata
*/
public void writeDSP(byte[] pcmdata)
{
if ((dsp != null) && (dspStarted == true)) dsp.writeAudioData(pcmdata);
}
/**
* Method to return DSP.
* @return Returns DSP
*/
public KJDigitalSignalProcessingAudioDataConsumer getDSP()
{
return dsp;
}
/**
* Set visual colors from skin.
* @param viscolor
*/
public void setVisColor(String viscolor)
{
ArrayList visColors = new ArrayList();
viscolor = viscolor.toLowerCase();
ByteArrayInputStream in = new ByteArrayInputStream(viscolor.getBytes());
BufferedReader bin = new BufferedReader(new InputStreamReader(in));
try
{
String line = null;
while ((line = bin.readLine()) != null)
{
visColors.add(getColor(line));
}
Color[] colors = new Color[visColors.size()];
visColors.toArray(colors);
Color[] specColors = new Color[15];
System.arraycopy(colors, 2, specColors, 0, 15);
List specList = Arrays.asList(specColors);
Collections.reverse(specList);
specColors = (Color[]) specList.toArray(specColors);
setSpectrumAnalyserColors(specColors);
setBackground((Color) visColors.get(0));
if (visColors.size()>23) setPeakColor((Color) visColors.get(23));
if (visColors.size()>18) setScopeColor((Color) visColors.get(18));
}
catch (IOException ex)
{
log.warn("Cannot parse viscolors", ex);
}
finally
{
try
{
if (bin != null) bin.close();
}
catch (IOException e)
{
}
}
}
/**
* Set visual peak color.
* @param c
*/
public void setPeakColor(Color c)
{
peakColor = c;
}
/**
* Set peak falloff delay.
* @param framestowait
*/
public void setPeakDelay(int framestowait)
{
int min = (int) Math.round((DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO - DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE) * fps);
int max = (int) Math.round((DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO + DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO_RANGE) * fps);
if ((framestowait >= min) && (framestowait <= max))
{
peakDelay = framestowait;
}
else
{
peakDelay = (int) Math.round(DEFAULT_SPECTRUM_ANALYSER_PEAK_DELAY_FPS_RATIO * fps);
}
}
/**
* Return peak falloff delay
* @return int framestowait
*/
public int getPeakDelay()
{
return peakDelay;
}
/**
* Convert string to color.
* @param linecolor
* @return Returns the Color converted from string
*/
public Color getColor(String linecolor)
{
Color color = Color.BLACK;
StringTokenizer st = new StringTokenizer(linecolor, ",");
int red = 0, green = 0, blue = 0;
try
{
if (st.hasMoreTokens()) red = Integer.parseInt(st.nextToken().trim());
if (st.hasMoreTokens()) green = Integer.parseInt(st.nextToken().trim());
if (st.hasMoreTokens())
{
String blueStr = st.nextToken().trim();
if (blueStr.length() > 3) blueStr = (blueStr.substring(0, 3)).trim();
blue = Integer.parseInt(blueStr);
}
color = new Color(red, green, blue);
}
catch (NumberFormatException e)
{
log.debug("Cannot parse viscolor : "+e.getMessage());
}
return color;
}
/**
* Set the mathematical formula to calculate the Spectrum analyser Color Scale
* and the VU Meter Color Scale.
*
*/
private void computeColorScale()
{
saColorScale = ((float) spectrumAnalyserColors.length / height) * barOffset * 1.0f;
vuColorScale = ((float) spectrumAnalyserColors.length / (width - 32)) * 2.0f;
}
/**
* Set the mathematical formula to calculate the Spectrum analyser Multiplier.
*
*/
private void computeSAMultiplier()
{
saMultiplier = (saFFTSampleSize / 2) / saBands;
}
/**
* Method to draw the Scope.
*
* @param pGrp
* @param pSample
*/
private void drawScope(Graphics pGrp, float[] pSample)
{
pGrp.setColor(scopeColor);
int wLas = (int) (pSample[0] * (float) height_2) + height_2;
int wSt = 2;
for (int a = wSt, c = 0; c < width; a += wSt, c++)
{
int wAs = (int) (pSample[a] * (float) height_2) + height_2;
pGrp.drawLine(c, wLas, c + 1, wAs);
wLas = wAs;
}
}
/**
* Method to draw the SpectrumAnalyzer.
*
* @param pGrp
* @param pSample
* @param pFrrh
*/
private void drawSpectrumAnalyser(Graphics pGrp, float[] pSample, float pFrrh)
{
float c = 0;
float[] wFFT = fft.calculate(pSample);
float wSadfrr = (saDecay * pFrrh);
float wBw = ((float) width / (float) saBands);
for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++)
{
float wFs = 0;
// -- Average out nearest bands.
for (int b = 0; b < saMultiplier; b++)
{
wFs += wFFT[a + b];
}
// -- Log filter.
wFs = (wFs * (float) Math.log(bd + 2));
if (wFs > 1.0f)
{
wFs = 1.0f;
}
// -- Compute SA decay...
if (wFs >= (old_FFT[a] - wSadfrr))
{
old_FFT[a] = wFs;
}
else
{
old_FFT[a] -= wSadfrr;
if (old_FFT[a] < 0)
{
old_FFT[a] = 0;
}
wFs = old_FFT[a];
}
drawSpectrumAnalyserBar(pGrp, (int) c, height, (int) wBw - 1, (int) (wFs * height), bd);
c += wBw;
}
}
/**
* Method to draw VU Meter
*
* @param pGrp
* @param pLeft
* @param pRight
* @param pFrrh
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -