听我抚琴一曲可好---新年好呀~新年好呀

902 阅读4分钟

PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

大家好,我是怀瑾握瑜,一只大数据萌新,家有两只吞金兽,嘉与嘉,上能code下能teach的全能奶爸

如果您喜欢我的文章,可以[关注⭐]+[点赞👍]+[评论📃],您的三连是我前进的动力,期待与您共同成长~


前言🧨

一帆风顺年年好,万事如意步步高,祝大家新年万事如意。

新年到,对联有了,烟花有了,怎能无音乐。

下面请您欣赏,童年第一首环绕立体式接红包BGM-新年好~

认识简谱📖

先学习谱子,才能知道怎样弹奏,下面是新年好的简谱:

  • 1、2、3、4、5、6、7,分别代表do、re、mi、fa、sol、la、si
  • 音符上方加记一个“·”,表示该音升高一个八度,称为高音;加记两个" :",则表示该音升高两个八度,称为倍高音
  • 音符下方加记一个"·",表示该音降低一个八度,称为低音;加记两个" :",则表示该音降低两个八度,称为倍低音。在钢琴键盘上共有五个音区部分,分别从左到右,对应从高音到低音
  • 带下划线的音符表示1/2拍(八分音符♪),单独一个音符表示1拍(四分音符♩),音符-表示2拍(二分音符)

钢琴音符🎵

从网上收集的钢琴音符,W盘地址如下,注意中央C的do是41!.mp3。

链接: https://pan.baidu.com/s/1zAZsvXAchCRo0Cb16zQjow 提取码: g2mg 

播放音乐🎧

1. 创建工程修改POM

使用idea创建一个project,在pom.xml中添加相关依赖

<!-- MP3文件 解码 -->
<dependency>
	<groupId>com.googlecode.soundlibs</groupId>
	<artifactId>mp3spi</artifactId>
	<version>1.9.5.4</version>
</dependency>

<!-- 音频标签 -->
<dependency>
	<groupId>org</groupId>
	<artifactId>jaudiotagger</artifactId>
	<version>2.0.3</version>
</dependency>

2. 播放MP3文件

获取文件路径,播放相应的mp3文件。

public void playMp3(String path) throws UnsupportedAudioFileException, IOException {
        File file = new File(path);
        if (!file.exists() || !path.toLowerCase().endsWith(".mp3")) {
            throw new RuntimeException("文件不存在");
        }
        AudioInputStream stream = null;
        //使用 mp3spi 解码 mp3 音频文件
        MpegAudioFileReader mp = new MpegAudioFileReader();
        stream = mp.getAudioInputStream(file);
        AudioFormat baseFormat = stream.getFormat();
        //设定输出格式为pcm格式的音频文件
        AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
        // 输出到音频
        stream = AudioSystem.getAudioInputStream(format, stream);
        AudioFormat target = stream.getFormat();
        DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, target, AudioSystem.NOT_SPECIFIED);
        SourceDataLine line = null;
        int len = -1;
        try {
            line = (SourceDataLine) AudioSystem.getLine(dinfo);
            line.open(target);
            line.start();
            byte[] buffer = new byte[1024];
            while ((len = stream.read(buffer)) > 0) {
                line.write(buffer, 0, len);
            }
            line.drain();
            line.stop();
            line.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            stream.close();
        }
    }

3. 解决拍子快慢的问题

因为音符的mp3文件播放是长都是2秒,我以1秒为一拍计时,那么八分音符就只能播放0.5秒。

整个播放方法看是不支持播放时长的,那么我们只能使用一个折中的办法,就是在外面套一个线程,然后在外面统计播放时间,然后调用方法终止正在执行线程,并用锁去控制进程保证事件统一。

重新封装一个带现成的对象。

public class PlayMusicMp3 {

    private static DataLine.Info info = null;
    private static AudioFormat target = null;
    private static SourceDataLine data = null;
    private static AudioInputStream stream = null;
    private static volatile boolean playing = false;
    private static Thread thread = null;

    private PlayMusicMp3() {

    }
    
    public static PlayMusicMp3 player() {
        return Music.modle;
    }

    public static boolean isPlaying() {
        return playing;
    }

