m@0: /*============================================================================= m@0: * File: Block.java m@0: * Author: Marcus Pearce m@0: * Created: <2008-01-07 10:38:45 marcusp> marcus@16: * Time-stamp: <2011-12-09 17:59:20 marcusp> m@0: *============================================================================= m@0: */ m@0: m@0: import java.util.Collections; m@0: import java.util.ArrayList; m@0: import java.util.Iterator; JShulver@23: import java.util.HashMap; m@0: import java.io.*; m@0: m@0: public class Block { m@0: m@0: /* Label */ m@0: private String label; m@0: private boolean writeResults; m@0: m@0: /* the list of midi files, the current midi file and the midi directory*/ m@0: private FileList filelist; m@0: private String filename; m@0: private int melodyNumber; m@0: m@0: /* The Experiment and GUI */ m@0: private ExperimentGui gui; m@0: private Experiment exp; m@0: m@0: /* The MidiPlayer */ m@0: private MidiPlayer mp; m@0: m@0: /* Probe positions, note onsets, durations, IOIs and pitches */ JShulver@23: //private ArrayList probes, onsets, iois, durations, pitches, clockStartTimes; JShulver@23: private ArrayList iois, pitches; JShulver@23: private ArrayList onsets, durations, clockStartTimes; JShulver@23: private ArrayList probes; m@0: private long tatum; m@0: m@0: /* The start of the song in nanoseconds */ m@0: private long startTime; m@0: m@0: /* Results */ m@0: private MelodyResults mResults; m@0: m@0: /* whether the current song has run yet or not */ m@0: private boolean hasRun; m@0: m@0: /* m@0: * Accessors m@0: */ m@0: public String getLabel() { return label; } m@0: public int getMelodyNumber() { return melodyNumber; } m@0: public void setMelodyNumber(int n) { melodyNumber = n; } m@0: public long getTatum() { return tatum; } m@0: public MelodyResults getMelodyResults() { return mResults; } m@0: public ArrayList getProbePositions() { return probes; } JShulver@23: public ArrayList getInterOnsetIntervals() { return iois; } JShulver@23: public ArrayList getOnsets() { return onsets; } JShulver@23: public ArrayList getClockStartTimes() { return clockStartTimes; } m@4: public MidiPlayer getMidiPlayer() { return mp; } m@0: m@0: /* set the start time in nanoseconds to NOW */ m@0: public long getStartTime() { return startTime; } m@4: public void setStartTime() { startTime = System.nanoTime(); } m@0: m@0: /* m@0: * constructor m@0: */ m@0: public Block(Experiment e, ExperimentGui eg, String fl, String lab, m@0: boolean wr) { m@0: // set-up variables m@0: exp = e; m@0: gui = eg; m@0: label = lab; m@0: filelist = new FileList(fl); m@0: filename = (String)filelist.currentFile(); m@0: melodyNumber = 1; m@0: writeResults = wr; m@0: // initialise the block m@0: hasRun = false; m@0: initialiseBlock(); jeremy@27: jeremy@27: // Initialise the Midiplayer - already done in initialiseBlock? jeremy@27: //mp = new MidiPlayer(exp.getMidiDirectory().concat(filename), exp.getMidiDeviceNumber(), false); jeremy@27: m@0: // Write out stimulus structure for all melodies in block marcus@16: //writeStimuli(); m@0: } m@0: m@0: /* initialise the block */ m@0: public void initialiseBlock() { jeremy@27: if (exp.getDebug()) jeremy@27: System.out.println("Initialising block for " + filename); jeremy@27: m@0: // Initialise the Midiplayer jeremy@27: mp = new MidiPlayer(exp.getMidiDirectory().concat(filename), exp.getMidiDeviceNumber(), false); m@0: // Set up the melody structure and the probe positions m@0: setupSong(); m@10: setupProbes(); m@10: if (exp.getDebug()) m@10: printProbes(); m@0: // Set up the results object for this melody m@0: mResults = new MelodyResults(filename, probes, m@0: onsets, iois, durations, pitches); m@0: mResults.setSubjectID(exp.getSubjectID()); m@0: hasRun = false; m@0: } m@0: m@0: public void storeMelodyResult() { m@0: if (writeResults && hasRun) m@0: exp.addToSubjectResults(mResults); m@0: } m@0: m@0: private void setupSong() { m@0: // Get the note IOI and Onset lists m@0: onsets = mp.getOnsets(); m@0: durations = mp.getDurations(); m@0: iois = mp.getInterOnsetIntervals(); m@0: pitches = mp.getPitches(); m@10: tatum = mp.getTatum(); m@10: if (exp.getDebug()) jeremy@27: System.out.println("\nTatum = " + tatum); m@0: } m@0: m@0: private void setupProbes() { m@0: ArrayList probePos = filelist.currentProbes(); m@0: Iterator ppi = probePos.iterator(); m@0: m@0: // By convention, the first probe position is the unexpected m@0: // one and the second is the expected one. m@0: //probeValues.add(ProbeID.PROBE_UNEX); m@0: //probeValues.add(ProbeID.PROBE_EX); m@0: m@0: ArrayList probeValues = new ArrayList(probePos.size()); m@0: for (int i = 0; i < probePos.size(); i++) m@0: probeValues.add(ProbeID.PROBE); m@0: Iterator pvi = probeValues.iterator(); m@0: m@0: // Set up probes m@0: probes = new ArrayList(onsets.size()); m@0: for (int i = 0; i < onsets.size(); i++) m@0: probes.add(ProbeID.NOT_PROBE); m@0: m@0: while(ppi.hasNext()) { m@10: int probe = ((Integer)ppi.next()).intValue(); jeremy@27: System.out.println(filename + ": probe at " + (probe + 1) + " out of " + onsets.size()); m@0: // probes.set(probe - numEvents, ProbeID.START_CLOCK); JShulver@23: m@0: probes.set(probe - 1, ProbeID.BEFORE_PROBE); m@0: probes.set(probe, (ProbeID)pvi.next()); marcus@16: if (probe < (onsets.size() - 1)) marcus@16: probes.set(probe + 1, ProbeID.AFTER_PROBE); m@0: } m@0: m@0: // Set up the clock start times m@0: clockStartTimes = new ArrayList(probePos.size()); m@0: long clockTimeInMicroseconds = m@0: (tatum * exp.getClockUnits() * exp.getNumUnits()); m@0: for (int i = 0; i < probePos.size(); i++) { m@0: int ppos = ((Integer)probePos.get(i)).intValue(); m@0: long onset = ((Long)(onsets.get(ppos))).longValue(); m@10: clockStartTimes.add(onset - clockTimeInMicroseconds); m@10: if (exp.getDebug()) m@10: System.out.println("ppos = " + ppos + "; onset = " + onset + "; clockTimeInMicroseconds = " + clockTimeInMicroseconds); m@0: } m@0: try { m@0: Collections.sort(clockStartTimes); m@0: } catch (Exception e) { m@0: e.printStackTrace(); m@0: } m@0: } JShulver@23: m@0: m@0: public void printProbes() { m@0: Iterator pi = probes.iterator(); jeremy@27: Iterator oi = onsets.iterator(); m@0: m@0: int i = 1; jeremy@27: System.out.println("Events for " + filename + "..."); jeremy@27: while(pi.hasNext() && oi.hasNext()) { jeremy@27: System.out.println("Event " + i + ": " + pi.next() + ", " + oi.next()); m@0: i++; m@0: } m@0: } m@0: m@0: public String nextFile() { m@0: filelist.incrementFileIndex(); m@0: filename = filelist.currentFile(); m@0: melodyNumber = melodyNumber + 1; m@0: return filename; m@0: } m@0: m@0: /* add a reponse i and time t (nanoseconds) */ m@0: public void addResponse(int i, long t) { m@5: //System.out.println("answer = " + i + m@0: // "; responseTime = " + t + m@0: // "; startTime = " + startTime + m@0: // "; answer = " + (t - startTime) / 1000); m@0: // add relative responseTime in microseconds m@0: mResults.addResponse(i, (t - startTime) / 1000); m@0: } m@0: m@0: public void addMelodyQA(String q, String a) { m@0: mResults.addQuestion(q); m@0: mResults.addAnswer(a); m@0: } m@0: m@0: public void presentStimulus() { m@0: // Start the experiment m@4: //mp.stop(); m@0: setStartTime(); m@0: mp.play(); m@0: hasRun = true; m@0: m@0: // Wait for midi file to stop playing m@0: //try { Thread.sleep((mp.getLength() / 1000) + 2000); } m@0: //catch (InterruptedException e) {} m@0: } m@0: m@0: public boolean isRunning() { return mp.getSequencer().isRunning(); } m@0: public boolean hasRun() { return hasRun; } m@0: m@0: m@0: /* m@0: * Write out stimulus onsets and probe positions m@0: */ m@0: m@0: public void writeStimuli() { m@0: String midiFile; m@0: while((midiFile = filelist.currentFile()) != null) { m@0: m@0: Writer writer = null; m@0: String composition = midiFile.substring(0, midiFile.length() - 4); m@0: String outFile = m@0: exp.RESULTS_DIRECTORY + File.separator + m@0: "stimuli" + File.separator + composition m@0: + ".onsets"; m@0: File outputFile = new File(outFile); m@0: m@0: MidiPlayer midip = jeremy@27: new MidiPlayer(exp.getMidiDirectory().concat(midiFile), exp.getMidiDeviceNumber(), false); m@0: m@0: // Setup the probes m@0: ArrayList probePos = filelist.currentProbes(); m@0: // Write the data m@0: try { m@0: writer = new FileWriter (outputFile, true); m@0: } catch (IOException e) { m@0: System.out.println("Could not write file: " + m@0: outputFile.getPath()); m@0: return; m@0: } m@0: try { m@0: writeResults(writer, midip, probePos, composition); m@0: writer.close(); m@0: } catch (IOException e) { m@0: System.out.println (e.getMessage()); m@0: return; m@0: } m@0: // increment the file index m@0: filelist.incrementFileIndex(); m@0: } m@0: // Reset filelist m@0: filelist.setFileIndex(0); m@0: } m@0: m@0: private void writeResults(Writer w, MidiPlayer mipl, ArrayList probePos, m@0: String composition) m@0: throws IOException { m@0: m@0: System.out.println(composition); m@0: m@0: ArrayList ons = mipl.getOnsets(); m@0: ArrayList pits = mipl.getPitches(); m@0: m@0: Iterator oi = ons.iterator(); m@0: Iterator piti = pits.iterator(); m@0: m@0: // setup probes m@0: Iterator ppi = probePos.iterator(); m@0: m@0: // By convention, the first probe position is the unexpected m@0: // one and the second is the expected one. m@0: // probeValues.add(ProbeID.PROBE_UNEX); m@0: // probeValues.add(ProbeID.PROBE_EX); m@0: m@0: ArrayList probeValues = new ArrayList(probePos.size()); m@0: for (int i = 0; i < probePos.size(); i++) m@0: probeValues.add(ProbeID.PROBE); m@0: m@0: Iterator pvi = probeValues.iterator(); m@0: m@0: ArrayList pprobes = new ArrayList(ons.size()); m@0: for (int i = 0; i < ons.size(); i++) m@0: pprobes.add(ProbeID.NOT_PROBE); m@0: m@0: while(ppi.hasNext()) { m@0: int probe = ((Integer)ppi.next()).intValue(); m@0: pprobes.set(probe - 1, ProbeID.BEFORE_PROBE); m@0: pprobes.set(probe, (ProbeID)pvi.next()); m@0: pprobes.set(probe + 1, ProbeID.AFTER_PROBE); m@0: } m@0: m@0: Iterator pi = pprobes.iterator(); m@0: int eventIndex = 1; m@0: m@0: //writeHeader(w); JShulver@23: //might be sensible to create the hashmap somewhere else JShulver@23: HashMap idMap = new HashMap(); JShulver@23: idMap.put(ProbeID.NOT_PROBE, 0); JShulver@23: idMap.put(ProbeID.START_CLOCK, 0); JShulver@23: idMap.put(ProbeID.BEFORE_PROBE, 0); JShulver@23: idMap.put(ProbeID.AFTER_PROBE, 0); JShulver@23: idMap.put(ProbeID.PROBE, 1); JShulver@23: idMap.put(ProbeID.PROBE_EX, 2); JShulver@23: idMap.put(ProbeID.PROBE_UNEX, 1); m@0: while(oi.hasNext()) { m@0: long onset = ((Long)oi.next()).longValue(); m@0: int pitch = ((Integer)piti.next()).intValue(); m@0: m@0: ProbeID p = (ProbeID)pi.next(); m@0: m@0: int probe = 0; m@0: JShulver@23: if(idMap.containsKey(p)) JShulver@23: { JShulver@23: probe = idMap.get(p); JShulver@23: System.out.println("Adding probe: "); m@0: } JShulver@23: JShulver@23: else JShulver@23: System.out.println("Unexpected probe id: " + p); JShulver@23: JShulver@23: m@0: w.write(composition + " " + eventIndex + " " + m@0: onset + " " + pitch + " " + m@0: probe + "\n"); m@0: eventIndex++; m@0: } m@0: } m@0: m@0: private void writeHeader(Writer w) throws IOException { m@0: w.write("melody note " + m@0: "onset pitch " + m@0: "probe"); m@0: w.write("\n"); m@0: } m@0: m@0: } m@0: