1 package fi.jyu.mit.Music;
2
3 import java.util.LinkedList;
4 import java.util.List;
5
6 import java.util.Vector;
7
8
12 public class ThreadedMidiPlayer extends MidiPlayer implements BasicMidiPlayer {
13
14 private class SoundConsumer extends Thread {
15 public void run() {
16 Clock c = new Clock();
17 while (true) {
18 Note n = null;
19 synchronized(queue) {
20 while (queue.size() == 0) {
22 if (stop)
23 break;
24 try {
25 queue.wait(); } catch (InterruptedException ie) {
27
28 }
29 }
30 if (stop)
31 break;
32 n = queue.remove(0);
33 queue.notifyAll();
34
35 }
36 message(String.format("%6d Pysäytin %s",c.getElapsed(),n.message()));
38 channelOff(n.getNote());
39 }
40
41 }
42 }
43
46 private class SoundProducer extends Thread {
47 private double noteLength;
48 private Vector<Note> notes;
49
50 public SoundProducer() {
51 noteLength = 0.25;
52 notes = new Vector<Note>();
53 }
54
55 public void addNote(Note note) {
56 notes.add(note);
57 }
58
59 public void run() {
61 Clock c = new Clock();
62 long breakLength = (long)((getBeatLength() * 4) * noteLength);
63 if (notes.size() == 0)
64 return;
65 Vector<Note> played = new Vector<Note>();
66 while (true) {
67 if (notes.isEmpty())
68 break;
69 played.clear();
70 while (!notes.isEmpty()) {
71 Note n = notes.firstElement();
72 if ( !n.isDelay() ) {
73 message(String.format("%6d Käynnistän %s",c.getElapsed(),n.message()));
74 played.add(n);
75 channelOn(n.getNote(), n.getVelocity());
76 } else {
77 notes.remove(0);
78 break;
79 }
80 notes.remove(0);
81 }
82
83 try {
85 Thread.sleep(breakLength);
86 } catch (InterruptedException ie) {
87
88 }
89
90 for (Note n : played) {
92 synchronized(queue) {
93 queue.add(new Note(n.getNote(), n.getLength(), n.getVelocity()));
96 queue.notifyAll(); }
98 }
99 }
100 }
101
102 private void setNoteLength(double noteLength) {
103 this.noteLength = noteLength;
104 }
105 }
106 class Clock {
107 long startMillis = 0;
108 public Clock() {
109 startMillis = System.currentTimeMillis();
110 }
111 public long getElapsed() {
112 return (System.currentTimeMillis() - startMillis);
113 }
114 }
115 private Vector<SoundProducer> producers;
116
117 private LinkedList<Note> queue = new LinkedList<Note>();
118
119 private SoundConsumer sc;
120
121 private boolean stop = false;
123 public ThreadedMidiPlayer() {
124 init();
125 sc = new SoundConsumer();
126 producers = new Vector<SoundProducer>();
127 }
128
129
132 public void begin() {
133 sc.start();
134 }
135
136
139 public void end() {
140 synchronized(queue) {
141 stop = true;
142 queue.notifyAll();
143 }
144 }
145
146
150 @Override
151 public void play(String sequence, double length, int octave, int velocity) {
152 List<Note> notes = getNotes(sequence, length, octave, velocity);
153 SoundProducer sp = getFreeProducer();
154 for (Note n : notes)
155 sp.addNote(n);
156 sp.setNoteLength(length);
157 sp.start();
158 }
159
160
161
168 public void playChord(String chord, double length, int octave, int velocity) {
169 List<Note> notes = getNotes(chord, length, octave, velocity);
170 SoundProducer sp = getFreeProducer();
171 for (Note n : notes) {
172 if ( !n.isDelay() )
174 sp.addNote(n);
175 }
176 sp.setNoteLength(length);
177 sp.start();
178 try {
179 Thread.sleep((long)((getBeatLength()*4) * length));
180 } catch (InterruptedException e) {
181
182 }
183 }
184
185 public void rest() {}
186
187 protected SoundProducer getFreeProducer() {
188 for (int i = 0; i < producers.size(); i++) {
190 if (!producers.elementAt(i).isAlive()) {
191 producers.remove(i);
192 }
193 }
194 SoundProducer sp = new SoundProducer();
196 producers.addElement(sp);
197 return sp;
198 }
199 }
200