view testApp.mm @ 28:953db6518738

leap version more or less there, needs btter results feedback but thats detail. "no movement" bit is stupid cos peopel can move their hand. light flash not work.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Thu, 30 Oct 2014 18:35:00 +0000
parents 27cdf475aa4b
children e7af34b1af83
line wrap: on
line source
#include "testApp.h"
#include "ofAppiOSWindow.h"
#include "ExplorePresetManager.h"
extern EventLogger eventLogger;
extern ExplorePresetManager expPresetManager;
// static members inited here. not my choice.
int SynthParam::mappingUID = 88000;
//--------------------------------------------------------------
void testApp::setup(){
    
    
    
    ofxiPhoneSetOrientation( OF_ORIENTATION_90_LEFT );
    //ofxiPhoneExternalDisplay::mirrorOn();
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];

    initialiseVariables();

    
    
    
    //presetManager.startLoadAll();
    
    targetSynth.init(&core,"targetSynth");
    candidateSynth.init(&core,"candidateSynth");
    
    searchMessageOrganiser.init(targetSynth, candidateSynth);
    trainingMessageOrganiser.init(targetSynth,candidateSynth);
    expMessageOrganiser.init(targetSynth,candidateSynth);
    
    timeController.init();
    initialiseGUIs();
    initialiseMIDI();
    setupUIElements();

    light.setSpotlight(45. , 1.);
    light.enable();
    ofEnableSeparateSpecularLight();
    
    ofEnableDepthTest();
    glEnable(GL_DEPTH_TEST);
//    ofEnableAlphaBlending();
    whichInterfaceAreWeUsing = ALL_SLIDERS;


    //--------------------------------------
    
	int ticksPerBuffer = 8;	// 8 * 64 = buffer len of 512
	core.setup(2, 2, 44100, ticksPerBuffer);

    // setup OF sound stream
    bufSize = ofxPd::blockSize()*ticksPerBuffer;
    wavetableNew = (float *) malloc(bufSize * sizeof(float));
    
	ofSoundStreamSetup(2, 2, this, 44100, ofxPd::blockSize()*ticksPerBuffer, 3);
    
    if(false){ // force start
        startTheTrainingTests();
    }else{
        
        if(eventLogger.questionnaireCompleted){ // then show play again dialog, and log the test number
            
        }else{
            // then we're in timed session mode
            [usernameAlertViewController showUserNamePrompt];
        }
    }
    paused = false;
    
    eventLogger.logEvent(APP_LOADED);

    ofSoundStreamStart();

}

//-----------------------------------------------------------------------------

//DeviceID3523537000
void testApp::initialiseVariables(){
    paused = true;
    ofBackground( 0, 0, 0 );
    //ofEnableAlphaBlending();
    //ofEnableSmoothing();
    
	// open an outgoing connection to HOST:PORT for OSC
	// sender.setup( OSC_HOST, OSC_PORT );
    ofSetFrameRate(60);
    props = new UIProps();

}
//---------------------------------------------------------
void testApp::initialiseGUIs(){

    // set up iOS gui stuff
    
    helpViewController	= [[HelpViewController alloc] initWithNibName:@"HelpViewController" bundle:nil];
    [ofxiPhoneGetGLParentView() addSubview:helpViewController.view];
    [helpViewController setAppRef:(__bridge id)this];
    helpViewController.view.hidden = YES;
    

    usernameAlertViewController = [[UsernameAlertViewController alloc] init];
    [usernameAlertViewController setAppRef:(__bridge id)this];
 
}

