view Experiment.java @ 40:af173212eb42

Changed Experiment.java to now list descriptions of MIDI files on request (not just names). Changed SubjectDataPanel.java to include "0%" option for familiarity.
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Mon, 03 Jun 2013 18:33:31 +0100
parents 796b3e3e053f
children 75354c638975
line wrap: on
line source
/*=============================================================================
 * File:       Experiment.java
 * Author:     Marcus Pearce <m.pearce@gold.ac.uk>
 * Created:    <2007-02-14 11:28:27 marcusp>
 * Time-stamp: <2012-01-16 17:10:48 marcusp>
 *=============================================================================
 */

import java.io.*;
import javax.swing.UIManager; 
import java.awt.*;
import java.awt.Color;
import javax.sound.midi.*;
import java.util.Scanner;

public class Experiment { 

    /* pathnames */ 
    private final String BASE_DIRECTORY = 
        new File("").getAbsolutePath() + File.separator; 
    private final String DATA_DIRECTORY = 
        BASE_DIRECTORY + "Data" + File.separator; 

    public String RESULTS_DIRECTORY = 
        BASE_DIRECTORY + "Results" + File.separator; 
    public String RESULTS_EXTENSION = ".dat"; 
    public String SUBJECT_RESULTS_FILE = 
        RESULTS_DIRECTORY + "subjects" + RESULTS_EXTENSION; 

    public String INSTRUCTIONS_FILE = 
        DATA_DIRECTORY + "instructions.html"; 

    public String MIDI_DIRECTORY = 
        DATA_DIRECTORY + "Midi" + File.separator;
    public String MIDIFILELIST_FILE = 
        MIDI_DIRECTORY + "filelist.txt"; 
    public String PRACTICE_MIDIFILELIST_FILE = 
        MIDI_DIRECTORY + "pfilelist.txt"; 


    /* The GUI */ 
    private ExperimentGui gui; 

    /* whether to show the clock */
    private boolean showClock;
    /* the units of the clock as multiples of the tatum */
    private int clockUnits; 
    /* number of units that clock runs for before a probe event */ 
    private int numUnits; 

    /* whether to ask about familiarity of each song */
    private boolean askFamiliarity;
    /* whether to ask about liking of each song */
    private boolean askLiking;
    /* whether to include final questionnaire */
    private boolean finalQuestionnaire;
    
    /* the blocks of the experiment */ 
    Block[] blocks;
    int currentBlockID; 
    
    /* Subject ID */ 
    private String subjectID; 

    /* Results */ 
    private SubjectResults results; 

    /* the details of the rating scale */
    private int scaleLength;
    private String lowAnchor;
    private String highAnchor;

    /* the midi device */
    private int midiDevice;

    /* debugging */ 
    private boolean debug;

    /* accessors */ 
    public boolean getDebug() { return debug; }
    public boolean getAskLiking() { return askLiking; }
    public boolean getAskFamiliarity() { return askFamiliarity; }
    public boolean getFinalQuestionnaire() { return finalQuestionnaire; }

    public int getMidiDeviceNumber() { return midiDevice; }
    public int getScaleLength() { return scaleLength; }
    public String getLowAnchor() { return lowAnchor; }
    public String getHighAnchor() { return highAnchor; }

    public String getMidiDirectory() { return MIDI_DIRECTORY; }
    public SubjectResults getSubjectResults() { return results; }
    public Block getCurrentBlock() { return blocks[currentBlockID]; }
    public int getCurrentBlockID() { return currentBlockID + 1; }
    public boolean showClock() { return showClock; }
    public int getClockUnits() { return clockUnits; } 
    public int getNumUnits() { return numUnits; } 
    public String getInstructionsFile() { return INSTRUCTIONS_FILE; }
    public String getSubjectID() { return subjectID; }
    public void setSubjectID(String id) { 
        subjectID = id; 
        results.setSubjectID(id); 
        results.setOutputFile(id); 
        getCurrentBlock().getMelodyResults().setSubjectID(id); 
	System.out.println("Subject ID = " + subjectID);
    }

