Java Clip 播放音频

Clip 是 Java 音频 API 中用于简化音频播放的类。它是 DataLine 接口的实现,属于 javax.sound.sampled 包。Clip 类提供了一种简便的方式来处理音频播放,通常用于短音频片段的播放,如音效或简短的音乐片段。

音频格式 支持情况
*.wav (JDK 原生支持)
*.pcm (JDK 原生支持)
*.au (JDK 原生支持)
*.aiff (JDK 原生支持)
*.mp3 mp3spi.jar
*.flac jflac-codec.jar

FloatControl.Type 是 Java Sound API 中的一个内部类,定义了 FloatControl 可以支持的控制类型。 FloatControl 提供了一种方式来控制以浮点数表示的参数,这些参数通常是音频系统的某些方面。常见的控制类型包括音量控制、平衡控制、增益控制等。

FloatControl.Type 类型
MASTER_GAIN 主增益控制。调整整个音频系统的增益(音量)。
AUX_SEND 辅助发送电平控制。调整发送到辅助总线的电平。
AUX_RETURN 辅助返回电平控制。调整从辅助总线返回的电平。
REVERB_SEND 混响发送电平控制。调整发送到混响效果器的电平。
PAN 声道平衡控制。调整立体声左右声道的平衡。
BALANCE 声道平衡控制。类似于 PAN 控制,调整音频信号在左右声道之间的平衡。
SAMPLE_RATE 采样率控制。调整音频流的采样率。

1 依赖

<!-- 如果需要解码播放mp3文件则引入这个jar包 -->
<dependency>
	<groupId>com.googlecode.soundlibs</groupId>
	<artifactId>mp3spi</artifactId>
	<version>1.9.5.4</version>
</dependency>

<!-- 如果需要解码播放flac文件则引入这个jar包 -->
<dependency>
	<groupId>org.jflac</groupId>
	<artifactId>jflac-codec</artifactId>
	<version>1.5.2</version>
</dependency>

2 接口

package com.xu.music;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.AudioInputStream;
import java.io.File;
import java.net.URL;

/**
 * Java 音频播放
 *
 * @author hyacinth
 * @date 2019年10月31日19:06:39
 */
public interface Player {

    /**
     * Java Music 加载音频
     *
     * @param url 音频文件url
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(URL url) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param file 音频文件
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(File file) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param path 文件路径
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(String path) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param stream 音频文件输入流
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(AudioInputStream stream) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param encoding Encoding
     * @param stream   AudioInputStream
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(Encoding encoding, AudioInputStream stream) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param format AudioFormat
     * @param stream AudioInputStream
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(AudioFormat format, AudioInputStream stream) throws Exception;

    /**
     * Java Music 暂停播放
     *
     * @date 2019年10月31日19:06:39
     */
    void pause();

    /**
     * Java Music 继续播放
     *
     * @param duration 音频位置
     * @date 2019年10月31日19:06:39
     */
    void resume(long duration);

    /**
     * Java Music 开始播放
     *
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void play() throws Exception;

    /**
     * Java Music 结束播放
     *
     * @date 2019年10月31日19:06:39
     */
    void stop();

    /**
     * Java Music 设置音量
     *
     * @param volume 音量
     * @date 2019年10月31日19:06:39
     */
    void volume(float volume);
}

3 实现

package com.xu.music;

import cn.hutool.core.text.CharSequenceUtil;
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import java.io.File;
import java.net.URL;

/**
 * Java 音频播放
 *
 * @author hyacinth
 * @date 2019年10月31日19:06:39
 */
public class ClipPlayer implements Player {

    /**
     * Clip
     */
    private Clip clip;

    /**
     * FloatControl
     */
    private FloatControl control = null;

    /**
     * 播放位置
     */
    private volatile long position = 0;

    /**
     * 暂停
     */
    private volatile boolean paused = false;


    private ClipPlayer() {

    }

    public static ClipPlayer createPlayer() {
        return ClipPlayer.SingletonHolder.player;
    }

    private static class SingletonHolder {
        private static final ClipPlayer player = new ClipPlayer();
    }

    @Override
    public void load(URL url) throws Exception {
        load(AudioSystem.getAudioInputStream(url));
    }

    @Override
    public void load(File file) throws Exception {
        String name = file.getName();
        if (CharSequenceUtil.endWithIgnoreCase(name, ".mp3")) {
            AudioInputStream stream = new MpegAudioFileReader().getAudioInputStream(file);

            AudioFormat format = stream.getFormat();
            format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),
                    format.getChannels() * 2, format.getSampleRate(), false);

            stream = AudioSystem.getAudioInputStream(format, stream);
            load(stream);
            return;
        }
        if (CharSequenceUtil.endWithIgnoreCase(name, ".flac")) {
            AudioInputStream stream = AudioSystem.getAudioInputStream(file);

            AudioFormat format = stream.getFormat();
            format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),
                    format.getChannels() * 2, format.getSampleRate(), false);

            stream = AudioSystem.getAudioInputStream(format, stream);

            load(stream);
            return;
        }
        load(AudioSystem.getAudioInputStream(file));
    }

    @Override
    public void load(String path) throws Exception {
        load(new File(path));
    }

    @Override
    public void load(AudioInputStream stream) throws Exception {
        DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(), AudioSystem.NOT_SPECIFIED);

        this.clip = (Clip) AudioSystem.getLine(info);
        this.clip.addLineListener(event -> {
            System.out.println(event.getType() + "\t" + event.getFramePosition());
        });

        this.clip.open(stream);
        if (this.clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
            control = (FloatControl) this.clip.getControl(FloatControl.Type.MASTER_GAIN);
        }
    }

    @Override
    public void load(AudioFormat.Encoding encoding, AudioInputStream stream) throws Exception {
        load(AudioSystem.getAudioInputStream(encoding, stream));
    }

    @Override
    public void load(AudioFormat format, AudioInputStream stream) throws Exception {
        load(AudioSystem.getAudioInputStream(format, stream));
    }

    @Override
    public void pause() {
        if (this.clip != null && this.clip.isRunning()) {
            paused = true;
            position = this.clip.getMicrosecondPosition();
            this.clip.stop();
        }
    }

    @Override
    public void resume(long duration) {
        if (this.clip != null && paused) {
            paused = false;
            this.position = (0 == duration) ? position : duration;
            this.clip.setMicrosecondPosition(position);
            this.clip.start();
        }
    }

    @Override
    public void play() {
        if (this.clip != null) {
            this.clip.start();
            this.clip.drain();
        }
    }

    @Override
    public void stop() {
        if (this.clip != null) {
            this.clip.stop();
            this.clip.close();
        }
    }

    @Override
    public void volume(float volume) {
        if (null == control) {
            return;
        }
        if (volume < control.getMinimum() || volume > control.getMaximum()) {
            return;
        }
        control.setValue(volume);
    }

}

4 测试

package com.xu.music.player.player;

/**
 * Java 音频播放
 *
 * @author hyacinth
 * @date 2019年10月31日19:06:39
 */
public class Test {

    public static void main(String[] args) throws Exception {
        ClipPlayer player = ClipPlayer.createPlayer();
        player.load("D:\\Kugou\\梦涵 - 加减乘除.mp3");
        player.play();

        Thread.sleep(5000);
        player.pause();

        Thread.sleep(5000);
        player.resume(0);

        Thread.sleep(5000);
        player.stop();
    }

}
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