第二步:編輯文件首先在src下創建一個test包并在test包下新建一個類MyRecord具體步驟代碼如下所示:
package test;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import javax.sound.sampled.*;
public class MyRecord extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
// 定義錄音格式
AudioFormat af = null;
// 定義目標數據行,可以從中讀取音頻數據,該 TargetDataLine 接口提供從目標數據行的緩沖區讀取所捕獲數據的方法。
TargetDataLine td = null;
// 定義源數據行,源數據行是可以寫入數據的數據行。它充當其混頻器的源。應用程序將音頻字節寫入源數據行,這樣可處理字節緩沖并將它們傳遞給混頻器。
SourceDataLine sd = null;
// 定義字節數組輸入輸出流
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
// 定義音頻輸入流
AudioInputStream ais = null;
// 定義停止錄音的標志,來控制錄音線程的運行
Boolean stopflag = false;
// 定義所需要的組件
JPanel jp1, jp2, jp3;
JLabel jl1 = null;
JButton captureBtn, stopBtn, playBtn, saveBtn;
public static void main(String[] args) {
// 創造一個實例
MyRecord mr = new MyRecord();
}
// 構造函數
public MyRecord() {
// 組件初始化
jp1 = new JPanel();
jp2 = new JPanel();
jp3 = new JPanel();
// 定義字體
Font myFont = new Font("華文新魏", Font.BOLD, 30);
jl1 = new JLabel("錄音機功能的實現");
jl1.setFont(myFont);
jp1.add(jl1);
captureBtn = new JButton("開始錄音");
// 對開始錄音按鈕進行注冊監聽
captureBtn.addActionListener(this);
captureBtn.setActionCommand("captureBtn");
// 對停止錄音進行注冊監聽
stopBtn = new JButton("停止錄音");
stopBtn.addActionListener(this);
stopBtn.setActionCommand("stopBtn");
// 對播放錄音進行注冊監聽
playBtn = new JButton("播放錄音");
playBtn.addActionListener(this);
playBtn.setActionCommand("playBtn");
// 對保存錄音進行注冊監聽
saveBtn = new JButton("保存錄音");
saveBtn.addActionListener(this);
saveBtn.setActionCommand("saveBtn");
this.add(jp1, BorderLayout.NORTH);
this.add(jp2, BorderLayout.CENTER);
this.add(jp3, BorderLayout.SOUTH);
jp3.setLayout(null);
jp3.setLayout(new GridLayout(1, 4, 10, 10));
jp3.add(captureBtn);
jp3.add(stopBtn);
jp3.add(playBtn);
jp3.add(saveBtn);
// 設置按鈕的屬性
captureBtn.setEnabled(true);
stopBtn.setEnabled(false);
playBtn.setEnabled(false);
saveBtn.setEnabled(false);
// 設置窗口的屬性
this.setSize(400, 300);
this.setTitle("錄音機");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("captureBtn")) {
// 點擊開始錄音按鈕后的動作
// 停止按鈕可以啟動
captureBtn.setEnabled(false);
stopBtn.setEnabled(true);
playBtn.setEnabled(false);
saveBtn.setEnabled(false);
// 調用錄音的方法
capture();
} else if (e.getActionCommand().equals("stopBtn")) {
// 點擊停止錄音按鈕的動作
captureBtn.setEnabled(true);
stopBtn.setEnabled(false);
playBtn.setEnabled(true);
saveBtn.setEnabled(true);
// 調用停止錄音的方法
stop();
} else if (e.getActionCommand().equals("playBtn")) {
// 調用播放錄音的方法
play();
} else if (e.getActionCommand().equals("saveBtn")) {
// 調用保存錄音的方法
save();
}
}
// 開始錄音
public void capture() {
try {
// af為AudioFormat也就是音頻格式
af = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, af);
td = (TargetDataLine) (AudioSystem.getLine(info));
// 打開具有指定格式的行,這樣可使行獲得所有所需的系統資源并變得可操作。
td.open(af);
// 允許某一數據行執行數據 I/O
td.start();
// 創建播放錄音的線程
Record record = new Record();
Thread t1 = new Thread(record);
t1.start();
} catch (LineUnavailableException ex) {
ex.printStackTrace();
return;
}
}
// 停止錄音
public void stop() {
stopflag = true;
}
// 播放錄音
public void play() {
// 將baos中的數據轉換為字節數據
byte audioData[] = baos.toByteArray();
// 轉換為輸入流
bais = new ByteArrayInputStream(audioData);
af = getAudioFormat();
ais = new AudioInputStream(bais, af, audioData.length
/ af.getFrameSize());
try {
DataLine.Info dataLineInfo = new DataLine.Info(
SourceDataLine.class, af);
sd = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
sd.open(af);
sd.start();
// 創建播放進程
Play py = new Play();
Thread t2 = new Thread(py);
t2.start();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 關閉流
if (ais != null) {
ais.close();
}
if (bais != null) {
bais.close();
}
if (baos != null) {
baos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 保存錄音
public void save() {
// 取得錄音輸入流
af = getAudioFormat();
byte audioData[] = baos.toByteArray();
bais = new ByteArrayInputStream(audioData);
ais = new AudioInputStream(bais, af, audioData.length
/ af.getFrameSize());
// 定義最終保存的文件名
File file = null;
// 寫入文件
try {
// 以當前的時間命名錄音的名字
// 將錄音的文件存放到F盤下語音文件夾下
File filePath = new File("F:/語音文件");
if (!filePath.exists()) {// 如果文件不存在,則創建該目錄
filePath.mkdir();
}
file = new File(filePath.getPath() + "/"
+ System.currentTimeMillis() + ".mp3");
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關閉流
try {
if (bais != null) {
bais.close();
}
if (ais != null) {
ais.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 設置AudioFormat的參數
public AudioFormat getAudioFormat() {
// 下面注釋部分是另外一種音頻格式,兩者都可以
AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
float rate = 8000f;
int sampleSize = 16;
String signedString = "signed";
boolean bigEndian = true;
int channels = 1;
return new AudioFormat(encoding, rate, sampleSize, channels,
(sampleSize / 8) * channels, rate, bigEndian);
}
// 錄音類,因為要用到MyRecord類中的變量,所以將其做成內部類
class Record implements Runnable {
// 定義存放錄音的字節數組,作為緩沖區
byte bts[] = new byte[10000];
// 將字節數組包裝到流里,最終存入到baos中
// 重寫run函數
public void run() {
baos = new ByteArrayOutputStream();
try {
System.out.println("ok3");
stopflag = false;
while (stopflag != true) {
// 當停止錄音沒按下時,該線程一直執行
// 從數據行的輸入緩沖區讀取音頻數據。
// 要讀取bts.length長度的字節,cnt 是實際讀取的字節數
int cnt = td.read(bts, 0, bts.length);
if (cnt > 0) {
baos.write(bts, 0, cnt);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 關閉打開的字節數組流
if (baos != null) {
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
td.drain();
td.close();
}
}
}
}
// 播放類,同樣也做成內部類
class Play implements Runnable {
// 播放baos中的數據即可
public void run() {
byte bts[] = new byte[10000];
try {
int cnt;
// 讀取數據到緩存數據
while ((cnt = ais.read(bts, 0, bts.length)) != -1) {
if (cnt > 0) {
// 寫入緩存數據
// 將音頻數據寫入到混頻器
sd.write(bts, 0, cnt);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sd.drain();
sd.close();
}
}
}
}