    /* Constructor */ 
    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 de) {
        
        // Setup variables 
	debug = (de != 0);
        results = new SubjectResults(this); 
        if (sc == 0) 
            showClock = false;
        else 
            showClock = true;
        clockUnits = positiveInteger(cu, 1); 
	numUnits = positiveInteger(nu, 4); 
        scaleLength = positiveInteger(sl, 7);
        midiDevice = md;
        lowAnchor = la;
        highAnchor = ha;
        MIDI_DIRECTORY = mfd + File.separator;
        MIDIFILELIST_FILE = MIDI_DIRECTORY + "filelist.txt"; 
        PRACTICE_MIDIFILELIST_FILE = MIDI_DIRECTORY + "pfilelist.txt"; 
        INSTRUCTIONS_FILE = inf;
        RESULTS_DIRECTORY = rdr + File.separator;
        SUBJECT_RESULTS_FILE = 
            RESULTS_DIRECTORY + "subjects" + RESULTS_EXTENSION;
        
        if (fam == 0)
            askFamiliarity = false;
        else 
            askFamiliarity = true; 
        if (lik == 0)
            askLiking = false;
        else 
            askLiking = true; 
        if (quest == 0)
            finalQuestionnaire = false;
        else 
            finalQuestionnaire = true; 

	if (debug)
	    displayMIDIDevices();

        // Initialise the experiment 
        Block practice = new Block(this, gui, PRACTICE_MIDIFILELIST_FILE, 
                                   "Practice", false); 
        Block main = new Block(this, gui, MIDIFILELIST_FILE, 
                               "Main", true); 
        blocks  = new Block[2]; 
        blocks[0] = practice; 
        blocks[1] = main; 
        currentBlockID = 0; 

        // Create the GUI 
        gui = new ExperimentGui(this); 
    }

    public Boolean nextBlock() { 
        boolean lastBlock = true; 
        if (currentBlockID + 1 < blocks.length) 
            currentBlockID = currentBlockID + 1; 
        else 
            lastBlock = false; 
        return lastBlock; 
    }

    public void addToSubjectResults(MelodyResults mr) { results.addResult(mr); }

    public void runExperiment () { 
        (new Thread(gui)).start();
        getCurrentBlock().presentStimulus(); 
    }
    public boolean isRunning() {
	Block cur = getCurrentBlock();;
	return cur != null && cur.isRunning();
    }
    
    public boolean hasRun() {
	Block cur = getCurrentBlock();
	return cur == null || cur.hasRun();
    } 

    /* Show the GUI */ 
    public void showGUI(int width, int height) { 
        gui.pack();
        gui.setSize(width, height); 
        // UIManager.put("Button.focus", UIManager.get("Button.select"));
        gui.setVisible(true);
    } 

    /* Main method */ 
    public static void main(String[] args) {
	
	if (args.length == 14) {

        // Parse Arguments 
        int n = 0;
        int sc = Integer.parseInt(args[n++]); 
        int cu = Integer.parseInt(args[n++]); 
        int nu = Integer.parseInt(args[n++]); 
        String mdInput = args[n++];
        int md = -1;
        int sl = Integer.parseInt(args[n++]); 
        String la = args[n++];
        String ha = args[n++];
        String mfd = args[n++];
        String inf = args[n++];
        String rdr = args[n++];
        int fam = Integer.parseInt(args[n++]);
        int lik = Integer.parseInt(args[n++]);
        int quest = Integer.parseInt(args[n++]);
        int de = Integer.parseInt(args[n++]);

    if(isBooleanFormat(mdInput)){
        boolean defaultMD = Boolean.parseBoolean(mdInput);
        
        if(!defaultMD){
            displayMIDIDevices();
            System.out.print("Specify the desired MIDI Device: ");
            Scanner scan = new Scanner(System.in);
            String input = scan.next();
            
            while(!isMIDIDevice(input)){
                System.out.print("Enter a valid input:");
                input = scan.next();
            }
            md = Integer.parseInt(input);
        }
        else{
            md = -1;
        }
    }
    else if(isMIDIDevice(mdInput)){
            md = Integer.parseInt(mdInput);
    }
    else{
        showUsage();
    }

        // Create experiment 
        Experiment exp = new Experiment(sc, cu, nu, sl, md, la, ha, mfd, inf, rdr, fam, lik, quest, de);
        
        // Show the GUI 
        int width=(int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        int height=(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        exp.showGUI(width, height); 

	} else {
        showUsage();
	}
    }
    
    public static void showUsage(){
        System.out.println("Usage: " + "\t" + "java Experiment " +
                           "<show clock?> <clock units> <number of units> " +
                           "<default MIDI device?> " +
                           "<scale length> <low anchor> <high anchor> " +
                           "<midi file directory> <instructions file> <results directory>" +
                           "<familiarity>" + "<pleasantness>" + "<questionnaire>" + "<debug>");
        System.exit(1);
    }

    /*
     * Print a list of accessible MIDI devices
     */
    public static void displayMIDIDevices() {
	System.out.println("Searching for MIDI devices...");
	    
	MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo();
	if (devices.length == 0) {
	    System.out.println("No MIDI devices found");
	} else {
	    for (int i=0; i<devices.length; i++) {
            MidiDevice.Info m = devices[i];
            System.out.println(i+". MIDI device: " + m.getName() + " - " + m.getDescription());
	    }
	}
    }
    
    public static boolean isBooleanFormat(String s){
        if(s.toLowerCase().equals("true") || s.toLowerCase().equals("false")){
            return true;
        }
        else {
            return false;
        }
    }

	public static boolean isMIDIDevice(String dev){
		boolean output;
        MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo();
        
		try {
			int device = Integer.parseInt(dev);
            if(device>devices.length-1 || device<0){
                output = false;
            }
            else { output = true; }
		} catch(NumberFormatException e) {
			output = false;
		}
		return output;
	}

    private int positiveInteger(int x, int def) {
	if (x > 0) 
	    return x;
	else
	    return def;
    }

}