-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMidiPlayer.java
More file actions
117 lines (99 loc) · 4.14 KB
/
MidiPlayer.java
File metadata and controls
117 lines (99 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import java.util.ArrayList;
import java.util.HashMap;
import javax.sound.midi.*;
public class MidiPlayer {
private static final int DEFAULT_INSTRUMENT = 0; // Default instrument (piano)
private static final int DEFAULT_VELOCITY = 64; // Default velocity (volume)
private static final int NOTE_ON = 0x90; // MIDI message for note on
private static final int NOTE_OFF = 0x80; // MIDI message for note off
private static Sequencer sequencer;
private static Sequence sequence;
private static Track track;
static {
try {
sequencer = MidiSystem.getSequencer();
sequencer.open();
sequence = new Sequence(Sequence.PPQ, 4); // 4 ticks per quarter note
track = sequence.createTrack();
sequencer.setSequence(sequence);
sequencer.addMetaEventListener(new MetaEventListener() {
@Override
public void meta(MetaMessage meta) {
if (meta.getType() == 47) { // End of track event
clearSequence(); // Clear the sequence
}
}
});
} catch (MidiUnavailableException | InvalidMidiDataException e) {
e.printStackTrace();
}
}
public static void playSong(HashMap<Double, ArrayList<Note>> notes) {
for (HashMap.Entry<Double, ArrayList<Note>> e : notes.entrySet()) {
for (Note n : e.getValue()) {
addNoteToSequence(n, (long) Math.floor(e.getKey() * Measure.NOTES_PER_MEASURE));
}
}
playSequence();
}
public static void addNoteToSequence(Note note, long index) {
if (sequence == null) {
try {
sequence = new Sequence(Sequence.PPQ, 4); // 4 ticks per quarter note
track = sequence.createTrack();
} catch (InvalidMidiDataException e) {
e.printStackTrace();
return;
}
}
int channel = 0; // MIDI channel (0-15)
int noteValue = note.getPitch();
int velocity = DEFAULT_VELOCITY;
// Calculate the tick value based on the index and the tempo of the sequence
long tick = index * sequence.getResolution();
try {
ShortMessage noteOn = new ShortMessage();
noteOn.setMessage(NOTE_ON, channel, noteValue, velocity);
track.add(new MidiEvent(noteOn, tick)); // Note on at the specified tick
// Calculate the duration of the note in ticks
long durationTicks = (long) (sequence.getResolution() * note.getDuration());
// Adding a note off event after the calculated duration
ShortMessage noteOff = new ShortMessage();
noteOff.setMessage(NOTE_OFF, channel, noteValue, 0);
track.add(new MidiEvent(noteOff, tick + durationTicks)); // Note off after the calculated duration
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}
public static void clearSequence() {
sequence.deleteTrack(track); // Delete the track from the sequence
track = sequence.createTrack(); // Recreate the track
}
public static void playSequence() {
if (sequencer != null) {
if (sequencer.isRunning()) {
sequencer.stop();
}
sequencer.setMicrosecondPosition(0); // Reset the sequencer position
try {
sequencer.setSequence(sequence);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
return;
}
sequencer.start();
}
}
public static void stopSequence() {
if (sequencer != null && sequencer.isRunning()) {
sequencer.stop();
sequencer.setMicrosecondPosition(0); // Reset the sequencer position
}
}
public static void close() {
if (sequencer != null) {
sequencer.close();
sequence = null; // Reset sequence when closing
}
}
}