view TrainingMessageOrganiser.mm @ 44:d810aa9ca03a

times. cosmetic stuff
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Mon, 15 Dec 2014 17:33:41 +0000
parents 4ad0d218f890
children 80112c9349c4
line wrap: on
line source
//
//  TrainingMessageOrganiser.mm
//  riftathon
//
//  Created by Robert Tubb on 17/10/2014.
//
//

#include "TrainingMessageOrganiser.h"

void TrainingMessageOrganiser::init( PDSynthWrapper& cs, PDSynthWrapper& ts, bool soundOnlyMode, controlPanelType whichInterfaceAreWeUsing){
    
    MessageOrganiser::init(cs,ts);
    
    TickListenerFunction callback;
    callback = boost::bind(&TrainingMessageOrganiser::onNextTickAnim, this, _1);
    candidateSynth.registerForTicks(callback);
    
    numParamsToUse = TOTAL_NUM_PARAMS;
    
    sequenceController.init(soundOnlyMode,whichInterfaceAreWeUsing);
    
    setup(whichInterfaceAreWeUsing);
}

void TrainingMessageOrganiser::setup(controlPanelType whichInterfaceAreWeUsing){
    
    setupDefaultMapping(whichInterfaceAreWeUsing);
    
    candidateSynth.setAllParams(expPresetManager.getNeutralPreset()->getValues());
    
    doHand(true);
    doGuides(false,expPresetManager.getNeutralPreset());
    bottomPanel->showAllElements();

}

void TrainingMessageOrganiser::setForgotButton(Buttron* butt){
    forgotButton = butt;
}
//----------------------------------------------------------------------------------------
void TrainingMessageOrganiser::showMyPanels(){
    presetIconPanel->show();
    instructionPanel->show();
    bottomPanel->show();
    controlPanel->show();
    if (panelType == LEAP6DOF){
        okToGetMidi = true; // allow midi input to thing
    }else{
        okToGetMidi = false;
    }
}

//-----------------------------------------------------------------------
void TrainingMessageOrganiser::displayInstructions(string text){
    
    instructionPanel->setText(text);
    instructionPanel->show();
    
}

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

void TrainingMessageOrganiser::showUserHowTheyDid(){
    // colour flash
    // distance ?
    // score
    
}



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

