java实现 mp3格式转换wav

Python015

java实现 mp3格式转换wav,第1张

/*

* 实现录音机的功能

*/

package com.liuyun.MyRecord1

import java.awt.*

import javax.swing.*

import java.awt.event.*

import java.io.*

import javax.sound.sampled.*

import java.lang.*

public class MyRecord extends JFrame implements ActionListener{

//定义录音格式

AudioFormat af = null

//定义目标数据行,可以从中读取音频数据,该 TargetDataLine 接口提供从目标数据行的缓冲区读取所捕获数据的方法。

TargetDataLine td = null

//定义源数据行,源数据行是可以写入数据的数据行。它充当其混频器的源。应用程序将音频字节写入源数据行,这样可处理字节缓冲并将它们传递给混频器。

SourceDataLine sd = null

//定义字节数组输入输出流

ByteArrayInputStream bais = null

ByteArrayOutputStream baos = null

//定义音频输入流

AudioInputStream ais = null

//定义停止录音的标志,来控制录音线程的运行

Boolean stopflag = false

//记录开始录音的时间

long startPlay

//定义所需要的组件

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()

//记录开始录音的时间

startPlay = System.currentTimeMillis()

}else if (e.getActionCommand().equals("stopBtn")) {

//点击停止录音按钮的动作

captureBtn.setEnabled(true)

stopBtn.setEnabled(false)

playBtn.setEnabled(true)

saveBtn.setEnabled(true)

//调用停止录音的方法

stop()

//记录停止录音的时间

long stopPlay = System.currentTimeMillis()

//输出录音的时间

System.out.println("Play continues " + (stopPlay-startPlay))

}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()

}

long time = System.currentTimeMillis()

file = new File(filePath+"/"+time+".wav")

AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file)

//将录音产生的wav文件转换为容量较小的mp3格式

//定义产生后文件名

String tarFileName = time+".mp3"

Runtime run = null

try {

run = Runtime.getRuntime()

long start=System.currentTimeMillis()

//调用解码器来将wav文件转换为mp3文件

<strong><span style="color:#ff0000">Process p=run.exec(filePath+"/"+"lame -b 16 "+filePath+"/"+file.getName()+" "+filePath+"/"+tarFileName) //16为码率,可自行修改

</span></strong>//释放进程

p.getOutputStream().close()

p.getInputStream().close()

p.getErrorStream().close()

p.waitFor()

long end=System.currentTimeMillis()

System.out.println("convert need costs:"+(end-start)+"ms")

//删除无用的wav文件

if(file.exists())

{

file.delete()

}

} catch (Exception e) {

e.printStackTrace()

}finally{

//最后都要执行的语句

//run调用lame解码器最后释放内存

run.freeMemory()

}

} 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)

//      //采样率是每秒播放和录制的样本数

//      float sampleRate = 16000.0F

//      // 采样率8000,11025,16000,22050,44100

//      //sampleSizeInBits表示每个具有此格式的声音样本中的位数

//      int sampleSizeInBits = 16

//      // 8,16

//      int channels = 1

//      // 单声道为1,立体声为2

//      boolean signed = true

//      // true,false

//      boolean bigEndian = true

//      // true,false

//      return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,bigEndian)

}

//录音类,因为要用到MyRecord类中的变量,所以将其做成内部类

class Record implements Runnable

{

//定义存放录音的字节数组,作为缓冲区

byte bts[] = new byte[10000]

//将字节数组包装到流里,最终存入到baos中

//重写run函数

public void run() {

baos = new ByteArrayOutputStream()

try {

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()

}

}

}

}

首先下载播放mp3的包,比如mp3spi1.9.4.jar。在工程中添加这个包。

播放器演示代码如下

package com.test.audio

import java.io.File

import java.awt.BorderLayout

import java.awt.FileDialog

import java.awt.Frame

import java.awt.GridLayout

import java.awt.Label

import java.awt.List

import java.awt.Menu

import java.awt.MenuBar

import java.awt.MenuItem

import java.awt.MenuShortcut

import java.awt.Panel

import java.awt.event.ActionEvent

import java.awt.event.ActionListener

import java.awt.event.KeyEvent

import java.awt.event.MouseAdapter

import java.awt.event.MouseEvent

import java.awt.event.WindowAdapter

import java.awt.event.WindowEvent

import javax.sound.sampled.AudioFormat

import javax.sound.sampled.AudioInputStream

import javax.sound.sampled.AudioSystem

import javax.sound.sampled.DataLine

import javax.sound.sampled.SourceDataLine

public class MusicPlayer extends Frame {

    /**

 * 

 */

private static final long serialVersionUID = -2605658046194599045L

boolean isStop = true// 控制播放线程

