m@0
|
1 /*=============================================================================
|
m@0
|
2 * File: Block.java
|
m@0
|
3 * Author: Marcus Pearce <m.pearce@gold.ac.uk>
|
m@0
|
4 * Created: <2008-01-07 10:38:45 marcusp>
|
marcus@16
|
5 * Time-stamp: <2011-12-09 17:59:20 marcusp>
|
m@0
|
6 *=============================================================================
|
m@0
|
7 */
|
m@0
|
8
|
m@0
|
9 import java.util.Collections;
|
m@0
|
10 import java.util.ArrayList;
|
m@0
|
11 import java.util.Iterator;
|
JShulver@23
|
12 import java.util.HashMap;
|
m@0
|
13 import java.io.*;
|
m@0
|
14
|
m@0
|
15 public class Block {
|
m@0
|
16
|
m@0
|
17 /* Label */
|
m@0
|
18 private String label;
|
m@0
|
19 private boolean writeResults;
|
m@0
|
20
|
m@0
|
21 /* the list of midi files, the current midi file and the midi directory*/
|
m@0
|
22 private FileList filelist;
|
m@0
|
23 private String filename;
|
m@0
|
24 private int melodyNumber;
|
m@0
|
25
|
m@0
|
26 /* The Experiment and GUI */
|
m@0
|
27 private ExperimentGui gui;
|
m@0
|
28 private Experiment exp;
|
m@0
|
29
|
m@0
|
30 /* The MidiPlayer */
|
m@0
|
31 private MidiPlayer mp;
|
m@0
|
32
|
m@0
|
33 /* Probe positions, note onsets, durations, IOIs and pitches */
|
JShulver@23
|
34 //private ArrayList probes, onsets, iois, durations, pitches, clockStartTimes;
|
JShulver@23
|
35 private ArrayList<Integer> iois, pitches;
|
JShulver@23
|
36 private ArrayList<Long> onsets, durations, clockStartTimes;
|
JShulver@23
|
37 private ArrayList<ProbeID> probes;
|
m@0
|
38 private long tatum;
|
m@0
|
39
|
m@0
|
40 /* The start of the song in nanoseconds */
|
m@0
|
41 private long startTime;
|
m@0
|
42
|
m@0
|
43 /* Results */
|
m@0
|
44 private MelodyResults mResults;
|
m@0
|
45
|
m@0
|
46 /* whether the current song has run yet or not */
|
m@0
|
47 private boolean hasRun;
|
m@0
|
48
|
m@0
|
49 /*
|
m@0
|
50 * Accessors
|
m@0
|
51 */
|
m@0
|
52 public String getLabel() { return label; }
|
m@0
|
53 public int getMelodyNumber() { return melodyNumber; }
|
m@0
|
54 public void setMelodyNumber(int n) { melodyNumber = n; }
|
m@0
|
55 public long getTatum() { return tatum; }
|
m@0
|
56 public MelodyResults getMelodyResults() { return mResults; }
|
m@0
|
57 public ArrayList getProbePositions() { return probes; }
|
JShulver@23
|
58 public ArrayList<Integer> getInterOnsetIntervals() { return iois; }
|
JShulver@23
|
59 public ArrayList<Long> getOnsets() { return onsets; }
|
JShulver@23
|
60 public ArrayList<Long> getClockStartTimes() { return clockStartTimes; }
|
m@4
|
61 public MidiPlayer getMidiPlayer() { return mp; }
|
m@0
|
62
|
m@0
|
63 /* set the start time in nanoseconds to NOW */
|
m@0
|
64 public long getStartTime() { return startTime; }
|
m@4
|
65 public void setStartTime() { startTime = System.nanoTime(); }
|
m@0
|
66
|
m@0
|
67 /*
|
m@0
|
68 * constructor
|
m@0
|
69 */
|
m@0
|
70 public Block(Experiment e, ExperimentGui eg, String fl, String lab,
|
m@0
|
71 boolean wr) {
|
m@0
|
72 // set-up variables
|
m@0
|
73 exp = e;
|
m@0
|
74 gui = eg;
|
m@0
|
75 label = lab;
|
m@0
|
76 filelist = new FileList(fl);
|
m@0
|
77 filename = (String)filelist.currentFile();
|
m@0
|
78 melodyNumber = 1;
|
m@0
|
79 writeResults = wr;
|
m@0
|
80 // initialise the block
|
m@0
|
81 hasRun = false;
|
m@0
|
82 initialiseBlock();
|
jeremy@27
|
83
|
jeremy@27
|
84 // Initialise the Midiplayer - already done in initialiseBlock?
|
jeremy@27
|
85 //mp = new MidiPlayer(exp.getMidiDirectory().concat(filename), exp.getMidiDeviceNumber(), false);
|
jeremy@27
|
86
|
m@0
|
87 // Write out stimulus structure for all melodies in block
|
marcus@16
|
88 //writeStimuli();
|
m@0
|
89 }
|
m@0
|
90
|
m@0
|
91 /* initialise the block */
|
m@0
|
92 public void initialiseBlock() {
|
jeremy@27
|
93 if (exp.getDebug())
|
jeremy@27
|
94 System.out.println("Initialising block for " + filename);
|
jeremy@27
|
95
|
m@0
|
96 // Initialise the Midiplayer
|
jeremy@27
|
97 mp = new MidiPlayer(exp.getMidiDirectory().concat(filename), exp.getMidiDeviceNumber(), false);
|
m@0
|
98 // Set up the melody structure and the probe positions
|
m@0
|
99 setupSong();
|
m@10
|
100 setupProbes();
|
m@10
|
101 if (exp.getDebug())
|
m@10
|
102 printProbes();
|
m@0
|
103 // Set up the results object for this melody
|
m@0
|
104 mResults = new MelodyResults(filename, probes,
|
m@0
|
105 onsets, iois, durations, pitches);
|
m@0
|
106 mResults.setSubjectID(exp.getSubjectID());
|
m@0
|
107 hasRun = false;
|
m@0
|
108 }
|
m@0
|
109
|
m@0
|
110 public void storeMelodyResult() {
|
m@0
|
111 if (writeResults && hasRun)
|
m@0
|
112 exp.addToSubjectResults(mResults);
|
m@0
|
113 }
|
m@0
|
114
|
m@0
|
115 private void setupSong() {
|
m@0
|
116 // Get the note IOI and Onset lists
|
m@0
|
117 onsets = mp.getOnsets();
|
m@0
|
118 durations = mp.getDurations();
|
m@0
|
119 iois = mp.getInterOnsetIntervals();
|
m@0
|
120 pitches = mp.getPitches();
|
m@10
|
121 tatum = mp.getTatum();
|
m@10
|
122 if (exp.getDebug())
|
jeremy@27
|
123 System.out.println("\nTatum = " + tatum);
|
m@0
|
124 }
|
m@0
|
125
|
m@0
|
126 private void setupProbes() {
|
m@0
|
127 ArrayList probePos = filelist.currentProbes();
|
m@0
|
128 Iterator ppi = probePos.iterator();
|
m@0
|
129
|
m@0
|
130 // By convention, the first probe position is the unexpected
|
m@0
|
131 // one and the second is the expected one.
|
m@0
|
132 //probeValues.add(ProbeID.PROBE_UNEX);
|
m@0
|
133 //probeValues.add(ProbeID.PROBE_EX);
|
m@0
|
134
|
m@0
|
135 ArrayList probeValues = new ArrayList(probePos.size());
|
m@0
|
136 for (int i = 0; i < probePos.size(); i++)
|
m@0
|
137 probeValues.add(ProbeID.PROBE);
|
m@0
|
138 Iterator pvi = probeValues.iterator();
|
m@0
|
139
|
m@0
|
140 // Set up probes
|
m@0
|
141 probes = new ArrayList(onsets.size());
|
m@0
|
142 for (int i = 0; i < onsets.size(); i++)
|
m@0
|
143 probes.add(ProbeID.NOT_PROBE);
|
m@0
|
144
|
m@0
|
145 while(ppi.hasNext()) {
|
m@10
|
146 int probe = ((Integer)ppi.next()).intValue();
|
jeremy@27
|
147 System.out.println(filename + ": probe at " + (probe + 1) + " out of " + onsets.size());
|
m@0
|
148 // probes.set(probe - numEvents, ProbeID.START_CLOCK);
|
JShulver@23
|
149
|
m@0
|
150 probes.set(probe - 1, ProbeID.BEFORE_PROBE);
|
m@0
|
151 probes.set(probe, (ProbeID)pvi.next());
|
marcus@16
|
152 if (probe < (onsets.size() - 1))
|
marcus@16
|
153 probes.set(probe + 1, ProbeID.AFTER_PROBE);
|
m@0
|
154 }
|
m@0
|
155
|
m@0
|
156 // Set up the clock start times
|
m@0
|
157 clockStartTimes = new ArrayList(probePos.size());
|
m@0
|
158 long clockTimeInMicroseconds =
|
m@0
|
159 (tatum * exp.getClockUnits() * exp.getNumUnits());
|
m@0
|
160 for (int i = 0; i < probePos.size(); i++) {
|
m@0
|
161 int ppos = ((Integer)probePos.get(i)).intValue();
|
m@0
|
162 long onset = ((Long)(onsets.get(ppos))).longValue();
|
m@10
|
163 clockStartTimes.add(onset - clockTimeInMicroseconds);
|
m@10
|
164 if (exp.getDebug())
|
m@10
|
165 System.out.println("ppos = " + ppos + "; onset = " + onset + "; clockTimeInMicroseconds = " + clockTimeInMicroseconds);
|
m@0
|
166 }
|
m@0
|
167 try {
|
m@0
|
168 Collections.sort(clockStartTimes);
|
m@0
|
169 } catch (Exception e) {
|
m@0
|
170 e.printStackTrace();
|
m@0
|
171 }
|
m@0
|
172 }
|
JShulver@23
|
173
|
m@0
|
174
|
m@0
|
175 public void printProbes() {
|
m@0
|
176 Iterator pi = probes.iterator();
|
jeremy@27
|
177 Iterator oi = onsets.iterator();
|
m@0
|
178
|
m@0
|
179 int i = 1;
|
jeremy@27
|
180 System.out.println("Events for " + filename + "...");
|
jeremy@27
|
181 while(pi.hasNext() && oi.hasNext()) {
|
jeremy@27
|
182 System.out.println("Event " + i + ": " + pi.next() + ", " + oi.next());
|
m@0
|
183 i++;
|
m@0
|
184 }
|
m@0
|
185 }
|
m@0
|
186
|
m@0
|
187 public String nextFile() {
|
m@0
|
188 filelist.incrementFileIndex();
|
m@0
|
189 filename = filelist.currentFile();
|
m@0
|
190 melodyNumber = melodyNumber + 1;
|
m@0
|
191 return filename;
|
m@0
|
192 }
|
m@0
|
193
|
m@0
|
194 /* add a reponse i and time t (nanoseconds) */
|
m@0
|
195 public void addResponse(int i, long t) {
|
m@5
|
196 //System.out.println("answer = " + i +
|
m@0
|
197 // "; responseTime = " + t +
|
m@0
|
198 // "; startTime = " + startTime +
|
m@0
|
199 // "; answer = " + (t - startTime) / 1000);
|
m@0
|
200 // add relative responseTime in microseconds
|
m@0
|
201 mResults.addResponse(i, (t - startTime) / 1000);
|
m@0
|
202 }
|
m@0
|
203
|
m@0
|
204 public void addMelodyQA(String q, String a) {
|
m@0
|
205 mResults.addQuestion(q);
|
m@0
|
206 mResults.addAnswer(a);
|
m@0
|
207 }
|
m@0
|
208
|
m@0
|
209 public void presentStimulus() {
|
m@0
|
210 // Start the experiment
|
m@4
|
211 //mp.stop();
|
m@0
|
212 setStartTime();
|
m@0
|
213 mp.play();
|
m@0
|
214 hasRun = true;
|
m@0
|
215
|
m@0
|
216 // Wait for midi file to stop playing
|
m@0
|
217 //try { Thread.sleep((mp.getLength() / 1000) + 2000); }
|
m@0
|
218 //catch (InterruptedException e) {}
|
m@0
|
219 }
|
m@0
|
220
|
m@0
|
221 public boolean isRunning() { return mp.getSequencer().isRunning(); }
|
m@0
|
222 public boolean hasRun() { return hasRun; }
|
m@0
|
223
|
m@0
|
224
|
m@0
|
225 /*
|
m@0
|
226 * Write out stimulus onsets and probe positions
|
m@0
|
227 */
|
m@0
|
228
|
m@0
|
229 public void writeStimuli() {
|
m@0
|
230 String midiFile;
|
m@0
|
231 while((midiFile = filelist.currentFile()) != null) {
|
m@0
|
232
|
m@0
|
233 Writer writer = null;
|
m@0
|
234 String composition = midiFile.substring(0, midiFile.length() - 4);
|
m@0
|
235 String outFile =
|
m@0
|
236 exp.RESULTS_DIRECTORY + File.separator +
|
m@0
|
237 "stimuli" + File.separator + composition
|
m@0
|
238 + ".onsets";
|
m@0
|
239 File outputFile = new File(outFile);
|
m@0
|
240
|
m@0
|
241 MidiPlayer midip =
|
jeremy@27
|
242 new MidiPlayer(exp.getMidiDirectory().concat(midiFile), exp.getMidiDeviceNumber(), false);
|
m@0
|
243
|
m@0
|
244 // Setup the probes
|
m@0
|
245 ArrayList probePos = filelist.currentProbes();
|
m@0
|
246 // Write the data
|
m@0
|
247 try {
|
m@0
|
248 writer = new FileWriter (outputFile, true);
|
m@0
|
249 } catch (IOException e) {
|
m@0
|
250 System.out.println("Could not write file: " +
|
m@0
|
251 outputFile.getPath());
|
m@0
|
252 return;
|
m@0
|
253 }
|
m@0
|
254 try {
|
m@0
|
255 writeResults(writer, midip, probePos, composition);
|
m@0
|
256 writer.close();
|
m@0
|
257 } catch (IOException e) {
|
m@0
|
258 System.out.println (e.getMessage());
|
m@0
|
259 return;
|
m@0
|
260 }
|
m@0
|
261 // increment the file index
|
m@0
|
262 filelist.incrementFileIndex();
|
m@0
|
263 }
|
m@0
|
264 // Reset filelist
|
m@0
|
265 filelist.setFileIndex(0);
|
m@0
|
266 }
|
m@0
|
267
|
m@0
|
268 private void writeResults(Writer w, MidiPlayer mipl, ArrayList probePos,
|
m@0
|
269 String composition)
|
m@0
|
270 throws IOException {
|
m@0
|
271
|
m@0
|
272 System.out.println(composition);
|
m@0
|
273
|
m@0
|
274 ArrayList ons = mipl.getOnsets();
|
m@0
|
275 ArrayList pits = mipl.getPitches();
|
m@0
|
276
|
m@0
|
277 Iterator oi = ons.iterator();
|
m@0
|
278 Iterator piti = pits.iterator();
|
m@0
|
279
|
m@0
|
280 // setup probes
|
m@0
|
281 Iterator ppi = probePos.iterator();
|
m@0
|
282
|
m@0
|
283 // By convention, the first probe position is the unexpected
|
m@0
|
284 // one and the second is the expected one.
|
m@0
|
285 // probeValues.add(ProbeID.PROBE_UNEX);
|
m@0
|
286 // probeValues.add(ProbeID.PROBE_EX);
|
m@0
|
287
|
m@0
|
288 ArrayList probeValues = new ArrayList(probePos.size());
|
m@0
|
289 for (int i = 0; i < probePos.size(); i++)
|
m@0
|
290 probeValues.add(ProbeID.PROBE);
|
m@0
|
291
|
m@0
|
292 Iterator pvi = probeValues.iterator();
|
m@0
|
293
|
m@0
|
294 ArrayList pprobes = new ArrayList(ons.size());
|
m@0
|
295 for (int i = 0; i < ons.size(); i++)
|
m@0
|
296 pprobes.add(ProbeID.NOT_PROBE);
|
m@0
|
297
|
m@0
|
298 while(ppi.hasNext()) {
|
m@0
|
299 int probe = ((Integer)ppi.next()).intValue();
|
m@0
|
300 pprobes.set(probe - 1, ProbeID.BEFORE_PROBE);
|
m@0
|
301 pprobes.set(probe, (ProbeID)pvi.next());
|
m@0
|
302 pprobes.set(probe + 1, ProbeID.AFTER_PROBE);
|
m@0
|
303 }
|
m@0
|
304
|
m@0
|
305 Iterator pi = pprobes.iterator();
|
m@0
|
306 int eventIndex = 1;
|
m@0
|
307
|
m@0
|
308 //writeHeader(w);
|
JShulver@23
|
309 //might be sensible to create the hashmap somewhere else
|
JShulver@23
|
310 HashMap<ProbeID, Integer> idMap = new HashMap<ProbeID, Integer>();
|
JShulver@23
|
311 idMap.put(ProbeID.NOT_PROBE, 0);
|
JShulver@23
|
312 idMap.put(ProbeID.START_CLOCK, 0);
|
JShulver@23
|
313 idMap.put(ProbeID.BEFORE_PROBE, 0);
|
JShulver@23
|
314 idMap.put(ProbeID.AFTER_PROBE, 0);
|
JShulver@23
|
315 idMap.put(ProbeID.PROBE, 1);
|
JShulver@23
|
316 idMap.put(ProbeID.PROBE_EX, 2);
|
JShulver@23
|
317 idMap.put(ProbeID.PROBE_UNEX, 1);
|
m@0
|
318 while(oi.hasNext()) {
|
m@0
|
319 long onset = ((Long)oi.next()).longValue();
|
m@0
|
320 int pitch = ((Integer)piti.next()).intValue();
|
m@0
|
321
|
m@0
|
322 ProbeID p = (ProbeID)pi.next();
|
m@0
|
323
|
m@0
|
324 int probe = 0;
|
m@0
|
325
|
JShulver@23
|
326 if(idMap.containsKey(p))
|
JShulver@23
|
327 {
|
JShulver@23
|
328 probe = idMap.get(p);
|
JShulver@23
|
329 System.out.println("Adding probe: ");
|
m@0
|
330 }
|
JShulver@23
|
331
|
JShulver@23
|
332 else
|
JShulver@23
|
333 System.out.println("Unexpected probe id: " + p);
|
JShulver@23
|
334
|
JShulver@23
|
335
|
m@0
|
336 w.write(composition + " " + eventIndex + " " +
|
m@0
|
337 onset + " " + pitch + " " +
|
m@0
|
338 probe + "\n");
|
m@0
|
339 eventIndex++;
|
m@0
|
340 }
|
m@0
|
341 }
|
m@0
|
342
|
m@0
|
343 private void writeHeader(Writer w) throws IOException {
|
m@0
|
344 w.write("melody note " +
|
m@0
|
345 "onset pitch " +
|
m@0
|
346 "probe");
|
m@0
|
347 w.write("\n");
|
m@0
|
348 }
|
m@0
|
349
|
m@0
|
350 }
|
m@0
|
351
|