作为同时热爱编程与midi编曲的人,我决定自己动手,送给自己一份融合编程与编曲的小礼物!这个小程序利用了Java提供的midi包,在程序中创建音序器以及一个音轨,然后硬编码地写入了生日快乐歌的音符(乐谱),再调用虚拟乐器播放出生日快乐歌,最后还在控制台输出了一行生日祝福。
这篇的代码我借助了CSDN提供的AI创作助手,功能很强大!其中部分代码我有改动,还加了一些注释。正好我也借着这个机会初步了解了Java的midi包。其实把乐谱硬编码在程序中,这样扩展性不好,更好的方式是用Java加载本地的midi文件。
以下是程序代码。
import javax.sound.midi.*; //导入midi包
public class HappyBirthday { /*功能:在程序中硬编码生日快乐歌的音符,并利用midi接口播放这首歌。*/
public static void main(String[] args) {
try {
/*使用MidiSystem类获取一个MIDI音序器Sequencer对象,
* 并打开它,以便准备播放MIDI音乐
*/
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
/*创建一个Sequence对象,它将作为MIDI音乐的容器,使用默认的节拍类型
* (PPQ,即“每拍的脉冲数”)和一个缩放因子4(即一个四分音符的长度为4个单位)。
*/
Sequence sequence = new Sequence(Sequence.PPQ, 4);
/*在Sequence对象中创建一个Track对象,作为MIDI音乐的轨道,
* 音符和控制信息可以添加到这个轨道上。
*/
Track track = sequence.createTrack();
/*//设置MIDI音乐的“乐器”,以便为之后的音符指定正确的声音。
* ShortMessage类是MIDI消息的一种类型,可以使用它来构建
* 不同类型的MIDI消息,MidiEvent类则用于将MIDI消息插入到轨道中。
*/
ShortMessage first = new ShortMessage();
first.setMessage(ShortMessage.PROGRAM_CHANGE, 0, 1, 0);
MidiEvent firstEvent = new MidiEvent(first, 0);
track.add(firstEvent);
/*指定生日快乐歌曲的音符和时长。数组notes存储的是每个音符的MIDI值,
* 数组durations则存储每个音符的持续时间。
*/
int[] notes = {60, 60, 62, 60, 65, 64, 60, 60, 62, 60, 67, 65, 60, 60, 72, 69, 65, 64, 62, 70, 70, 69, 65, 67, 65 };
int[] durations = {4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
/*在轨道上依次添加每个音符和其对应的持续时间。
* MidiMessage类的静态方法NOTE_ON和NOTE_OFF分别表示开启和停止一个音符,
* 这个方法的参数是MIDI信道(音色)、音符的音高(即notes数组中的元素)、以及音符的强度
*/
for (int i = 0; i < notes.length; i++) {
ShortMessage a = new ShortMessage();
a.setMessage(ShortMessage.NOTE_ON, 5, notes[i], 100); //第二个参数是选乐器 9是打击乐,其它都是钢琴
MidiEvent noteOn = new MidiEvent(a,i * 4 ); //第二个参数是每拍的时间戳,实际上可用于改变播放速度
track.add(noteOn);
ShortMessage b = new ShortMessage();
b.setMessage(ShortMessage.NOTE_OFF, 0, notes[i], 100);
MidiEvent noteOff = new MidiEvent(b, (i * 4) + durations[i]);
track.add(noteOff);
}
/*将创建好的Sequence对象设置到Sequencer对象中,并启动播放。
* 此时程序将以MIDI格式播放生日快乐曲目。
*/
sequencer.setSequence(sequence);
sequencer.setTempoInBPM(120);
sequencer.start();
} catch (Exception ex) { //异常处理
ex.printStackTrace();
}
System.out.println("HAPPY BIRTHDAY!!!"); //在控制台输出文本
}
}