📄 samplinggraph.java
字号:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import javax.sound.sampled.*;
import java.awt.geom.Line2D;
import java.util.Vector;
class SamplingGraph extends JPanel implements ComponentListener,Runnable
{
private Thread thread;
private String path=(System.getProperty("user.dir"));
private AudioInputStream wavStream;
private AudioFormat wavFormat;
private Vector lines=new Vector();
private double duration, seconds;
private byte[] audioBytes;
private int frames_per_pixel;
private int[] audioData;
public SamplingGraph()
{
setBackground(Color.black);
//这个监听用来实现当该Panel大小改变时,重绘波形的功能
addComponentListener(this);
}
public void componentResized(ComponentEvent e)
{
createWaveForm(audioBytes);
}
public void componentMoved(ComponentEvent e){}
public void componentShown(ComponentEvent e){}
public void componentHidden(ComponentEvent e){}
public void getAudioInputStream(AudioInputStream wavStream)
{
if(wavStream==null)
{
this.wavStream=null;
wavFormat=null;
return;
}
this.wavStream=wavStream;
wavFormat=wavStream.getFormat();
}
public int[] getAudioData()
{
return audioData;
}
public void incSize()
{
Dimension d=getSize();
int w=d.width;
int h=d.height;
int newW=w*2;
d=new Dimension(newW,h);
setPreferredSize(d);
setSize(d);
repaint();
}
public void decSize()
{
Dimension d=getSize();
int w=d.width;
int h=d.height;
int newW=(int)w/2;
int newH=(int)h/2;
d=new Dimension(newW,newH);
setPreferredSize(d);
setSize(d);
repaint();
}
public void createWaveForm(byte[] audioBytes)
{
if(wavStream==null)
{
repaint();
return;
}
wavFormat = wavStream.getFormat();
//lines里保存着每次根据采样点值画的连续曲线
//所以要先清空,以便以后载入新的连续曲线
lines.removeAllElements();
//将波形文件中的每个采样点的值导入audioBytes里
if (audioBytes == null)
{
try
{
audioBytes = new byte[
(int) (wavStream.getFrameLength()
* wavFormat.getFrameSize())];
wavStream.read(audioBytes);
}
catch (Exception ex)
{
return;
}
}
this.audioBytes=audioBytes;
Dimension d = getSize();
int w = d.width; //panel的宽
int h = d.height; //panel的高
int[] audioData = null;
//如果采样点是16Bit的
if (wavFormat.getSampleSizeInBits() == 16)
{
int nlengthInSamples = audioBytes.length / 2;
audioData = new int[nlengthInSamples];
//bigEndian:
//Indicates whether the audio data is stored in big-endian
//or little-endian order.
//似乎是用来判断wav是从MSB开始记录还是从LSB开始记录
if (wavFormat.isBigEndian())
{
for (int i = 0; i < nlengthInSamples; i++)
{
/* First byte is MSB (high order) */
int MSB = (int) audioBytes[2*i];
/* Second byte is LSB (low order) */
int LSB = (int) audioBytes[2*i+1];
audioData[i] = MSB << 8 | (255 & LSB);
}
}
else
{
for (int i = 0; i < nlengthInSamples; i++)
{
/* First byte is LSB (low order) */
int LSB = (int) audioBytes[2*i];
/* Second byte is MSB (high order) */
int MSB = (int) audioBytes[2*i+1];
audioData[i] = MSB << 8 | (255 & LSB);
}
}
}
//如果采样点是8Bit的
else if (wavFormat.getSampleSizeInBits() == 8)
{
int nlengthInSamples = audioBytes.length;
audioData = new int[nlengthInSamples];
if (wavFormat.getEncoding().toString().startsWith("PCM_SIGN"))
{
for (int i = 0; i < audioBytes.length; i++)
{
audioData[i] = audioBytes[i];
}
}
else
{
for (int i = 0; i < audioBytes.length; i++)
{
audioData[i] = audioBytes[i] - 128;
}
}
}
this.audioData=audioData;
//设置帧/每象素值,默认情况下使所有的帧恰好满窗口显示
frames_per_pixel = (audioBytes.length / wavFormat.getFrameSize())/w;
byte my_byte = 0;
double y_last = 0,x_last=0;
//声道
int numChannels = wavFormat.getChannels();
//以下为将采样点画出曲线的核心算法
for (double x = 0; x < w && audioData != null; x++)
{
int idx=frames_per_pixel*numChannels*(int)x;
int temp=audioData[idx];
//奇数次循环取最大值,偶数次循环取最小值
for(int i=idx;i<idx+frames_per_pixel*numChannels;i++)
{
if((int)x%2==0)
{
if(temp>audioData[i])
{
temp=audioData[i];
}
}
else
{
if(temp<audioData[i])
{
temp=audioData[i];
}
}
}
if (wavFormat.getSampleSizeInBits() == 8)
{
my_byte=(byte)temp;
//my_byte = (byte) audioData[idx];
}
else
{
my_byte=(byte)(128*temp/32768);
//my_byte = (byte) (128 * audioData[idx] / 32768 );
}
//以抽样值确定所画线中Y点坐标值。
double y_new = (double) (h * (128 - my_byte) / 256);
//将画好的一段段线加入到lines这个容器里
lines.add(new Line2D.Double(x_last, y_last, x, y_new));
y_last = y_new;
x_last = x;
}
repaint();
}
public void paint(Graphics g)
{
Dimension d = getSize();
int w = d.width;
int h = d.height;
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(getBackground());
g2.clearRect(0, 0, w, h);
for(int i=0;i<10;i++)
{
Shape l=new Line2D.Float(w/10*i,0,w/10*i,h);
g2.setColor(Color.red);
g2.draw(l);
}
//画十字格
for(int i=0;i<10;i++)
{
Shape l=new Line2D.Float(w/10*i,0,w/10*i,h);
g2.setColor(Color.GRAY);
g2.draw(l);
l=new Line2D.Float(0,h/10*i,w,h/10*i);
g2.draw(l);
}
Shape l=new Line2D.Float(0,h/2,w,h/2);
if(wavStream == null)
{
g2.setColor(Color.red);
g2.draw(l);
}
if (wavStream != null)
{
// .. render sampling graph ..
g2.setColor(Color.red);
g2.draw(l);
g2.setColor(Color.CYAN);
for (int i = 1; i < lines.size(); i++)
{
g2.draw((Line2D) lines.get(i));
}
}
}
public void start()
{
thread = new Thread(this);
thread.setName("SamplingGraph");
thread.start();
}
public void stop()
{
if (thread != null)
{
thread.interrupt();
}
thread = null;
}
public void run()
{
while (thread != null)
{
try { thread.sleep(100); } catch (Exception e) { break; }
repaint();
}
}
//用来进行测试的语句
public static void main(String agrs[])
{
JFrame frm=new JFrame();
JButton testBtn=new JButton("test");
SamplingGraph test=new SamplingGraph();
frm.getContentPane().add(test,BorderLayout.CENTER);
// new JScrollPane(test,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS),
// BorderLayout.CENTER);
frm.getContentPane().add(testBtn,BorderLayout.SOUTH);
frm.setSize(400,400);
frm.setVisible(true);
//窗口打开后在屏幕中央显示
int ScreenWidth=frm.getToolkit().getScreenSize().width;
int ScreenHeight=frm.getToolkit().getScreenSize().height;
frm.setLocation((ScreenWidth-frm.getWidth())/2,(ScreenHeight-frm.getHeight())/2);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.load();
test.createWaveForm(null);
//test.decSize();
}
public void load()
{
//载入wave文件
//======读取.wav文件=======
JFileChooser chooser = new JFileChooser(path);
chooser.setDialogTitle("载入wav文件");
//设定打开文件类型为*.wav
ExampleFileFilter filter = new ExampleFileFilter();
filter.addExtension("wav");
filter.setDescription("wave波形文件");
chooser.setFileFilter(filter);
int result=chooser.showOpenDialog(null);
if(result==JFileChooser.CANCEL_OPTION) return;
File wavFile=chooser.getSelectedFile();
try
{
wavStream=AudioSystem.getAudioInputStream(wavFile);
AudioFormat wavFormat=wavStream.getFormat();
/**
* we can't yet open the device for ALAW/ULAW playback,
* convert ALAW/ULAW to PCM
*/
if ((wavFormat.getEncoding() == AudioFormat.Encoding.ULAW) ||
(wavFormat.getEncoding() == AudioFormat.Encoding.ALAW))
{
AudioFormat tmp = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
wavFormat.getSampleRate(),
wavFormat.getSampleSizeInBits() * 2,
wavFormat.getChannels(),
wavFormat.getFrameSize() * 2,
wavFormat.getFrameRate(),
true);
wavStream = AudioSystem.getAudioInputStream(tmp, wavStream);
wavFormat = tmp;
}
}catch(Exception e){}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -