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来表现音乐了,不知道各位客官是否感受到了新年好的节奏~
结束语
如果您喜欢我的文章,可以[关注⭐]+[点赞👍]+[评论📃],您的三连是我前进的动力,期待与您共同成长~
可关注公众号【怀瑾握瑜的嘉与嘉】,获取资源下载方式