//--------------------------------------------------------------
// GUI for finding and saving presets to express concepts
void testApp::setupExpressViewPanels(){
    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+props->sliderPanelHeight,ofGetWidth(),250,*props);
    
    Buttron * playCandidateButton = new Buttron(props->buttonWidth*1.4,680, *props);
    playCandidateButton->setLabel("PLAY");
    expMessageOrganiser.mapButtonToAction(playCandidateButton, TRIGGER_CANDIDATE_ID);
    bottomButtonPanel->addButton(playCandidateButton);

    Buttron * savePresetButton = new Buttron(props->buttonWidth*1.4,680, *props);
    savePresetButton->setLabel("SAVE/NEXT");
    expMessageOrganiser.mapButtonToAction(savePresetButton, SAVE_PRESET_HIT);
    bottomButtonPanel->addButton(savePresetButton);
    
    expMessageOrganiser.setBottomPanel(bottomButtonPanel);
    UIElements.push_back(bottomButtonPanel);
    bottomButtonPanel->hide();
    
    TextPanel * instructionPanel = new TextPanel("Instrcution panel", 10, 50, 300,150,(*props));
    instructionPanel->setFontSize(MEDIUMFONT);
    UIElements.push_back(instructionPanel);
    expMessageOrganiser.setInstructionPanel(instructionPanel);
    instructionPanel->show();
}
//--------------------------------------------------------------
// gui for the main training stage
void testApp::setupTrainingViewPanels(){

    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+props->sliderPanelHeight,ofGetWidth(),250,*props);
    
    // play and submit are now same thing
    Buttron * playCandidateButton = new Buttron(props->buttonWidth*1.4,680, *props);
    playCandidateButton->setLabel("START");
    trainingMessageOrganiser.mapButtonToAction(playCandidateButton, TRIGGER_CANDIDATE_ID);
    bottomButtonPanel->addButton(playCandidateButton);
    bottomButtonPanel->hide();
    
    trainingMessageOrganiser.setBottomPanel(bottomButtonPanel);
    UIElements.push_back(bottomButtonPanel);
    bottomButtonPanel->hide();

    
    TextPanel * instructionPanel = new TextPanel("Instrcution panel", 10, 50, 300,150,(*props));
    instructionPanel->setFontSize(MEDIUMFONT);
    UIElements.push_back(instructionPanel);
    trainingMessageOrganiser.setInstructionPanel(instructionPanel);
    instructionPanel->hide();
    
    TextPanel * middlePanel = new TextPanel("Middle panel", 200, 200, 400,400,(*props));
    middlePanel->setFontSize(LARGEFONT);
    UIElements.push_back(middlePanel);
    trainingMessageOrganiser.setMiddlePanel(middlePanel);
    middlePanel->hide();
    
    
}
//--------------------------------------------------------------
// gui for the old style tweakathlon  stage
void testApp::setupSearchViewPanels(){

    ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+(*props).sliderPanelHeight,ofGetWidth(),250,(*props));
    
    Buttron* playTargetButton = new Buttron((*props).buttonWidth*0.2,680, (*props));
    playTargetButton->setLabel("Target");
    searchMessageOrganiser.mapButtonToAction(playTargetButton, TRIGGER_TARGET_ID);
    bottomButtonPanel->addButton(playTargetButton);
    searchMessageOrganiser.setTargetButton(playTargetButton);
    
    Buttron * playCandidateButton = new Buttron((*props).buttonWidth*1.4,680, (*props));
    playCandidateButton->setLabel("Current");
    searchMessageOrganiser.mapButtonToAction(playCandidateButton, TRIGGER_CANDIDATE_ID);
    bottomButtonPanel->addButton(playCandidateButton);
    
    
    // submit button - only one for now
    Buttron * submitButton = new Buttron(ofGetWidth()*0.5 - (*props).buttonWidth*0.5,680, (*props));
    submitButton->setLabel("Submit");
    searchMessageOrganiser.mapButtonToAction(submitButton, SUBMIT_CANDIDATE);
    bottomButtonPanel->addButton(submitButton);
    
    //  button - just for spacing pruposes
    Buttron * saveButton = new Buttron(ofGetWidth()*0.5 - (*props).buttonWidth*0.5,680, (*props));
    saveButton->setLabel("SAVE");
    searchMessageOrganiser.mapButtonToAction(saveButton, SAVE_PRESET_HIT);
    bottomButtonPanel->addButton(saveButton);
    saveButton->hide();
    
    Buttron * recallButton = new Buttron(ofGetWidth()*0.5 - (*props).buttonWidth*0.5,680, (*props));
    recallButton->setLabel("RECALL");
    searchMessageOrganiser.mapButtonToAction(recallButton, RECALL_PRESET_HIT);
    bottomButtonPanel->addButton(recallButton);
    recallButton->hide();
    
    searchMessageOrganiser.setBottomPanel(bottomButtonPanel);
    UIElements.push_back(bottomButtonPanel);
    bottomButtonPanel->showBorder(false);
    bottomButtonPanel->hide();
// -   -   - - - -- -  - OTHER BITS
    
    CountdownText * countDownBox = new CountdownText("5" , 500, 380, 455, 455, (*props));
    UIElements.push_back(countDownBox);
    searchMessageOrganiser.setCountdownPanel(countDownBox);
    countDownBox->hide();
    
    TextPanel * scoreFeedback = new TextPanel("Feedback panel", ofGetWidth()*0.5 - (*props).buttonWidth*0.5, 666, 400,100,(*props));
    scoreFeedback->setFontSize(SMALLFONT);
    UIElements.push_back(scoreFeedback);
    searchMessageOrganiser.setScorePanel(scoreFeedback);
    scoreFeedback->hide();
    
    TextPanel * finishPanel = new TextPanel("Finish txt panel", 250, 250, 1000,400,(*props));
    finishPanel->setFontSize(LARGEFONT);
    finishPanel->setText("Experiment completed");
    searchMessageOrganiser.setFinishPanel(finishPanel);
    
    UIElements.push_back(finishPanel);
    finishPanel->hide();
    
    
    Buttron * newTestButton = new Buttron(ofGetWidth()-300,690, (*props));
    newTestButton->setLabel("Next Test");
    UIElements.push_back(newTestButton);
    searchMessageOrganiser.mapButtonToAction(newTestButton, NEW_TEST_ID);
    newTestButton->hide();
    searchMessageOrganiser.setNewTestButton(newTestButton);
    
    TextPanel * instructionPanel = new TextPanel("Instrcution panel", 10, 50, 300,150,(*props));
    instructionPanel->setFontSize(MEDIUMFONT);
    UIElements.push_back(instructionPanel);
    searchMessageOrganiser.setInstructionPanel(instructionPanel);
    instructionPanel->hide();
    
