m@0
|
1 /*=============================================================================
|
m@0
|
2 * File: Experiment.java
|
m@0
|
3 * Author: Marcus Pearce <m.pearce@gold.ac.uk>
|
m@0
|
4 * Created: <2007-02-14 11:28:27 marcusp>
|
marcus@50
|
5 * Time-stamp: <2015-02-25 09:43:12 marcusp>
|
m@0
|
6 *=============================================================================
|
m@0
|
7 */
|
m@0
|
8
|
m@0
|
9 import java.io.*;
|
m@0
|
10 import javax.swing.UIManager;
|
m@0
|
11 import java.awt.*;
|
jeremy@27
|
12 import javax.sound.midi.*;
|
CBussey@39
|
13 import java.util.Scanner;
|
m@0
|
14
|
m@0
|
15 public class Experiment {
|
m@0
|
16
|
m@0
|
17 /* pathnames */
|
m@0
|
18 private final String BASE_DIRECTORY =
|
m@0
|
19 new File("").getAbsolutePath() + File.separator;
|
marcus@14
|
20 private final String DATA_DIRECTORY =
|
marcus@14
|
21 BASE_DIRECTORY + "Data" + File.separator;
|
m@4
|
22
|
marcus@14
|
23 public String RESULTS_DIRECTORY =
|
m@0
|
24 BASE_DIRECTORY + "Results" + File.separator;
|
marcus@14
|
25 public String RESULTS_EXTENSION = ".dat";
|
marcus@14
|
26 public String SUBJECT_RESULTS_FILE =
|
m@0
|
27 RESULTS_DIRECTORY + "subjects" + RESULTS_EXTENSION;
|
c@48
|
28
|
m@7
|
29 public String INSTRUCTIONS_FILE =
|
m@0
|
30 DATA_DIRECTORY + "instructions.html";
|
m@4
|
31
|
m@4
|
32 public String MIDI_DIRECTORY =
|
m@4
|
33 DATA_DIRECTORY + "Midi" + File.separator;
|
m@4
|
34 public String MIDIFILELIST_FILE =
|
m@4
|
35 MIDI_DIRECTORY + "filelist.txt";
|
m@4
|
36 public String PRACTICE_MIDIFILELIST_FILE =
|
c@48
|
37 MIDI_DIRECTORY + "pfilelist.txt";
|
c@48
|
38 public String POST_SCRIPT;
|
m@4
|
39
|
m@0
|
40
|
m@0
|
41 /* The GUI */
|
c@41
|
42 private ExperimentGui gui;
|
c@41
|
43 private boolean fullScreen;
|
m@0
|
44
|
m@3
|
45 /* whether to show the clock */
|
m@3
|
46 private boolean showClock;
|
m@0
|
47 /* the units of the clock as multiples of the tatum */
|
m@0
|
48 private int clockUnits;
|
m@0
|
49 /* number of units that clock runs for before a probe event */
|
m@0
|
50 private int numUnits;
|
m@0
|
51
|
m@8
|
52 /* whether to ask about familiarity of each song */
|
m@8
|
53 private boolean askFamiliarity;
|
m@8
|
54 /* whether to ask about liking of each song */
|
m@8
|
55 private boolean askLiking;
|
m@8
|
56 /* whether to include final questionnaire */
|
m@8
|
57 private boolean finalQuestionnaire;
|
m@8
|
58
|
m@0
|
59 /* the blocks of the experiment */
|
m@0
|
60 Block[] blocks;
|
m@0
|
61 int currentBlockID;
|
m@0
|
62
|
m@0
|
63 /* Subject ID */
|
jeremy@37
|
64 private String subjectID;
|
m@0
|
65
|
m@0
|
66 /* Results */
|
m@0
|
67 private SubjectResults results;
|
m@0
|
68
|
m@0
|
69 /* the details of the rating scale */
|
m@0
|
70 private int scaleLength;
|
m@0
|
71 private String lowAnchor;
|
m@0
|
72 private String highAnchor;
|
m@0
|
73
|
m@1
|
74 /* the midi device */
|
m@1
|
75 private int midiDevice;
|
c@41
|
76
|
m@10
|
77 /* debugging */
|
jeremy@32
|
78 private boolean debug;
|
c@48
|
79
|
c@48
|
80 /* Post-run script */
|
c@48
|
81 private boolean runPostScript;
|
m@10
|
82
|
m@0
|
83 /* accessors */
|
m@10
|
84 public boolean getDebug() { return debug; }
|
m@8
|
85 public boolean getAskLiking() { return askLiking; }
|
m@8
|
86 public boolean getAskFamiliarity() { return askFamiliarity; }
|
m@8
|
87 public boolean getFinalQuestionnaire() { return finalQuestionnaire; }
|
m@8
|
88
|
m@1
|
89 public int getMidiDeviceNumber() { return midiDevice; }
|
m@0
|
90 public int getScaleLength() { return scaleLength; }
|
m@0
|
91 public String getLowAnchor() { return lowAnchor; }
|
m@0
|
92 public String getHighAnchor() { return highAnchor; }
|
m@0
|
93
|
m@0
|
94 public String getMidiDirectory() { return MIDI_DIRECTORY; }
|
m@0
|
95 public SubjectResults getSubjectResults() { return results; }
|
m@0
|
96 public Block getCurrentBlock() { return blocks[currentBlockID]; }
|
m@0
|
97 public int getCurrentBlockID() { return currentBlockID + 1; }
|
m@3
|
98 public boolean showClock() { return showClock; }
|
m@0
|
99 public int getClockUnits() { return clockUnits; }
|
m@0
|
100 public int getNumUnits() { return numUnits; }
|
m@0
|
101 public String getInstructionsFile() { return INSTRUCTIONS_FILE; }
|
jeremy@37
|
102 public String getSubjectID() { return subjectID; }
|
c@48
|
103 public boolean getRunPostScript() { return runPostScript; }
|
jeremy@37
|
104 public void setSubjectID(String id) {
|
m@0
|
105 subjectID = id;
|
m@0
|
106 results.setSubjectID(id);
|
c@45
|
107 results.setOutputFile(id);
|
c@45
|
108 results.setSubjectDataFile(id);
|
m@0
|
109 getCurrentBlock().getMelodyResults().setSubjectID(id);
|
jeremy@27
|
110 System.out.println("Subject ID = " + subjectID);
|
m@0
|
111 }
|
m@0
|
112
|
m@0
|
113 /* Constructor */
|
c@48
|
114 public Experiment (int sc, int cu, int nu, int sl, int md, String la, String ha, String mfd, String inf, String rdr, int fam, int lik, int quest, int fs, String ps, int de) {
|
m@0
|
115
|
m@0
|
116 // Setup variables
|
jeremy@32
|
117 debug = (de != 0);
|
m@0
|
118 results = new SubjectResults(this);
|
m@3
|
119 if (sc == 0)
|
m@3
|
120 showClock = false;
|
m@3
|
121 else
|
m@3
|
122 showClock = true;
|
jeremy@33
|
123 clockUnits = positiveInteger(cu, 1);
|
jeremy@33
|
124 numUnits = positiveInteger(nu, 4);
|
jeremy@33
|
125 scaleLength = positiveInteger(sl, 7);
|
m@1
|
126 midiDevice = md;
|
m@0
|
127 lowAnchor = la;
|
m@0
|
128 highAnchor = ha;
|
m@4
|
129 MIDI_DIRECTORY = mfd + File.separator;
|
m@4
|
130 MIDIFILELIST_FILE = MIDI_DIRECTORY + "filelist.txt";
|
m@4
|
131 PRACTICE_MIDIFILELIST_FILE = MIDI_DIRECTORY + "pfilelist.txt";
|
m@7
|
132 INSTRUCTIONS_FILE = inf;
|
marcus@14
|
133 RESULTS_DIRECTORY = rdr + File.separator;
|
m@8
|
134
|
c@41
|
135 if (fs == 0)
|
c@41
|
136 fullScreen = false;
|
c@41
|
137 else
|
c@41
|
138 fullScreen = true;
|
c@48
|
139 if (ps.equals("0"))
|
c@48
|
140 runPostScript = false;
|
c@48
|
141 else{
|
c@48
|
142 runPostScript = true;
|
c@48
|
143 POST_SCRIPT = ps;
|
c@48
|
144 }
|
m@8
|
145 if (fam == 0)
|
m@8
|
146 askFamiliarity = false;
|
m@8
|
147 else
|
m@8
|
148 askFamiliarity = true;
|
m@8
|
149 if (lik == 0)
|
m@8
|
150 askLiking = false;
|
m@8
|
151 else
|
m@8
|
152 askLiking = true;
|
m@8
|
153 if (quest == 0)
|
m@8
|
154 finalQuestionnaire = false;
|
m@8
|
155 else
|
m@8
|
156 finalQuestionnaire = true;
|
m@0
|
157
|
jeremy@32
|
158 if (debug)
|
jeremy@32
|
159 displayMIDIDevices();
|
jeremy@32
|
160
|
m@0
|
161 // Initialise the experiment
|
m@0
|
162 Block practice = new Block(this, gui, PRACTICE_MIDIFILELIST_FILE,
|
m@0
|
163 "Practice", false);
|
m@0
|
164 Block main = new Block(this, gui, MIDIFILELIST_FILE,
|
m@0
|
165 "Main", true);
|
m@0
|
166 blocks = new Block[2];
|
m@0
|
167 blocks[0] = practice;
|
m@0
|
168 blocks[1] = main;
|
m@0
|
169 currentBlockID = 0;
|
m@0
|
170
|
m@0
|
171 // Create the GUI
|
m@0
|
172 gui = new ExperimentGui(this);
|
m@0
|
173 }
|
m@0
|
174
|
m@0
|
175 public Boolean nextBlock() {
|
m@0
|
176 boolean lastBlock = true;
|
m@0
|
177 if (currentBlockID + 1 < blocks.length)
|
m@0
|
178 currentBlockID = currentBlockID + 1;
|
m@0
|
179 else
|
m@0
|
180 lastBlock = false;
|
m@0
|
181 return lastBlock;
|
m@0
|
182 }
|
m@0
|
183
|
m@0
|
184 public void addToSubjectResults(MelodyResults mr) { results.addResult(mr); }
|
m@0
|
185
|
m@0
|
186 public void runExperiment () {
|
m@0
|
187 (new Thread(gui)).start();
|
m@0
|
188 getCurrentBlock().presentStimulus();
|
m@0
|
189 }
|
jeremy@27
|
190 public boolean isRunning() {
|
jeremy@27
|
191 Block cur = getCurrentBlock();;
|
jeremy@27
|
192 return cur != null && cur.isRunning();
|
jeremy@27
|
193 }
|
jeremy@27
|
194
|
jeremy@27
|
195 public boolean hasRun() {
|
jeremy@27
|
196 Block cur = getCurrentBlock();
|
jeremy@29
|
197 return cur == null || cur.hasRun();
|
jeremy@27
|
198 }
|
m@0
|
199
|
m@0
|
200 /* Show the GUI */
|
c@41
|
201 public void showGUI(int width, int height) {
|
c@41
|
202 GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
|
c@41
|
203 if(fullScreen){
|
c@41
|
204 if (gd.isFullScreenSupported()) {
|
c@41
|
205 System.out.println("Entering full Screen... Press <enter> to continue.");
|
c@41
|
206 Scanner scanner = new Scanner(System.in);
|
c@41
|
207 scanner.nextLine();
|
c@41
|
208 gui.setUndecorated(true);
|
c@41
|
209 gd.setFullScreenWindow(gui);
|
c@41
|
210 } else {
|
c@41
|
211 System.out.println("Not Full Screen Supported :(");
|
c@41
|
212 showDefaultGUI(width, height);
|
c@41
|
213 }
|
c@41
|
214 }
|
c@41
|
215 else{
|
c@41
|
216 showDefaultGUI(width, height);
|
c@41
|
217 }
|
c@41
|
218 }
|
c@41
|
219
|
c@41
|
220 public void showDefaultGUI(int width, int height) {
|
m@0
|
221 gui.pack();
|
c@41
|
222 gui.setSize(width, height);
|
m@0
|
223 // UIManager.put("Button.focus", UIManager.get("Button.select"));
|
m@0
|
224 gui.setVisible(true);
|
c@41
|
225 }
|
m@0
|
226
|
c@41
|
227 /* Main method */
|
m@0
|
228 public static void main(String[] args) {
|
marcus@49
|
229
|
marcus@49
|
230 Toolkit.getDefaultToolkit();
|
jeremy@36
|
231
|
c@45
|
232 System.out.println("Working Directory = " +
|
c@45
|
233 System.getProperty("user.dir"));
|
c@45
|
234
|
marcus@50
|
235 int nargs = 16;
|
marcus@50
|
236
|
marcus@50
|
237 if (args.length == nargs) {
|
jeremy@36
|
238
|
m@0
|
239 // Parse Arguments
|
m@3
|
240 int n = 0;
|
m@3
|
241 int sc = Integer.parseInt(args[n++]);
|
m@0
|
242 int cu = Integer.parseInt(args[n++]);
|
m@0
|
243 int nu = Integer.parseInt(args[n++]);
|
CBussey@39
|
244 String mdInput = args[n++];
|
CBussey@39
|
245 int md = -1;
|
m@0
|
246 int sl = Integer.parseInt(args[n++]);
|
m@0
|
247 String la = args[n++];
|
m@0
|
248 String ha = args[n++];
|
m@4
|
249 String mfd = args[n++];
|
m@7
|
250 String inf = args[n++];
|
marcus@14
|
251 String rdr = args[n++];
|
m@8
|
252 int fam = Integer.parseInt(args[n++]);
|
m@8
|
253 int lik = Integer.parseInt(args[n++]);
|
m@8
|
254 int quest = Integer.parseInt(args[n++]);
|
c@41
|
255 int fs = Integer.parseInt(args[n++]);
|
c@48
|
256 String ps = args[n++];
|
jeremy@32
|
257 int de = Integer.parseInt(args[n++]);
|
m@0
|
258
|
CBussey@39
|
259 if(isBooleanFormat(mdInput)){
|
CBussey@39
|
260 boolean defaultMD = Boolean.parseBoolean(mdInput);
|
CBussey@39
|
261
|
CBussey@39
|
262 if(!defaultMD){
|
CBussey@39
|
263 displayMIDIDevices();
|
CBussey@39
|
264 System.out.print("Specify the desired MIDI Device: ");
|
CBussey@39
|
265 Scanner scan = new Scanner(System.in);
|
CBussey@39
|
266 String input = scan.next();
|
CBussey@39
|
267
|
CBussey@39
|
268 while(!isMIDIDevice(input)){
|
CBussey@39
|
269 System.out.print("Enter a valid input:");
|
CBussey@39
|
270 input = scan.next();
|
CBussey@39
|
271 }
|
CBussey@39
|
272 md = Integer.parseInt(input);
|
CBussey@39
|
273 }
|
CBussey@39
|
274 else{
|
CBussey@39
|
275 md = -1;
|
CBussey@39
|
276 }
|
CBussey@39
|
277 }
|
CBussey@39
|
278 else if(isMIDIDevice(mdInput)){
|
CBussey@39
|
279 md = Integer.parseInt(mdInput);
|
CBussey@39
|
280 }
|
CBussey@39
|
281 else{
|
marcus@50
|
282 System.out.println("Unexpected number of arguments: " + args.length + ". Should be " + nargs + ".");
|
CBussey@39
|
283 showUsage();
|
CBussey@39
|
284 }
|
CBussey@39
|
285
|
m@0
|
286 // Create experiment
|
c@48
|
287 Experiment exp = new Experiment(sc, cu, nu, sl, md, la, ha, mfd, inf, rdr, fam, lik, quest, fs, ps, de);
|
m@0
|
288
|
m@0
|
289 // Show the GUI
|
m@0
|
290 int width=(int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
|
m@0
|
291 int height=(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight();
|
m@0
|
292 exp.showGUI(width, height);
|
jeremy@36
|
293
|
jeremy@36
|
294 } else {
|
CBussey@39
|
295 showUsage();
|
jeremy@36
|
296 }
|
m@0
|
297 }
|
CBussey@39
|
298
|
CBussey@39
|
299 public static void showUsage(){
|
CBussey@39
|
300 System.out.println("Usage: " + "\t" + "java Experiment " +
|
CBussey@39
|
301 "<show clock?> <clock units> <number of units> " +
|
CBussey@39
|
302 "<default MIDI device?> " +
|
CBussey@39
|
303 "<scale length> <low anchor> <high anchor> " +
|
c@41
|
304 "<midi file directory> <instructions file> <results directory> " +
|
c@48
|
305 " <familiarity> " + " <pleasantness> " + " <questionnaire> " + " <fullscreen> " + " <post-run script> " + " <debug>");
|
CBussey@39
|
306 System.exit(1);
|
CBussey@39
|
307 }
|
jeremy@27
|
308
|
jeremy@27
|
309 /*
|
jeremy@27
|
310 * Print a list of accessible MIDI devices
|
jeremy@27
|
311 */
|
CBussey@39
|
312 public static void displayMIDIDevices() {
|
jeremy@27
|
313 System.out.println("Searching for MIDI devices...");
|
jeremy@27
|
314
|
jeremy@27
|
315 MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo();
|
jeremy@27
|
316 if (devices.length == 0) {
|
jeremy@27
|
317 System.out.println("No MIDI devices found");
|
jeremy@27
|
318 } else {
|
CBussey@39
|
319 for (int i=0; i<devices.length; i++) {
|
CBussey@39
|
320 MidiDevice.Info m = devices[i];
|
c@40
|
321 System.out.println(i+". MIDI device: " + m.getName() + " - " + m.getDescription());
|
jeremy@27
|
322 }
|
jeremy@27
|
323 }
|
jeremy@27
|
324 }
|
CBussey@39
|
325
|
CBussey@39
|
326 public static boolean isBooleanFormat(String s){
|
CBussey@39
|
327 if(s.toLowerCase().equals("true") || s.toLowerCase().equals("false")){
|
CBussey@39
|
328 return true;
|
CBussey@39
|
329 }
|
CBussey@39
|
330 else {
|
CBussey@39
|
331 return false;
|
CBussey@39
|
332 }
|
CBussey@39
|
333 }
|
CBussey@39
|
334
|
CBussey@39
|
335 public static boolean isMIDIDevice(String dev){
|
CBussey@39
|
336 boolean output;
|
CBussey@39
|
337 MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo();
|
CBussey@39
|
338
|
CBussey@39
|
339 try {
|
CBussey@39
|
340 int device = Integer.parseInt(dev);
|
CBussey@39
|
341 if(device>devices.length-1 || device<0){
|
CBussey@39
|
342 output = false;
|
CBussey@39
|
343 }
|
CBussey@39
|
344 else { output = true; }
|
CBussey@39
|
345 } catch(NumberFormatException e) {
|
CBussey@39
|
346 output = false;
|
CBussey@39
|
347 }
|
CBussey@39
|
348 return output;
|
CBussey@39
|
349 }
|
jeremy@27
|
350
|
jeremy@33
|
351 private int positiveInteger(int x, int def) {
|
jeremy@33
|
352 if (x > 0)
|
jeremy@33
|
353 return x;
|
jeremy@33
|
354 else
|
jeremy@33
|
355 return def;
|
jeremy@33
|
356 }
|
jeremy@33
|
357
|
m@0
|
358 }
|