void TrainingMessageOrganiser::buttonPressCallback(int mappingID, int value){
    if(mappingID == VOLUME_CHANGE_ID){
        targetSynth.sendVolume(value);
        candidateSynth.sendVolume(value);
        return;
    }
    
    if (mappingID == START_TRAINING_SEQUENCE_ID){
        // start next run
        if (candidateSynth.isMetronomeRunning()){
            // skip to next run?
            eventLogger.logEvent(RUN_SKIPPED);
        }else{
            candidateSynth.setMetroTime(sequenceController.getStartIntervalTime()/4.);
            candidateSynth.startMetronome();
            bottomPanel->hide();
            
            vector<int> details;
            details.push_back(panelType);
            // TODO sequence length
            
            eventLogger.logEvent(START_NEW_RUN, details);
        }
        return;
    }
    
    if(mappingID == TO_MENU_ID){
        // tell testapp to start again?
        candidateSynth.stopMetronome();
        controlPanel->hide();
        controlPanel->setColor(ofColor::black);
        seqNumPanel->hide();
        eventLogger.logEvent(RUN_SKIPPED);
        eventLogger.saveSessionToFile();
    }
    
    if(mappingID == FORGOT_SEQ_ID){
        //
        eventLogger.logEvent(FORGOT_SEQ);
        cout << "FORGOT" << endl;
    }
    if(mappingID == SKIP_RUN_ID){
        sequenceController.skipRun();
        int r = sequenceController.getCurrentRunNumber();
        stringstream s;
        s << "GOTO RUN " << r+1;
        skipButton->setLabel(s.str());
        
    
    }
    
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------
void TrainingMessageOrganiser::onNextTick(int tickNumber){
    static int showingCountdown = false;
    
    downCounter = 4 - tickNumber % 4;
    
    if (showingCountdown){
        middlePanel->setText(ofToString(downCounter));
    }
    
    // only first beat in bar is active one
    if ( tickNumber % 4  != 0){
        
        return;
    }
    
}
void TrainingMessageOrganiser::lastOfRun(int which){
    candidateSynth.stopMetronome();
    stringstream s;
    
    s << "FINISHED RUN " << which << " OF " << sequenceController.getTotNumRuns() << endl;
    controlPanel->hide();
    controlPanel->setColor(ofColor::black);
    middlePanel->setText(s.str());
    middlePanel->show();
    //playCandidateButton->setLabel("NEXT");
    s.str("");
    s << "GOTO RUN " << which+1;
    skipButton->setLabel(s.str());
    
    bottomPanel->show();
    seqNumPanel->hide();
    forgotButton->hide();
    eventLogger.logEvent(FINISHED_RUN);
    eventLogger.saveSessionToFile();
    // TODO keep track of how far we are into experiment
}
void TrainingMessageOrganiser::lastOfAll(){
    candidateSynth.stopMetronome();
    cout << "FINISHED BLOCK" << endl;
    controlPanel->hide();
    controlPanel->setColor(ofColor::black);
    middlePanel->setText("CONGRATULATIONS.\n FINISHED BLOCK!");
    middlePanel->show();
    bottomPanel->showOnlyElementNamed("MENU");
    bottomPanel->show();
    seqNumPanel->hide();
    forgotButton->hide();
    eventLogger.saveSessionToFile();
}

void TrainingMessageOrganiser::logNewStep(AnimStep newStep, vector<int> targetVals){
    
    vector<int> details;
    details.push_back(int(newStep.type));
    details.push_back(newStep.whichInSequence);
    details.push_back(newStep.showsGuides);
    details.push_back(newStep.showsIcons);
    details.push_back(newStep.presetIndex);
    details.push_back(newStep.tempo);
    details.insert(details.end(),targetVals.begin(), targetVals.end());
    eventLogger.logEvent(NEW_STEP, details);
    
}

//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::onNextTickAnim(int tickNumber){
    static AnimStep oldStep;
    static vector<int> lastPosition = zeros<int>(TOTAL_NUM_PARAMS);
    
    //cout << "TICK " << tickNumber << endl;
    downCounter = 4 - tickNumber % 4;
    
    updateCountdown(downCounter);
    // only first beat in bar is active one (at the moment)
    //  send next target values 1 step before them play
    if ( tickNumber % 4  != 0) {
        if (tickNumber % 4  == 3){
            targetSynth.sendAllParams();
        }
        return;
    };
    
    
    Preset* previousTargetPreset;
    vector<int> curCandidateSettings = candidateSynth.getAllParamValues();
    if (oldStep.showsResultsAtEnd){
        // this if should be in getpreset
        if(oldStep.presetIndex == -1){
            previousTargetPreset =  expPresetManager.getNeutralPreset();
            cout << "SHOULDNT SCORE NEUTRAL??" << endl;
        }else{
            
            previousTargetPreset =  expPresetManager.getPresetAtIndex(oldStep.presetIndex);
        }
        
        eventLogger.logEvent(FINISH_POS, curCandidateSettings);
        TrainingTestResult result =  doResults(oldStep,
                                               previousTargetPreset,
                                               lastPosition,
                                               curCandidateSettings);
        
        flashResult(result);
    }
    
    AnimStep newStep = sequenceController.getNextStep(); // ADVANCES COUNTS 
    
    
    
    if(newStep.isLastOfAll){
        lastOfAll();
        return;
    }
    if(newStep.isLastOfRun){
        lastOfRun(newStep.runNumber);
        return;
    }
    
    candidateSynth.setMetroTime(newStep.getTimeBetweenTicks());
    Preset * currentTargetPreset;
    if(newStep.presetIndex == -1){
        currentTargetPreset =  expPresetManager.getNeutralPreset();
        
    }else{
        
        currentTargetPreset =  expPresetManager.getPresetAtIndex(newStep.presetIndex);
        if (currentTargetPreset == NULL){
            displayInstructions("No stored preset!\n please go back to menu and choose EXP");
            
            bottomPanel->show();
            bottomPanel->showOnlyElementNamed("MENU");
            candidateSynth.stopMetronome();
            return;
        }
    }
    
    switch (newStep.type){
        case AnimStep::PREVIEW_NEUTRAL_COUNT :
            previewNeutralCount(newStep,currentTargetPreset);
            break;
        case AnimStep::PREVIEW_MOVE :
            previewMove(newStep,currentTargetPreset);
            break;
        case AnimStep::PREVIEW_LAST :
            previewLast( newStep,currentTargetPreset);
            break;
        case AnimStep::MATCHING_NEUTRAL_COUNT :
            //matchingNeutralCount( newStep,currentTargetPreset);
            break;
        case AnimStep::MATCHING_MOVE :
            matchingMove( newStep,currentTargetPreset);
            break;
        case AnimStep::MATCHING_LAST :
            matchingLast( newStep,currentTargetPreset);
            break;
        case AnimStep::GUIDED_MOVE :
            //guidedMove( newStep);
            break;
            
        case AnimStep::GUIDED_HIT :
            //guidedHit( newStep);
            break;
        default:
            break;
    }
    logNewStep(newStep, currentTargetPreset->getValues());
    oldStep = newStep;
    lastPosition = curCandidateSettings;
    
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::updateCountdown(int n){
    
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::previewNeutralCount(AnimStep newStep, Preset * currentTargetPreset){
    okToGetMidi = false;
    candidateSynth.playDownbeatBlip();
    middlePanel->hide();
    
    // your 'hand' is hidden
    controlPanel->showValueIndicators(false);
    
    
    // guide is set to neutral values
    currentTargetPreset = expPresetManager.getNeutralPreset();
    vector<int> newTargetValues = currentTargetPreset->getValues();
    controlPanel->setValues(newTargetValues);
    presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
    presetIconPanel->show();
    
    controlPanel->setAndShowHint(newTargetValues, currentTargetPreset->getImage());
    doHand(false);
    controlPanel->show();
    
    targetSynth.setAllParams(newTargetValues);
    //candidateSynth.setAllParams(newTargetValues);
    
    displayInstructions("Get ready for preview");
    seqNumPanel->hide();
    oldTargetValues = newTargetValues;
    controlPanel->setColor(ofColor::black);
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::previewMove(AnimStep newStep, Preset * currentTargetPreset){
    
    targetSynth.trigger(); // PLAYS LAST TARGET
    
    
    vector<int> newTargetValues = currentTargetPreset->getValues();
    
    targetSynth.setAllParamsWithoutSend(newTargetValues);
    
    doGuides(newStep.showsGuides, currentTargetPreset);
    
    doHand(false, newStep.showsGuides, newStep.getTimeBetweenTicks()*4, newTargetValues);
    
    doIcons(newStep.showsIcons, currentTargetPreset);
    
    
    controlPanel->show();
    
    displayInstructions("PREVIEW");
    showSeqNum(newStep.whichInSequence);
    oldTargetValues = newTargetValues;
    
    controlPanel->setColor(ofColor::black);
    bottomPanel->hide();
    forgotButton->hide();
    forgotButton->turnOff();
}


//-----------------------------------------------------------------------------
// lest setep of preview seq - plays moves back to neutral pos?
void TrainingMessageOrganiser::previewLast(AnimStep newStep, Preset * currentTargetPreset){
    targetSynth.trigger();
    
    // wrong?
    targetSynth.setAllParamsWithoutSend(currentTargetPreset->getValues());
    
    // your hand shows, we dont bother animating back to neutral!?
    doHand(true);
    
    doIcons(newStep.showsIcons,currentTargetPreset);
    
    doGuides(newStep.showsGuides, currentTargetPreset);
    
    showSeqNum(newStep.whichInSequence);
    displayInstructions("PREVIEW FINISHED");
    // set candidate and sliders to neutral
    candidateSynth.setAllParams(expPresetManager.getNeutralPreset()->getValues());
    controlPanel->setColor(ofColor::darkMagenta);
}

//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::matchingMove(AnimStep newStep, Preset * currentTargetPreset){
    
    
    middlePanel->hide();
    
    vector<int> newTargetValues = currentTargetPreset->getValues();
    eventLogger.logEvent(NEW_TARGET, newTargetValues);
    targetSynth.setAllParamsWithoutSend(newTargetValues);
    
    // if showing guides show the hint hand
    doGuides(newStep.showsGuides, currentTargetPreset);
    
    doIcons(newStep.showsIcons, currentTargetPreset);
    
    doHand(true);
    
    if (newStep.showsGuides){
        displayInstructions("MATCH THE GUIDES");
        // trigger "guide sound"?
        triggerCandidateSound();
    }else{
        displayInstructions("MATCH WITHOUT GUIDES");
    }
    showSeqNum(newStep.whichInSequence);
    // trigger where we're at at the moment
    triggerCandidateSound();
    
    
    oldTargetValues = newTargetValues;
    if (!newStep.showsGuides || !newStep.showsIcons){
        controlPanel->setColor(ofColor::red);
        // set sliders to default texture
        controlPanel->setIndicatorTexture(NULL);
        forgotButton->show();
    }else{
        
        controlPanel->setColor(ofColor::darkMagenta);
        
        
    }
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::matchingLast(AnimStep newStep, Preset * currentTargetPreset){
    // why is this different from match it?
    
    vector<int> newTargetValues = currentTargetPreset->getValues();
    eventLogger.logEvent(NEW_TARGET, newTargetValues);
    targetSynth.setAllParamsWithoutSend(newTargetValues);
    
    doGuides(newStep.showsGuides, currentTargetPreset);
    
    doIcons(newStep.showsIcons, currentTargetPreset);
    
    doHand(true);
    
    //displayInstructions("MATCHING FINISHED");
    showSeqNum(newStep.whichInSequence);
    
    triggerCandidateSound();
    oldTargetValues = newTargetValues;
    if (!newStep.showsGuides || !newStep.showsIcons){
        controlPanel->setColor(ofColor::red);
        // set sliders to default texture
        controlPanel->setIndicatorTexture(NULL);
        forgotButton->show();
    }else{
        
        controlPanel->setColor(ofColor::darkMagenta);
        
        
    }
}
//-----------------------------------------------------------------------------

TrainingTestResult TrainingMessageOrganiser::doResults(AnimStep step,
                                                       Preset * targetPreset,
                                                       vector<int> startingPosition,
                                                       vector<int> currentPosition){
    // targetParams, startPosition, answer, timeAllowed
    TrainingTestResult result =
    
    trainingScoreManager.getScoreForAnswer(targetPreset->getValues(),
                                           startingPosition,
                                           currentPosition,
                                           step.getTimeAllowed(),
                                           step.difficulty,
                                           step.whichInSequence,
                                           step.presetIndex,
                                           step.tempoLevel,
                                           step.totalLengthOfSeq);
    
    sequenceController.saveResultForCurrentStep(result);
    instructionPanel->setColor(result.colorBand);
    
    
    displayInstructions(result.displayText);
    
    showScoreNum(trainingScoreManager.getScore());
    
    return result;
}

void TrainingMessageOrganiser::flashResult(TrainingTestResult r){
    
    // stick a colored number over target position
    controlPanel->flashResultLight(r.colorBand, r.timeAllowed*ofGetFrameRate()/6000.);
    
    
}


//------------------------------------------------------------------------------------
void TrainingMessageOrganiser::doIcons(bool showIcons, Preset * currentTargetPreset){
    
    if (showIcons){
        presetIconPanel->setTextAndImage(currentTargetPreset->name, currentTargetPreset->getImage(), false);
        presetIconPanel->show();
    }else{
        presetIconPanel->hide();
    }
}
//------------------------------------------------------------------------------------
void TrainingMessageOrganiser::doGuides(bool showGuides, Preset * currentTargetPreset){
    
    // show icon and guides
    if (showGuides){ // always show neutral one
        
        // show where we're going
        controlPanel->setAndShowHint(currentTargetPreset->getValues(), currentTargetPreset->getImage());
        if (panelType == LEAP6DOF) distanceSlider->show();
        
    }else{
        controlPanel->showHint(false);
        distanceSlider->hide();
    }
    // special case - always show guide for neutral position
    if(currentTargetPreset->name == "Neutral"){
        controlPanel->setAndShowHint(currentTargetPreset->getValues(), currentTargetPreset->getImage());
    }
    
}
//-----------------------------------------------------------------------------
void TrainingMessageOrganiser::doHand(bool showControllableHand, bool showAnimatedHand, float animTime, vector<int> newTargetValues)
{
    // show how to get there
    if (showAnimatedHand){
        //if (panelType == LEAP6DOF){
        controlPanel->animateToNewValues(newTargetValues, animTime);
        controlPanel->showValueIndicators(true); // for animation
        controlPanel->setActive(false);
        //}
        
    }else if(showControllableHand){
        controlPanel->showValueIndicators(true); // for animation
        controlPanel->setActive(true); // allow user control
        if (panelType == LEAP6DOF){
            okToGetMidi = true; // allow midi input to thing
        }else{
            okToGetMidi = false;
            setSlidersToCandidate(); // cos hand won't be controlling them
        }
        
    }else{
        controlPanel->showValueIndicators(false); // hand/ slider bars invisible
        controlPanel->setActive(false); // cant control it
    }
    
}
void TrainingMessageOrganiser::forgotByMidi(){
    forgotButton->turnOn();
    buttonPressCallback(FORGOT_SEQ_ID, 1);
}