//    TargetSymbol* targetSymbol = new TargetSymbol(ofGetWidth()*0.5,160,30,(*props));
//    searchMessageOrganiser.setTargetSymbol(targetSymbol);
//    UIElements.push_back(targetSymbol);
//    
}
//--------------------------------------------------------------
void testApp::setupSliderPanel(){
// setupMutualPanels
    vector<controllerType> sl2;
    sl2.push_back(SLIDER);
    
    SliderPanel * controlPanel = new SliderPanel(1,
                                                 160,
                                                 ofGetWidth(),
                                                 (*props).sliderPanelHeight,
                                                 (*props),
                                                 sl2);
    
    UIElements.push_back(controlPanel);
    AnimatedUIElements.push_back(controlPanel);
    searchMessageOrganiser.setControlPanel(controlPanel);
    trainingMessageOrganiser.setControlPanel(controlPanel);
    expMessageOrganiser.setControlPanel(controlPanel);
    controlPanel->showBorder(true);
    controlPanel->hide();
    
    
    IconPanel* iconPanel = new IconPanel(420, 10, 150, 150, *props);
    trainingMessageOrganiser.setIconPanel(iconPanel);
    expMessageOrganiser.setIconPanel(iconPanel);
    searchMessageOrganiser.setIconPanel(iconPanel);
    UIElements.push_back(iconPanel);
    iconPanel->hide();
    
    
//    Leap6DBox * box = new Leap6DBox(400 , 210 , (*props).XYsize*0.75,(*props).XYsize*0.75,150,50, *props);
//    searchMessageOrganiser.setBox(box);
//    trainingMessageOrganiser.setBox(box);
//    expMessageOrganiser.setBox(box);
//    UIElements.push_back(box);
//    box->show();
}
//--------------------------------------------------------------
void testApp::setupUIElements(){

    ofBackground(0,0,0);

    setupSearchViewPanels();

    setupSliderPanel();

    setupTrainingViewPanels();
    
    setupExpressViewPanels();
}
//--------------------------------------------------------------------------
void testApp::initialiseMIDI(){
    
    /////////////////////////
    // MIDI
    
    midiChannel = 8;
    midiOffset = 0;
	
	// enables the network midi session between iOS and Mac OSX on a
	// local wifi network
	//
	// in ofxMidi: open the input/outport network ports named "Session 1"
	//
	// on OSX: use the Audio MIDI Setup Utility to connect to the iOS device
	//
	ofxMidi::enableNetworking();
	
	// list the number of available input & output ports
	ofxMidiIn::listPorts();
	ofxMidiOut::listPorts();
	
	// create and open input ports
	for(int i = 0; i < ofxMidiIn::getNumPorts(); ++i) {
		
		// new object
		inputs.push_back(new ofxMidiIn);
		
		// set this class to receive incoming midi events
		inputs[i]->addListener(this);
		
		// open input port via port number
		inputs[i]->openPort(i);
	}
	
	// create and open output ports
	for(int i = 0; i < ofxMidiOut::getNumPorts(); ++i) {
		
		// new object
		outputs.push_back(new ofxMidiOut);
		
		// open input port via port number
		outputs[i]->openPort(i);
	}
	
	// set this class to receieve midi device (dis)connection events
	ofxMidi::setConnectionListener(this);
    
    // END MIDI

}
//--------------------------------------------------------------

template <class T>
void deleteVectorOfPointers( T * inVectorOfPointers )
{
    typename T::iterator i;
    for ( i = inVectorOfPointers->begin() ; i < inVectorOfPointers->end(); i++ )
    {
        delete * i;
    }
    //delete inVectorOfPointers;
}


//--------------------------------------------------------------
void testApp::exit(){
    eventLogger.logEvent(APP_EXITED);
    eventLogger.exitAndSave();
    
    core.exit();
    
    // are these handled automatically?
    //[introViewController release];
    //[topButtonViewController release];
    //[bottomTabViewController release];
    
    // clean up MIDI
	for(int i = 0; i < inputs.size(); ++i) {
		inputs[i]->closePort();
		inputs[i]->removeListener(this);
		delete inputs[i];
	}
    
	for(int i = 0; i < outputs.size(); ++i) {
		outputs[i]->closePort();
		delete outputs[i];
	}
    deleteVectorOfPointers(&UIElements); // TODO this crashes??

    
    cout << "exit done \n";
}

#pragma mark GUI
////////////////////////////
// These functions called from iOS toolbars
//--------------------------------------------------------------

//--------------------------------------------------------------
void testApp::showQuestionnaire(){

    
    questionnaireViewController	= [[QuestionnaireViewController alloc] initWithNibName:@"QuestionnaireViewController" bundle:nil];
    [ofxiPhoneGetGLParentView() addSubview:questionnaireViewController.view];
	
    [questionnaireViewController setAppRef:(__bridge id)this];
    [questionnaireViewController show:(__bridge id)this];
    
    whichInterfaceShowing = QUESTIONNAIRE;
    
    
}
//--------------------------------------------------------------
void testApp::questionnaireHidden(vector<int> answers, const char* userComments){
    // send answers to server as json
    eventLogger.questionnaireAnswersObtained(answers, userComments);

}