    public void load(URL url) {
        try {
            end();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        try {
            stream = AudioSystem.getAudioInputStream(url);
            AudioFormat format = stream.getFormat();
            if (format.getEncoding().toString().toLowerCase().contains("mpeg")) {//mp3
                MpegAudioFileReader mp = new MpegAudioFileReader();
                stream = mp.getAudioInputStream(url);
                format = new AudioFormat(Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(), format.getChannels() * 2, format.getSampleRate(), false);
                stream = AudioSystem.getAudioInputStream(format, stream);
            } else if (format.getEncoding().toString().toLowerCase().contains("flac")) {//flac
                format = new AudioFormat(Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(), format.getChannels() * 2, format.getSampleRate(), false);
                stream = AudioSystem.getAudioInputStream(format, stream);
            }
            info = new DataLine.Info(SourceDataLine.class, format, AudioSystem.NOT_SPECIFIED);
            data = (SourceDataLine) AudioSystem.getLine(info);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public void stop() {
        if (data != null && data.isOpen()) {
            data.stop();
            synchronized (thread) {
                try {
                    thread.wait(0);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
            playing = false;
        }
    }

    public void end() throws IOException {
        if (data != null) {
            data.stop();
            data.drain();
            stream.close();
            if (thread != null) {
                thread.stop();
                thread = null;
            }
        }
        playing = false;
    }

    public void start() {
        if (thread != null) {
            synchronized (thread) {
                thread.notify();
                data.start();
                playing = true;
            }
        } else {
            playing = true;
            thread = new Thread(() -> {
                try {
                    if (info != null) {
                        data.open(target);
                        data.start();
                        byte[] buffer = new byte[1024];
                        int len = -1;
                        while ((len = stream.read(buffer)) > 0) {
                            data.write(buffer, 0, len);
                        }
                        end();// 结束播放流
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            });
            thread.setDaemon(true);
            thread.start();
        }

    }

    private static class Music {
        private static PlayMusicMp3 modle = new PlayMusicMp3();
    }

}

弹奏乐谱🎼

应对新年好的简谱封装一个音符对象

public class Click {
    String node;
    String pitch;
    String type;

    public Click(String node, String pitch, String type) {
        this.node = node;
        this.pitch = pitch;
        this.type = type;
    }
}

录入新年好的谱子,点击运行。

public static void main(String[] args) throws Exception {
        JSONArray list = new JSONArray();
        list.add(JSONObject.toJSON(new Click("1", "4", "half")));
        list.add(JSONObject.toJSON(new Click("1", "4", "half")));
        list.add(JSONObject.toJSON(new Click("1", "4", "one")));
        list.add(JSONObject.toJSON(new Click("5", "3", "one")));

        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "one")));
        list.add(JSONObject.toJSON(new Click("1", "4", "one")));

        list.add(JSONObject.toJSON(new Click("1", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("5", "4", "one")));
        list.add(JSONObject.toJSON(new Click("5", "4", "one")));

        list.add(JSONObject.toJSON(new Click("4", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("2", "4", "two")));

        list.add(JSONObject.toJSON(new Click("2", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("4", "4", "one")));
        list.add(JSONObject.toJSON(new Click("4", "4", "one")));

        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("2", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "one")));
        list.add(JSONObject.toJSON(new Click("1", "4", "one")));

        list.add(JSONObject.toJSON(new Click("1", "4", "half")));
        list.add(JSONObject.toJSON(new Click("3", "4", "half")));
        list.add(JSONObject.toJSON(new Click("2", "4", "one")));
        list.add(JSONObject.toJSON(new Click("5", "3", "one")));

        list.add(JSONObject.toJSON(new Click("7", "3", "half")));
        list.add(JSONObject.toJSON(new Click("2", "4", "half")));
        list.add(JSONObject.toJSON(new Click("1", "4", "two")));

        System.out.println(list.toJSONString());

        list.forEach(o -> {
            Click click = JSONObject.parseObject(o.toString(), Click.class);
            long sleep = 0;
            if ("half".equals(click.getType())) {
                sleep = 500;
            } else if ("one".equals(click.getType())) {
                sleep = 1000;
            } else if ("two".equals(click.getType())) {
                sleep = 2000;
            }
            try {
                play(click.getPitch() + click.getNode() + "!", sleep);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });
}

接着奏乐接着舞~

弹琴.gif

20200714202600_39634.gif

限制与个人水平的局限性,只能通过gif来表现音乐了,不知道各位客官是否感受到了新年好的节奏~


结束语

如果您喜欢我的文章,可以[关注⭐]+[点赞👍]+[评论📃],您的三连是我前进的动力,期待与您共同成长~

可关注公众号【怀瑾握瑜的嘉与嘉】,获取资源下载方式