JFugue简介
JFugue 是一个开放源代码编程库,它允许人们使用 Java 编程语言来编程音乐,而无需 MIDI 的复杂性。它由 David Koelle 于 2002 年首次发布。当前版本是 JFugue 5.0,已于 2015 年 3 月发布。Brian Eubanks 将 JFugue 描述为 “对于需要快速便捷地播放音乐或生成 MIDI 文件的应用程序有用”。JFugue 是根据 Apache License 发布的免费软件。
官网地址:JFugue
开启音乐编程之旅
引入pom依赖
<dependencies><!-- https://mvnrepository.com/artifact/jfugue/jfugue --><dependency><groupId>jfugue</groupId><artifactId>jfugue</artifactId><version>5.0.9</version></dependency></dependencies><repositories><repository><id>jfugue repository</id><url>https://maven.sing-group.org/repository/maven/</url></repository></repositories>
HelloJFugue
public class HelloMusic {public static void main(String[] args) {Player player = new Player();player.play("C D E F G A B");}
}
运行程序即可听到电脑发出的音乐声
注:下面内容可能涉及到一些音乐基本知识和JFugue的语法问题,这里我在网上找了一篇比较不错的博客,供大家参考学习,JFugue4.0 中文说明_鼠晓的博客-CSDN博客
这里是JFugue4.0中文说明,引入的版本是5.0,我都试过,仅在一些类库上有一些升级。
演奏千千阙歌
下面是我从某宝购买的《千千阙歌》的简谱【五线谱入门门槛是在是高】
刚开始学习的我也是对照着语法一个音符一个音符手敲的,发现太费力气了,例如下面这样。
R5q R5q R5q G5s A5s C6s D6s E6q E6i D6s E6s_E6q C6s D6s E6s G6s A6q A6i G6s A6s_A6q A6s G6s E6s C6s D6qi D6s E6s D6i C6i A5i C6s C6ws C5q C5i D5s E5s_E5is G5s A5s C6is B5i B5i B5i G5i E5h D5s D5is D5i E5s F5s_F5is F5s A5s E6is D6q D6i D6s B5s_B5s G5is R5q C5q C5i D5s E5s_E5is G5s A5s C6is B5i B5i B5i G5i E5h D5s D5is D5i E5s F5s_F5is A5s C6s E6is D6i D6i D6i D6s B5s_B5s G5is R5q A5i G5s A5s_A5i G5s A5s B5s B5s A5s B5s_B5q D6s D6i D6s D6i B5i C6i D6s E6s_E6i E6s E6s D6i D6i D6i C6s E6s_E6q B5i G5i A5h R5q G5s A5s C6s D6s E6q E6i D6s E6s_E6q E6s D6s C6s D6s C6i A5s A5s_A5h G5s A5s C6s D6s E6q E6i D6s E6s_E6q E6i_G6i_A6i G6i E6s E6s_E6h R5i E6s E6s D6q D6i C6s D6s_D6s C6s A5i_A5i E6s E6s F6i E6i D6i C6s D6s_D6s E6s E6i_E6i D6s E6s D6q D6i C6s D6s_D6i C6i A5s C6is C6h R5q G5s A5s C6s D6s E6q E6i D6s E6s_E6q C6s D6s E6s G6s A6q A6i G6s A6s_A6q A6s G6s E6s C6s D6qi D6s E6s D6i C6i A5i C6s C6wsR5q R5q R5q R5q C3i G3i C4i E4i G4q E4q A3i E4i A4i C5i E5q C5q D3i A3i D4i A3i F3i C4i F4q C3i G3i C4i D4i E4h C3i G3i C4i G3i E4i G3i C4q E3i B3i E4i B3i G4i B3i E4i B3i D3i A3i D4i A3i F4i A3i D4q G3i D4i G4i B4i D5q G4q C3i G3i C4i G3i E4i G3i C4i G3i E3i B3i E4i B3i G4i B3i E4i B3i D3i A3i D4i A3i F4i A3i D4q G3i D4i G4i B4i D5q G4q F3s C4s F4s G4s A4q G3s D4s G4s A4s B4q E3s B3s E4s G4s B4q A3s E4s A4s B4s C5q D3s A3s D4s E4s F4q E3s B3s E4s G4s B4q A3s E4s A4s B4s C5i E4s+A3s E4s+A3s R5h C3i G3i C4i G3i E4i G3i C4i G3i A3i E4i A4i E4i C5i E4i A4i E4i C3i G3i C4i G3i E4i G3i C4q E3i B3i E4i B3i G4i B3i E4i B3i D3i A3i D4i A3i A3i E4i A4q D3i A3i D4i A3i A3i E4i A4q D3i A3i D4i A3i F3i C4i F4i C4i C3i G3i C4i G3i E4i G3i C4q C3i G3i C4i E4i G4q E4q A3i E4i A4i C5i E5q C5q D3i A3i D4i A3i F3i C4i F4q C3i G3i C4i D4i E4h
于是我在音符规则上包了一层属于自己的、比较好理解的数字规则【还是废力,但比以前好点】。
/*** 1.识别开头 1=?【需要推出规律】* 2.规定按照 " " 【空格符号】作为分隔每一拍进行处理*/
public class CreateMusicApp {private static final String[] C_HEADER = {"R", "C", "D", "E", "F", "G", "A", "B"};private static final Map<String, String> MUSIC_MAP;static {MUSIC_MAP = new HashMap<>();MUSIC_MAP.put("1", "w");MUSIC_MAP.put("2", "h");MUSIC_MAP.put("4", "q");MUSIC_MAP.put("8", "i");MUSIC_MAP.put("16", "s");MUSIC_MAP.put("32", "t");MUSIC_MAP.put("1644", "hs");MUSIC_MAP.put("1641", "qis");MUSIC_MAP.put("164", "qs");MUSIC_MAP.put("41", "qi");MUSIC_MAP.put("88", "q");MUSIC_MAP.put("81", "is");MUSIC_MAP.put("844", "hi");MUSIC_MAP.put("44", "h");MUSIC_MAP.put("84", "qi");MUSIC_MAP.put("1616", "i");MUSIC_MAP.put("168", "is");MUSIC_MAP.put("16411", "ws");MUSIC_MAP.put("444", "hq");MUSIC_MAP.put("161", "st");}public static String outputMusic(String filePath) {// 创建文件输入流并读取文件try (FileReader fileReader = new FileReader(filePath);BufferedReader bufferedReader = new BufferedReader(fileReader)) {String line;List<String> keys = new ArrayList<>();while ((line = bufferedReader.readLine()) != null) {// 2!! 1! 4^/*** pattern.add("T72 KEY:C V1 Rh C6i D6i E6i G6s G6hs | E6i D6i C6i D6s E6hs " +"| C6i D6i E6i B6s C7qis | C7i B6i C7s B6s_B6i G6s A6is | G6qi C6i D6i E6i G6s G6hs " +"| E6i D6i C6i D6s C6hs | C6i D6i E6i G6s C6qis | C6i C6i Bi Ai Bs C6hs Rq C6s E6i E6hs" +"| E6i D6i C6i D6q | E6qi Rq C6s E6i E6hs | F6i E6i G6is C6hs R | C6s F6i F6hs" +"| F6i E6i C6i Gq | E6qi B+G C6s E6i D6qs | C6s E6i D6qs C6s E6i D6qs Rh C6s E6i E6hs E6i D6i C6i D6q" +"| G6qi_G6q C6s E6i E6hs | F6i E6i G6i C6hi Rq C6s F6i F6hs | F6i E6i C6i G6q | E6q C7i_C7h" +"| Bi");*/// 音符-音调-时长// 1-6-8_2-4-5 1-6-8,2-4-5 1-4-5_1-6-8_2-4-5 1-6-8,2-4-5,3-4-5 1-6-8 2-7-8String[] strings = line.split(" ");for (String string : strings) {if (string.contains("_")) {String[] split1 = string.split("_");String key = "";for (int i = 0; i < split1.length; i++) {String[] split = split1[i].split("-");if (split.length != 3) {throw new RuntimeException("格式不正确...");}key += C_HEADER[Integer.parseInt(split[0])];key += split[1];key += MUSIC_MAP.get(split[2]);if (i != split1.length - 1) {key += "_";}}keys.add(key);} else if (string.contains(",")) {String[] split1 = string.split(",");String key = "";for (int i = 0; i < split1.length; i++) {String[] split = split1[i].split("-");if (split.length != 3) {throw new RuntimeException("格式不正确...");}key += C_HEADER[Integer.parseInt(split[0])];key += split[1];key += MUSIC_MAP.get(split[2]);if (i != split1.length - 1) {key += "+";}}keys.add(key);} else {String key = "";String[] split = string.split("-");if (split.length != 3) {throw new RuntimeException("格式不正确...");}key += C_HEADER[Integer.parseInt(split[0])];key += split[1];key += MUSIC_MAP.get(split[2]);keys.add(key);}}}String str = "";for (String key : keys) {str += " " + key;}return str;} catch (IOException e) {e.printStackTrace();}return null;}}
由原来的手敲字母变为了下面这样,手敲数字 doge【纯属实现功能,没关注代码整体设计方面】
0-5-4 0-5-4 0-5-4 5-5-16 6-5-16 1-6-16 2-6-16 3-6-4 3-6-8 2-6-16 3-6-16_3-6-4 1-6-16 2-6-16 3-6-16 5-6-16
6-6-4 6-6-8 5-6-16 6-6-16_6-6-4 6-6-16 5-6-16 3-6-16 1-6-16 2-6-41 2-6-16 3-6-16 2-6-8 1-6-8 6-5-8 1-6-16 1-6-16411
1-5-4 1-5-8 2-5-16 3-5-16_3-5-81 5-5-16 6-5-16 1-6-81 7-5-8 7-5-8 7-5-8 5-5-8 3-5-44 2-5-16 2-5-81 2-5-8 3-5-16 4-5-16_4-5-81 4-5-16 6-5-16 3-6-81
2-6-4 2-6-8 2-6-16 7-5-16_7-5-16 5-5-81 0-5-4 1-5-4 1-5-8 2-5-16 3-5-16_3-5-81 5-5-16 6-5-16 1-6-81 7-5-8 7-5-8 7-5-8 5-5-8 3-5-44
2-5-16 2-5-81 2-5-8 3-5-16 4-5-16_4-5-81 6-5-16 1-6-16 3-6-81 2-6-8 2-6-8 2-6-8 2-6-16 7-5-16_7-5-16 5-5-81 0-5-4 6-5-8 5-5-16 6-5-16_6-5-8 5-5-16 6-5-16 7-5-16 7-5-16 6-5-16 7-5-16_7-5-4
2-6-16 2-6-8 2-6-16 2-6-8 7-5-8 1-6-8 2-6-16 3-6-16_3-6-8 3-6-16 3-6-16 2-6-8 2-6-8 2-6-8 1-6-16 3-6-16_3-6-4 7-5-8 5-5-8
6-5-44 0-5-4 5-5-16 6-5-16 1-6-16 2-6-16 3-6-4 3-6-8 2-6-16 3-6-16_3-6-4 3-6-16 2-6-16 1-6-16 2-6-16
1-6-8 6-5-16 6-5-16_6-5-44 5-5-16 6-5-16 1-6-16 2-6-16 3-6-4 3-6-8 2-6-16 3-6-16_3-6-4 3-6-8_5-6-8_6-6-8 5-6-8 3-6-16 3-6-16_3-6-44 0-5-8 3-6-16 3-6-16
2-6-4 2-6-8 1-6-16 2-6-16_2-6-16 1-6-16 6-5-8_6-5-8 3-6-16 3-6-16 4-6-8 3-6-8 2-6-8 1-6-16 2-6-16_2-6-16 3-6-16 3-6-8_3-6-8 2-6-16 3-6-16 2-6-4 2-6-8 1-6-16 2-6-16_2-6-8 1-6-8 6-5-16 1-6-81
1-6-44 0-5-4 5-5-16 6-5-16 1-6-16 2-6-16 3-6-4 3-6-8 2-6-16 3-6-16_3-6-4 1-6-16 2-6-16 3-6-16 5-6-16 6-6-4 6-6-8 5-6-16 6-6-16_6-6-4 6-6-16 5-6-16 3-6-16 1-6-16
2-6-41 2-6-16 3-6-16 2-6-8 1-6-8 6-5-8 1-6-16 1-6-16411
0-5-4 0-5-4 0-5-4 0-5-4 1-3-8 5-3-8 1-4-8 3-4-8 5-4-4 3-4-4
6-3-8 3-4-8 6-4-8 1-5-8 3-5-4 1-5-4 2-3-8 6-3-8 2-4-8 6-3-8 4-3-8 1-4-8 4-4-4 1-3-8 5-3-8 1-4-8 2-4-8 3-4-44
1-3-8 5-3-8 1-4-8 5-3-8 3-4-8 5-3-8 1-4-4 3-3-8 7-3-8 3-4-8 7-3-8 5-4-8 7-3-8 3-4-8 7-3-8 2-3-8 6-3-8 2-4-8 6-3-8 4-4-8 6-3-8 2-4-4
5-3-8 2-4-8 5-4-8 7-4-8 2-5-4 5-4-4 1-3-8 5-3-8 1-4-8 5-3-8 3-4-8 5-3-8 1-4-8 5-3-8 3-3-8 7-3-8 3-4-8 7-3-8 5-4-8 7-3-8 3-4-8 7-3-8
2-3-8 6-3-8 2-4-8 6-3-8 4-4-8 6-3-8 2-4-4 5-3-8 2-4-8 5-4-8 7-4-8 2-5-4 5-4-4 4-3-16 1-4-16 4-4-16 5-4-16 6-4-4 5-3-16 2-4-16 5-4-16 6-4-16 7-4-4
3-3-16 7-3-16 3-4-16 5-4-16 7-4-4 6-3-16 3-4-16 6-4-16 7-4-16 1-5-4 2-3-16 6-3-16 2-4-16 3-4-16 4-4-4 3-3-16 7-3-16 3-4-16 5-4-16 7-4-4
6-3-16 3-4-16 6-4-16 7-4-16 1-5-8 3-4-16,6-3-16 3-4-16,6-3-16 0-5-2 1-3-8 5-3-8 1-4-8 5-3-8 3-4-8 5-3-8 1-4-8 5-3-8
6-3-8 3-4-8 6-4-8 3-4-8 1-5-8 3-4-8 6-4-8 3-4-8 1-3-8 5-3-8 1-4-8 5-3-8 3-4-8 5-3-8 1-4-4 3-3-8 7-3-8 3-4-8 7-3-8 5-4-8 7-3-8 3-4-8 7-3-8
2-3-8 6-3-8 2-4-8 6-3-8 6-3-8 3-4-8 6-4-4 2-3-8 6-3-8 2-4-8 6-3-8 6-3-8 3-4-8 6-4-4 2-3-8 6-3-8 2-4-8 6-3-8 4-3-8 1-4-8 4-4-8 1-4-8
1-3-8 5-3-8 1-4-8 5-3-8 3-4-8 5-3-8 1-4-4 1-3-8 5-3-8 1-4-8 3-4-8 5-4-4 3-4-4 6-3-8 3-4-8 6-4-8 1-5-8 3-5-4 1-5-4
2-3-8 6-3-8 2-4-8 6-3-8 4-3-8 1-4-8 4-4-4 1-3-8 5-3-8 1-4-8 2-4-8 3-4-44
有两份文件是因为简谱中将谱分为了左右手两个谱,对应简谱里就是两行。
0-5-4 可以理解为用 "-" 号将音符-音调-时长分隔开,"_" 代表连音符
主程序运行
public static void main(String[] args) {String song1 = CreateMusicApp.outputMusic("E:\\IdeaCode\\Shuttle_Music\\src\\main\\resources\\qqqg\\temp.txt");String song2 = CreateMusicApp.outputMusic("E:\\IdeaCode\\Shuttle_Music\\src\\main\\resources\\qqqg\\temp2.txt");System.out.println(song1);System.out.println();System.out.println(song2);Player player = new Player();Pattern music = new Pattern();Pattern pattern1 = new Pattern("T60 KEY:C V0 " + song1);Pattern pattern2 = new Pattern("T60 KEY:C V1 " + song2);music.add(pattern1);music.add(pattern2);player.play(music);}
运行程序即可享受到动听的音乐~
如果想保存到本地可以调用以下方法保存为 mid 格式文件
MidiFileManager.savePatternToMidi(pattern, new File("千千阙歌.mid"));
写在最后
研究 Java 音乐编程纯属个人兴趣爱好,有想了解更多的朋友推荐看看JFugue5.0官方提供的电子书【虽然收费,而且很贵,25$,但没事,我买了...】
博客限制原因没法上传资源,评论区留言邮箱即可。