    boolean hasStop = true// 播放线程状态

 

    String filepath// 播放文件目录

    String filename// 播放文件名称

    AudioInputStream audioInputStream// 文件流

    AudioFormat audioFormat// 文件格式

    SourceDataLine sourceDataLine// 输出设备

 

    List list// 文件列表

    Label labelfilepath//播放目录显示标签

    Label labelfilename//播放文件显示标签

 

    public MusicPlayer() {

        // 设置窗体属性

        setLayout(new BorderLayout())

        setTitle("MP3 Music Player")

        setSize(350, 370)

 

        // 建立菜单栏

        MenuBar menubar = new MenuBar()

        Menu menufile = new Menu("File")

        MenuItem menuopen = new MenuItem("Open", new MenuShortcut(KeyEvent.VK_O))

        menufile.add(menuopen)

        menufile.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {

                open()

            }

        })

        menubar.add(menufile)

        setMenuBar(menubar)

 

        // 文件列表

        list = new List(10)

        list.addMouseListener(new MouseAdapter() {

            public void mouseClicked(MouseEvent e) {

                // 双击时处理

                if (e.getClickCount() == 2) {

                    // 播放选中的文件

                    filename = list.getSelectedItem()

                    play()

                }

            }

        })

        add(list, "Center")

 

        // 信息显示

        Panel panel = new Panel(new GridLayout(2, 1))

        labelfilepath = new Label("Dir:")

        labelfilename = new Label("File:")

        panel.add(labelfilepath)

        panel.add(labelfilename)

        add(panel, "North")

 

        // 注册窗体关闭事件

        addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {

                System.exit(0)

            }

        })

        setVisible(true)

    }

 

    // 打开

    private void open() {

        FileDialog dialog = new FileDialog(this, "Open", 0)

        dialog.setVisible(true)

        filepath = dialog.getDirectory()

        if (filepath != null) {

            labelfilepath.setText("Dir:" + filepath)

 

            // 显示文件列表

            list.removeAll()

            File filedir = new File(filepath)

            File[] filelist = filedir.listFiles()

            for (File file : filelist) {

                String filename = file.getName().toLowerCase()

                if (filename.endsWith(".mp3") || filename.endsWith(".wav")) {

                    list.add(filename)

                }

            }

        }

    }

 

    // 播放

    private void play() {

        try {

            isStop = true// 停止播放线程

            // 等待播放线程停止

            System.out.print("Start:" + filename)

            while (!hasStop) {

                System.out.print(".")

                try {

                    Thread.sleep(10)

                } catch (Exception e) {

                }

            }

            System.out.println("")

            File file = new File(filepath + filename)

            labelfilename.setText("Playing:" + filename)

 

            // 取得文件输入流

            audioInputStream = AudioSystem.getAudioInputStream(file)

            audioFormat = audioInputStream.getFormat()

            // 转换mp3文件编码

            if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {

                audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,

                        audioFormat.getSampleRate(), 16, audioFormat

                                .getChannels(), audioFormat.getChannels() * 2,

                        audioFormat.getSampleRate(), false)

                audioInputStream = AudioSystem.getAudioInputStream(audioFormat,

                        audioInputStream)

            }

 

            // 打开输出设备

            DataLine.Info dataLineInfo = new DataLine.Info(

                    SourceDataLine.class, audioFormat,

                    AudioSystem.NOT_SPECIFIED)

            sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo)

            sourceDataLine.open(audioFormat)

            sourceDataLine.start()

 

            // 创建独立线程进行播放

            isStop = false

            Thread playThread = new Thread(new PlayThread())

            playThread.start()

        } catch (Exception e) {

            e.printStackTrace()

        }

    }

    

    class PlayThread extends Thread {

        byte tempBuffer[] = new byte[320]

        

        public void run() {

            try {

                int cnt

                hasStop = false

                // 读取数据到缓存数据

                while ((cnt = audioInputStream.read(tempBuffer, 0,

                        tempBuffer.length)) != -1) {

                    if (isStop)

                        break

                    if (cnt > 0) {

                        // 写入缓存数据

                        sourceDataLine.write(tempBuffer, 0, cnt)

                    }

                }

                // Block等待临时数据被输出为空

                sourceDataLine.drain()

                sourceDataLine.close()

                hasStop = true

            } catch (Exception e) {

                e.printStackTrace()

                System.exit(0)

            }

        }

    }

 

    public static void main(String args[]) {

        new MusicPlayer()

    }

}

知识点:pcm是音频文件最原始的格式,是没有经过任何压缩的,mp3文件是编码(压缩)后的音频文件

要实现的功能:将mp3文件解码为pcm文件

看下fwrite的描述