//--------------------------------------------------------------
void testApp::showIntro(){
    // display a thing that gives us an option as to which stage to start
    // EXPLORE, PERFORMANCE TRAINING, SEARCH
    cout << "SHOW INTRO\n";

    introViewController	= [[IntroViewController alloc] initWithNibName:@"IntroViewController" bundle:nil];
    [ofxiPhoneGetGLParentView() addSubview:introViewController.view];
	
    [introViewController setAppRef:(__bridge id)this];
    [introViewController show:(__bridge id)this];
    
    whichInterfaceShowing = INTRO;
    
}
//--------------------------------------------------------------
//void testApp::introHidden(){
//    eventLogger.consentGiven = true;
//    eventLogger.logEvent(INTRO_CONSENTED);
//    [usernameAlertViewController showUserNamePrompt];
//    // after prompt goes it calls usernameEntered()
//}
//--------------------------------------------------------------
void testApp::introHidden(int mode){
    eventLogger.consentGiven = true;
    eventLogger.logEvent(INTRO_CONSENTED);
    
    if(mode == 1){
        startTheExpTests();
    }else if(mode == 2){
        startTheTrainingTests();
    }else if(mode == 3){
        startTheSearchTests();
    }
    
}
//-------------------------------
void testApp::interfaceSelected(int interfaceSelection){
    if (interfaceSelection == 0){
        whichInterfaceAreWeUsing = ALL_SLIDERS;
    }else{
        whichInterfaceAreWeUsing = LEAP6DOF;
    }
}
//--------------------------------------------------------------
void testApp::usernameEntered(){

    eventLogger.onUsernameEntered();
    expPresetManager.onAppLoad();
    
    showIntro();
    
}
//--------------------------------------------------------------
void testApp::startTheExpTests(){
    eventLogger.logEvent(START_THE_EXP_TESTS);
    whichInterfaceShowing = COUNT_DOWN;
    // do countdown etc
    
    trainingMessageOrganiser.hideMyPanels();
    searchMessageOrganiser.hideMyPanels();
    expMessageOrganiser.setup(whichInterfaceAreWeUsing);
    
    expMessageOrganiser.showMyPanels();

    currentStage = EXPRESS;
    
}
//--------------------------------------------------------------
void testApp::startTheSearchTests(){
    eventLogger.logEvent(START_THE_SEARCH_TESTS);
    whichInterfaceShowing = COUNT_DOWN;
    // do countdown etc
    
    trainingMessageOrganiser.hideMyPanels();
    searchMessageOrganiser.countdownToNewTest();
    // TODO how is testApp going to kknow whichInterfaceShowing ???
    currentStage = SEARCH;
}
void testApp::startTheTrainingTests(){
    eventLogger.logEvent(START_THE_TRAINING_TESTS);
    
    trainingMessageOrganiser.setup(whichInterfaceAreWeUsing);
    trainingMessageOrganiser.showMyPanels();
    currentStage = TRAINING;
}
//--------------------------------------------------------------
//--------------------------------------------------------------
void testApp::showHelp(){
    // stop clock etc
    previousInterface = whichInterfaceShowing;
    whichInterfaceShowing = HELP;
    helpViewController.view.hidden = NO;
    eventLogger.logEvent(HELP_PRESSED);
    
}
void testApp::helpHidden(){
    whichInterfaceShowing = previousInterface;
    
}
//--------------------------------------------------------------
//--------------------------------------------------------------
//--------------------------------------------------------------
#pragma mark sending to pd and midi
void testApp::sendParametersToPD(){

    
}
//--------------------------------------------------------------
void testApp::sendMidiParam(int which){
    int midiChannel = 8;
    int offset = 0;
    
    for(int i = 0; i < outputs.size(); ++i) {
        outputs[i]->sendControlChange(midiChannel, offset+which, 66);
    }
    
    
}

void testApp::setupNewUser(){
    // this function is for supervised trials with my ipad
    eventLogger.newUser();
}
//--------------------------------------------------------------
#pragma mark STANDARD OF FUNCTIONS
//--------------------------------------------------------------
void testApp::update(){
    
    if(paused) return;
    
    // run timer check here
    // look at time, work out difference
    timeController.tick();
    
    vector<UIElement *>::iterator UIitr;
    for(UIitr = AnimatedUIElements.begin(); UIitr < AnimatedUIElements.end(); UIitr++){
        (*UIitr)->update();
    }
}
//--------------------------------------------------------------

