-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBeatModel.java
More file actions
125 lines (105 loc) · 3.33 KB
/
BeatModel.java
File metadata and controls
125 lines (105 loc) · 3.33 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
118
119
120
121
122
123
124
125
package MVCPattern.DJExample;
import java.util.ArrayList;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
public class BeatModel implements BeatModelInterface, MetaEventListener {
Sequencer sequencer;
ArrayList<BeatObserver> beatObservers = new ArrayList<>();
ArrayList<BPMObserver> bpmObservers = new ArrayList<>();
int bpm = 90;
Sequence sequence;
Track track;
public void initialize() {
setUpMidi();
buildTrackAndStart();
}
public void on() {
sequencer.start();
setBPM(90);
}
public void off() {
setBPM(0);
sequencer.stop();
}
public void setBPM(int bpm) {
this.bpm = bpm;
sequencer.setTempoInBPM(getBPM());
notifyBPMObservers();
}
public int getBPM() {
return bpm;
}
void beatEvent() {
notifyBeatObservers();
}
@Override
public void registerObserver(BeatObserver o) {
beatObservers.add(o);
}
@Override
public void removeObserver(BeatObserver o) {
beatObservers.remove(o);
}
@Override
public void registerObserver(BPMObserver o) {
bpmObservers.add(o);
}
@Override
public void removeObserver(BPMObserver o) {
bpmObservers.remove(o);
}
// Called by the MIDI sequencer on each meta event; type 47 = end of track (one beat)
@Override
public void meta(MetaMessage message) {
if (message.getType() == 47) {
beatEvent();
}
}
private void notifyBPMObservers() {
for (BPMObserver observer : bpmObservers) {
observer.updateBPM();
}
}
private void notifyBeatObservers() {
for (BeatObserver observer : beatObservers) {
observer.updateBeat();
}
}
private void setUpMidi() {
try {
// true = connect to the default synthesizer so audio is actually produced
sequencer = MidiSystem.getSequencer(true);
sequencer.open();
sequencer.addMetaEventListener(this);
sequence = new Sequence(Sequence.PPQ, 4);
} catch (MidiUnavailableException | InvalidMidiDataException e) {
e.printStackTrace();
}
}
private void buildTrackAndStart() {
// Channel 9 is the GM percussion channel; note 35 = bass drum
int bassDrum = 35;
try {
track = sequence.createTrack();
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_ON, 9, bassDrum, 100);
track.add(new MidiEvent(msg, 1));
msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_OFF, 9, bassDrum, 100);
track.add(new MidiEvent(msg, 3));
sequencer.setSequence(sequence);
// Loop indefinitely; each end-of-track fires meta(47) which triggers beatEvent()
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}
}