[java 音频处理篇]第3章 从指定位置播放

时间:2022-12-09 01:28:56

前言:

进行音频处理,肯定需要从指定的位置播放,本章将介绍如何通过设置帧的方式,指定播放的位置。

目标:

知道什么帧,如何设置帧,代码【1】处

正文:

要明白本章从指定位置进行播放声音的代码,就要先知道什么是帧,先看下图:

[java 音频处理篇]第3章 从指定位置播放

 我们知道电脑中的声音文件例如wav其实就是保存的连续的采样数据,每一个采样数据就是上图中的圆圈。简单点说,当我们播放wav时,就是从最左侧开始播放这些采样的点(实际中采样的点非常的多,这里只是便于理解)。

那么什么是帧呢?帧就是按照某个固定规则,讲这些连续不断地采样点进行了划分,这样就可以通过帧定位到点了。举个例子就明白了:图中如果不考虑帧,我想从采样点3开始播放,你可以定位到采样点3就行,你也可以直接通过指定到第2帧,然后就自动会从采样点3开始播放了。

既然通过采样点也可以操作,为什么还要帧呢?我们说过实际采样时,采样数据非常多,这时候用采样点做最小单位没有太大的意义,所以人们就设置了一个更大一点的,相对于我们来说更有意义的单位,帧。这就好比我们说二进制是一般都用字节表示,而没有说第几位的。但是本质上最终操作的还是里面的采样点。

我这里的描述只是为了方便理解,专业只是大家可自行百度。

下面上代码,代码中通过设置帧位置,来指定从什么位置开始播放声音,注意【1】处

package my;

import javax.sound.sampled.*;
import java.io.File;
import java.util.Scanner;

public class Player{
    private static int consoleInput=-1;
    private static final int EXIT = 0;
    public static void main(String[] args) throws Exception {
        /**
         * 这个线程主要用来接收控制台输入退出命令【输入0】,跳出while循环,结束程序。。
         */
        new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            while (true){
                if(scanner.nextInt()==0){
                    consoleInput = 0;
                    break;
                }
            }
        }).start();

        Player player = new Player();
        Clip clip = player.loadSound();
        player.playSound(clip);
    }

    public Clip loadSound() throws Exception {
        String filePath = "C:\\Users\\cook\\Desktop\\javasounddemo-150249\\JavaSoundDemo\\audio\\1-welcome.wav";
        File file = new File(filePath);

        AudioInputStream stream = AudioSystem.getAudioInputStream(file);
        AudioFormat format = stream.getFormat();
        //1-welcome.wav共152736帧,每个帧占存储2个字节的采样数据,所以一共需要内存152736*2 = 305472个字节空间
        // stream.getFrameLength()获取我们音频中总共有多少帧,所有的采样数据都分配在这些帧里面
        // format.getFrameSize()获取每个帧的存储空间(几个字节)
        DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat(), ((int) stream.getFrameLength() * format.getFrameSize()));

        Clip clip = (Clip) AudioSystem.getLine(info);
        clip.addLineListener((event)->{
            System.out.println(event.getType().toString());
        });

        clip.open(stream);
        return clip;
    }

    public void playSound(Clip clip ){
        //【1】设置从第几帧开始播放,然后播放时就会从帧中读取当前位置的采样数据,开始播放了。本例中的1-welcome.wav共152736帧,设置从100000播放
        clip.setFramePosition(100000);
        clip.start();
        while (true) {
            try {
                if(consoleInput == EXIT){
                    break;
                }
                System.out.println(clip.getMicrosecondPosition());
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();break;}
        }
        clip.stop();
        clip.close();
    }
}

上面代码中【1】处,设置了音频直接从第100000帧开始播放,大家可以注释掉此句代码,来听一下播放的效果。

另外除了通过帧来指定播放位置外,我们还可以直接通过时间来指定,代码如下,可以替换到上面代码【1】处测试

// 从指定的时间段开始播放,单位是为妙
clip.setMicrosecondPosition(4679092); 
clip.start();

要想知道当前音频播放了多长时间了,通过如下代码即可

clip.getMicrosecondPosition();

到此,本章结束。学完这一章Clip接口中的几个方法就已经涉及到了。