void testApp::appModeChange(interfaceType mode){
    whichInterfaceShowing = mode;
}


//------------------------------------------------------------------------

void testApp::draw(){
    
    switch (whichInterfaceShowing){
        case QUESTIONNAIRE:
            break;
        case INTRO:
            break;
        case TEST_IN_PROGRESS:
            break;
        case SCORE_AND_HINT:
            break;
        case COUNT_DOWN:
            break;
        case READY_FOR_NEXT:
            break;
        default:
            break;
    }
    
    
    
    drawUIElements();
    
    //ofSetColor(234, 234, 234);
    //ofLine(0,150,1024,150);
    
    //drawWaveform();
    if (currentStage == SEARCH)
        searchMessageOrganiser.drawScore();
    
    //image.draw(10,10,200,200);

}
//------------------------------------------------------------------------
void testApp::drawUIElements(){

    vector<UIElement *>::iterator UIitr;
    for(UIitr = UIElements.begin(); UIitr < UIElements.end(); UIitr++){
        (*UIitr)->draw();
    }
}

//------------------------------------------------------------------------

//--------------------------------------------------------------
// passes touch to UI elements
//--------------------------------------------------------------

void testApp::touchToUIElements(int x, int y, touchType ttype, int tid){
    vector<UIElement *>::iterator UIitr;
    for(UIitr = UIElements.begin(); UIitr < UIElements.end(); UIitr++){
        (*UIitr)->touch(x,y,ttype, tid);
    }
}

//--------------------------------------------------------------
void testApp::touchDown(ofTouchEventArgs &touch){
    //touch = transformTouchCoords(touch);
    touchToUIElements(touch.x, touch.y, TOUCH_DOWN, touch.id);
    
}

//--------------------------------------------------------------
void testApp::touchMoved(ofTouchEventArgs &touch){

    touchToUIElements(touch.x, touch.y, TOUCH_MOVED, touch.id);
    
}

//--------------------------------------------------------------
void testApp::touchUp(ofTouchEventArgs &touch){

    touchToUIElements(touch.x, touch.y, TOUCH_UP, touch.id);
}


//--------------------------------------------------------------
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
    
}

//--------------------------------------------------------------
void testApp::lostFocus(){
    //exit();
}

//--------------------------------------------------------------
void testApp::gotFocus(){
    
}

//--------------------------------------------------------------
void testApp::gotMemoryWarning(){
    
}

//--------------------------------------------------------------

void testApp::deviceOrientationChanged(int newOrientation){
    
    cout << "orientation: " << newOrientation;
    
    // do something here?

}



//--------------------------------------------------------------
void testApp::touchCancelled(ofTouchEventArgs& args){
    
}
//---------------------------------------------------------------
// AUDIO STUFF
//---------------------------------------------------------------

#pragma mark AUDIO STREAMS
//--------------------------------------------------------------
void testApp::audioReceived(float * input, int bufferSize, int nChannels) {
	//core.audioReceived(input, bufferSize, nChannels);
}

void testApp::audioRequested(float * output, int bufferSize, int nChannels) {

	core.audioRequested(output, bufferSize, nChannels);
//    for(int i=0;i<bufferSize/2;i++){
//        output[i] = 0.2;
//    }
//    // pass buffer to drawable thing
//    for(int i=0;i<bufferSize;i++){
//        wavetableNew[i] = output[i];
//    }
    
}

void testApp::drawWaveform(){
    // draw the actual waveform in the corner
    
    int width = 768;
    int height = 128;
    double sampval = 0.0;
    int leftsampnum = 0;
    int rightsampnum = 0;
    float sampscale = 0.0, prevsampscale = 0.0, interp = 0.0;
    
    ofSetColor(256, 0, 0);
    double step = double(bufSize)/width; // how much we are stepping thru wave per pixel
    for(int i = 0; i < width; i++){
        
        leftsampnum = floor(i * step); // basic nearest neighbour interpolation
        rightsampnum = ceil(i*step);
        interp  = (i*step)-leftsampnum;
        if(rightsampnum < bufSize){
            sampval = (1 - interp)*wavetableNew[leftsampnum] + interp*wavetableNew[rightsampnum];
        }
        sampscale = (sampval * 700) + height/2.0; // centre and scale
        ofSetLineWidth(2);
        ofLine(sampscale, i, prevsampscale, i-1); // draw a line from pixel to pixel (?)
        prevsampscale = sampscale;
    }
    
}
//---------------------------------------------------------------
#pragma mark UTILITIES
//-------------------------------------------------------------------------
//--------------------------------------------------------------

#pragma mark MIDI
void testApp::addMessage(string msg) {
	cout << msg << endl;
	messages.push_back(msg);
	while(messages.size() > maxMessages)
		messages.pop_front();
}

//--------------------------------------------------------------
void testApp::newMidiMessage(ofxMidiMessage& msg) {
    
    // looks out for: 30 31 32... on channel 8
    if(msg.channel == midiChannel && msg.status == MIDI_CONTROL_CHANGE){
        int ctl_num = msg.control - 30;
        int ctl_val = msg.value;
        // TODO route control change message here
        //cout << " ctrl : " << ctl_num << " : " << ctl_val << endl;
        if (currentStage == SEARCH)
            searchMessageOrganiser.midiFromLeap(ctl_num, ctl_val);
        if (currentStage == EXPRESS)
            expMessageOrganiser.midiFromLeap(ctl_num, ctl_val);
        if (currentStage == TRAINING)
            trainingMessageOrganiser.midiFromLeap(ctl_num, ctl_val);
        
    }
 
}

//--------------------------------------------------------------
void testApp::midiInputAdded(string name, bool isNetwork) {
	stringstream msg;
	msg << "ofxMidi: input added: " << name << " network: " << isNetwork;
    cout << msg.str();
	addMessage(msg.str());
	
	// create and open a new input port
	ofxMidiIn * newInput = new ofxMidiIn;
	newInput->openPort(name);
	newInput->addListener(this);
	inputs.push_back(newInput);
}

//--------------------------------------------------------------
void testApp::midiInputRemoved(string name, bool isNetwork) {
	stringstream msg;
	msg << "ofxMidi: input removed: " << name << " network: " << isNetwork << endl;
    cout << msg.str();
	addMessage(msg.str());
	
	// close and remove input port
	vector<ofxMidiIn*>::iterator iter;
	for(iter = inputs.begin(); iter != inputs.end(); ++iter) {
		ofxMidiIn * input = (*iter);
		if(input->getName() == name) {
			input->closePort();
			input->removeListener(this);
			delete input;
			inputs.erase(iter);
			break;
		}
	}
}

//--------------------------------------------------------------
void testApp::midiOutputAdded(string name, bool isNetwork) {
	stringstream msg;
	msg << "ofxMidi: output added: " << name << " network: " << isNetwork << endl;
    cout << msg.str();
	addMessage(msg.str());
	
	// create and open new output port
	ofxMidiOut * newOutput = new ofxMidiOut;
	newOutput->openPort(name);
	outputs.push_back(newOutput);
}

//--------------------------------------------------------------
void testApp::midiOutputRemoved(string name, bool isNetwork) {
	stringstream msg;
	msg << "ofxMidi: output removed: " << name << " network: " << isNetwork << endl;
    cout << msg.str();
	addMessage(msg.str());
	
	// close and remove output port
	vector<ofxMidiOut*>::iterator iter;
	for(iter = outputs.begin(); iter != outputs.end(); ++iter) {
		ofxMidiOut * output = (*iter);
		if(output->getName() == name) {
			output->closePort();
			delete output;
			outputs.erase(iter);
			break;
		}
	}
}