# HG changeset patch # User Robert Tubb # Date 1412938002 -3600 # Node ID a223551fdc1f82b3b72627e7131d977420c8fd2c First commit - copy from tweakathlon. diff -r 000000000000 -r a223551fdc1f 2dvector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/2dvector.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,74 @@ +/* + * 2dvector.h + * simplespring + * + * Created by Robert Tubb on 01/06/2011. + * Copyright 2011 __MyCompanyName__. All rights reserved. + * + */ +#ifndef _2DVECTORH +#define _2DVECTORH +#include + +class TwoVector{ +public: + double x, y; + TwoVector(); + TwoVector(double ax, double ay); + +// public methods + double norm(); + void setCoord(double ax, double ay); + TwoVector minus(TwoVector otherPoint); + TwoVector operator-(TwoVector otherPoint); + TwoVector operator+(TwoVector otherPoint); + + TwoVector operator*(TwoVector otherPoint); + TwoVector operator*(const double& scalar); // scalar is right operand + + //TwoVector operator=(TwoVector otherPoint); + + double distanceTo(TwoVector otherPoint); + +}; +using namespace std; +// output text formatting: (x,y) in super precise output +inline ostream& operator<<(ostream& ostr, const TwoVector& tvec){ + ostr.setf(ios_base::fixed,ios_base::floatfield); + ostr.precision(1); + + ostr << "(" << tvec.x << "," << tvec.y << ")"; + return ostr; +} +inline istream& operator>>(istream& istr, TwoVector& tvec){ + // um + + char l_paren , comma, r_paren; + + + if(istr.bad()){ + cout << "BAD INPUT"; + return istr; + } + + istr.setf(ios_base::fixed,ios_base::floatfield); + istr.precision(1); + + istr >> l_paren >> tvec.x >> comma >> tvec.y >> r_paren; + if(l_paren != '('){ + cout << "BAD INPUT ("; + return istr; + } + + if(comma != ','){ + cout << "BAD INPUT ,"; + return istr; + } + + if(r_paren != ')'){ + cout << "BAD INPUT )"; + return istr; + } + return istr; +} +#endif // #ifndef _2DVECTORH \ No newline at end of file diff -r 000000000000 -r a223551fdc1f 2dvector.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/2dvector.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,80 @@ +/* + * 2dvector.cpp + * simplespring + * + * Created by Robert Tubb on 01/06/2011. + * Copyright 2011 __MyCompanyName__. All rights reserved. + * + */ + +#include "2dvector.h" + + +TwoVector::TwoVector(){ + x = 0.0; + y = 0.0; + //cout << "def constr set vector to zeros" << endl; +} + +TwoVector::TwoVector(double ax, double ay){ + x = ax; + y = ay; + //cout << "spec constr set vector to " << ax << "," << ay << endl; +} + +double TwoVector::norm(){ + double norm; + norm = sqrt(x * x + y * y); + return norm; + +} + +void TwoVector::setCoord(double ax, double ay){ + x = ax; + y = ay; + +} + +TwoVector TwoVector::minus(TwoVector otherPoint){ + TwoVector diff; + diff.setCoord(x - otherPoint.x, y - otherPoint.y); + return diff; +} + +TwoVector TwoVector::operator-(TwoVector otherPoint){ + TwoVector diff; + diff.setCoord(x - otherPoint.x, y - otherPoint.y); + return diff; +} + +TwoVector TwoVector::operator*(TwoVector otherPoint){ // if multiplying two vectors - elementwise + TwoVector diff; + diff.setCoord(x * otherPoint.x, y * otherPoint.y); + return diff; +} + +TwoVector TwoVector::operator*(const double& scalar){ + TwoVector diff; + diff.setCoord(x * scalar, y * scalar); + return diff; +} + +TwoVector TwoVector::operator+(TwoVector otherPoint){ + TwoVector diff; + diff.setCoord(otherPoint.x + x, otherPoint.y + y); + return diff; +} + +/* +TwoVector TwoVector::operator=(TwoVector otherPoint){ + TwoVector result; + result.setCoord(otherPoint.x, otherPoint.y); + return result; +} +*/ +double TwoVector::distanceTo(TwoVector otherPoint){ + TwoVector diff; + diff.setCoord(otherPoint.x - x, otherPoint.y - y); + return diff.norm(); +} + diff -r 000000000000 -r a223551fdc1f AppCore.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AppCore.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011 Dan Wilcox + * + * BSD Simplified License. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. + * + * See https://github.com/danomatika/ofxPd for documentation + * + */ +#pragma once + +#include "ofMain.h" + +#include "ofxPd.h" + +// a namespace for the Pd types +using namespace pd; + +class AppCore : public PdReceiver, public PdMidiReceiver { + + public: + string patchName; + // main + void setup(const int numOutChannels, const int numInChannels, + const int sampleRate, const int ticksPerBuffer); + void update(); + void draw(); + void exit(); + + // do something + void playTone(int pitch); + + // input callbacks + void keyPressed(int key); + + // audio callbacks + void audioReceived(float * input, int bufferSize, int nChannels); + void audioRequested(float * output, int bufferSize, int nChannels); + + // pd message receiver callbacks + void print(const std::string& message); + + void receiveBang(const std::string& dest); + void receiveFloat(const std::string& dest, float value); + void receiveSymbol(const std::string& dest, const std::string& symbol); + void receiveList(const std::string& dest, const List& list); + void receiveMessage(const std::string& dest, const std::string& msg, const List& list); + + // pd midi receiver callbacks + void receiveNoteOn(const int channel, const int pitch, const int velocity); + void receiveControlChange(const int channel, const int controller, const int value); + void receiveProgramChange(const int channel, const int value); + void receivePitchBend(const int channel, const int value); + void receiveAftertouch(const int channel, const int value); + void receivePolyAftertouch(const int channel, const int pitch, const int value); + + void receiveMidiByte(const int port, const int byte); + + // demonstrates how to manually poll for messages + void processEvents(); + + ofxPd pd; + vector scopeArray; + + int midiChan; +}; diff -r 000000000000 -r a223551fdc1f AppCore.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AppCore.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2011 Dan Wilcox + * + * BSD Simplified License. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. + * + * See https://github.com/danomatika/ofxPd for documentation + * + */ +#include "AppCore.h" + +//-------------------------------------------------------------- +void AppCore::setup(const int numOutChannels, const int numInChannels, + const int sampleRate, const int ticksPerBuffer) { + + ofSetFrameRate(60); + ofSetVerticalSync(true); + //ofSetLogLevel(OF_LOG_VERBOSE); + + // double check where we are ... + cout << ofFilePath::getCurrentWorkingDirectory() << endl; + + if(!pd.init(numOutChannels, numInChannels, sampleRate, ticksPerBuffer)) { + ofLog(OF_LOG_ERROR, "Could not init pd"); + OF_EXIT_APP(1); + } + midiChan = 1; // midi channels are 1-16 + + // subscribe to receive source names + pd.subscribe("toOF"); + pd.subscribe("env"); + + // add message receiver, disables polling (see processEvents) + pd.addReceiver(*this); // automatically receives from all subscribed sources + pd.ignore(*this, "env"); // don't receive from "env" + //pd.ignore(*this); // ignore all sources + //pd.receive(*this, "toOF"); // receive only from "toOF" + + // add midi receiver + //pd.addMidiReceiver(*this); // automatically receives from all channels + //pd.ignoreMidi(*this, 1); // ignore midi channel 1 + pd.ignoreMidi(*this); // ignore all channels + //pd.receiveMidi(*this, 1); // receive only from channel 1 + + // add the data/pd folder to the search path + pd.addToSearchPath("pd"); + + // audio processing on + pd.start(); + + // open patch + //patchName = "targetSynth6.pd"; + patchName = "tweakathon_synth_pulse.pd"; + Patch patch = pd.openPatch(patchName); + cout << patch << endl; + + +} + +//-------------------------------------------------------------- +void AppCore::update() { + ofBackground(100, 100, 100); + + // update scope array from pd + pd.readArray("scope", scopeArray); +} + +//-------------------------------------------------------------- +void AppCore::draw() { + + // draw scope + ofSetColor(0, 255, 0); + ofSetRectMode(OF_RECTMODE_CENTER); + float x = 0, y = ofGetHeight()/2; + float w = ofGetWidth() / (float) scopeArray.size(), h = ofGetHeight()/2; + for(int i = 0; i < scopeArray.size()-1; ++i) { + ofLine(x, y+scopeArray[i]*h, x+w, y+scopeArray[i+1]*h); + x += w; + } +} + +//-------------------------------------------------------------- +void AppCore::exit() { + pd.stop(); +} + +//-------------------------------------------------------------- +void AppCore::playTone(int pitch) { + pd << StartMessage() << "pitch" << pitch << FinishList("tone") << Bang("tone"); +} + +//-------------------------------------------------------------- +void AppCore::keyPressed (int key) { + + switch(key) { + + case 'a': + playTone(60); + break; + case 'w': + playTone(61); + break; + case 's': + playTone(62); + break; + case 'e': + playTone(63); + break; + case 'd': + playTone(64); + break; + case 'f': + playTone(65); + break; + case 't': + playTone(66); + break; + case 'g': + playTone(67); + break; + case 'y': + playTone(68); + break; + case 'h': + playTone(69); + break; + case 'u': + playTone(70); + break; + case 'j': + playTone(71); + break; + case 'k': + playTone(72); + break; + + case ' ': + if(pd.isReceiving(*this, "env")) { + pd.ignore(*this, "env"); + cout << "ignoring env" << endl; + } + else { + pd.receive(*this, "env"); + cout << "receiving from env" << endl; + } + break; + + default: + break; + } +} + +//-------------------------------------------------------------- +void AppCore::audioReceived(float * input, int bufferSize, int nChannels) { + pd.audioIn(input, bufferSize, nChannels); +} + +//-------------------------------------------------------------- +void AppCore::audioRequested(float * output, int bufferSize, int nChannels) { + pd.audioOut(output, bufferSize, nChannels); +} + +//-------------------------------------------------------------- +void AppCore::print(const std::string& message) { + cout << message << endl; +} + +//-------------------------------------------------------------- +void AppCore::receiveBang(const std::string& dest) { + cout << "OF: bang " << dest << endl; +} + +void AppCore::receiveFloat(const std::string& dest, float value) { + cout << "OF: float " << dest << ": " << value << endl; +} + +void AppCore::receiveSymbol(const std::string& dest, const std::string& symbol) { + cout << "OF: symbol " << dest << ": " << symbol << endl; +} + +void AppCore::receiveList(const std::string& dest, const List& list) { + cout << "OF: list " << dest << ": "; + + // step through the list + for(int i = 0; i < list.len(); ++i) { + if(list.isFloat(i)) + cout << list.getFloat(i) << " "; + else if(list.isSymbol(i)) + cout << list.getSymbol(i) << " "; + } + + // you can also use the built in toString function or simply stream it out + // cout << list.toString(); + // cout << list; + + // print an OSC-style type string + cout << list.types() << endl; +} + +void AppCore::receiveMessage(const std::string& dest, const std::string& msg, const List& list) { + cout << "OF: message " << dest << ": " << msg << " " << list.toString() << list.types() << endl; +} + +//-------------------------------------------------------------- +void AppCore::receiveNoteOn(const int channel, const int pitch, const int velocity) { + cout << "OF MIDI: note on: " << channel << " " << pitch << " " << velocity << endl; +} + +void AppCore::receiveControlChange(const int channel, const int controller, const int value) { + cout << "OF MIDI: control change: " << channel << " " << controller << " " << value << endl; +} + +// note: pgm nums are 1-128 to match pd +void AppCore::receiveProgramChange(const int channel, const int value) { + cout << "OF MIDI: program change: " << channel << " " << value << endl; +} + +void AppCore::receivePitchBend(const int channel, const int value) { + cout << "OF MIDI: pitch bend: " << channel << " " << value << endl; +} + +void AppCore::receiveAftertouch(const int channel, const int value) { + cout << "OF MIDI: aftertouch: " << channel << " " << value << endl; +} + +void AppCore::receivePolyAftertouch(const int channel, const int pitch, const int value) { + cout << "OF MIDI: poly aftertouch: " << channel << " " << pitch << " " << value << endl; +} + +// note: pd adds +2 to the port num, so sending to port 3 in pd to [midiout], +// shows up at port 1 in ofxPd +void AppCore::receiveMidiByte(const int port, const int byte) { + cout << "OF MIDI: midi byte: " << port << " " << byte << endl; +} + +//-------------------------------------------------------------- +void AppCore::processEvents() { + + cout << "Number of waiting messages: " << pd.numMessages() << endl; + + while(pd.numMessages() > 0) { + Message& msg = pd.nextMessage(); + + switch(msg.type) { + + case pd::PRINT: + cout << "OF: " << msg.symbol << endl; + break; + + // events + case pd::BANG: + cout << "OF: bang " << msg.dest << endl; + break; + case pd::FLOAT: + cout << "OF: float " << msg.dest << ": " << msg.num << endl; + break; + case pd::SYMBOL: + cout << "OF: symbol " << msg.dest << ": " << msg.symbol << endl; + break; + case pd::LIST: + cout << "OF: list " << msg.list << msg.list.types() << endl; + break; + case pd::MESSAGE: + cout << "OF: message " << msg.dest << ": " << msg.symbol << " " + << msg.list << msg.list.types() << endl; + break; + + // midi + case pd::NOTE_ON: + cout << "OF MIDI: note on: " << msg.channel << " " + << msg.pitch << " " << msg.velocity << endl; + break; + case pd::CONTROL_CHANGE: + cout << "OF MIDI: control change: " << msg.channel + << " " << msg.controller << " " << msg.value << endl; + break; + case pd::PROGRAM_CHANGE: + cout << "OF MIDI: program change: " << msg.channel << " " + << msg.value << endl; + break; + case pd::PITCH_BEND: + cout << "OF MIDI: pitch bend: " << msg.channel << " " + << msg.value << endl; + break; + case pd::AFTERTOUCH: + cout << "OF MIDI: aftertouch: " << msg.channel << " " + << msg.value << endl; + break; + case pd::POLY_AFTERTOUCH: + cout << "OF MIDI: poly aftertouch: " << msg.channel << " " + << msg.pitch << " " << msg.value << endl; + break; + case pd::BYTE: + cout << "OF MIDI: midi byte: " << msg.port << " 0x" + << hex << (int) msg.byte << dec << endl; + break; + + case pd::NONE: + cout << "OF: NONE ... empty message" << endl; + break; + } + } +} diff -r 000000000000 -r a223551fdc1f HelpViewController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HelpViewController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,16 @@ +// +// HelpViewController.h +// sonicZoom +// +// Created by Robert Tubb on 01/02/2013. +// +// + +#import + +@interface HelpViewController : UIViewController +@property (nonatomic, assign) id theOFAppRef; +-(IBAction)hide:(id)sender; +-(IBAction)show:(id)sender; +-(void)setAppRef:(id)theOFApp; +@end diff -r 000000000000 -r a223551fdc1f HelpViewController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HelpViewController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,53 @@ +// +// HelpViewController.m +// sonicZoom +// +// Created by Robert Tubb on 01/02/2013. +// +// + +#import "HelpViewController.h" +#import "testApp.h" +@interface HelpViewController () + +@end + +@implementation HelpViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)setAppRef:(id)theOFApp{ + self.theOFAppRef = theOFApp; + +} +-(IBAction)show:(id)sender{ + self.view.hidden = NO; +} + +- (IBAction)hide:(id)sender +{ + self.view.hidden = YES; + ((testApp *)self.theOFAppRef)->helpHidden(); + + +} +@end diff -r 000000000000 -r a223551fdc1f HelpViewController.xib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HelpViewController.xib Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,250 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBProxyObject + IBUIButton + IBUILabel + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBIPadFramework + + + IBFirstResponder + IBIPadFramework + + + + 292 + + + + 292 + {{319, 941}, {130, 44}} + + + + _NS:9 + NO + IBIPadFramework + 0 + 0 + 1 + BACK TO APP + + 3 + MQA + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + 3 + MC41AA + + + 2 + 15 + + + Helvetica-Bold + 15 + 16 + + + + + 292 + {{64, 53}, {640, 872}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + SEVMUOKAqOKAqOKAqEkgbmVlZCBzb21lb25lLiBOb3QganVzdCBhbnlvbmUuDQ + + 1 + MCAxIDAuOTc2NDI2Mjc5OAA + + + 0 + 300 + + 1 + 16 + + + Helvetica + 16 + 16 + + NO + 640 + + + {1024, 768} + + + + + 1 + MCAwIDAAA + + NO + + 3 + 3 + + + IBUIScreenMetrics + + YES + + + + + + {768, 1024} + {1024, 768} + + + IBIPadFramework + iPad Full Screen + 1 + + IBIPadFramework + + + + + + + view + + + + 3 + + + + hide: + + + 7 + + 24 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 2 + + + + + + + + + 14 + + + + + + 26 + + + + + + + HelpViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 26 + + + + + HelpViewController + UIViewController + + id + id + + + + hide: + id + + + show: + id + + + + IBProjectSource + ./Classes/HelpViewController.h + + + + + 0 + IBIPadFramework + YES + 3 + 2083 + + diff -r 000000000000 -r a223551fdc1f IntroViewController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IntroViewController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,20 @@ +// +// IntroViewController.h +// sonicZoom +// +// Created by Robert Tubb on 29/01/2013. +// +// + +#import + +@interface IntroViewController : UIViewController + +@property (nonatomic, assign) id theOFAppRef; +@property (retain, nonatomic) IBOutlet UILabel *text; + +-(IBAction)hide:(id)sender; +-(IBAction)show:(id)sender; +-(IBAction)disagree:(id)sender; +-(void)setAppRef:(id)theOFApp; +@end diff -r 000000000000 -r a223551fdc1f IntroViewController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IntroViewController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,68 @@ +// +// IntroViewController.m +// sonicZoom +// +// Created by Robert Tubb on 29/01/2013. +// +// + +#import "IntroViewController.h" +#import "testApp.h" +@interface IntroViewController () + +@end + +@implementation IntroViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)setAppRef:(id)theOFApp{ + self.theOFAppRef = theOFApp; + +} + +- (IBAction)show:(id)sender +{ + self.theOFAppRef = sender; + self.view.hidden = NO; +} +- (IBAction)hide:(id)sender +{ + self.view.hidden = YES; + ((testApp *)self.theOFAppRef)->introHidden(); + +} +- (IBAction)disagree:(id)sender +{ + // shut down the app + self.view.hidden = YES; + ((testApp *)self.theOFAppRef)->introHidden(); +} +- (void)dealloc { + [_text release]; + [super dealloc]; +} +- (void)viewDidUnload { + [self setText:nil]; + [super viewDidUnload]; +} +@end diff -r 000000000000 -r a223551fdc1f IntroViewController.xib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IntroViewController.xib Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 000000000000 -r a223551fdc1f MessageOrganiser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MessageOrganiser.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,699 @@ +// +// MessageOrganiser.h +// tweakathlon +// +// Created by Robert Tubb on 10/12/2013. +// +// This object handles the mapping from GUI to params +// +// and sends their messages to PD and eventLogger +#pragma once +#include "eventLogger.h" +#include +#include +#include +#include "boost/bind.hpp" +#include "boost/function.hpp" + +#include +#include +#include +#include +#include "AppCore.h" +#include "ofxPd.h" +#include "TestController.h" +#include "timeController.h" +#include "PDSynthWrapper.h" +#include "ofxTimer.h" +#include "sliderPanel.h" +//#include "testApp.h" +#include "targetSymbol.h" +#include "3Dbox.h" +#include "TextPanel.h" +#include "CountdownText.h" +#include "buttonPanel.h" + +// event logger needs to know +// which controls were showing in what mode +// which controls were mapped to what param +// what was the target sound params +// all the updates of control movements, submit, quit etc + +// this is the bit that handles mapping from UI elements to synth i.e testApp DOESNT DO THAT + +// has links to panel sliders can show hide them + +// controls flow of stuff + +//--------------------------------------------------------------------- +//--------------------------------------------------------------------- +extern TimeController timeController; + +extern EventLogger eventLogger; + +typedef boost::function AppModeChangeFunction; + +class MessageOrganiser { +private: + AppCore* core; + //testApp* theOFApp; + PDSynthWrapper targetSynth; + PDSynthWrapper candidateSynth; + + map currentMapping; // could get more sophisticated if not 1-1 ? + + SliderPanel* panel; + TimeController altPlaybackController; + + TestController* testController; + Buttron* newTestButton; + //Buttron* submitButton; + + ButtonPanel* bottomPanel; // shows during test : play buttons and submit + Buttron* targetPlayButton; // so we can hide target in memory test. this pointer stuff is getting out of hand + CountdownText* countdownPanel; + TargetSymbol* targetSymbol; + Leap3DBoxGL* box3D; + TextPanel* scorePanel; + TextPanel* finishPanel; + AppModeChangeFunction testAppModeChange; + + //int scoreRunningTotal; + TimerID currentSoundPlayTimer; + + int alternationSpeed; // ms between cand and target + bool playingAlternating; + + bool okToGetLeapMidi; + + void testsFinished(){ + panel->hide(); + bottomPanel->hide(); + newTestButton->hide(); + + vector eData; + eData.push_back(testController->getScoreRunningTotal()); + eventLogger.logEvent(ALL_TESTS_COMPLETED, eData); + + // TODO set final score screen txt to testController->getScoreRunningTotal() + finishPanel->show(); + + string user = eventLogger.getUsername(); + stringstream s; + s << "Experiment completed" + << endl << endl + << "You scored: " << testController->getScoreRunningTotal() << " well done " << user << endl << endl + << "to retake test please close " << endl << endl + << "the app and restart with username"; + finishPanel->setText(s.str()); + // get test app to do something... + + eventLogger.saveSessionToFile(); + }; + + void setupNewTest(){ + // get mapping for new test and make sure we have right controls and stuff + + + Test newTest = testController->goToNextTest(); + + // V0.2 put details about what kind of test it is + vector eData; + eData.push_back(newTest.isPractice()); + eData.push_back(newTest.isWithHint()); + eData.push_back(newTest.isMemoryTest()); + eventLogger.logEvent(NEW_TEST, eData); + + + vector mappingIDsForChangeableParams = setSynthsUpForNewTest(newTest); + + vector UIElemHandles = panel->generateControls(testController->getCurrentListOfControls(), testController->getCurrentPanelType()); + + mapUIToNewTestParams(UIElemHandles, mappingIDsForChangeableParams); + + countdownPanel->setTestTypeString(newTest.getTestTypeAdvanceWarning()); + + + }; + void startNewTest(){ + Test t = testController->getCurrentTest(); + + countdownPanel->hide(); + panel->show(); + panel->setActive(true); + if(t.isWithHint()){ + panel->showHint(true); + } + + bottomPanel->show(); + targetPlayButton->show(); // incase it was memory test + if (t.isMemoryTest()){ + targetPlayButton->setLabel("Memorise!"); + }else{ + targetPlayButton->setLabel("Target"); + } + //startAlternatingPlayback(); + //timeController.scheduleEvent(boost::bind(&MessageOrganiser::sendSynthValuesAgain, this), 200); + timeController.startStopwatch(); + eventLogger.logEvent(TEST_TIMER_STARTED); + + + if(t.getListOfControlTypes()[0] == LEAP3D){ + okToGetLeapMidi = true; + } + }; + + vector setSynthsUpForNewTest(Test newTest){ + targetSynth.setAllParams(newTest.getTargetValues()); + eventLogger.logEvent(TARGET_PARAM_SET, newTest.getTargetValues()); // unless something goes wrong in setAllParams + + candidateSynth.setAllParams(newTest.getStartingCandidateValues()); + eventLogger.logEvent(CANDIDATE_PARAM_SET,newTest.getStartingCandidateValues()); + + // eventLogger.logEvent(NEW_TARGET_PARAMS, vector ); + // eventLogger.logEvent(NEW_CANDIDATE_PARAMS, vector ); + + vector mids = candidateSynth.getMappingIDForIndices(newTest.getChangeableIndices()); + + eventLogger.logEvent(CANDIDATE_CHANGEABLE_IDX, newTest.getChangeableIndices()); + eventLogger.logEvent(CANDIDATE_MAPPING_IDS, mids); + + return mids; + }; + void sendSynthValuesAgain(){ + candidateSynth.sendAllParams(); + targetSynth.sendAllParams(); + }; + + // could have been cleverer. takes forever due to searching ??? + void mapUIToNewTestParams(vector elems, vector mids){ + + vector::iterator elit; + vector typeListLog; + int i = 0; + for(elit=elems.begin(); elitgetType() == XYPAD){ + if(i+1 >= mids.size()){ + cout << "ERROR ERROR: too many controls for mapping IDs" << endl; + } + + ButtronXY* theXY = (ButtronXY*)(*elit); + mapXYToParams(theXY, mids[i], mids[i+1]); + theXY->setValueAndScale(candidateSynth.getParamValueForID(mids[i]), candidateSynth.getParamValueForID(mids[i+1])); + theXY->setHintValue(targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i])) + ,targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i+1]))); + i+=2; + typeListLog.push_back(int(XYPAD)); + }else if ( (*elit)->getType() == SLIDER){ + if(i >= mids.size()){ + cout << "ERROR ERROR: too many controls for mapping IDs" << endl; + } + + ButtronSlider* theSlider = (ButtronSlider*)(*elit); + mapControlToParam((*elit), mids[i]); + theSlider->setValueAndScale(candidateSynth.getParamValueForID(mids[i])); + cout << "Hint Value " << targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i])) << endl; + theSlider->setHintValue(targetSynth.getParamValueFromName(candidateSynth.getNameForMappingID(mids[i]))); + i++; + typeListLog.push_back(int(SLIDER)); + }else if ( (*elit)->getType() == LEAP3D ){ + set3Dbox((Leap3DBoxGL*)(*elit)); + // UH + string nameX = candidateSynth.getNameForMappingID(mids[i]); + box3D->setHintValue(0,targetSynth.getParamValueFromName(nameX)); + box3D->setValueAndScale(0, candidateSynth.getParamValueForID(mids[i])); + i++; + + string nameY = candidateSynth.getNameForMappingID(mids[i]); + box3D->setHintValue(1,targetSynth.getParamValueFromName(nameY)); + box3D->setValueAndScale(1, candidateSynth.getParamValueForID(mids[i])); + i++; + + string nameZ = candidateSynth.getNameForMappingID(mids[i]); + box3D->setHintValue(2,targetSynth.getParamValueFromName(nameZ)); + box3D->setValueAndScale(2, candidateSynth.getParamValueForID(mids[i])); + i++; + + + box3D->setLabels(nameX,nameY,nameZ); + typeListLog.push_back(int(LEAP3D)); + + }else{ + cout << "ERROR ERROR: ui type not handled my mapping function !" << endl; + } + } + + eventLogger.logEvent(CONTROL_LIST,typeListLog); + }; + + // TODO - no, triggering playback needs to be logged + void startAlternatingPlayback(){ + + cout << "start alt playback" << endl; + // use our special timer to fire off play to pd + // sets off timed alternating playback + + playAlternating(); + playingAlternating = true; + + }; + void stopAlternatingPlayback(){ + cout << "stop alt playback" << endl; + // kill the alternation + timeController.cancelEvent(currentSoundPlayTimer); + playingAlternating = false; + }; + + void playAlternating(){ + + static bool alt; + int nextTime; + if (alt){ + targetSynth.trigger(); + // flash the target thingy + targetSymbol->flash(); + nextTime = alternationSpeed*1.503; // gap after target + }else{ + sendSynthValuesAgain(); // and again and again + candidateSynth.trigger(); + panel->flash(); + nextTime = alternationSpeed; + } + alt = !alt; + candidateSynth.setNoteLength(alternationSpeed); + targetSynth.setNoteLength(alternationSpeed); // could be user alterable + currentSoundPlayTimer = timeController.scheduleEvent(boost::bind(&MessageOrganiser::playAlternating,this), nextTime); + + + + }; + + void delayedShowNewTest(){ + newTestButton->show(); + // JUST IN CASE IT CRASHES near end... + //eventLogger.saveSessionToFile(); + }; + void submitSingleControl(){ + // if last one + // submitPressed() + + // else + + // grey out that slider, + // activate next slider and show it's button (same button but moved!???) + + }; + + + void submitPressed(){ + + // depending on mode go to next control + // if(testController->getCurrentPanelType() == SEQUENTIAL){ + // submitSingleControl(); + // return; + // } + // otherwise do this other - or call + + okToGetLeapMidi = false; + + TimerMillisec timeTaken = timeController.stopStopwatch(); + vector answer = candidateSynth.getAllParamValues(); + + eventLogger.logEvent(SUBMIT_PRESSED, answer); //, answer, scoreRunningTotal, time taken (why not?)); + + TestResult result = testController->submitAnswer(answer, timeTaken); // TODO returns all the results + + vector logResult; + logResult.push_back(result.realDistanceToTarget*1000); // measured in milliCC !??! + logResult.push_back(result.timeTaken); // milliseconds + logResult.push_back(result.score); + logResult.push_back(result.targetBandHit); + logResult.push_back(result.timeWindowHit); + + eventLogger.logEvent(DISTANCE_TIME_SCORE, logResult); + + + // gui stuff - different controller? + panel->setActive(false); + panel->showHint(true); // add some encouraging feedback to hint + bottomPanel->hide(); + + showScoreForTest(result); + + stopAlternatingPlayback(); + + // was it the final sumbit? + if(testController->isLastTest()){ + // thats it - show a final score screen etc + timeController.scheduleEvent(boost::bind(&MessageOrganiser::testsFinished, this), 500); + return; + }else{ + timeController.scheduleEvent(boost::bind(&MessageOrganiser::delayedShowNewTest, this), 300); + } + + + }; + + void showScoreForTest(TestResult result){ + scorePanel->setText(result.displayText); + scorePanel->show(); + + ofColor c; + if(result.targetBandHit == 1){ + // yellow red blue + c = ofColor(255,255,0,255); + }else if(result.targetBandHit == 2){ + c = ofColor(255,0,0,255); + }else if(result.targetBandHit == 3){ + c = ofColor(45,45,255,255); + }else if(result.targetBandHit == 4){ + c = ofColor(0,255,0,255); + }else{ + c = ofColor(150,235,200,255); + } + scorePanel->setColor(c); + panel->setHintColor(c); + }; + + // we want to set UI object + void setUIToParam(int index, int value){ // e.g. from MIDI incoming, will handle both box and sliders... + // theXY->setValueAndScale(candidateSynth.getParamValueForID(mids[i]), candidateSynth.getParamValueForID(mids[i+1])); + UIElement* elem; + // get the element + if(panel->subElements.size() <= index){ + return; + } + elem = panel->subElements[index]; + if ( elem->getType() == SLIDER){ + ButtronSlider* theSlider = (ButtronSlider*)elem; + theSlider->setValueAndScale(value); + + }else{ + cout << "ERROR ERROR: ui type not handled by setUIToParam!" << endl; + } + + }; + + + void mapControlToParam(UIElement* control, int mappingID){ + + UICallbackFunction callbackF; + callbackF = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2); + control->addHandler(callbackF, mappingID); + // put in our map so we can send param values to gui + currentMapping.insert(std::pair(mappingID,control)); + cout << " Mapped control to ID: " << mappingID << "Name: " << candidateSynth.getNameForMappingID(mappingID) << endl; + control->setLabel(candidateSynth.getNameForMappingID(mappingID)); + }; + + void mapXYToParams(ButtronXY* control, int mappingIDX, int mappingIDY){ + UICallbackFunction callback; + + callback = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2); + + control->addHandler(callback, mappingIDX, mappingIDY); + + // put in our map so we can send param values to gui + //currentMapping.insert(std::pair(mappingID,control)); + + + cout << " Mapped control to XID: " << mappingIDX << "Name: " << candidateSynth.getNameForMappingID(mappingIDX) << endl; + cout << " Mapped control to YID: " << mappingIDY << "Name: " << candidateSynth.getNameForMappingID(mappingIDY) << endl; + control->setLabel(candidateSynth.getNameForMappingID(mappingIDX), candidateSynth.getNameForMappingID(mappingIDY)); + + }; + + void mapLeapToParams(ButtronXY* control, int mappingIDX, int mappingIDY, int mappingIDZ){ +// UICallbackFunction callbackX; +// UICallbackFunction callbackY; +// UICallbackFunction callbackZ; +// +// callbackX = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2); +// callbackY = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2); +// callbackZ = boost::bind(&MessageOrganiser::paramChangeCallback, this, _1,_2); +// +// control->addHandler(callbackX, mappingIDX); +// control->addHandler(callbackY, mappingIDY); +// +// // put in our map so we can send param values to gui +// //currentMapping.insert(std::pair(mappingID,control)); +// +// +// cout << " Mapped control to XID: " << mappingIDX << "Name: " << candidateSynth.getNameForMappingID(mappingIDX) << endl; +// cout << " Mapped control to YID: " << mappingIDY << "Name: " << candidateSynth.getNameForMappingID(mappingIDY) << endl; +// control->setLabel(candidateSynth.getNameForMappingID(mappingIDX), candidateSynth.getNameForMappingID(mappingIDY)); + + }; + + void mapControlToParam(UIElement* control, string paramName){ + // get mapping ID from synth + int mappingID = candidateSynth.getMappingIDForName(paramName); + mapControlToParam(control, mappingID); + control->setLabel(paramName); + }; +public: + void init(AppCore* aCore, TestController* tc){ + // set PD core... + + core = aCore; + targetSynth.init(aCore,"targetSynth"); + candidateSynth.init(aCore,"candidateSynth"); + + testController = tc; + currentSoundPlayTimer = -1; + okToGetLeapMidi = false; + + alternationSpeed = 200; + + candidateSynth.setNoteLength(alternationSpeed); + targetSynth.setNoteLength(alternationSpeed); + + playingAlternating = false; + }; + void setNewTestButton(Buttron * ntb){ + newTestButton = ntb; + }; + void set3Dbox(Leap3DBoxGL* box){ + box3D = box; + }; + void setBottomPanel(ButtonPanel * ntb){ + bottomPanel = ntb; + }; + void setControlPanel(SliderPanel* p){ + panel = p; + + }; + void setCountdownPanel(CountdownText* cd){ + countdownPanel = cd; + }; + void setTargetSymbol(TargetSymbol* ts){ + targetSymbol = ts; + }; + void setScorePanel(TextPanel* tp){ + scorePanel = tp; + }; + void setFinishPanel(TextPanel* fp){ + finishPanel = fp; + } + void setTargetButton(Buttron* tb){ + targetPlayButton = tb; + } + int getScore(){ + return testController->getScoreRunningTotal(); + }; + + pair getTime(){ + TimerMillisec tms = timeController.getStopwatchElapsedTime(); + int s = int(tms/1000); + int hs = int((tms%1000)/10); + pair p(s,hs); + return p; + }; + void countdownToNewTest(){ + + panel->hide(); + panel->setActive(false); + scorePanel->hide(); + bottomPanel->hide(); + newTestButton->hide(); + + // set up stuff + setupNewTest(); + eventLogger.logEvent(COUNTDOWN_INITIATED); + + countdownPanel->showAndStart(3); + + timeController.scheduleEvent(boost::bind(&MessageOrganiser::startNewTest, this), 3000); + + }; + void sendToGUI(vector paramsToMap){ + // look up these ids in mapping table + }; + void saveGoodTest(Test t){ + + }; + void playTargetButtonPressed(){ + + static int numPlays = 3; + + Test* t = testController->getCurrentTestPtr(); + if (!t->checkTargetPlaysRemaining()){ + cout << t->getTargetPlaysLeft() << endl; + + sendSynthValuesAgain(); + targetSynth.trigger(); + eventLogger.logEvent(TARGET_PLAYED); + targetPlayButton->hide(); + return; + + } + cout << t->getTargetPlaysLeft() << endl; + + sendSynthValuesAgain(); + targetSynth.trigger(); + eventLogger.logEvent(TARGET_PLAYED); + + return; + } + void playCandidateButtonPressed(){ + // + } + void buttonPressCallback(int mappingID, int value){ + if(mappingID == VOLUME_CHANGE_ID){ + targetSynth.sendVolume(value); + candidateSynth.sendVolume(value); + + } + if(mappingID == SPEED_CHANGE_ID){ + alternationSpeed = 2*(140 - value); + vector eData; + eData.push_back(alternationSpeed); + eventLogger.logEvent(SPEED_CHANGED, eData); + } + if(mappingID == NEW_TEST_ID){ + countdownToNewTest(); + return; + } + if (mappingID == START_ALTERNATE_ID){ + if(!playingAlternating){ + startAlternatingPlayback(); + + }else{ + stopAlternatingPlayback(); + } + return; + } + if(mappingID == GOOD_TEST_ID){ + Test t = testController->getCurrentTest(); + saveGoodTest(t); + } + if (mappingID == RANDOMISE_TARGET_ID){ // bleyeueurrrr + targetSynth.randomiseParams(); + return; + } + if (mappingID == TRIGGER_TARGET_ID){ + playTargetButtonPressed(); + + } + if (mappingID == TRIGGER_CANDIDATE_ID){ + // log event + sendSynthValuesAgain(); + candidateSynth.trigger(); + eventLogger.logEvent(CANDIDATE_PLAYED); + // flash panel? + panel->flash(); + return; + } + if (mappingID == SUBMIT_CANDIDATE){ + // log event + submitPressed(); + + return; + } + if (mappingID == CRAP_TEST_ID){ + // this is rubbish! send a log of target values, and mapping ids + vector data; + vector tvals = targetSynth.getAllParamValues(); + vector pidx = testController->getCurrentChangeableParams(); + data.insert(data.end(), tvals.begin(), tvals.end()); + data.insert(data.end(), pidx.begin(), pidx.end()); + + eventLogger.logEvent(CRAP_TEST, data); + } + if(mappingID == SHOW_HIDE_PANEL){ + static bool showing; + + if(showing){ + cout << " showing"<show(); + + }else{ + cout << " hiding"<hide(); + } + showing = !showing; + } + if(mappingID == SHOW_HIDE_HINT){ + static bool showingHint; + if(showingHint){ + panel->showHint(false); + showingHint = false; + }else{ + panel->showHint(true); + showingHint = true; + } + } + } + // called from UI + void paramChangeCallback(int mappingID, int value){ + candidateSynth.paramChangeCallback(mappingID, value); + vector evtData; + evtData.push_back(mappingID); // or just index? + evtData.push_back(value); + + eventLogger.logEvent(CANDIDATE_PARAM_ADJUSTED, evtData); + }; + + // could template for ui element type?? + void mapButtonToAction(UIElement* control, int mappingID){ + UICallbackFunction callbackF; + callbackF = boost::bind(&MessageOrganiser::buttonPressCallback, this, _1,_2); + control->addHandler(callbackF, mappingID); + currentMapping.insert(std::pair(mappingID,control)); + } + + + void midiFromLeap(int ctl_num, int ctl_val){ + + + if (!okToGetLeapMidi){ + return; + } + + // this fails - try pointer version? + + Test *theTest = testController->getCurrentTestPtr(); + if (theTest == NULL) return; + + box3D->setValueAndScale(ctl_num, ctl_val); + + + vector ci = theTest->getChangeableIndices(); + vector mids = candidateSynth.getMappingIDForIndices(ci); + if (ctl_num >= mids.size() || ctl_num < 0) return; + + candidateSynth.paramChangeCallback(mids[ctl_num], ctl_val); + + vector evtData; + evtData.push_back(mids[ctl_num]); // or just index? + evtData.push_back(ctl_val); + + eventLogger.logEvent(CANDIDATE_PARAM_ADJUSTED, evtData); + // also call UI object + // get mapping ID for + // setUIToParam(ctl_num, ctl_val); + } + +}; + diff -r 000000000000 -r a223551fdc1f PDSynthWrapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PDSynthWrapper.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,229 @@ +// +// pdSynthWrapper.h +// tweakathlon +// +// Created by Robert Tubb on 14/01/2014. +// +// + +#pragma once + +#include "AppCore.h" +#include "eventLogger.h" +#include "ofxPd.h" +#include +#include "boost/bind.hpp" +#include "boost/function.hpp" +#include "SynthParam.h" + + +//--------------------------------------------------------------------- +//--------------------------------------------------------------------- +//--------------------------------------------------------------------- + +class PDSynthWrapper { +public: + void init(AppCore* aCore, string sp){ + core = aCore; + + synthPrefix = sp; + // init all the params, refer to synth in pd patch + timbreParams.push_back(SynthParam(64,aCore,"Pitch",sp)); + timbreParams.push_back(SynthParam(64,aCore,"Pulse",sp)); + timbreParams.push_back(SynthParam(64,aCore,"Attack",sp)); + timbreParams.push_back(SynthParam(64,aCore,"Decay",sp)); + timbreParams.push_back(SynthParam(64,aCore,"FiltTyp",sp)); + timbreParams.push_back(SynthParam(64,aCore,"FiltFrq",sp)); + //timbreParams.push_back(SynthParam(64,aCore,"reson",sp)); + + if (timbreParams.size() != TOTAL_NUM_PARAMS){ + cout << "ERROR ERROR: WRONG NUM OF timbreParams or TOTAL_NUM_PARAMS" << endl; + } + cout << "initialised synth: " << sp << " with " << timbreParams.size() << " params" << endl; + }; + void sendAllParams(){ + std::vector::const_iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + psp->sendToPD(); + } + } + void sendVolume(int value){ + List toPD; + toPD.addSymbol(synthPrefix); + toPD.addSymbol("Volume"); + toPD.addFloat(value); // rounding here?? + + core->pd.sendList("fromOF", toPD); + } + void setNoteLength(int lms){ + List toPD; + toPD.addSymbol(synthPrefix); + toPD.addSymbol("noteLength"); + toPD.addFloat(lms); // volume here, just in case?? + + core->pd.sendList("fromOF", toPD); + } + const int getParamValueForID(int pid){ + int v = 0; + std::vector::const_iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + if (psp->getID() == pid){ + v = psp->getValue(); + return v; + } + + } + cout << "ERROR ERROR getParamValueForID not found" << endl; + } + const int getMappingIDForName(string name) const{ + + int rID = -1; + std::vector::const_iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + if (psp->getName() == name){ + rID = psp->getID(); + return rID; + } + + } + cout << "ERROR ERROR getMappingIDForName not found" << endl; + }; + const string getNameForMappingID(int pid) const{ + + string rname = "no name"; + std::vector::const_iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + if (psp->getID() == pid){ + rname = psp->getName(); + return rname; + } + + } + cout << "ERROR ERROR getNameForMappingID not found" << endl; + }; + vector getMappingIDForIndices(vector idx){ + vector result; + + for(int i = 0 ; i < idx.size(); i++){ + if (idx[i] < timbreParams.size()){ + int mapid = timbreParams[idx[i]].getID(); + + result.push_back(mapid); + //cout << " Map id for param no: " << idx[i] << " is " << *(result.end()-1); + }else{ + cout << "ERROR ERROR: index bigger than num timbre params" << endl; + + } + } + return result; + } + + void paramChangeCallback(int mappingID, int value){ + + // look for id in params + std::vector::iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + if ( psp->getID() == mappingID){ + psp->setValue(value); + return; + } + } + cout << "ERROR ERROR: paramChangeCallback mappingID not found" << endl; + }; + + void trigger(){ + // play the noise + List toPD; + toPD.addSymbol(synthPrefix); + toPD.addSymbol("playSound"); + toPD.addFloat(1.0); // volume here, just in case?? + + core->pd.sendList("fromOF", toPD); + + }; + + void randomiseParams(){ + + cout << " randomising" << endl; + std::vector::iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + + int value = ofRandom(0,127); + psp->setValue(value); + + } + + }; + + void setSameAsOtherSynth(const PDSynthWrapper* otherSynth){ + // loop thru all params and set them to other synth + std::vector::iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + psp->setValue(otherSynth->getParamValueFromName(psp->getName())); + + } + }; + + vector randomiseParamSubset(int howMany){ + vector randomisedIDs; + for (int i=0;i::const_iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + if (psp->getName() == name){ + value = psp->getValue(); + return value; + } + + } + cout << "ERROR ERROR: getParamValueFromName name not found" << endl; + }; + + const int getNumParams(){ + return timbreParams.size(); + }; + + void setAllParams(vector params){ + if(params.size() != timbreParams.size()){ + cout << "Error not right number of params in set in synth" << endl; + return; + } + std::vector::iterator psp; + int i=0; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + psp->setValue(params[i]); + i++; + } + + + } + vector getAllParamValues(){ + vector pl; + std::vector::const_iterator psp; + for(psp = timbreParams.begin(); psp < timbreParams.end(); psp++){ + pl.push_back(psp->getValue()); + } + return pl; + } +private: + string synthPrefix; + AppCore* core; + + vector timbreParams; // array of everything in synth + +}; + +//--------------------------------------------------------------------- +//--------------------------------------------------------------------- \ No newline at end of file diff -r 000000000000 -r a223551fdc1f Question.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Question.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,25 @@ +// +// Question.h +// sonicZoom +// +// Created by Robert Tubb on 21/01/2013. +// +// included by Qviewcont +#define NUM_CHOICES 5 + +#import +typedef enum QuestionType{AGREE_DISAGREE, SLIDERS_ZOOMER} QuestionType; + +@interface Question : NSObject +{ + + +} +@property (strong, nonatomic) NSString *questionText; +@property QuestionType questionType; +@property int answer; // answer 0 means no answer was given (the blank line in picker) this distiguishes between "neither" and "don't know / no answer" + +-(id)initWithTextAndType:(NSString *)text:(QuestionType)type; ++ (int)count; ++(NSArray *)answersWithType:(QuestionType)type; +@end diff -r 000000000000 -r a223551fdc1f Question.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Question.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,65 @@ +// +// Question.m +// sonicZoom +// +// Created by Robert Tubb on 21/01/2013. +// +// + +#import "Question.h" + +@implementation Question + +@synthesize questionText = _questionText; +@synthesize questionType = _questionType; +@synthesize answer = _answer; + +static int theCount = 0; +// WRONG +-(id)initWithTextAndType:(NSString *)text:(QuestionType)type{ + self = [super init]; + if(self){ + self.questionText = text; + self.questionType = type; + self.answer = -1; + } + + return self; + +} +//// +- (id)init +{ + return [self initWithTextAndType:@"Quo Vadis?":AGREE_DISAGREE]; +} + ++ (int) count { return theCount; } ++ (void) setCount:(int)c { theCount = c; } + + + ++(NSArray *)answersWithType:(QuestionType)type{ +// get the set of answers depending on what type the q was + // pseudo static variable + if(type == AGREE_DISAGREE){ + [Question setCount:NUM_CHOICES]; + + NSArray *answers = [[[NSArray alloc] initWithObjects: + @"Strongly agree",@"Agree", @"Neither agree nor disagree", + @"Disagree",@"Strongly disagree", nil] autorelease]; + + return answers; + + }else if(type == SLIDERS_ZOOMER){ + [Question setCount:NUM_CHOICES]; + NSArray *answers = [[[NSArray alloc] initWithObjects: + @"definitely the Sliders", @"maybe the Sliders", @"Neither/Both equal", + @"maybe the Zoomer", @"definitely the Zoomer", nil] autorelease]; + + return answers; + }else{ + return nil; + } +} +/// +@end diff -r 000000000000 -r a223551fdc1f QuestionnaireViewController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QuestionnaireViewController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,52 @@ +// +// QuestionnaireViewController.h +// oscSenderExample +// +// Created by Robert Tubb on 16/01/2013. +// +// + +#import + +#import "Question.h" + +@interface QuestionnaireViewController : UIViewController + +{ + + UIPickerView *picker; + + +} +@property (retain, nonatomic) IBOutlet UILabel *questionText; +@property (retain, nonatomic) IBOutlet UILabel *titleText; +@property (retain, nonatomic) IBOutlet UIButton *finishButton; +@property (retain, nonatomic) IBOutlet UIButton *nextButton; +@property (retain, nonatomic) IBOutlet UIButton *previousButton; + +@property (strong, nonatomic) IBOutlet UIPickerView *picker; + +@property (retain, nonatomic) IBOutlet UITextView *commentText; +@property (retain, nonatomic) IBOutlet UISegmentedControl *numberChooser; +@property (retain, nonatomic) IBOutlet UIView *interfacePreferenceOptions; +@property (retain, nonatomic) IBOutlet UIView *lickertOptions; +@property (retain, nonatomic) IBOutlet UILabel *pleaseAnswer; + +//---------------------------------------------------------------- +- (IBAction)answerChosen:(id)sender; + +-(IBAction)hide:(id)sender; +-(IBAction)show:(id)sender; +- (IBAction)nextQuestionPressed:(id)sender; +- (IBAction)previousQuestionPressed:(id)sender; +-(void)unlockAll; +//---------------------------------------------------------------- +- (void)setAppRef:(id)theOFApp; +- (void)populateQuestionArray; +- (void)loadQuestion:(NSInteger)questionIndex; +//---------------------------------------------------------------- +@end + +//---------------------------------------------------------------- +//---------------------------------------------------------------- +//---------------------------------------------------------------- diff -r 000000000000 -r a223551fdc1f QuestionnaireViewController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QuestionnaireViewController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,306 @@ +// +// QuestionnaireViewController.m +// oscSenderExample +// +// Created by Robert Tubb on 16/01/2013. +// +// + +#import "QuestionnaireViewController.h" + +#include "testApp.h" + +#pragma mark - +#pragma mark QuestionnaireViewController + +@interface QuestionnaireViewController () + // the "model" is an array of questions +@property (strong, nonatomic) NSArray * questionArray; +@property (nonatomic) NSInteger currentQuestionIndex; +@property (nonatomic, assign) id theOFAppRef; + +/* + + +*/ + +@end + +@implementation QuestionnaireViewController + +@synthesize picker; +@synthesize nextButton = _nextButton; +@synthesize questionArray = _questionArray; + + +//---------------------------------------------------------------- +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + + [self populateQuestionArray ]; + + } + return self; +} +- (void)setAppRef:(id)theOFApp{ + self.theOFAppRef = theOFApp; + +} +//---------------------------------------------------------------- +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + self.currentQuestionIndex = 0; + + // load question 1 + [self loadQuestion:self.currentQuestionIndex]; + + self.previousButton.hidden = NO; // bother + self.commentText.hidden = YES; + self.finishButton.hidden = YES; + self.nextButton.hidden = YES; + + self.lickertOptions.hidden = NO; + self.interfacePreferenceOptions.hidden = YES; +} +//---------------------------------------------------------------- +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} +//---------------------------------------------------------------- +- (void)dealloc { + + [super dealloc]; +} +//---------------------------------------------------------------- +- (void)viewDidUnload { + [self.questionArray release]; + [self setQuestionText:nil]; + [self setTitleText:nil]; + [self setFinishButton:nil]; + [self setNextButton:nil]; + [self setPreviousButton:nil]; + [self setCommentText:nil]; + [self setNumberChooser:nil]; + [self setInterfacePreferenceOptions:nil]; + [self setLickertOptions:nil]; + [self setPleaseAnswer:nil]; + [super viewDidUnload]; +} +//---------------------------------------------------------------- +-(IBAction)hide:(id)sender{ + // called when finish button hit + // c++ call with NSArray argument?? + // load answers into a c++ vector; + vector answersArray; + + Question *q; + + for(int i=0;i<[self.questionArray count];i++){ + q = [self.questionArray objectAtIndex:i]; + answersArray.push_back(q.answer); + + } + const char *userComments = [self.commentText.text cStringUsingEncoding: NSUTF8StringEncoding]; + [self.commentText resignFirstResponder]; + + self.view.hidden = YES; + ((testApp *)self.theOFAppRef)->questionnaireHidden(answersArray, userComments); + +} + +//---------------------------------------------------------------- +-(IBAction)show:(id)sender{ + self.view.hidden = NO; +} +//---------------------------------------------------------------- + +- (IBAction)nextQuestionPressed:(id)sender { + // save answer ? no button did that hopefully + + // if last question show thanks + // else go to next + self.currentQuestionIndex++; + if(self.currentQuestionIndex >= [self.questionArray count]){ + [self showThanks]; + }else{ + [self loadQuestion:self.currentQuestionIndex]; + + } +} +//---------------------------------------------------------------- +- (IBAction)previousQuestionPressed:(id)sender { + self.currentQuestionIndex--; + if(self.currentQuestionIndex < 0){ + // nothing + self.currentQuestionIndex = 0; + }else{ + [self loadQuestion:self.currentQuestionIndex]; + } +} + +//---------------------------------------------------------------- + +- (void)showThanks{ + // hide next question button + self.nextButton.hidden = YES; + // hide selector + self.picker.hidden = YES; + self.previousButton.hidden = YES; + self.finishButton.hidden = NO; + + self.lickertOptions.hidden = YES; + self.interfacePreferenceOptions.hidden = YES; + + self.titleText.text = @"Thank you!"; + self.numberChooser.hidden = YES; + self.commentText.hidden = NO; + + self.questionText.text = @"Thanks for helping science help you. Feel free to add further comments in the text box below, and then press 'finish' to go back and use the app."; +} + +//---------------------------------------------------------------- +- (void)loadQuestion:(NSInteger)questionIndex { + // populate text fields with question + NSString *qtitle; + qtitle = [@"Question " stringByAppendingFormat:@"%d / %d",questionIndex+1, [self.questionArray count]]; + self.titleText.text = qtitle; + + Question *curQ = [self.questionArray objectAtIndex:self.currentQuestionIndex]; + + self.questionText.text = curQ.questionText; + + + // refresh picker view content + //[picker reloadComponent:0]; + + // show correct option number labels + if(curQ.questionType == AGREE_DISAGREE){ + self.lickertOptions.hidden = NO; + self.interfacePreferenceOptions.hidden = YES; + }else if(curQ.questionType == SLIDERS_ZOOMER){ + self.lickertOptions.hidden = YES; + self.interfacePreferenceOptions.hidden = NO; + } + + //NSLog(@"Prev answer answerInt %d", curQ.answer); + //[picker selectRow:2 inComponent:0 animated:YES]; + + // what about unselecting segment? + +} +// 1/3/13 removed q 6 and 15. now only 15 qs +//---------------------------------------------------------------- +- (void)populateQuestionArray{ +// potential leak + self.questionArray = [NSArray arrayWithObjects: + [[Question alloc] initWithTextAndType:@"I am familiar with music software and sound synthesis.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"The ability to retrace my steps using the history path was useful...":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"The best interface for discovering interesting sounds quickly was...":SLIDERS_ZOOMER], + [[Question alloc] initWithTextAndType:@"The best interface for fine tuning a sound was...":SLIDERS_ZOOMER], + [[Question alloc] initWithTextAndType:@"The correspondence between the sliders and the grid was understandable.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"Scrolling a greater distance on the grid seemed to correspond to larger difference in the sound.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"The interface that I felt more in control using was...":SLIDERS_ZOOMER], + [[Question alloc] initWithTextAndType:@"Being able to see previously saved presets on the grid is useful.":AGREE_DISAGREE], // + [[Question alloc] initWithTextAndType:@"The interface that felt more creative was...":SLIDERS_ZOOMER], + [[Question alloc] initWithTextAndType:@"The range of sounds was too limited to be able to judge the eventual usefulness of the interface.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"The interface better for generating new ideas was...":SLIDERS_ZOOMER], + [[Question alloc] initWithTextAndType:@"The interface better for performing live would be...":SLIDERS_ZOOMER], + [[Question alloc] initWithTextAndType:@"The Zoomer was an improvement on just using a randomiser.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"The combination of Zoomer and Sliders was better than either individually.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"I enjoy 'happy accidents' in the creative process.":AGREE_DISAGREE], + [[Question alloc] initWithTextAndType:@"Overall, the interface I preferred using was...":SLIDERS_ZOOMER], // ?????? + nil]; + // The zoomer seemed more appropriate to explore the synth sound controls (red) than the note sequence controls (blue) +// I enjoyed the sounds produced + +} + +//---------------------------------------------------------------- +#pragma mark - +#pragma mark PickerView DataSource + +- (NSInteger)numberOfComponentsInPickerView: +(UIPickerView *)pickerView +{ + return 1; +} +//---------------------------------------------------------------- +- (NSInteger)pickerView:(UIPickerView *)pickerView +numberOfRowsInComponent:(NSInteger)component +{ + + return NUM_CHOICES; // always 6 +} +//---------------------------------------------------------------- +- (NSString *)pickerView:(UIPickerView *)pickerView + titleForRow:(NSInteger)row + forComponent:(NSInteger)component +{ + Question *curQ = [self.questionArray objectAtIndex:self.currentQuestionIndex]; + + // get array of answers from Question class + NSArray * answers = [Question answersWithType:curQ.questionType]; + return [answers objectAtIndex:row]; + +} +//---------------------------------------------------------------- +#pragma mark - +#pragma mark PickerView Delegate +-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row + inComponent:(NSInteger)component +{ + Question *curQ = [self.questionArray objectAtIndex:self.currentQuestionIndex]; + // set question answerArray + curQ.answer = row; + + // chek wot we just rote + + NSLog(@"Answer: %d",curQ.answer); + +} +//---------------------------------------------------------------- +#pragma mark UITextViewDelegate functions +/* + This answer was useful to me, but I was also looking for the callback function from the "Go" button, which I found is: + - (BOOL) textFieldShouldReturn:(UITextField *)textField { // Customer code return YES; } + + You will need to send the UITextField delegate to your view controller for that to work. + + */ + - (BOOL) textFieldShouldReturn:(UITextField *)textField { + // Customer code + NSLog(@"RETURN DELEGATE"); + [self hide:self ]; + return NO; + } +- (IBAction)answerChosen:(id)sender { + self.pleaseAnswer.hidden = YES; + UISegmentedControl *seg = (UISegmentedControl *)sender; + Question *curQ = [self.questionArray objectAtIndex:self.currentQuestionIndex]; + // set question answerArray + curQ.answer = seg.selectedSegmentIndex; + + // chek wot we just rote + + NSLog(@"Answer: %d",curQ.answer); + + // automatically go next q + self.currentQuestionIndex++; + if(self.currentQuestionIndex >= [self.questionArray count]){ + [self showThanks]; + }else{ + [self loadQuestion:self.currentQuestionIndex]; + + } + +} +@end // end implementation +//---------------------------------------------------------------- +//---------------------------------------------------------------- diff -r 000000000000 -r a223551fdc1f QuestionnaireViewController.xib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QuestionnaireViewController.xib Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,1117 @@ + + + + 1280 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBProxyObject + IBUIButton + IBUILabel + IBUIPickerView + IBUISegmentedControl + IBUITextView + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBIPadFramework + + + IBFirstResponder + IBIPadFramework + + + + 292 + + + + 292 + {{324, 706}, {121, 44}} + + + + _NS:9 + NO + IBIPadFramework + 0 + 0 + 1 + Finish + + 3 + MQA + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + 3 + MC41AA + + + 2 + 15 + + + Helvetica-Bold + 15 + 16 + + + + + 292 + {{143, 220}, {275, 53}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Question 1 + + 1 + MCAwLjg3MTEwNjY5ODMgMQA + + + 0 + + Helvetica + Helvetica + 0 + 31 + + + Helvetica + 31 + 16 + + NO + + + + 292 + {{144, 281}, {472, 138}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Questions: + + 1 + MC45Mjc2NzQyNjcgMC45MjIwNTE5OTg4IDAuOTMzMjk2NTM1MwA + + + 0 + 4 + + 1 + 22 + + + Helvetica + 22 + 16 + + NO + 472 + + + + 292 + {{425, 706}, {121, 44}} + + + + _NS:9 + NO + IBIPadFramework + 0 + 0 + 1 + Next Question + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + + + + + 292 + {{51, 706}, {157, 44}} + + + + _NS:9 + NO + IBIPadFramework + 0 + 0 + 1 + Previous Question + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + + + + + + -2147483358 + {{413, 788}, {590, 216}} + + + _NS:9 + IBIPadFramework + YES + + + + 292 + {{212, 468}, {334, 230}} + + + + _NS:9 + + 1 + MSAxIDEAA + + YES + YES + IBIPadFramework + NO + + + 2 + IBCocoaTouchFramework + + + 1 + 14 + + + Helvetica + 14 + 16 + + + + + 292 + {{51, 533}, {667, 44}} + + + + _NS:9 + NO + IBIPadFramework + 5 + + 1 + 2 + 3 + 4 + 5 + + + + + + + + + + + + + + + + + {0, 0} + {0, 0} + {0, 0} + {0, 0} + {0, 0} + + + + + + + + + YES + + + + -2147483356 + + + + 292 + {{7, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Definitely the sliders + + 1 + MSAxIDEAA + + 1 + + + + 0 + 2 + 1 + + 1 + 17 + + + Helvetica + 17 + 16 + + NO + 132 + + + + 292 + {{139, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Maybe the sliders + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{267, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Neither / both equal + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{399, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Maybe the Zoomer + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{535, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Definitely the Zoomer + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + {{51, 416}, {667, 118}} + + + + _NS:9 + + 1 + MC4yNzY0OTQ1NjUyIDAuMjc2NDk0NTY1MiAwLjI3NjQ5NDU2NTIAA + + IBIPadFramework + + + + -2147483356 + + + + 292 + {{7, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Strongly disagree + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{139, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Disagree + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{267, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Neither agree nor disagree + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{399, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Agree + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + + 292 + {{535, 29}, {132, 69}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Strongly agree + + 1 + MSAxIDEAA + + + + 0 + 2 + 1 + + + NO + 132 + + + {{50, 416}, {667, 118}} + + + + _NS:9 + + 1 + MC4yNzY0OTQ1NjUyIDAuMjc2NDk0NTY1MiAwLjI3NjQ5NDU2NTIAA + + IBIPadFramework + + + + 292 + {{143, 104}, {434, 21}} + + + + _NS:9 + NO + YES + 7 + NO + IBIPadFramework + Thanks very much. Now please answer a few questions... + + 1 + MSAxIDEAA + + + + 0 + + + NO + + + {1024, 768} + + + + + 1 + MCAwIDAAA + + NO + NO + + 3 + 3 + + + IBUIScreenMetrics + + YES + + + + + + {768, 1024} + {1024, 768} + + + IBIPadFramework + iPad Full Screen + 1 + + IBIPadFramework + + + + + + + view + + + + 3 + + + + questionText + + + + 41 + + + + titleText + + + + 42 + + + + finishButton + + + + 51 + + + + nextButton + + + + 52 + + + + picker + + + + 59 + + + + previousButton + + + + 60 + + + + commentText + + + + 64 + + + + numberChooser + + + + 72 + + + + interfacePreferenceOptions + + + + 81 + + + + lickertOptions + + + + 88 + + + + pleaseAnswer + + + + 91 + + + + nextQuestionPressed: + + + 7 + + 40 + + + + previousQuestionPressed: + + + 7 + + 50 + + + + hide: + + + 7 + + 39 + + + + dataSource + + + + 57 + + + + delegate + + + + 58 + + + + answerChosen: + + + 13 + + 89 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 2 + + + + + + + + + + + + + + + + + + 4 + + + + + + 5 + + + + + + 6 + + + + + + 7 + + + + + 9 + + + + + 55 + + + + + 63 + + + + + 71 + + + + + 75 + + + + + + + + + + + + 76 + + + + + 77 + + + + + 78 + + + + + 79 + + + + + 80 + + + + + 82 + + + + + + + + + + + + 87 + + + + + 86 + + + + + 85 + + + + + 84 + + + + + 83 + + + + + 90 + + + + + + + QuestionnaireViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 91 + + + + + QuestionnaireViewController + UIViewController + + id + id + id + id + id + + + + answerChosen: + id + + + hide: + id + + + nextQuestionPressed: + id + + + previousQuestionPressed: + id + + + show: + id + + + + UITextView + UIButton + UIView + UIView + UIButton + UISegmentedControl + UIPickerView + UILabel + UIButton + UILabel + UILabel + + + + commentText + UITextView + + + finishButton + UIButton + + + interfacePreferenceOptions + UIView + + + lickertOptions + UIView + + + nextButton + UIButton + + + numberChooser + UISegmentedControl + + + picker + UIPickerView + + + pleaseAnswer + UILabel + + + previousButton + UIButton + + + questionText + UILabel + + + titleText + UILabel + + + + IBProjectSource + ./Classes/QuestionnaireViewController.h + + + + + 0 + IBIPadFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + YES + 3 + 2083 + + diff -r 000000000000 -r a223551fdc1f ServerComms.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerComms.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,36 @@ +// +// ServerComms.h +// httpPost +// +// Created by Robert Tubb on 24/02/2013. +// Copyright (c) 2013 Robert Tubb. All rights reserved. +// + +#import + +@interface ServerComms : NSObject +{ +NSURL *serverURL; +NSString *filePath; +id delegate; +SEL doneSelector; +SEL errorSelector; + +BOOL uploadDidSucceed; +} + +- (id)initWithURL: (NSURL *)serverURL + filePath: (NSString *)filePath + delegate: (id)delegate + doneSelector: (SEL)doneSelector + errorSelector: (SEL)errorSelector; + +- (NSString *)filePath; + +-(BOOL)doSyncPostRequest:(NSString *)type withData:(NSString *)data; +-(BOOL)doPostRequest:(NSString *)type withData:(NSString *)data; +@property (strong,nonatomic) NSMutableData * data; +@property BOOL requestInProgress; +@property (strong, nonatomic) NSString * currentRequestType; + +@end diff -r 000000000000 -r a223551fdc1f ServerComms.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerComms.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,203 @@ +// +// ServerComms.m +// httpPost +// +// Created by Robert Tubb on 24/02/2013. +// Copyright (c) 2013 Robert Tubb. All rights reserved. +// + +#import "ServerComms.h" +#import "eventLogger.h" + +extern EventLogger eventLogger; + +@implementation ServerComms +// +-(id)init{ + self = [super init]; + if(self != nil){ + self.requestInProgress = NO; + } + return self; +} +//------------------------------------------------------------------------------- +// asynchronous one +-(BOOL)doPostRequest:(NSString *)type withData:(NSString *)data{ + + if(self.requestInProgress){ + return NO; + } + self.currentRequestType = type; + NSString *localServerURL = @"http://127.0.0.1:8080/newtestservice/"; + NSString *webServerURL = @"http://www.isophonics.net/tweakathlondatacollector/"; + + NSString *urls = [webServerURL stringByAppendingString:type]; + NSURL *url = [NSURL URLWithString:urls]; + + + // request object + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + + // the data + NSString *post = [@"jsontext=" stringByAppendingString:[NSString stringWithFormat:data]]; + NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding]; + // length of data + NSString *postLength = [NSString stringWithFormat:@"%d",[postData length]]; + + // request properties/header fields + [request setHTTPMethod:@"POST"]; + [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:postData ]; + + NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self]; + [theConnection release]; + self.requestInProgress = YES; + return YES; + // asynchronous one?? +} +//-------------------------------------------------------------------- + +// schncronous +-(BOOL)doSyncPostRequest:(NSString *)type withData:(NSString *)data{ + BOOL success; + + NSString *localServerURL = @"http://127.0.0.1:8080/testservice/"; + NSString *webServerURL = @"http://www.isophonics.net/datacollector/"; + + NSString *urls = [webServerURL stringByAppendingString:type]; + NSURL *url = [NSURL URLWithString:urls]; + + + // request object + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + + // the data + NSString *post = [@"jsontext=" stringByAppendingString:[NSString stringWithFormat:data]]; + NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding]; + // length of data + NSString *postLength = [NSString stringWithFormat:@"%d",[postData length]]; + + // request properties/header fields + [request setHTTPMethod:@"POST"]; + [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:postData ]; + + NSURLResponse* response; + NSError* error = nil; + NSData* result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; + + NSString *responseDataString = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]; + + //NSString* responseDataString = [NSString stringWithUTF8String: ]; + NSLog(@"sync req. data %@", responseDataString); + [self.data appendData:result]; + + if([responseDataString isEqualToString:@"testConnection:OK"]){ + + eventLogger.testConnectionOK(); + [responseDataString release]; + success = true; + }else if([responseDataString isEqualToString:@"questionnaire:OK"]){ + eventLogger.questionnaireOK(); + success = true; + }else if([responseDataString isEqualToString:@"eventlog:OK"]){ + // call eventLogger eventlogUploadOK + eventLogger.eventlogOK(); + success = true; + }else{ + success = false; + if([type isEqualToString:@"testConnection"]) eventLogger.testConnectionNotOK(); + if([type isEqualToString:@"eventlog"]) eventLogger.eventlogNotOK(); + if([type isEqualToString:@"questionnaire"]) eventLogger.questionnaireNotOK(); + } + + // else check error?? + + // check result + self.requestInProgress = NO; + return success; +} +//------------------------------------------------------------------------------------------------- + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + [self.data setLength:0]; + NSLog(@"didReceiveResponse : %@",response); +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d { + NSString *responseDataString = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]; + + //NSString* responseDataString = [NSString stringWithUTF8String: ]; + //NSLog(@" %@ didRecieveData %@",self.currentRequestType, responseDataString); + [self.data appendData:d]; + + if([responseDataString isEqualToString:@"testConnection:OK"]){ + + eventLogger.testConnectionOK(); + [responseDataString release]; + }else if([responseDataString isEqualToString:@"questionnaire:OK"]){ + eventLogger.questionnaireOK(); + }else if([responseDataString isEqualToString:@"eventlog:OK"]){ + // call eventLogger eventlogUploadOK + eventLogger.eventlogOK(); + }else{ + if([self.currentRequestType isEqualToString:@"testConnection"]) eventLogger.testConnectionNotOK(); + if([self.currentRequestType isEqualToString:@"eventlog"]) eventLogger.eventlogNotOK(); + if([self.currentRequestType isEqualToString:@"questionnaire"]) eventLogger.questionnaireNotOK(); + } +} +//------------------------------------------------------------------------------- +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + + NSLog(@"fail with error"); + if([self.currentRequestType isEqualToString:@"testConnection"]) { + UIAlertView * av = [ [UIAlertView alloc] initWithTitle:NSLocalizedString(@"Sorry", @"") + message:[error localizedDescription] + delegate:nil + cancelButtonTitle:NSLocalizedString(@"OK", @"") + otherButtonTitles:nil ]; + [av show]; + eventLogger.testConnectionNotOK(); + + } + if([self.currentRequestType isEqualToString:@"eventlog"]) eventLogger.eventlogNotOK(); + if([self.currentRequestType isEqualToString:@"questionnaire"]) eventLogger.questionnaireNotOK(); + self.requestInProgress = NO; + // we won't know what kind of request method this was... +} +//------------------------------------------------------------------------------- +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + NSString *responseText = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]; + + // Do anything you want with it + NSLog(@"response text: %@",responseText); + [responseText release]; + + self.requestInProgress = NO; + +} +//------------------------------------------------------------------------------- +// Handle basic authentication challenge if needed +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + NSString *username = @"username"; + NSString *password = @"password"; + + NSURLCredential *credential = [NSURLCredential credentialWithUser:username + password:password + persistence:NSURLCredentialPersistenceForSession]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; +} +/* +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse{ + +} +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{ + +} +*/ +//------------------------------------------------------------------------------- +@end diff -r 000000000000 -r a223551fdc1f SynthParam.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SynthParam.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,57 @@ +// +// SynthParam.h +// tweakathlon +// +// Created by Robert Tubb on 10/10/2014. +// +// + +#ifndef tweakathlon_SynthParam_h +#define tweakathlon_SynthParam_h + +// class that handles what a synth param "is" , a wrapper for the pd control +class SynthParam { +public: + static int mappingUID; + + + AppCore* core; + SynthParam(int aVal , AppCore* aCore, string aName, string aSynthPrefix){ + mappingID = mappingUID++; + value = aVal; + core = aCore; + name = aName; + synthPrefix = aSynthPrefix; + // log the fact that this id is mapped to a certain param? + }; + void setValue(int i){ + value = i; + // TODO should this send an eventlog message? what if called from randomise ? what if different synth? + sendToPD(); + }; + int getValue() const{ + return value; + } + int getID() const {return mappingID;}; + string getName() const {return name;}; + void sendToPD() const + { + // sends this parameter to pd synth + List toPD; + toPD.addSymbol(synthPrefix); + toPD.addSymbol(name); + toPD.addFloat(value); // rounding here?? + + core->pd.sendList("fromOF", toPD); + //cout << "sending" << synthPrefix << ":" << name << " : " << value << "\n"; + }; + +private: + int value; // 0 to 127 + int mappingID; // should be globally unique + string name; // the string that gets routed in PD, and also the display label (?) + string synthPrefix; + +}; + +#endif diff -r 000000000000 -r a223551fdc1f TestController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TestController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,657 @@ +// +// TestController.h +// tweakathlon +// +// Created by Robert Tubb on 16/01/2014. +// +// + +#ifndef __tweakathlon__TestController__ +#define __tweakathlon__TestController__ + +#include +#include "ofMain.h" +#include "globalVariables.h" +#include "boost/foreach.hpp" +#include "boost/bind.hpp" +#include "boost/function.hpp" +#include "timeController.h" +#include +#include // std::transform + +//------------------------------------------------------------- +//------------------------------------------------------------- +template +class randomiseCCVal : public unary_function{ +public: + T operator()(T a){ + return ofRandom(0,127); + + }; +}; +template +class randomiseCCValIf : public binary_function{ +public: + T operator()(T a, bool doit ){ + if (doit) + return ofRandom(0,127); + return a; + + }; +}; +template +class printThing : public unary_function{ +public: + void operator()(T a){ + cout << a << endl; + + }; +}; + +template +class difference : public binary_function{ +public: + T operator()(T a, T b ){ + return abs(a - b); + }; +}; +template +class squared : public unary_function{ +public: + T operator()(T a ){ + return a*a; + }; +}; + +//------------------------------------------------------------- + +struct TestResult{ + float realDistanceToTarget; + int targetBandHit; // eg bullseye = 0 edge = 7 + TimerMillisec timeTaken; + int timeWindowHit; // eg < 5s = 0 + int dimensionMult; + int score; + string displayText; +}; + +//------------------------------------------------------------- +// tests, once genrated by the testcontroller get passed around and used to set synths and so on +//------------------------------------------------------------- +class Test { +public: + Test(){ + //? + identifyingLetter = '?'; + timeGiven = 0; + panelType= SEQUENTIAL; + numDimensions = 0; + + generateListOfControls(); + makeRandomTarget(); + setCandidateToTarget(); + randomParamSelection(numDimensions); + randomiseCandidate(); + scored = true; + withHint = false; + memoryTest = false; + targetPlaysLeft = 2; // only decr if memory test + }; + // test with random params + Test(char letter, int atimeGiven, controlPanelType apanelType, int anumDimensions){ + // init the stuff + //cout << "Making test " << letter << endl; + + identifyingLetter = letter; + timeGiven = atimeGiven; + panelType= apanelType; + numDimensions = anumDimensions; + + generateListOfControls(); + makeRandomTarget(); + setCandidateToTarget(); + randomParamSelection(numDimensions); + randomiseCandidate(); + scored = true; + }; + // constructor that copies params from other test, pass em in + // also serves as a constructor that passes in specific settings + Test(char letter, int atimeGiven, controlPanelType apanelType, int anumDimensions, vector aTargetValues, vector aCandidateValues, vector adjustables){ + identifyingLetter = letter; + timeGiven = atimeGiven; + panelType= apanelType; + numDimensions = anumDimensions; + + whichCandidateParamAdjustable = adjustables; + generateListOfControls(); + targetParams = aTargetValues; + candidateParams = aCandidateValues; + scored = true; + + } + // constructot that enables you to set the space the test is carried out in but not start + Test(char letter, int aTimeGiven, controlPanelType pType, int aNumDimensions, vector adjustables){ + identifyingLetter = letter; + timeGiven = aTimeGiven; + panelType= pType; + numDimensions = aNumDimensions; + + generateListOfControls(); + makeRandomTarget(); + setCandidateToTarget(); + whichCandidateParamAdjustable = adjustables; + randomiseCandidate(); + scored = true; + } + + + + // constructor that takes target values, but leaves those not adjustable + Test(char letter, int aTimeGiven, controlPanelType pType, int aNumDimensions, vector adjustables, vector aTargetValues){ + identifyingLetter = letter; + timeGiven = aTimeGiven; + panelType= pType; + numDimensions = aNumDimensions; + + generateListOfControls(); + targetParams = aTargetValues; + whichCandidateParamAdjustable = adjustables; + randomiseTargetAdjustable(); + setCandidateToTarget(); + + randomiseCandidate(); + scored = true; + } + + // the one that is called from generate some tests!! + Test(char letter, int aTimeGiven, controlPanelType pType, int aNumDimensions, vector adjustables, vector aTargetValues, bool ascored = true, bool ahint = false, bool aMemoryTest = false){ + identifyingLetter = letter; + timeGiven = aTimeGiven; + panelType= pType; + numDimensions = aNumDimensions; + + generateListOfControls(); + targetParams = aTargetValues; + whichCandidateParamAdjustable = adjustables; + randomiseTargetAdjustable(); + setCandidateToTarget(); + + randomiseCandidate(); + scored = ascored; + withHint = ahint; + memoryTest = aMemoryTest; + targetPlaysLeft = 1; // only decr if memory test + }; + bool isWithHint(){ + return withHint; + }; + bool isMemoryTest(){ + return memoryTest; + }; + bool isPractice(){ + return !scored; + }; + float euclideanDistance(vector v1, vector v2) const{ + if (v1.size() != v2.size()){ + cout << "ERROR ERROR: vectors must be same length for Mr Euclid"; + return 0.; + } + vector diff; + + std::transform(v1.begin(), v1.end(), v2.begin(), v1.begin(), difference()); + // sqr diff + + std::transform(v1.begin(), v1.end(), v1.begin(),squared()); + float ans = std::accumulate(v1.begin(),v1.end(),0.0); + + return sqrt(ans); + + }; + + TestResult getScoreForAnswer(vector answer, TimerMillisec timeTaken) const { + TestResult result; + stringstream msg; + int score = 0; + // work out euc distance from actual point + //for_each(answer.begin(),answer.end(),printThing()); + //for_each(targetParams.begin(),targetParams.end(),printThing()); + float dist = euclideanDistance(targetParams, answer); + auto dimComp = sqrt(numDimensions); + int band = -1; + if (dist < TARGET_SCORE_CC_BAND*dimComp){ + score = 50; + band = 1; + + msg << "DOUBLE BULLSEYE!" << endl; + + + }else if (dist < TARGET_SCORE_CC_BAND*2*dimComp){ + + score = 25; + band = 2; + + msg << "SINGLE BULLSEYE!" << endl; + + }else if (dist < TARGET_SCORE_CC_BAND*3*dimComp){ + + score = 15; + band = 3; + msg << "CLOSE..." << endl; + + }else if (dist < TARGET_SCORE_CC_BAND*4*dimComp){ + score = 5; + band = 4; + msg << "OK...ISH" << endl; + + }else if (dist < TARGET_SCORE_CC_BAND*6*dimComp){ // 30 + score = 2; + band = 5; + msg << "MEDIOCRE" << endl; + + }else if (dist < TARGET_SCORE_CC_BAND*9*dimComp){ // 45 + score = 1; + band = 6; + msg << "POOR..." << endl; + + }else{ + score = 0; + band = 7; + msg << "MISSED COMPLETELY!" << endl; + + + } + msg << "Distance from target: " << dist << endl; + msg << "Basic Score: " << score << endl; + msg << "-----" << endl; + msg << "Time taken: " << timeTaken/1000.0 << endl; + int window = -1; + if (timeTaken < 5000){ + msg << "Under 5 seconds: 10x bonus" << endl; + score *= 10; + window = 1; + }else if (timeTaken < 10000){ + msg << "Under 10 seconds: 5x bonus" << endl; + score *= 5; + window = 2; + }else if (timeTaken < 15000){ + msg << "Under 15 seconds: 3x bonus" << endl; + score *=3; + window = 3; + }else if (timeTaken < 20000){ + msg << "Under 20 seconds: 2x bonus" << endl; + score *=2; + window = 4; + }else if (timeTaken < 20000){ + msg << "Under 25 seconds: no bonus" << endl; + score *=2; + window = 4; + }else if (timeTaken > 30000){ + msg << "Over 30 seconds: TOO LATE!" << endl; + score *=0; + window = 4; + } + score *= numDimensions; // dimension bonus + msg << numDimensions*numDimensions << "X Dimension bonus" << endl; + msg << "-----" << endl; + if (!scored){ + + msg << "PRACTICE RUN, scored: " << score << endl; + score = 0; + }else{ + msg << "Total: " << score << endl; + } + result.realDistanceToTarget = dist; + result.targetBandHit = band; // eg bullseye = 0 edge = 7 + result.timeTaken = timeTaken; + result.timeWindowHit = window; // eg < 5s = 0 + result.dimensionMult = numDimensions*numDimensions; + result.score = score; + result.displayText = msg.str(); + + + return result; + } + + vector getChangeableIndices() { + vector ids; + for(int i=0; i< whichCandidateParamAdjustable.size();i++){ + if (whichCandidateParamAdjustable[i]){ + ids.push_back(i); + } + } + return ids; + }; + vector getTargetValues() const{ + return targetParams; + + }; + vector getStartingCandidateValues() const{ + return candidateParams; + + }; + + int getNumDimensions() const{ + return numDimensions; + } + char getTestLetter() const{ + return identifyingLetter; + } + vector getAdjustableMask() const{ + return whichCandidateParamAdjustable; + } + vector getListOfControlTypes() const{ + return listOfControls; + } + controlPanelType getControlPanelType() const{ + return panelType; + }; + string getTestTypeAdvanceWarning(){ + stringstream msg; + + msg << "Next test: " << endl << endl; + if (panelType == REVISITABLE){ + msg << "Sliders " << " x " << numDimensions << endl; + } + if (panelType == SIMULTANEOUS && numDimensions == 2){ + msg << "XY pad " << endl; + } + if (panelType == SIMULTANEOUS && numDimensions == 3){ + msg << "LEAP MOTION 3D -> -> -> -> ->" << endl; + } + if (isMemoryTest()){ + msg << endl << "MEMORY TEST - ONE TARGET LISTEN ONLY!!" << endl; + } + if (!scored){ + msg << "PRACTICE RUN" << endl; + } + + return msg.str(); + }; + bool checkTargetPlaysRemaining(){ + if (isMemoryTest()){ + targetPlaysLeft--; + if (targetPlaysLeft <= 0){ + return false; + } + + } + return true; + } + int getTargetPlaysLeft(){ + return targetPlaysLeft; + } + +private: + char identifyingLetter; + int timeGiven; + int timeElapsed; + controlPanelType panelType; + vector listOfControls; + int numDimensions; + vector targetParams; + vector candidateParams; + vector whichCandidateParamAdjustable; + int targetPlaysLeft; + bool scored, withHint, memoryTest; + + + void setCandidateToTarget(){ + + for(vector::iterator ii = targetParams.begin(); ii < targetParams.end(); ii++){ + candidateParams.push_back(*ii); + } + }; + + void generateListOfControls(){ + // need ? + if(panelType == SEQUENTIAL || panelType == REVISITABLE){ + for(int i=0;i()); + notFarEnough = ( euclideanDistance(candidateParams,targetParams) < reasonableDistance ); + } + cout << "Test distance = " << euclideanDistance(candidateParams,targetParams) << endl; + + }; + + void randomiseTargetAdjustable(){ + // randomises only those who are adjustable, in the case where we want exactly the same space + // i.e. original target was fed in + transform(targetParams.begin(), + targetParams.end(), + whichCandidateParamAdjustable.begin(), + targetParams.begin(), + randomiseCCValIf()); + + + }; + + // select a few params that will be the ones to chng + void randomParamSelection(int numToChange){ + + for(int i= 0; i()); + + }; + + +}; +//------------------------------------------------------------- +//------------------------------------------------------------- + + +class TestController { +public: + static const int numDifferentTests; + static const int totalNumTests; + vector::iterator currentTest; + TestController(){ + + generateSomeTests(1, 3, SIMULTANEOUS,1, false, true, true); + + generateSomeTests(4, 2, SIMULTANEOUS, 1, true); + + // 3 demo runs + generateSomeTests(1, 1, REVISITABLE, 1, false, false, false); + generateSomeTests(1, 2, SIMULTANEOUS, 1, false, false, true); + generateSomeTests(1, 3, SIMULTANEOUS,1, false, true, false); + // 3 practice runs + + //---------------------- + // 1D set 1 + // 7 to 12 + generateSomeTests(2, 1, REVISITABLE, 1, true); + generateSomeTests(2, 1, REVISITABLE, 2, true); + generateSomeTests(2, 1, REVISITABLE, 4, true); + + + // 2D tests 1 + // 13 to 28 + generateSomeTests(4, 2, REVISITABLE, 1, true); + generateSomeTests(4, 2, SIMULTANEOUS, 1, true); + generateSomeTests(4, 2, SIMULTANEOUS, 2, true); + generateSomeTests(4, 2, REVISITABLE, 2, true); + + // 3D Tests 1 + // 29 to 44 + generateSomeTests(8,3,SIMULTANEOUS,1, true); + generateSomeTests(8,3,REVISITABLE,1, true); + + //---------------------- + + // 1D set 2 (WITH HINTS) + // 45 to 47 + generateSomeTests(1, 1, REVISITABLE, 1, true, true); + generateSomeTests(1, 1, REVISITABLE, 2, true, true); + generateSomeTests(1, 1, REVISITABLE, 4, true, true); + + // 2D set 2 (WITH HINTS) + // 48 to 51 + generateSomeTests(2, 2, SIMULTANEOUS, 1, true, true); + generateSomeTests(2, 2, REVISITABLE, 1, true, true); + + // 3D set 2 (WITH HINTS) + // 52 to 59 + generateSomeTests(4,3,REVISITABLE ,1, true, true); + generateSomeTests(4,3,SIMULTANEOUS,1, true, true); + + //---------------------- + + // NOW MEMORY TESTS! + // 1D memory test + generateSomeTests(2, 1, REVISITABLE, 1, true,false, true); + generateSomeTests(2, 1, REVISITABLE, 2, true,false, true); + generateSomeTests(2, 1, REVISITABLE, 4, true,false, true); + + // 2D set 3 + generateSomeTests(4, 2, SIMULTANEOUS, 1, true,false, true); + generateSomeTests(4, 2, REVISITABLE, 1, true,false, true); + generateSomeTests(4, 2, REVISITABLE, 2, true,false, true); + generateSomeTests(4, 2, SIMULTANEOUS, 2, true,false, true); + + + // 3D set 3 + // MEMORY + generateSomeTests(8,3,REVISITABLE ,1, true,false, true); + generateSomeTests(8,3,SIMULTANEOUS,1, true,false, true); + // 72 + //---------------------- + + + + //generate1DSpecificTests(); + + //generate2DSpecificTests(); + //generate3DSpecificTests(); + //generate2DRandomTests(); + //generate4DTests(); + currentTest = testList.begin()-1; // dont do this + scoreRunningTotal = 0; + }; + + + bool isLastTest(){ + if (currentTest == testList.end()-1){ + return true; + } + return false; + } + Test goToNextTest(){ + + if (currentTest < testList.end()-1){ + currentTest++; + cout << "***************** NEXT TEST : " << (*currentTest).getTestLetter() << endl; + // return a copy + // (*currentTest).logThisTestSetup(); + + return *currentTest; + + }else{ + cout << "Sequence finished!!!!!!" << endl; + Test dummyTest; + return dummyTest; + } + }; + + Test getCurrentTest(){ + // check for valid current test? + return *currentTest; + } + + Test* getCurrentTestPtr(){ + // check for valid current test? + if (currentTest < testList.end() && currentTest >= testList.begin()){ + return &(*currentTest); + }else{ + return NULL; + } + } + // + TestResult submitAnswer(vector answer, TimerMillisec timeTaken){ + TestResult result; + result = (*currentTest).getScoreForAnswer(answer, timeTaken); + scoreRunningTotal += result.score; + return result; + } + vector getCurrentListOfControls(){ + return (*currentTest).getListOfControlTypes(); + } + int getScoreRunningTotal(){ + return scoreRunningTotal; + }; + char getCurrentTestLetter(){ + return (*currentTest).getTestLetter(); + }; + controlPanelType getCurrentPanelType(){ + return (*currentTest).getControlPanelType(); + }; + vector getCurrentChangeableParams(){ + return (*currentTest).getChangeableIndices(); + } +private: + void generate2DRandomTests(); + void generate1DSpecificTests(); + void generate2DSpecificTests(); + void generate3DSpecificTests(); + void generate4DTests(); + void generateSomeTests(int howManyTests, int dimensions, controlPanelType panelType, int whichSpace, bool scored = true,bool aHint = false, bool aMemoryTest = false); + + void generateTestSequence(){ + + }; + //aregaergeargera + vector testList; + + long scoreRunningTotal; + + +}; + + + + +#endif /* defined(__tweakathlon__TestController__) */ diff -r 000000000000 -r a223551fdc1f TestController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TestController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,152 @@ +// +// TestController.mm +// tweakathlon +// +// Created by Robert Tubb on 16/01/2014. +// +// + +#include "TestController.h" +const int TestController::numDifferentTests = 80; +const int TestController::totalNumTests = 80; + + +template +vector makeVector(T a1, T a2,T a3,T a4,T a5,T a6){ + + vector vec; + vec.push_back(a1); + vec.push_back(a2); + vec.push_back(a3); + vec.push_back(a4); + vec.push_back(a5); + vec.push_back(a6); + + return vec; +} + +void randomise(int& n){ + n = ofRandom(0,127); + +} + +vector > makeCombinations(){ + // make all unordered pairs + int N = TOTAL_NUM_PARAMS; + + vector > table; + for(int n=0; n < N-1; n++){ + + vector c(6, false); + for(int m=n+1; m > ap = makeCombinations(); + // 4 tests for each + int testsPerSpace = 2; + int numTests = 2 * testsPerSpace * ap.size(); + int testNum = testList.size(); + panelType = REVISITABLE; + for(int i=0;i adjustables = makeVector(false, false, false, false, false, false); + vector target = makeVector(40,64, 10, 74, 21, 80); // the default target + + // big if - good spaces for each num of dimensions + if(numDimensions == 1){ + // def 64,64, 30, 55, 42, 43; + + adjustables[whichSpace-1] = true; + + }else if(numDimensions == 2){ + + if (whichSpace == 1){ + target = makeVector(64,64, 30, 55, 40, 43); + adjustables[0] = true; // pitch + adjustables[3] = true; // decay + }else if(whichSpace == 2){ + + + target = makeVector(64,64, 0, 90, 20, 127); + adjustables[3] = true; // decay + adjustables[5] = true; // cutoff + }else if(whichSpace == 3){ + target = makeVector(56,64, 20, 64, 10, 90); + + adjustables[1] = true; // pulse + adjustables[2] = true; // attack + }else if(whichSpace == 4){ + target = makeVector(64,64, 0, 55, 40, 43); + adjustables[1] = true; // pulse + adjustables[4] = true; // ftype + } + }else if(numDimensions == 3){ + if(whichSpace == 1){ + target = makeVector(64,64, 10, 64, 41, 43); + adjustables[0] = true; // pitch + adjustables[3] = true; // decay + adjustables[5] = true; // cutoff + }else if(whichSpace == 2){ + target = makeVector(12,64, 10, 67, 41, 64); + adjustables[1] = true; // pulse + adjustables[2] = true; // attack + adjustables[4] = true; // ftype + } + } + // 4 ??? + + for(int i=0; i < howManyTests; i++){ + char letter = char(testNum+65); + testList.push_back(Test(letter,20, panelType, numDimensions, adjustables, target, scored, aHint, aMemoryTest)); + } +} + + +//------------------------------------------- +void TestController::generate4DTests(){ + // 4d seq - learnable?? +} \ No newline at end of file diff -r 000000000000 -r a223551fdc1f TimedCallController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TimedCallController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,18 @@ + +// Super lightweight timer object that is +// +#define SECONDS_PER_INTERFACE 300 +#import + + +@interface TimedCallController : NSObject +@property (nonatomic, assign) id theOFAppRef; +@property (nonatomic,strong) NSTimer * theCurrentTimer; + +- (void)setAppRef:(id)theOFApp; +-(void)resetTime:(int)newTime; // if we want to put ourselves somewhen +-(void)startTimer; // go from start +-(void)cancelTimers; // stop the whole thing +-(void)callTheCallback; + +@end diff -r 000000000000 -r a223551fdc1f TimedCallController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TimedCallController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,47 @@ +// +// TimedSessionController.m +// sonicZoom +// +// Created by Robert Tubb on 18/02/2013. +// +// + +#import "TimedCallController.h" +@interface TimedCallController() + // private stuff +@end + +@implementation TimedCallController + + +// nicer if it was initWithAppRef ? +- (void)setAppRef:(id)theOFApp{ + self.theOFAppRef = theOFApp; + +} +-(void)startTimer{ + +} +-(void)resetTime:(int)newTime{ + +} + + +-(void)cancelTimers{ + + if(self.theCurrentTimer){ + [self.theCurrentTimer invalidate]; + self.theCurrentTimer = nil; + } +} + +-(void)setTimer:(int)numMillisec{ + self.theCurrentTimer = [NSTimer scheduledTimerWithTimeInterval:numMillisec target:self selector:@selector(callTheCallback) userInfo:nil repeats:NO]; + +} +-(void)callTheCallback{ + NSLog(@"iostimer callback"); +} + + +@end diff -r 000000000000 -r a223551fdc1f UI code/.DS_Store Binary file UI code/.DS_Store has changed diff -r 000000000000 -r a223551fdc1f UI code/3Dbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/3Dbox.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,185 @@ +// +// 3Dbox.h +// tweakathlon +// +// Created by Robert Tubb on 13/02/2014. +// +// + +#ifndef __tweakathlon___Dbox__ +#define __tweakathlon___Dbox__ + +#include +#include "UIElement.h" +#include "ofMain.h" + + +class Leap3DBox : public UIElement { + +public: + Leap3DBox(float ax, + float ay, + float awidth, + float aheight, + float azx, + float azy, + const UIProps& props); + void init(const UIProps& props); + + void setValueAndScale(int which, int val){ + if(which == 0) xVal = (val - minVal)/(maxVal - minVal); + if(which == 1) yVal = (val - minVal)/(maxVal - minVal); + if(which == 2) zVal = (val - minVal)/(maxVal - minVal); + //cout << zVal << endl; + } + + void setHintValue(int which, int val){ + if(which == 0) hintX = (val - minVal)/(maxVal - minVal); + if(which == 1) hintY = (val - minVal)/(maxVal - minVal); + if(which == 2) hintZ = (val - minVal)/(maxVal - minVal); + + }; + + void draw(){ + if(hidden)return; + if(on){ + ofSetColor(foregroundHi); + }else{ + ofSetColor(foregroundLo); + + } + if(inactive){ + ofSetColor(fgInactive); + } + + + // draw rear face zy+ + ofLine(zx+x,zy+y,zx+x,zy+y+height); // left + ofLine(zx+x,zy+y,zx+x+width,zy+y); // top + ofLine(zx+x+width,zy+y,zx+x+width,zy+y+height); //right + ofLine(zx+x+width,zy+y+height,zx+x,zy+y+height); // bottom + + // draw indicators + drawIndicator(); + + ofSetColor(foregroundHi); + + // draw connectors + ofLine(x,y,zx+x,zy+y); // top left + ofLine(x+width,y,zx+x+width,zy+y); // top right + ofLine(x,y+height,zx+x,zy+y+height); // bot left + ofLine(x+width,y+height,zx+x+width,zy+y+height); // bot right + + + // draw front face + ofLine(x,y,x,y+height); // left + ofLine(x,y,x+width,y); // top + ofLine(x+width,y,x+width,y+height); //right + ofLine(x+width,y+height,x,y+height); // bottom + + drawLabels(); + + }; + + void drawLabels(){ + ofColor fg,bg; + + if(on){ + fg = foregroundHi; + bg = backgroundHi; + }else{ + fg = foregroundLo; + bg = backgroundLo; + } + if(inactive){ + fg = fgInactive; + } + ofSetColor(fg); + verdana16.drawString(labelNameX + " (L/R)", ofGetWidth()/2 - 120, y + height + 50 ); + verdana16.drawString(labelNameY + " (Up/Dn)", ofGetWidth()/2 - width + 50, y + height/2 ); + verdana16.drawString(labelNameZ + " Fwd/Bck)", ofGetWidth()/2 + width - 20, y+height); + + // TODO up down etc + }; + void setLabels(string ax, string ay, string az){ + labelNameX = ax; + labelNameY = ay; + labelNameZ = az; + } + + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + return false; + }; + void showHint(bool show){ + hintShowing = show; + } + void setHintColor(ofColor c){ + hintColor = c; + }; + +protected: + void drawIndicator(){ + ofSetColor(foregroundHi); + float px,py; + px = x + xVal*width + zx*zVal; + py = y + (1-yVal)*height + zy*zVal; + + // line to left wall (no x) + ofLine(px , py , x+zx*zVal, py); + + ofEllipse(px,py,thickness,thickness); + + + // line to bottom wall (no y) + ofLine(px , py , px, y+height+zy*zVal); + // line to front wall ( no z) + ofLine(px , py , x+ width*xVal, y + height*(1-yVal)); + + if(hintShowing) drawHintIndicator(); + }; + void drawHintIndicator(){ + ofSetColor(hintColor); + float px,py; + px = x + hintX*width + zx*hintZ; + py = y + (1-hintY)*height + zy*hintZ; + + // line to left wall (no x) + ofLine(px , py , x+zx*hintZ, py); + + ofEllipse(px,py,thickness,thickness); + + + // line to bottom wall (no y) + ofLine(px , py , px, y+height+zy*hintZ); + // line to front wall ( no z) + ofLine(px , py , x+ width*hintX, y + height*(1-hintY)); + + }; + + + float xVal,yVal,zVal; + float zx,zy; // how much of z and x shows up in diagonal x and y + + + float minVal; + float maxVal; + + + float hintX; + float hintY; + float hintZ; + bool hintShowing; + + string labelNameX; + string labelNameY; + string labelNameZ; + + float thickness; // width of border and indicator + ofColor foregroundHi; + ofColor backgroundHi; + ofColor foregroundLo; + ofColor backgroundLo; + ofColor fgInactive; + ofColor hintColor; +}; +#endif /* defined(__tweakathlon___Dbox__) */ diff -r 000000000000 -r a223551fdc1f UI code/3Dbox.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/3Dbox.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,42 @@ +// +// 3Dbox.cpp +// tweakathlon +// +// Created by Robert Tubb on 13/02/2014. +// +// + +#include "3Dbox.h" + +Leap3DBox::Leap3DBox(float ax, + float ay, + float awidth, + float aheight, + float azx, + float azy, + const UIProps& props) : +UIElement(ax,ay,awidth, aheight, props) +{ + zx = azx; + zy = -azy; // cos of stoopid screen coords + init(props); +} + +void Leap3DBox::init(const UIProps& props){ + minVal = 0.; + maxVal = 127.; + xVal = 0.1; + yVal = 0.1; + zVal = 0.1; + + thickness = props.borderThickness; + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.buttonLo; + backgroundLo = props.generalBackground; + fgInactive = props.inactiveGreyedOut; + hintShowing = false; + on = false; + + myType = LEAP3D; +} \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/3DboxGL.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/3DboxGL.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,232 @@ +// +// 3DboxGL.h +// tweakathlon +// +// Created by Robert Tubb on 17/04/2014. +// +// same as 3d biox but with better 3d visualisation + +#ifndef __tweakathlon___DboxGL__ +#define __tweakathlon___DboxGL__ + +#include +#include "3Dbox.h" +#include "UIElement.h" + +#endif /* defined(__tweakathlon___DboxGL__) */ + +//Universal function which sets normals for the triangle meshvoid +void setNormals( ofMesh &mesh ); + +float euclideanDistance(vector v1, vector v2); + +class Leap3DBoxGL : public Leap3DBox { +public: + Leap3DBoxGL(float ax, + float ay, + float awidth, + float aheight, + float azx, + float azy, + const UIProps& props); + + void draw(){ + if(hidden)return; + if(on){ + ofSetColor(foregroundHi); + }else{ + ofSetColor(foregroundLo); + + } + if(inactive){ + ofSetColor(fgInactive); + } + + + + ofPushMatrix(); + ofDisableAlphaBlending(); + ofEnableDepthTest(); + // move to correct pos + + ofTranslate( x+width/2, y+height/2, camTrans); + ofRotate( angleX, 1, 0, 0 ); + ofRotate( angleY, 0, 1, 0 ); + + setNormals(boxMesh); + ofSetColor(foregroundHi); + boxMesh.draw(); + + // draw indicators + drawIndicator(); + ofPopMatrix(); + + drawLabels(); + }; + + void drawIndicator(){ + + if (hintShowing && (hintZ > zVal)){ + hintColor = calculateHintColor(); + draw3DCrossHairs(hintX, hintY, hintZ,hintColor); + + } + + // draw indicator + draw3DCrossHairs(xVal,yVal,zVal, indicatorColor); + // put light in indicateor + // + + + if (hintShowing && hintZ <= zVal){ + hintColor = calculateHintColor(); + draw3DCrossHairs(hintX, hintY, hintZ,hintColor); + + } + } + void draw3DCrossHairs(float x , float y, float z, ofColor c){ + + float ix = x*width - width/2; + float iy = (1-y)*width - width/2; + float iz = (1-z)*width - width/2; + + float left = - width/2; + float bot = width/2; + float front = width/2; + // + ofSetColor(c); + ofSetLineWidth(2.); + // line to bottom + ofLine(ix,iy,iz,ix,bot,iz); + // line to left + ofLine(ix,iy,iz,left,iy,iz); + + //blob + ofDrawIcoSphere(ix,iy,iz,12); + // line to front (a bit wierd?) + ofLine(ix,iy,iz,ix,iy,front); + + + + } + ofColor calculateHintColor(){ + + + // this is all duplicate code and may change so a bit bad >:( + float dist = sqrt( 127.*127.*((xVal - hintX)*(xVal - hintX) + (yVal - hintY)*(yVal - hintY) + (zVal - hintZ)*(zVal - hintZ)) ); + + auto dimComp = sqrt(3.0); + int band = -1; + if (dist < TARGET_SCORE_CC_BAND*dimComp){ + + band = 1; + + }else if (dist < TARGET_SCORE_CC_BAND*2*dimComp){ + + band = 2; + + + }else if (dist < TARGET_SCORE_CC_BAND*3*dimComp){ + + band = 3; + + + }else if (dist < TARGET_SCORE_CC_BAND*4*dimComp){ + + band = 4; + + + }else if (dist < TARGET_SCORE_CC_BAND*6*dimComp){ // 30 + + band = 5; + + }else if (dist < TARGET_SCORE_CC_BAND*9*dimComp){ // 45 + band = 6; + + }else{ + band = 7; + + } + + + ofColor c; + if(band == 1){ + // yellow red blue + c = ofColor(255,255,0,255); + }else if(band == 2){ + c = ofColor(255,0,0,255); + }else if(band == 3){ + c = ofColor(45,45,255,255); + }else if(band == 4){ + c = ofColor(0,255,0,255); + }else{ + c = ofColor(150,235,200,255); + } + return c; + + } + void drawCylinders(){ + ofPushMatrix(); + ofTranslate( x, y, camTrans); + // vertical + ofSetColor(0,255,0); + ofDrawCylinder(0, 0, 32, 500*yVal); + + // into screen + ofSetColor(255,0,0); + ofRotate( 90, 1, 0, 0 ); + ofDrawCylinder(70, 0, 32, 500*zVal); + ofRotate( -90, 1, 0, 0 ); + // l/r horizona + ofSetColor(0,0,255); + ofRotate( 90, 0, 0, 1 ); + ofDrawCylinder(70, 300, 32, 500*xVal); + + + ofPopMatrix(); + } + float valToScreen(float val){ + float sc; + return sc; + }; + + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + static float lastTX = 0.,lastTY = 0.; + + + if (ttype == TOUCH_MOVED && touchID == 0){ + float dx = x -lastTX; + float dy = y - lastTY; + + angleY += dx/3; + angleX += dy/3; + + } + + if (ttype == TOUCH_MOVED && touchID == 1){ + float dx = x -lastTX; + float dy = y - lastTY; + + // adjust light angle? + angleY += dx/3; + angleX += dy/3; + + } + + //cout << angleX << " : " << angleY << endl; + + lastTX = x; + lastTY = y; + return true; + + }; + + float angleX; + float angleY; + float depth; + ofMesh boxMesh; + float camTrans; + ofColor indicatorColor; + +}; + diff -r 000000000000 -r a223551fdc1f UI code/3DboxGL.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/3DboxGL.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,157 @@ +// +// 3DboxGL.cpp +// tweakathlon +// +// Created by Robert Tubb on 17/04/2014. +// +// + +#include "3DboxGL.h" + + +Leap3DBoxGL::Leap3DBoxGL(float ax, + float ay, + float awidth, + float aheight, + float azx, + float azy, + const UIProps& props) : +Leap3DBox(ax,ay,awidth, aheight, azx, azy, props) +{ + indicatorColor = ofColor(123, 123, 220); + // how much to rotate the box + angleX = -25; + angleY = -24; + + depth = width; // its a cube + + // where is the camera + camTrans = 0; + + // cube is centred on 0,0,0 + float I = width/2; + float O = -width/2; + + // left face x=O + // back face z=O + // top face y=O + + // positions of vertices + ofPoint ltf = ofPoint( O,O,I ); + ofPoint lbf = ofPoint( O,I,I ); + ofPoint rtf = ofPoint( I,O,I ); + ofPoint rbf = ofPoint( I,I,I ); + + ofPoint ltr = ofPoint( O,O,O ); + ofPoint lbr = ofPoint( O,I,O ); + ofPoint rtr = ofPoint( I,O,O ); + ofPoint rbr = ofPoint( I,I,O ); + + // now build faces + // rear + boxMesh.addVertex(ltr); + boxMesh.addVertex(rtr); + boxMesh.addVertex(rbr); + + boxMesh.addVertex(ltr); + boxMesh.addVertex(rbr); + boxMesh.addVertex(lbr); + + // left + boxMesh.addVertex(ltf); + boxMesh.addVertex(ltr); + boxMesh.addVertex(lbr); + + boxMesh.addVertex(ltf); + boxMesh.addVertex(lbr); + boxMesh.addVertex(lbf); + + // bottom + boxMesh.addVertex(lbf); + boxMesh.addVertex(lbr); + boxMesh.addVertex(rbr); + + boxMesh.addVertex(lbf); + boxMesh.addVertex(rbr); + boxMesh.addVertex(rbf); + + // top +// boxMesh.addVertex(ltr); +// boxMesh.addVertex(rtr); +// boxMesh.addVertex(rtf); +// +// boxMesh.addVertex(ltr); +// boxMesh.addVertex(rtf); +// boxMesh.addVertex(ltf); +// +// // right +// boxMesh.addVertex(rtf); +// boxMesh.addVertex(rtr); +// boxMesh.addVertex(rbr); +// +// boxMesh.addVertex(rtf); +// boxMesh.addVertex(rbr); +// boxMesh.addVertex(rbf); + + // front +// boxMesh.addVertex(ltr); +// boxMesh.addVertex(rtr); +// boxMesh.addVertex(rbr); +// +// boxMesh.addVertex(ltr); +// boxMesh.addVertex(rbr); +// boxMesh.addVertex(lbr); + + boxMesh.setupIndicesAuto(); +} + + +//-------------------------------------------------------------- + +void setNormals( ofMesh &mesh ) + +{ + //The number of the vertices + int nV = mesh.getNumVertices(); + + //The number of the triangles + int nT = mesh.getNumIndices() / 3; + + vector norm( nV ); + + //Array for the normals + //Scan all the triangles. For each triangle add its + //normal to norm's vectors of triangle's vertices + + for (int t=0; t +#include "ofMain.h" +#include "UIElement.h" +#include "UIProperties.h" + +class Buttron : public UIElement{ + +public: + typedef enum {TOGGLE,MOMENTARY} Mode; // should be in subclasss + + float thickness; // width of border + float radius; // inner radius of corners, reccomended to be same as thickness + ofColor foregroundHi; + ofColor backgroundHi; + ofColor foregroundLo; + ofColor backgroundLo; + ofColor fgInactive; + + bool pressed; // on and pressed can be different + + Buttron(); + ~Buttron(){}; + + // this constructor sets up with defaults obtained from UIProperties (recoomemnded) + Buttron(float x, + float y, + const UIProps& props + ); + Buttron(float x, + float y, + float width, + float height, + const UIProps& props + ); + Buttron(float x, + float y, + float width, + float height, + const UIProps& props, + Mode mode + ); + + Buttron(float x, + float y, + float width, + float height, + float thickness, + float radius, + ofColor foregroundHi, + ofColor backgroundHi, + ofColor foregroundLo, + ofColor backgroundLo); + void draw(); + void drawOutline(); + void drawTextLabel(); + void setMode(Mode m){ + behaviourMode = m; + }; + virtual bool handleMyTouch(int x, int y, touchType ttype, int touchID); + +protected: + Mode behaviourMode; + +}; + + +#endif /* defined(__emptyExample__buttron__) */ diff -r 000000000000 -r a223551fdc1f UI code/Buttron.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/Buttron.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,179 @@ +// +// buttron.cpp +// emptyExample +// +// Created by Robert Tubb on 30/04/2013. +// +// + +#include "buttron.h" + +//------------------------------------------------------------------ + +Buttron::Buttron(){ + // + //cout << " buttron default constructur\n"; +} +//------------------------------------------------------------------ +Buttron::Buttron( + float ax, + float ay, + float awidth, + float aheight, + float athickness, + float aradius, + ofColor aforegroundHi, + ofColor abackgroundHi, + ofColor aforegroundLo, + ofColor abackgroundLo) : + UIElement(ax,ay,awidth,aheight,abackgroundLo), + thickness(athickness), + radius(aradius), + foregroundHi(aforegroundHi), + backgroundHi(abackgroundHi), + foregroundLo(aforegroundLo), + backgroundLo(abackgroundLo) { + //cout << "phew, buttron big constructur\n"; + on = false; +} +//------------------------------------------------------------------ +Buttron::Buttron(float ax, + float ay, + const UIProps& props): + UIElement(ax,ay,props.buttonWidth,props.buttonHeight, props) + +{ + + thickness = props.borderThickness; + radius = props.cornerRadius; + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.buttonLo; + backgroundLo = props.generalBackground; + + on = false; +} +//------------------------------------------------------------------ +Buttron::Buttron(float ax, + float ay, + float awidth, + float aheight, + const UIProps& props): + UIElement(ax,ay,awidth,aheight, props) + +{ + //cout << "slider (meh) recommended constructor\n"; + + thickness = props.borderThickness; + radius = props.cornerRadius; + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.buttonLo; + backgroundLo = props.generalBackground; + fgInactive = props.inactiveGreyedOut; + + on = false; +} +//------------------------------------------------------------------ +void Buttron::draw(){ + if(hidden) return; + //cout << "drawing button" << endl; + ofFill(); + UIElement::draw(); // should do background + drawOutline(); + drawTextLabel(); +} +//------------------------------------------------------------------ +void Buttron::drawTextLabel(){ + ofColor fg,bg; + + if(on){ + fg = foregroundHi; + bg = backgroundHi; + }else{ + fg = foregroundLo; + bg = backgroundLo; + } + if(inactive){ + fg = fgInactive; + } + ofSetColor(fg); + verdana16.drawString(labelName, x + thickness*2, y + 35); + +} +//------------------------------------------------------------------ +void Buttron::drawOutline(){ + + // draw bars + ofColor fg,bg; + + if(on){ + fg = foregroundHi; + bg = backgroundHi; + }else{ + fg = foregroundLo; + bg = backgroundLo; + } + ofSetColor(fg); + + float cornerSize = thickness + radius; + // left + ofRect(x, y+cornerSize, thickness, height - 2*(cornerSize)); + //right + ofRect(x + width - thickness, y+cornerSize, thickness, height - 2*(cornerSize)); + // top + ofRect(x+cornerSize, y, width-2*(cornerSize), thickness); + // bottom + ofRect(x+cornerSize, y+height-thickness, width-2*(cornerSize), thickness); + + // draw corner foreground circles + + //tl + ofCircle(x+cornerSize, y+cornerSize, cornerSize); + + + //tr + + ofCircle(x+width-cornerSize, y+cornerSize, cornerSize); + + //bl + + ofCircle(x+cornerSize, y+height-cornerSize, cornerSize); + + //br + + ofCircle(x+width-cornerSize, y+height-cornerSize, cornerSize); + + // draw corner inner bg circles + ofSetColor(bg); + ofCircle(x+cornerSize, y+cornerSize, radius); + + ofCircle(x+width-cornerSize, y+cornerSize, radius); + + ofCircle(x+cornerSize, y+height-cornerSize, radius); + + ofCircle(x+width-cornerSize, y+height-cornerSize, radius); + + // fill in background + ofRect(x+cornerSize,y+thickness,width-2*cornerSize,height-2*thickness); + ofRect(x+thickness, y+cornerSize, radius, height-2*cornerSize); + ofRect(x+width-cornerSize, y+cornerSize, radius, height-2*cornerSize); +} +//------------------------------------------------------------------------------ +bool Buttron::handleMyTouch(int tx, int ty, touchType ttype, int touchID){ + + //cout << "buttron handling touch\n"; + if(ttype == TOUCH_DOWN){ + on = true; + if(callback) callback(myParamID,1); + + }else if(ttype == TOUCH_MOVED){ + + }else if(ttype == TOUCH_UP){ + on = false; + } + return true; // necessary? + +} + +//------------------------------------------------------------------------------ diff -r 000000000000 -r a223551fdc1f UI code/ButtronSlider.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/ButtronSlider.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,82 @@ +// +// ButtronSlider.h +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#ifndef __emptyExample__ButtronSlider__ +#define __emptyExample__ButtronSlider__ +#include "Buttron.h" +#include + +class ButtronSlider : public Buttron{ +public: + + ~ButtronSlider(){}; + ButtronSlider(float ax, + float ay, + float awidth, + float aheight, + float athickness, + float aradius, + ofColor aforegroundHi, + ofColor abackgroundHi, + ofColor aforegroundLo, + ofColor abackgroundLo, + SliderType type); + + ButtronSlider(float ax, + float ay, + float awidth, + float aheight, + SliderType type, + const UIProps& props); + + void init(); + void draw(){ + Buttron::draw(); + drawIndicator(value); + if(hintShowing) drawHintIndicator(); + } + + void setHintValue(double hval){ + hintValue = (hval - minVal)/(maxVal - minVal); + }; + void setHintColor(ofColor c){ + hintColor = c; + }; + void showHint(bool tf){ + hintShowing = tf; + }; + void setValue(double avalue){ + // scale appropriately to 0-1 (maxVal - minVal)*prop + minVal + value = avalue; // (avalue - minVal)/(maxVal - minVal); + }; + + void setValueAndScale(double avalue){ + // scale appropriately to 0-1 (maxVal - minVal)*prop + minVal + value = (avalue - minVal)/(maxVal - minVal); + }; + + virtual bool handleMyTouch(int x, int y, touchType ttype, int touchID); + + void setRange(float lo, float hi){ + minVal = lo; + maxVal = hi; + } + +private: + void drawIndicator(double proportion); + float minVal; + float maxVal; + void drawHintIndicator(); + SliderType sliderType; + float value; // [0. 1.] + float hintValue; + bool hintShowing; + ofColor hintColor; +}; + +#endif /* defined(__emptyExample__ButtronSlider__) */ diff -r 000000000000 -r a223551fdc1f UI code/ButtronSlider.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/ButtronSlider.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,106 @@ +// +// ButtronSlider.cpp +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#include "ButtronSlider.h" + + +ButtronSlider::ButtronSlider(float ax, + float ay, + float awidth, + float aheight, + float athickness, + float aradius, + ofColor aforegroundHi, + ofColor abackgroundHi, + ofColor aforegroundLo, + ofColor abackgroundLo, + SliderType type) : +Buttron(ax,ay,awidth,aheight,athickness,aradius,aforegroundHi,abackgroundHi,aforegroundLo,abackgroundLo), +sliderType(type) + +{ + + init(); +} +ButtronSlider::ButtronSlider(float ax, + float ay, + float awidth, + float aheight, + SliderType type, + const UIProps& props) : +Buttron(ax,ay,awidth,aheight,props), +sliderType(type) + +{ + init(); +} +void ButtronSlider::init(){ + myType = SLIDER; + minVal = 0.; + maxVal = 127.; + value = 0.6; + hintShowing = false; +} +// +//--------------------------------------------------------------------- +void ButtronSlider::drawIndicator(double proportion){ + if(on){ + ofSetColor(foregroundHi); + }else{ + ofSetColor(foregroundLo); + + } + if(inactive){ + ofSetColor(fgInactive); + } + if(sliderType == FILL){ + + double maxH = height - 2 * thickness; // + double w = width - 2 * thickness;// + double barheight = value*maxH; + double top = y + height - thickness - barheight; + ofRect(x+thickness, top, w, barheight); + + }else if(sliderType == LINE){ + double loc = y + thickness + (1 -value)*(height-3*thickness); + ofRect(x+thickness,loc, width-2*thickness,thickness); + } + + +} + +void ButtronSlider::drawHintIndicator(){ + + ofSetColor(hintColor); + float hthick = 1; + double loc = y + hthick + (1 - hintValue)*(height-3*hthick); + ofRect(x+thickness,loc, width-2*thickness,hthick); + +} + +//--------------------------------------------------------------------- + +bool ButtronSlider::handleMyTouch(int tx, int ty, touchType ttype, int touchID){ + + double ly = ty - y - thickness - radius; + + double prop; + + prop = 1 - ly/(height - 2 * (thickness + radius)); + + if(prop > 1.) prop = 1.; + if(prop < 0.) prop = 0.; + + setValue(prop); + int scaleVal = int((maxVal - minVal)*prop + minVal); + + vector pass; + if(callback) callback(myParamID,scaleVal); + + return true; +} \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/ButtronXY.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/ButtronXY.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,109 @@ +// +// ButtronXY.h +// tweakathlon +// +// Created by Robert Tubb on 25/06/2013. +// +// + +#ifndef __tweakathlon__ButtronXY__ +#define __tweakathlon__ButtronXY__ + +#include +#include "buttron.h" + +class ButtronXY: public Buttron { + +public: + + UICallbackFunction callback; + + double xvalue, yvalue; // [0. 1.] + ~ButtronXY(){}; + ButtronXY(float ax, + float ay, + const UIProps& props); + ButtronXY(float ax, + float ay, + float awidth, + float athickness, + float aradius, + ofColor aforegroundHi, + ofColor abackgroundHi, + ofColor aforegroundLo, + ofColor abackgroundLo); + + void draw(){ + if(hidden) return; + Buttron::draw(); + drawIndicator(); + drawLabels(); + } + void drawLabels(){ + // where? + ofColor fg,bg; + + if(on){ + fg = foregroundHi; + bg = backgroundHi; + }else{ + fg = foregroundLo; + bg = backgroundLo; + } + ofSetColor(fg); + verdana16.drawString(labelNamex, x + width/2, y + thickness*4); + verdana16.drawString(labelNamey, x + thickness*2, y + height/2+7); + } + void init(); + + void setValue(double axvalue, double ayvalue){ + xvalue = axvalue; + yvalue = ayvalue; + }; + void setValueAndScale(double axvalue, double ayvalue){ + xvalue = (axvalue - minVal)/(maxVal - minVal); + yvalue = (ayvalue - minVal)/(maxVal - minVal); + } + void setHintValue(double hvalx, double hvaly){ + hintValuex = (hvalx - minVal)/(maxVal - minVal); + hintValuey = (hvaly - minVal)/(maxVal - minVal); + + }; + void setHintColor(ofColor c){ + // TODO somehow set the fill ? + }; + void setLabel(string xlabel, string ylabel){ + labelNamex = xlabel; + labelNamey = ylabel; + } + + + void showHint(bool tf){ + hintShowing = tf; + }; + virtual bool handleMyTouch(int x, int y, touchType ttype, int touchID); + + virtual void addHandler(UICallbackFunction handlerFunction, int paramIDX, int paramIDY) // virtual? + { + cout << "handler added to XYUIElement " << endl; + callback = handlerFunction; + myParamIDX = paramIDX; + myParamIDY = paramIDY; + }; + + +private: + void drawIndicator(); + void drawHintIndicator(); + float maxVal; + float minVal; + int myParamIDX; + int myParamIDY; + float hintValuex; + float hintValuey; + bool hintShowing; + string labelNamex; + string labelNamey; +}; + +#endif /* defined(__tweakathlon__ButtronXY__) */ diff -r 000000000000 -r a223551fdc1f UI code/ButtronXY.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/ButtronXY.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,132 @@ +// +// ButtronXY.cpp +// tweakathlon +// +// Created by Robert Tubb on 25/06/2013. +// +// + +#include "ButtronXY.h" + +ButtronXY::ButtronXY(float ax, + float ay, + float awidth, // width same as height + float athickness, + float aradius, + ofColor aforegroundHi, + ofColor abackgroundHi, + ofColor aforegroundLo, + ofColor abackgroundLo) : +Buttron(ax,ay,awidth,awidth,athickness,aradius,aforegroundHi,abackgroundHi,aforegroundLo,abackgroundLo) + +{ + + cout << "ButtronXY constructor\n"; + init(); +} + +ButtronXY::ButtronXY(float ax, + float ay, + const UIProps& props) : +Buttron(ax,ay,props.XYsize ,props.XYsize,props) +{ + cout << "ButtronXY constructor\n"; + init(); +}; +void ButtronXY::init(){ + xvalue = 0.6; + yvalue = 0.7; + minVal = 0.; + maxVal = 127.; + myType = XYPAD; + labelNamex = "xxx"; + labelNamey = "yyy"; +} +//--------------------------------------------------------------------- +void ButtronXY::drawIndicator(){ + if(hintShowing) drawHintIndicator(); + + if(on){ + ofSetColor(foregroundHi); + }else{ + ofSetColor(foregroundLo); + + } + if(inactive){ + ofSetColor(fgInactive); + } + + // circle and cross hairs + ofFill(); + + double left = x + thickness + radius; + double top = y + radius + thickness; + double activeWidth = width - 2*(radius + thickness); + double cx = left + xvalue*activeWidth; + double cy = top + (1-yvalue)*activeWidth; + + ofLine(cx,y,cx,y+height); + ofLine(x, cy, x+ width, cy); + + + ofEllipse(cx,cy , 2*radius,2*radius); + + +} +//--------------------------------------------------------------------- +void ButtronXY::drawHintIndicator(){ + double left = x + thickness + radius; + double top = y + radius + thickness; + double activeWidth = width - 2*(radius + thickness); + + // loc = y + hthick + (1 - hintValue)*(height-3*hthick); + ofSetColor(255,255,255); + float hthick = 1; + double locx = left + hintValuex*activeWidth; + double locy = top + (1 - hintValuey)*activeWidth; + ofEllipse(locx,locy, hthick,hthick); + + // draw target dart board thingy + ofNoFill(); + ofSetLineWidth(2); + // yellow red blue + ofSetColor(255,255,0,166); + + float rband = activeWidth*TARGET_SCORE_CC_BAND*sqrt(2.0)/127.; + ofCircle(locx, locy, rband); + ofSetColor(255,0,0,166); + ofCircle(locx, locy, rband*2); + ofSetColor(45,45,255,166); + ofCircle(locx, locy, rband*3); + ofSetColor(0,255,0,166); + ofCircle(locx, locy, rband*4); // within 20 cc vals? + ofFill(); + +} +//--------------------------------------------------------------------- + + +bool ButtronXY::handleMyTouch(int tx, int ty, touchType ttype, int touchID){ + + double lx = tx - x - thickness - radius; + double ly = ty - y - thickness - radius; + + double propx,propy; + propx = lx/(width - 2 * (thickness + radius)); + propy = 1 - ly/(height - 2 * (thickness + radius)); + if(propx > 1.) propx = 1.; + if(propx < 0.) propx = 0.; + if(propy > 1.) propy = 1.; + if(propy < 0.) propy = 0.; + //cout << "propx: " << propx << endl; + setValue(propx,propy); + + int scaleValx = int((maxVal - minVal)*propx + minVal); + int scaleValy = int((maxVal - minVal)*propy + minVal); + + if(callback) callback(myParamIDX,scaleValx); + if(callback) callback(myParamIDY,scaleValy); + return true; +} + +//--------------------------------------------------------------------- \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/CountdownText.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/CountdownText.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,69 @@ +// +// CountdownText.h +// tweakathlon +// +// Created by Robert Tubb on 10/03/2014. +// +// + +#ifndef __tweakathlon__CountdownText__ +#define __tweakathlon__CountdownText__ + +#include + +#include "ofMain.h" +#include "UIElement.h" +#include "timeController.h" +#include "boost/function.hpp" +#include "boost/bind.hpp" +// actuall a countdown box +extern TimeController timeController; +class CountdownText : public UIElement{ +public: + + CountdownText(string text, int x, int y,int w,int h, const UIProps& props); + void draw(); + + ofColor foregroundHi; + ofColor backgroundHi; + ofColor foregroundLo; + ofColor backgroundLo; + + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + return false; + } + + void showAndStart(int sec){ + show(); + stringstream s; + s << sec; + numSecondsText = s.str(); + t = sec; + timeController.scheduleEvent(tcb, 1000); + }; + + void secPassed(){ + t--; + if(t <= 0){ + //finish + numSecondsText = "0!"; + }else{ + stringstream ts; + ts << t; + numSecondsText = ts.str(); + timeController.scheduleEvent(tcb, 1000); + } + }; + void setTestTypeString(string s){ + testTypeString = s; + } +private: + int t; + TimerCallbackFunction tcb; + string testTypeString; + string numSecondsText; +}; + + + +#endif /* defined(__tweakathlon__CountdownText__) */ diff -r 000000000000 -r a223551fdc1f UI code/CountdownText.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/CountdownText.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,41 @@ +// +// CountdownText.mm +// tweakathlon +// +// Created by Robert Tubb on 10/03/2014. +// +// + +#include "CountdownText.h" + +CountdownText::CountdownText(string text, int ax, int ay,int aw,int ah, const UIProps& props): +UIElement(ax,ay,aw,ah, props) + + +{ + labelName = text; + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.buttonLo; + backgroundLo = props.generalBackground; + verdana16 = props.verdana16; + bigFont = props.bigFont; + tcb = boost::bind(&CountdownText::secPassed, this); +}; + +//------------------------------------------------------------------ +void CountdownText::draw(){ + if (hidden) return; + UIElement::draw(); // should do background? + ofSetColor(foregroundHi); + + verdana16.drawString(testTypeString, x, y + 8); + + + verdana16.drawString("STARTING IN...", x, y + 108); + bigFont.drawString(numSecondsText, x, y + 160); + + + //ofRect(x,y,width,height); +} +//------------------------------------------------------------------ \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/TextPanel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/TextPanel.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,41 @@ + +#ifndef __tweakathlon__TextPanel__ +#define __tweakathlon__TextPanel__ + +#include +#include "ofMain.h" +#include "UIElement.h" +#include "boost/function.hpp" +#include "boost/bind.hpp" + +class TextPanel : public UIElement{ +public: + + TextPanel(string text, int x, int y,int w,int h, const UIProps& props); + void draw(); + + void setText(string at){ + theText = at; + }; + void setColor(ofColor col){ + foregroundHi = col; + } + void setFontSize(FontSize f){ + fontSize = f; + } + ofColor foregroundHi; + ofColor backgroundHi; + ofColor foregroundLo; + ofColor backgroundLo; + + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + return false; + } + +private: + string theText; + bool transparent; + FontSize fontSize; +}; + +#endif /* defined(__tweakathlon__TextPanel__) */ diff -r 000000000000 -r a223551fdc1f UI code/TextPanel.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/TextPanel.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,43 @@ +// +// TextPanel.mm +// tweakathlon +// +// Created by Robert Tubb on 05/03/2014. +// +// + +#include "TextPanel.h" + +TextPanel::TextPanel(string text, int ax, int ay,int aw,int ah, const UIProps& props): +UIElement(ax,ay,aw,ah, props) + + +{ + labelName = text; + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.buttonLo; + backgroundLo = props.generalBackground; + verdana16 = props.verdana16; + bigFont = props.bigFont; + smallFont = props.smallFont; + transparent = true; +}; + +//------------------------------------------------------------------ +void TextPanel::draw(){ + if (hidden) return; + if(!transparent) UIElement::draw(); // should do background + ofSetColor(foregroundHi); + + // TODO check for fitting inside?? + if(fontSize == SMALLFONT){ + smallFont.drawString(theText, x, y + 8); + }else if(fontSize == LARGEFONT){ + bigFont.drawString(theText, x, y + 8); + }else{ + verdana16.drawString(theText, x, y + 8); + } + + //ofRect(x,y,width,height); +} \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/UIElement.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/UIElement.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,151 @@ +// +// UIElement.h +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// literally just an area of the screen that is a ui element + +#ifndef __emptyExample__UIElement__ +#define __emptyExample__UIElement__ +#include "ofMain.h" +#include "globalVariables.h" +#include +#include +#include "boost/function.hpp" +#include "UIProperties.h" + +typedef boost::function UICallbackFunction; + +class MessageOrganiser; + +class UIElement{ +public: + + + UICallbackFunction callback; + + UIElement(); + virtual ~UIElement(){}; + // recommended + UIElement(float ax, + float ay, + float awidth, + float aheight, + const UIProps& props); + + UIElement(float ax, + float ay, + float awidth, + float aheight, + ofColor bg); + + virtual void setLabel(string label){ + labelName = label; + } + virtual void draw(); + void hide(){ + hidden = true; + on = false; + + }; + void show(){ + hidden = false; + on = true; + + }; + bool touch(int x, int y, touchType ttype, int touchID); + + virtual void addHandler(UICallbackFunction handlerFunction, int paramID) // virtual? + { + cout << "handler added to UIElement " << endl; + callback = handlerFunction; + myParamID = paramID; + }; + + virtual void setValue(float value){ + cout << "not valid to set value on this?" << endl; + }; + virtual void setHintValue(float value){ + cout << "not valid to set value on this?" << endl; + }; + virtual void showHint(bool value){ + cout << "not valid to set value on this?" << endl; + }; + virtual void setHintColor(ofColor c){ + cout << "not valid to set value on this?" << endl; + }; + controllerType getType() const { + return myType; + } + float getWidth() const {return width;}; + virtual void setHighlight(bool hion){ + // ? + on = hion; + }; + void setActive(bool isActive){ + inactive = !isActive; // thats logic right? + } + void setX(float ax){ + x = ax; + }; + void setY(float ay){ + y = ay; + }; +protected: + + float x; + float y; + float width; + float height; + bool on; + int myParamID; + list myTouchIDs; + + ofColor background; + + string labelName; + ofTrueTypeFont verdana16; + ofTrueTypeFont bigFont; + ofTrueTypeFont smallFont; + controllerType myType; + + bool hidden; // don't draw dont touch + bool inactive; // dont touch, draw dimmed + + void init(); + + bool isExistingTouchID(int touchID){ + // is id in list + std::list::iterator findIter = std::find(myTouchIDs.begin(), myTouchIDs.end(), touchID); + if (findIter == myTouchIDs.end()){ + return false; + }else{ + return true; + } + }; + + void addTouchID(int touchID){ + //list::iterator findIter = std::find(myTouchIDs.begin(), myTouchIDs.end(), touchID); + //if(findIter == myTouchIDs.end()){ // checks for duplicates + myTouchIDs.insert(myTouchIDs.begin(), touchID); + //} + }; + void removeTouchID(int touchID){ + list::iterator findIter = std::find(myTouchIDs.begin(), myTouchIDs.end(), touchID); + if(findIter != myTouchIDs.end()){ + myTouchIDs.erase(findIter); + } + }; + static float sumWidth(float total, UIElement* element){ + return total + element->getWidth(); + } + bool isMyTouch(int x, int y, touchType ttype, int touchID); + bool touchIsInMyArea(int tx, int ty); + virtual bool handleMyTouch(int x, int y, touchType ttype, int touchID) = 0; // subclass handles it + + bool isCoordInMyRegion(double x, double y); // not used + + +}; +#endif /* defined(__emptyExample__UIElement__) */ diff -r 000000000000 -r a223551fdc1f UI code/UIElement.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/UIElement.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,147 @@ +// +// UIElement.cpp +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#include "UIElement.h" +//---------------------------------------------------------------------- +UIElement::UIElement(){ + // + //cout << " UIElement default constructur BAD !!!\n"; + init(); +} +//---------------------------------------------------------------------- +UIElement::UIElement(float ax, + float ay, + float awidth, + float aheight, + const UIProps& props) : +x(ax), +y(ay), +width(awidth), +height(aheight), +background(props.generalBackground) +{ + //cout << " UIElement constructur with defs \n"; + init(); + verdana16 = props.verdana16; + bigFont = props.bigFont; + +} +//---------------------------------------------------------------------- +UIElement::UIElement(float ax, + float ay, + float awidth, + float aheight, + ofColor bg) : +x(ax), +y(ay), +width(awidth), +height(aheight), +background(bg) +{ + init(); + +} +//---------------------------------------------------------------------- +void UIElement::init(){ + + + hidden = false; + inactive = false; +} +//---------------------------------------------------------------------- +void UIElement::draw(){ + if(hidden) return; + //cout<<"element draw\n"; + ofSetColor(background); + ofRect(x,y,width,height); + + +}; +//---------------------------------------------------------------------- +bool UIElement::touch(int tx, int ty, touchType ttype, int touchID){ + if(isMyTouch(tx,ty,ttype,touchID)){ + handleMyTouch(tx, ty, ttype,touchID); + return true; + }else{ + return false; + } +} +//---------------------------------------------------------------------- +// called first from all subclasses +bool UIElement::isMyTouch(int tx, int ty, touchType ttype, int touchID){ + if(hidden || inactive) return false; + + if(ttype == TOUCH_DOWN){ + if (touchIsInMyArea(tx, ty)){ + if (!isExistingTouchID(touchID)){ + //cout << "Touchdown in area, grabbing focus " << labelName << " mytouchID: " << myTouchID << " finger ID: " << touchID << endl; + addTouchID(touchID); + return true; + + }else{ + //shouldn't happen? + return true; + } + + }else{ + //cout << "Touchdown outside area, ignoring " << labelName << " mytouchID: " << myTouchID << " finger ID: " << touchID << endl; + return false; + + } + } + if(ttype == TOUCH_UP){ + if (isExistingTouchID(touchID)){ + //cout << "Touch Up for my ID, handling " << labelName << " mytouchID: " << myTouchID << " finger ID: " << touchID << endl; + //myTouchID = -1; + removeTouchID(touchID); + return true; + }else{ + //cout << "Touch Up NOT my ID, ignoring " << labelName << " mytouchID: " << myTouchID << " finger ID: " << touchID << endl; + return false; + } + } + + if(ttype == TOUCH_MOVED){ + if(isExistingTouchID(touchID)){ + //cout << "Touch moved for my ID, handling " << labelName << " mytouchID: " << myTouchID << " finger ID: " << touchID << endl; + return true; + }else{ + //cout << "Touch moved NOT my ID, ignore " << labelName << " mytouchID: " << myTouchID << " finger ID: " << touchID << endl; + return false; + } + } + + cout << "UNHANDLED SITUATION!" << labelName << endl; + return false; + +} + +//---------------------------------------------------------------------- +bool UIElement::touchIsInMyArea(int tx, int ty){ + + // work out relative coords + double relx = tx - x; + double rely = ty - y; + return !(relx < 0 || relx > width || rely < 0 || rely > height); +} +//---------------------------------------------------------------------- +bool UIElement::isCoordInMyRegion(double ax, double ay){ + if(hidden) return false; + + if( (ax > x && ax < x+width) && (ay > y && ay < y+height)){ + return true; + }else{ + return false; + } + +} +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/UIElementContainer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/UIElementContainer.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,107 @@ +// +// UIElementContainer.h +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + + +// a meta button, with border. + +#ifndef __emptyExample__UIElementContainer__ +#define __emptyExample__UIElementContainer__ + +#include +#include "globalVariables.h" +#include "ofMain.h" +#include "UIElement.h" +#include "boost/bind.hpp" +#include "boost/function.hpp" +#include "timeController.h" +// is a UI "panel" containing sub elements +// helps control the focus of the touch event + + +extern TimeController timeController; + +class UIElementContainer: public UIElement{ +public: + UIProps myProps; + vector subElements; + UIElementContainer(); + ~UIElementContainer(){ + removeAllSubelements(); + }; + UIElementContainer(float ax, + float ay, + float awidth, + float aheight, + const UIProps& props); // constructor 1 : we add stuff later + + void addElement(UIElement *elm){ + subElements.push_back(elm); + + }; + void removeAllSubelements(); + + int getNumberOfControls(); + UIElement* getElement(int idx){ + if (idx < subElements.size()){ + return subElements[idx]; + }else{ + cout << "ERROR ERROR: index too big for subelemens" << endl; + } + + } + void showBorder(bool s){ + if(s){ + cthickness = 1; + + } + } + virtual void draw(); + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->touch(x,y,ttype,touchID); + } + return true; + } + + void setActive(bool isActive){ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->setActive(isActive); + } + } + + void autoArrangeRow(){ + // goes thru subelements and sets x and y pos to something sensible + + // add up all element widths + float sum = accumulate(subElements.begin(), subElements.end(), 0.0, &UIElement::sumWidth); + + float spaceLeft = width - sum; + + float spac = spaceLeft/(getNumberOfControls()+1); + + if (spac <= 0){ + cout << "ERROR: not enough space for controls" << endl; + + } + float pos = spac; + vector::iterator ei; + for(ei = subElements.begin(); ei < subElements.end(); ei++){ + (*ei)->setX(pos); + pos = pos + (*ei)->getWidth() + spac; + } + // TODO y set to centred + } +private: + void drawBorder(); + double cthickness; + bool flashing; +}; + +#endif /* defined(__emptyExample__UIElementContainer__) */ diff -r 000000000000 -r a223551fdc1f UI code/UIElementContainer.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/UIElementContainer.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,73 @@ + // +// UIElementContainer.cpp +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#include "UIElementContainer.h" +#include "ButtronXY.h" +#include "ButtronSlider.h" + +//----------------------------------------------------------------------------- +UIElementContainer::UIElementContainer(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops) : +UIElement(ax,ay,awidth,aheight,aprops.generalBackground) +{ + cout << "UIElementContainer contructor\n"; + + myProps = aprops; + cthickness = 0.; + +} + +//----------------------------------------------------------------------------- +int UIElementContainer::getNumberOfControls(){ + return subElements.size(); +} + + +//----------------------------------------------------------------------------- + +void UIElementContainer::removeAllSubelements(){ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + delete (*UIitr); + } + subElements.clear(); +} +//------------------------------------------------------------------- +void UIElementContainer::draw(){ + if(hidden) return; + //cout << "DRAWING CONTAINER"<< endl; + UIElement::draw(); + // draw me + if(cthickness != 0.){ + // doh, duplicate code from buttron? + drawBorder(); + } + + // draw my subelems + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->draw(); + } +}; +//------------------------------------------------------------------- +void UIElementContainer::drawBorder(){ + ofSetLineWidth(cthickness); + ofSetColor(myProps.borderColor); + // top + ofLine(x,y,x+width,y); + // left + ofLine(x,y,x,y+height); + //right + ofLine(x+width-cthickness,y,x+width-cthickness,y+height); + // bottom + ofLine(x-cthickness,y+height,x+width-cthickness,y+height); +} +//------------------------------------------------------------------- \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UI code/UIGrid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/UIGrid.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,32 @@ +// +// UIGrid.h +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#ifndef __emptyExample__UIGrid__ +#define __emptyExample__UIGrid__ +#include "ofMain.h" +#include "Buttron.h" // no +#include "UIElement.h" +#include "UIElementContainer.h" +#include + +template +class UIGrid: public UIElementContainer{ +public: + int rows; + int columns; + int spacing; + // too fuckin long + UIGrid(int ax,int ay, int awidth, int aheight, int numRows, int numColumns, int spacing,ofColor hi, ofColor lo, ofColor bg); + vector > subElementsByCoordinate; + + // draw and touch all handled by UIElementContainer... + + void print(); + +}; +#endif /* defined(__emptyExample__UIGrid__) */ diff -r 000000000000 -r a223551fdc1f UI code/UIGrid.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/UIGrid.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,43 @@ +// +// UIGrid.cpp +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#include "UIGrid.h" + + + +template void UIGrid::print(){ + cout << "uh \n"; +} + +template UIGrid::UIGrid(int ax,int ay, int awidth, int aheight, int numColumns,int numRows, int spacing,ofColor hi, ofColor lo, ofColor bg) +{ + + // grid of what ? + double cw = width/(double)numColumns; + double ch = height/(double)numRows; + + double eWidth = cw - spacing; + double eHeight = ch - spacing; + double ex,ey; + double radius = (eWidth < eHeight ? eWidth : eHeight)/6.0; + double thickness = radius; + for(int i=0; i< numColumns; i++){ + ex = x + i*cw + spacing/2.0; + for(int j=0; j +#include "ofMain.h" +// this is all the default global colors and sizes for the UI, passed into uielement conststrutor + +struct UIProps { + + int buttonWidth; + int buttonHeight; + + int borderThickness; + int cornerRadius; + + int sliderPanelWidth; + int sliderPanelHeight; + int spacerSize; + int XYsize; + + int sliderWidth; + int sliderHeight; + float sliderMinVal; + float sliderMaxVal; + ofColor buttonLo; + ofColor buttonHi; + + ofColor inactiveGreyedOut; + + ofColor sliderMultiActive; + + ofColor sliderSimulInactive; + ofColor sliderSimulActive; + + ofColor generalBackground; + ofColor borderColor; + ofColor hintColor; + + ofTrueTypeFont verdana16; + ofTrueTypeFont bigFont; + ofTrueTypeFont smallFont; + + UIProps(){ + + // LOAD FONT SLOW + verdana16.loadFont("verdana.ttf", 14, true, true); + verdana16.setLineHeight(18.0f); + verdana16.setLetterSpacing(1.037); + + bigFont.loadFont("verdana.ttf", 28, true, true); + bigFont.setLineHeight(22.0f); + bigFont.setLetterSpacing(1.037); + + smallFont.loadFont("verdana.ttf", 10, true, true); + smallFont.setLineHeight(11.0f); + smallFont.setLetterSpacing(1.037); + + buttonWidth = 150; + buttonHeight = 60; + borderThickness = 5; + cornerRadius = 7; + + sliderPanelWidth = ofGetWidth(); + sliderPanelHeight = 500; + spacerSize = 40; + XYsize = sliderPanelHeight - spacerSize*2; + + sliderWidth = XYsize/4; + sliderHeight = XYsize; + sliderMinVal = 0. ; + sliderMaxVal = 127.; + + borderColor = ofColor(123,200,180,180); + hintColor = ofColor(255,0,0,255); + + buttonLo = ofColor(123,200,180,255); + buttonHi = ofColor(150,235,200,255); + + inactiveGreyedOut = ofColor(78,78,78,255); + + sliderMultiActive = ofColor(255,255,0,255); + + sliderSimulInactive = ofColor(200,0,0,255); + sliderSimulActive = ofColor(0,255,0,255); + + generalBackground = ofColor(23,23,23,255); + }; +}; diff -r 000000000000 -r a223551fdc1f UI code/buttonPanel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/buttonPanel.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,50 @@ +// +// buttonPanel.h +// tweakathlon +// +// Created by Robert Tubb on 11/02/2014. +// +// + +#ifndef __tweakathlon__buttonPanel__ +#define __tweakathlon__buttonPanel__ + +#include +#include +#include "UIElementContainer.h" +#include +#include "globalVariables.h" +#include "ofMain.h" +#include "UIElement.h" +#include "boost/bind.hpp" +#include "boost/function.hpp" +#include "timeController.h" +#include "ButtronSlider.h" +#include "ButtronXY.h" +#include "Buttron.h" +// a row of buttons, spaced out nicely + +class ButtonPanel : public UIElementContainer{ + +public: + ButtonPanel(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops, + vector elemList); + ButtonPanel(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops); + vector generateControls(vector elemList); + + void addButton(Buttron* aButton){ + subElements.push_back(aButton); + autoArrangeRow(); + } + +}; + +#endif /* defined(__tweakathlon__buttonPanel__) */ diff -r 000000000000 -r a223551fdc1f UI code/buttonPanel.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/buttonPanel.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,58 @@ +// +// buttonPanel.cpp +// tweakathlon +// +// Created by Robert Tubb on 11/02/2014. +// +// + +#include "buttonPanel.h" +ButtonPanel::ButtonPanel(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops, + vector elemList) : +UIElementContainer(ax,ay,awidth,aheight,aprops) +{ + cout << "ButtonPanel auto layout contructor\n"; + + generateControls(elemList); + autoArrangeRow(); +} +//--------------------------------------------------- +ButtonPanel::ButtonPanel(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops) : +UIElementContainer(ax,ay,awidth,aheight,aprops) +{ + cout << "ButtonPanel - ctrls added later constructor\n"; + +} +//--------------------------------------------------- +vector ButtonPanel::generateControls(vector elemList){ + removeAllSubelements(); + vector::iterator i; + + // 10 cm is 520 pixels + + // calc positions + int top = y + myProps.spacerSize; + + int n=0; + for(i=elemList.begin(); isetLabel("unassigned"); + subElements.push_back(butt); + n++; + + }else{ + cout << "ERROR: button panel only handles buttons" << endl; + } + } + return subElements; +} diff -r 000000000000 -r a223551fdc1f UI code/sliderPanel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/sliderPanel.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,81 @@ +// +// sliderPanel.h +// tweakathlon +// +// Created by Robert Tubb on 11/02/2014. +// +// + +#ifndef __tweakathlon__sliderPanel__ +#define __tweakathlon__sliderPanel__ + +#include +#include "UIElementContainer.h" +#include +#include "globalVariables.h" +#include "ofMain.h" +#include "UIElement.h" +#include "boost/bind.hpp" +#include "boost/function.hpp" +#include "timeController.h" +#include "ButtronSlider.h" +#include "ButtronXY.h" +#include "3Dbox.h" +#include "3DboxGL.h" +// panel with sliders and xy pads +class SliderPanel : public UIElementContainer{ + +public: + SliderPanel(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops, + vector elemList); + //------------------------ + void showHint(bool value){ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->showHint(value); + } + } + // + void setHintColor(ofColor c){ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->setHintColor(c); + } + } + //------------------------ + void flash(){ + // turn hilight on and off + if (!flashing){ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->setHighlight(true); + } + // set up timer + TimerCallbackFunction tcb; + tcb = boost::bind(&SliderPanel::flash, this); + timeController.scheduleEvent(tcb, 250); + flashing = true; + }else{ + vector::iterator UIitr; + for(UIitr = subElements.begin(); UIitr < subElements.end(); UIitr++){ + (*UIitr)->setHighlight(false); + } + flashing = false; + } + + } + //------------------------ + vector generateControls(vector elemList, controlPanelType panelType); + //------------------------ + + // TODO override touch thing to make revisitable +private: + bool flashing; + controlPanelType panelType; +}; + +#endif /* defined(__tweakathlon__sliderPanel__) */ diff -r 000000000000 -r a223551fdc1f UI code/sliderPanel.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/sliderPanel.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,99 @@ +// +// sliderPanel.cpp +// tweakathlon +// +// Created by Robert Tubb on 11/02/2014. +// +// + +#include "sliderPanel.h" + +//----------------------------------------------------------------------------- +SliderPanel::SliderPanel(float ax, + float ay, + float awidth, + float aheight, + const UIProps& aprops, + vector elemList) : +UIElementContainer(ax,ay,awidth,aheight,aprops) +{ + cout << "SliderPanel auto layout contructor\n"; + + // generateControls(elemList);// called from messageorganiser +} + +// NOT GENERIC +//----------------------------------------------------------------------------- +vector SliderPanel::generateControls(vector elemList, controlPanelType panelType){ + removeAllSubelements(); + vector::iterator i; + + // 10 cm is 520 pixels + + // calc positions + int top = y + myProps.spacerSize; + + float pixPerElem = width/(float)elemList.size(); + if (pixPerElem < myProps.sliderWidth ){ + cout << "error not enough room for sliders" << endl; + } + + int n=0; + for(i=elemList.begin(); isetLabel("unassigned"); + subElements.push_back(revslider); + revslider->showHint(false); + // grey out all but first + if(panelType == SEQUENTIAL && i != elemList.begin()){ + revslider->setActive(false); + } + + n++; + + }else if(*i == XYPAD){ + // add a xy + float c = (n + 0.5) * pixPerElem; + float left = c - myProps.XYsize/2; + ButtronXY * xyp = new ButtronXY(left , top , myProps); + xyp->setLabel("unassigned","unassigned"); + xyp->showHint(false); + subElements.push_back(xyp); + n++; + }else if(*i == LEAP3D){ + // add a threed box + float c = x+width*0.5; + float left = c - myProps.XYsize; + + //Leap3DBox * l3d = new Leap3DBox(left , top+50 , myProps.XYsize*0.75,myProps.XYsize*0.75,150,50, myProps); + + Leap3DBoxGL * l3d = new Leap3DBoxGL(left , top+50 , myProps.XYsize*0.75,myProps.XYsize*0.75,150,50, myProps); + + + + subElements.push_back(l3d); + n++; + + }else{ + cout << "ERROR: slider panel only handles xy pads and sliders" << endl; + } + + + } + + autoArrangeRow(); // will set positions + + + + return subElements; +} + diff -r 000000000000 -r a223551fdc1f UI code/targetSymbol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/targetSymbol.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,84 @@ +// +// targetSymbol.h +// tweakathlon +// +// Created by Robert Tubb on 11/02/2014. +// +// + +#ifndef __tweakathlon__targetSymbol__ +#define __tweakathlon__targetSymbol__ + +#include +#include "UIElement.h" +#include "timeController.h" +extern TimeController timeController; +class TargetSymbol : public UIElement { +public: + + TargetSymbol(int ax, int ay,int aw, const UIProps& props): + UIElement(ax,ay,aw,aw, props) + { + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.inactiveGreyedOut; // can't be touched + backgroundLo = props.generalBackground; + flashing = false; + on = false; + }; + + void draw(){ + if(hidden)return; + //UIElement::draw(); // don't do background + ofColor fg,bg; + + if(on){ + fg = foregroundHi; + bg = backgroundHi; + }else{ + fg = foregroundLo; + bg = backgroundLo; + } + ofSetColor(fg); + + ofEllipse(x,y,width,height); + + ofSetColor(bg); + ofEllipse(x,y,width*0.66,height*0.66); + + ofSetColor(fg); + ofEllipse(x,y,width*0.33,height*0.33); + + }; + + void flash(){ + // turn hilight on and off + if (!flashing){ + setHighlight(true); + + // set up timer + TimerCallbackFunction tcb; + tcb = boost::bind(&TargetSymbol::flash, this); + timeController.scheduleEvent(tcb, int(ALTERNATION_SPEED/4)); + flashing = true; + }else{ + setHighlight(false); + + flashing = false; + } + + } + + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + return false; // or? + } + +private: + ofColor foregroundHi; + ofColor backgroundHi; + ofColor foregroundLo; + ofColor backgroundLo; + ofColor fgInactive; + bool flashing; +}; +#endif /* defined(__tweakathlon__targetSymbol__) */ diff -r 000000000000 -r a223551fdc1f UI code/targetSymbol.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/targetSymbol.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,9 @@ +// +// targetSymbol.cpp +// tweakathlon +// +// Created by Robert Tubb on 11/02/2014. +// +// + +#include "targetSymbol.h" diff -r 000000000000 -r a223551fdc1f UI code/textLabel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/textLabel.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,66 @@ +// +// textLabel.h +// tweakathlon +// +// Created by Robert Tubb on 10/02/2014. +// +// + +#ifndef __tweakathlon__textLabel__ +#define __tweakathlon__textLabel__ + +#include +#include "ofMain.h" +#include "UIElement.h" +#include "timeController.h" +#include "boost/function.hpp" +#include "boost/bind.hpp" +// actuall a countdown box +extern TimeController timeController; +class TextLabel : public UIElement{ +public: + + TextLabel(string text, int x, int y,int w,int h, const UIProps& props); + void draw(); + + void setText(string at){ + labelName = at; + }; + + ofColor foregroundHi; + ofColor backgroundHi; + ofColor foregroundLo; + ofColor backgroundLo; + + bool handleMyTouch(int x, int y, touchType ttype, int touchID){ + return false; + } + + void showAndStart(int sec){ + show(); + stringstream s; + s << sec; + labelName = s.str(); + t = sec; + timeController.scheduleEvent(tcb, 1000); + }; + + void secPassed(){ + t--; + if(t <= 0){ + //finish + labelName = "!"; + }else{ + stringstream ts; + ts << t; + labelName = ts.str(); + timeController.scheduleEvent(tcb, 1000); + } + }; +private: + int t; + TimerCallbackFunction tcb; + +}; + +#endif /* defined(__tweakathlon__textLabel__) */ diff -r 000000000000 -r a223551fdc1f UI code/textLabel.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UI code/textLabel.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,37 @@ +// +// textLabel.cpp +// tweakathlon +// +// Created by Robert Tubb on 10/02/2014. +// +// + +#include "textLabel.h" + +TextLabel::TextLabel(string text, int ax, int ay,int aw,int ah, const UIProps& props): + UIElement(ax,ay,aw,ah, props) + + +{ + labelName = text; + foregroundHi = props.buttonHi; + backgroundHi = props.generalBackground; + foregroundLo = props.buttonLo; + backgroundLo = props.generalBackground; + verdana16 = props.verdana16; + bigFont = props.bigFont; + tcb = boost::bind(&TextLabel::secPassed, this); +}; + +//------------------------------------------------------------------ +void TextLabel::draw(){ + if (hidden) return; + UIElement::draw(); // should do background + ofSetColor(foregroundHi); + verdana16.drawString("NEXT TEST IN...", x, y + 8); + bigFont.drawString(labelName, x, y + 60); + + + //ofRect(x,y,width,height); +} +//------------------------------------------------------------------ \ No newline at end of file diff -r 000000000000 -r a223551fdc1f UsernameAlertViewController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UsernameAlertViewController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,19 @@ +// +// iViewController.h +// oscSenderExample +// +// Created by Robert Tubb on 07/01/2013. +// +// + +#import + +@interface UsernameAlertViewController : NSObject + +@property (strong,nonatomic) UIAlertView * alert; +@property (nonatomic, assign) id theOFAppRef; +-(void)showUserNamePrompt; +-(void)setAppRef:(id)theAppRef; + +@end + diff -r 000000000000 -r a223551fdc1f UsernameAlertViewController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UsernameAlertViewController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,87 @@ +// +// iViewController.m +// oscSenderExample +// +// Created by Robert Tubb on 07/01/2013. +// +// +#include "testApp.h" +#include "eventLogger.h" + +#import "usernameAlertViewController.h" + + +extern EventLogger eventLogger; + +@implementation UsernameAlertViewController + +-(void)showUserNamePrompt{ + + + self.alert = [[UIAlertView alloc] initWithTitle:@"Hello!" + message:@"Please enter your name:" + delegate:self + cancelButtonTitle:@"Continue" + otherButtonTitles:nil]; + self.alert.alertViewStyle = UIAlertViewStylePlainTextInput; + UITextField * alertTextField = [self.alert textFieldAtIndex:0]; + [alertTextField setDelegate:self]; + alertTextField.keyboardType = UIKeyboardTypeDefault; + alertTextField.placeholder = @"Username"; + [self.alert show]; + //[self.alert release]; + + +} +-(void)setAppRef:(id)theAppRef{ + self.theOFAppRef = theAppRef; +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ + + NSLog(@"Entered: %@",[[alertView textFieldAtIndex:0] text]); + NSString *userName = [[alertView textFieldAtIndex:0] text]; + if ([userName isEqualToString:@""]){ + [self showUserNamePrompt]; + return; + } + eventLogger.setUsername([userName cStringUsingEncoding:NSASCIIStringEncoding]); + + // call some start func + ((testApp *)self.theOFAppRef)->startTheTests(); + // rememebr to change return func too! + +} + +-(BOOL)textFieldShouldReturn:(UITextField *)textField{ + + NSLog(@"Entered: %@",[[self.alert textFieldAtIndex:0] text]); + NSString *userName = [[self.alert textFieldAtIndex:0] text]; + if ([userName isEqualToString:@""]){ + [self showUserNamePrompt]; + + }else{ + eventLogger.setUsername([userName cStringUsingEncoding:NSASCIIStringEncoding]); + ((testApp *)self.theOFAppRef)->startTheTests(); + + } + [self.alert dismissWithClickedButtonIndex:self.alert.firstOtherButtonIndex animated:YES]; + return YES; +} + +- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView +{ + UITextField *textField = [alertView textFieldAtIndex:0]; + if ([textField.text length] == 0) + { + return NO; + } + return YES; +} + + +@end + + +// global. again. + diff -r 000000000000 -r a223551fdc1f algorithms.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/algorithms.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,5 @@ +#pragma once + +#include "ofMain.h" +#include + diff -r 000000000000 -r a223551fdc1f eventLogger.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eventLogger.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,219 @@ +// +// eventLogger.h +// oscSenderExample +// +// Created by Robert Tubb on 05/11/2012. +// +// +// This class handle everything to do with loggin user actions, +// uploading logs to server, and storing locally if not uploaded + +#ifndef __oscSenderExample__eventLogger__ +#define __oscSenderExample__eventLogger__ + + +#include "ofMain.h" +#include "ofxiPhone.h" +#include "2dvector.h" +#include "ofxiPhoneExtras.h" +#include +#include +#include +#include +#include +#include "2dvector.h" +#include "json.h" +#import "ServerComms.h" +#include "boost/bind.hpp" +#include "boost/function.hpp" +#include "Poco/Mutex.h" + +#define EVENT_THIN_FACTOR 30 +#define EVENT_LOG_FILENAME "log.json" +#define UPLOAD_CHUNK_SIZE 1000 +#define APP_CREATION_TIME 0 // ignore this, pointless +#define PROGRAM_NAME "TWEAKATHLON" +#define PROGRAM_VERSION 0.2 + +#define SUPERVISED // this def will save files + + +// can add but don't change ordering - this will invalidate logs +enum leventType {APP_LOADED, // 0 + INTRO_CONSENTED, // 1 + APP_EXITED, // 2 + HELP_PRESSED, // 3 + QUESTIONNAIRE_COMPLETED, // 4 + + NEW_TEST, // 5 + // al the set up of the new test + TARGET_PARAM_SET, // 6 setting up the target sound, param id and value + CANDIDATE_PARAM_SET, // 7 setting up the cand sound starting pos, subset of param id and value + CANDIDATE_CHANGEABLE_IDX, // 8 list of changeable indexes + CANDIDATE_MAPPING_IDS, // 9 which kind of control was mapped to which param + CONTROL_LIST, // 10 list of control types + + TEST_TIMER_STARTED, // 11 we're off!! + + CANDIDATE_PARAM_ADJUSTED, // 12 interactions changing params + SUBMIT_PRESSED, // 13 this is the suer saying they've found it, along with the actual answer + DISTANCE_TIME_SCORE, // 14 list of the results, now we should go back to NEW_TEST + COUNTDOWN_INITIATED, // 15 just in case + ALL_TESTS_COMPLETED, // 16 ? + TARGET_PLAYED, // 17 however this happens it might be good to know when this happens + CANDIDATE_PLAYED, // 18 + START_THE_TESTS, // 19 probably superfluous + CRAP_TEST, // eliminate these coords somehow ??? + EMPTY_EVENT, + SPEED_CHANGED, // 22 ms between sounds + +}; + +//--------------------------------------------------------------------------- + +class lEvent{ +public: + // try and make this as compact as possible. + leventType eventType; + double val1; // x coord, scale if zoom + double val2; // y coord, 0 if zoom + int sliderID; // xtra int + long long eventTime; // MILLISECONDS since ref date + vector eventData; // variable length data int + + // old sonic zoom style event + lEvent(leventType eType, double v1 = 0.0, double v2 = 0.0,int sID = 0){ + eventType = eType; + val1 = v1; + val2 = v2; + sliderID = sID; + + double timemsd = [NSDate timeIntervalSinceReferenceDate]; // MILLISECONDS, but with fractional part ( + eventTime = (unsigned long long)(timemsd*1000) - APP_CREATION_TIME; + + } + + // new tweakathlon event + lEvent(leventType eType, vector theData){ + eventType = eType; + eventData = theData; + + double timemsd = [NSDate timeIntervalSinceReferenceDate]; // MILLISECONDS, but with fractional part ( + eventTime = (unsigned long long)(timemsd*1000) - APP_CREATION_TIME; + + } + + lEvent(const Json::Value &jevt){ + // constructor takes "jsonToEvent" readfile function role + eventType = (leventType)jevt["eType"].asInt(); + val1 = jevt["v1"].asDouble(); + val2 = jevt["v2"].asDouble(); + sliderID = jevt["sID"].asInt(); + eventTime = jevt["eTime"].asLargestInt(); + + // TODO what happens if we try to read one that isn't there? + + } + // new tweak event to json + Json::Value eventToJson(){ + Json::Value jevt; + jevt["eType"] = eventType; + // convert vector to json array + for(auto it = eventData.begin(); it < eventData.end(); it++){ + jevt["eData"].append(*it); + } + jevt["eTime"] = eventTime; + return jevt; + } + Json::Value eventToJsonOld(){ + Json::Value jevt; + jevt["eType"] = eventType; + // here: should give a certain number of sig figs? + jevt["v1"] = val1; + jevt["v2"] = val2; + jevt["sID"] = sliderID; + jevt["eTime"] = eventTime; + return jevt; + } +}; + + +//------------------------------------------ + +class EventLogger{ +public: + Poco::Mutex _mutex; + + int nextUploadNumber; + int nextUploadQty; + bool loggingEnabled; + + bool logUploadInProgress; + bool serverConnectionOK; + bool consentGiven; + bool questionnaireCompleted; + bool questionnaireUploaded; + + unsigned int deviceID; + unsigned int totalInteractionTime, savedInteractionTime, sessionTime, sessionStartTime; + string userName; // not unique + string questionnaireComments; +// constr + EventLogger(); + +// public methods: + void startLoadAll(); + void exitAndSave(); + void setUsername(const char *u); + string getUsername(){ + return userName; + } + void newUser(); + void logEvent(const leventType& evtType); + void logEvent(const leventType& evtType, const vector eventData); + + void questionnaireAnswersObtained(vector answers, const char* userComments); + void urlResponse(ofHttpResponse & response); + + void questionnaireOK(); + void eventlogOK(); + void testConnectionOK(); + void questionnaireNotOK(); + void eventlogNotOK(); + void testConnectionNotOK(); + + void printAll(); + void saveSessionToFile(); + +private: + void thinnedSliderEvent(lEvent newEvent); + vector theEvents; // all logged but not uploaded events + + vector questionnaireAnswers; + +// private methods + void testConnection(); + void checkLogFile(); + void deleteLogs(); // new user + bool uploadEventLog(bool async); + void firstEverAppOpen(); + void loadExistingLogFile(const string &jsonFile); + void uploadQuestionnaire(); + bool sendToServer(string functionName, Json::Value jsonData, bool async); + + Json::Value logsToJson(); + Json::Value questionnaireToJson(); + + + template bool matchID(T thing); + bool matchID2(); + // + ServerComms *serverComms; + +}; + + + //--------------------------------------------------------------------------- + + +#endif /* defined(__oscSenderExample__eventLogger__) */ diff -r 000000000000 -r a223551fdc1f eventLogger.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eventLogger.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,547 @@ +// +// eventLogger.mm +// oscSenderExample +// +// Created by Robert Tubb on 05/11/2012. +// +// + +//--------------------------------------------------------------------------- +#include "eventLogger.h" + +EventLogger eventLogger; + +//--------------------------------------------------------------------------- +EventLogger::EventLogger(){ + + consentGiven = true; // unless told otherwise firstAppOpen + loggingEnabled = true; + serverConnectionOK = false; + questionnaireCompleted = false; + questionnaireUploaded = false; + logUploadInProgress = false; + + nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events + serverComms = [[ServerComms alloc] init]; + +} +//--------------------------------------------------------------------------- +void EventLogger::startLoadAll(){ + + // TODO pilot doesn't check existing + //loadExistingLogFile(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME); + + + sessionStartTime = ofGetSystemTime(); + + // TODO pilot + // testConnection(); + + // if we have a back log of events upload them + if(theEvents.size() > nextUploadQty && ! logUploadInProgress){ + //try to upload + + // TODO pilot doesn't upload + //uploadEventLog(true); + } + + if(questionnaireCompleted && !questionnaireUploaded){ + uploadQuestionnaire(); + } + + //TODO if questionnaire wasn't reached but still opened then set the timer to something sensible + + //timer.setInteractionTime(savedInteractionTime); + //timer.setOrderFromPrevious(interfaceOrder); + + // for now sod it, start from scratch + if(!questionnaireCompleted){ + cout<<"Questionnaire NOT completed - first APP open called\n"; + firstEverAppOpen(); + } + +} +//--------------------------------------------------------------------------- +void EventLogger::testConnection(){ + Json::Value root; + root["x"] = "y"; + cout << "testConnection\n"; + sendToServer("testConnection", root, true); + +} +//--------------------------------------------------------------------------- +// this reads the persistent log file , checks if we've used the app before and +// if we've answered questionnaire or not + +// should just store stuff. the start up state should be handled by testAPp + +void EventLogger::loadExistingLogFile(const string &jsonFile){ + Json::Value root; + Json::Reader reader; + + ///////////// + // read file + + ifstream theFile(jsonFile.c_str()); + stringstream fileText; + string line; + if(!theFile){ + cout<<"No event log file found - first APP open called\n"; + firstEverAppOpen(); + return; + }else{ + while(theFile){ + theFile >> line; + // cout << line; // lots!!!! + fileText << line; + } + theFile.close(); + } + + cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n"; + + bool parsingSuccessful = reader.parse( fileText.str(), root ); + + if ( !parsingSuccessful ) + { + // report to the user the failure and their locations in the document. + std::cout << "Failed to parse event log JSON: \n" + << reader.getFormattedErrorMessages(); + return; + } + + ///////////////// + // now put user deets into variables + + userName = root["userName"].asString(); + deviceID = root["deviceID"].asLargestInt(); + nextUploadNumber = root["uploadNumber"].asInt(); + savedInteractionTime = root["savedInteractionTime"].asLargestInt(); + questionnaireCompleted = root["questionnaireCompleted"].asBool(); + questionnaireUploaded = root["questionnaireUploaded"].asBool(); + + // check for unuploaded evts + const Json::Value jlogs = root["events"]; + + for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index])); + + + ////////////// + + if(questionnaireCompleted && !questionnaireUploaded){ + // then read it in and upload it + Json::Value JQ = root["questionnaire"]; + Json::Value JArray = JQ["qAnswers"]; + if(JArray.size() < 2){ + cout << "Error - status of questionnaire is wierd\n"; + } + for ( unsigned int i = 0; i < JArray.size(); i++ ) + { + questionnaireAnswers.push_back(JArray[i].asInt()); + } + questionnaireComments = JQ["comments"].toStyledString(); + //uploadQuestionnaire(); + } + + // TODO interaction time seems to be balls + cout << "Total interaction time: " << savedInteractionTime << '\n'; + +} + +//--------------------------------------------------------------------------- + +void EventLogger::firstEverAppOpen(){ + + nextUploadNumber = 0; + deviceID = ofGetSystemTimeMicros(); + savedInteractionTime = 0; + questionnaireCompleted = false; + questionnaireUploaded = false; + +} + + +//--------------------------------------------------------------------------- +void EventLogger::questionnaireAnswersObtained(vector answers, const char* userComments){ + + questionnaireCompleted = true; + questionnaireAnswers = answers; + questionnaireComments = userComments; + uploadQuestionnaire(); + logEvent(QUESTIONNAIRE_COMPLETED); + +} +//--------------------------------------------------------------------------- +void EventLogger::uploadQuestionnaire(){ + // show indicator + cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n"; + cout << questionnaireToJson() << "\n"; + sendToServer("questionnaire", questionnaireToJson(), true); + +} +//--------------------------------------------------------------------------- +bool EventLogger::sendToServer(string functionName, Json::Value jsonData, bool async = false){ + + Json::FastWriter writer; + string jsontext = writer.write( jsonData ); + + // remove newline + if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') { + jsontext.erase(jsontext.length()-1); + } + ostringstream jd; + jd << jsontext; + NSString *theData = [NSString stringWithUTF8String:jd.str().c_str()]; + NSString *theType = [NSString stringWithUTF8String:functionName.c_str()]; + + if(async){ + [serverComms doPostRequest:theType withData:theData]; + }else{ + bool success = [serverComms doSyncPostRequest:theType withData:theData]; + return success; + } + +} +//----------------------------- +void EventLogger::questionnaireOK(){ + questionnaireUploaded = true; + questionnaireComments = ""; +} +//----------------------------- +void EventLogger::eventlogOK(){ + // COMMENT THIS IF UPLAODING FROM IPAD TO XCODE + + // it's a bad idea to do this in another thread... + theEvents.clear(); + cout << "EVENT LOG UPLOAD SUCCESS\n"; + nextUploadNumber++; + logUploadInProgress = false; +} +//----------------------------- +void EventLogger::testConnectionOK(){ + cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n"; + serverConnectionOK = true; +} +//----------------------------- +void EventLogger::questionnaireNotOK(){ + cout << "XXXXX questionnaire NOT OK XXXXXXX \n"; + questionnaireUploaded = false; +} +//----------------------------- +void EventLogger::eventlogNotOK(){ + // try later + cout << "XXXXX event log NOT OK XXXXXXX \n"; + nextUploadQty += UPLOAD_CHUNK_SIZE; + logUploadInProgress = false; +} +//----------------------------- +void EventLogger::testConnectionNotOK(){ + cout << "XXXXX server connection NOT OK XXXXXXX \n"; + serverConnectionOK = false; + // alert? + +} + + +//--------------------------------------------------------------------------- + +bool EventLogger::uploadEventLog(bool async){ + + // show indicator + logUploadInProgress = true; + cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n"; + if(!async){ + bool success = sendToServer("eventlog", logsToJson(), async); + if(!success){ + // try later + nextUploadQty += UPLOAD_CHUNK_SIZE; + // increment upload number? + }else{ + + // if success - clear memory + // IF UPLAODING FROM IPAD TO XCODE COMMENT OUT + theEvents.clear(); + cout << "UPLOAD SUCCESS\n"; + nextUploadNumber++; + } + logUploadInProgress = false; + return success; + }else{ + sendToServer("eventlog", logsToJson(), async); + } +} +//--------------------------------------------------------------------------- +// only called when doing supervised tests +void EventLogger::newUser(){ + // store old stuff + + saveSessionToFile(); + cout<<"setup new user\n"; + deleteLogs(); + nextUploadNumber = 0; + deviceID = ofGetSystemTimeMicros(); + savedInteractionTime = 0; + totalInteractionTime = 0; + sessionStartTime = ofGetSystemTime(); + questionnaireCompleted = false; + questionnaireUploaded = false; + + //((testApp *)ofGetAppPtr())->showIntro(); + +} +//--------------------------------------------------------------------------- +// called from alertView OK in iViewController +void EventLogger::setUsername(const char *u){ + userName = u; + +} +//--------------------------------------------------------------------------- +//new tweakathlon event logger with vector +void EventLogger::logEvent(const leventType& evtType, const vector eventData){ + Poco::Mutex::ScopedLock lock(_mutex); + if(!loggingEnabled) return; + + switch ( evtType ) { + +// case CANDIDATE_PARAM_ADJUSTED: +// // TODO thinning here. maybe. was a pain in the butt. +// thinnedSliderEvent(lEvent(evtType,eventData)); +// break; + default: + // default is just an event type with vector of ints. matlab will know what they are. + + + theEvents.push_back(lEvent(evtType, eventData)); + + break; + } + + if(theEvents.size() > nextUploadQty && !logUploadInProgress){ + //try to upload asynchronously + // TODO pilot doesn't upload + //uploadEventLog(true); + } + //TODO thiswrong? + totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds + +} +//--------------------------------------------------------------------------- +// OLD SONIC ZOOM EVT - still used for simple events with no data +void EventLogger::logEvent(const leventType& evtType){ + Poco::Mutex::ScopedLock lock(_mutex); + if(!loggingEnabled) return; + + switch ( evtType ) { + // data thinning here + case APP_LOADED: + theEvents.push_back(lEvent(evtType)); + default: + // default is just an event type with vector of ints. matlab will know what they are. + + + theEvents.push_back(lEvent(evtType)); + + } + + if(theEvents.size() > nextUploadQty && !logUploadInProgress){ + //try to upload asynchronously + // TODO pilot doesn't upload + //uploadEventLog(true); + } + //TODO thiswrong? + totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds + +} +// UnaryPredicate +template +bool EventLogger::matchID(T thing){ + return true; +} +bool EventLogger::matchID2(){ + return true; +} +//--------------------------------------------------------------------------- +void EventLogger::thinnedSliderEvent(lEvent newEvent){ + static vector unloggedEventsCache; // list of all different slider events + static int eventCounter = 0; + + // if first event then log it. + if(theEvents.size() == 0){ + theEvents.push_back(newEvent); + } + + // look for last event in the cache that had this mappingID + cout << unloggedEventsCache.size() << endl; + + vector::iterator lastMatching; + for(lastMatching = unloggedEventsCache.begin(); + lastMatching != unloggedEventsCache.end() && ( (*lastMatching).eventData[0] != newEvent.eventData[0]); + lastMatching++); + + + if (lastMatching != unloggedEventsCache.end()){ + //cout << "matching id logevent: " << (*lastMatching).eventData[0] << " " << newEvent.eventData[0] << endl; + // we have another, check gap + int gap = newEvent.eventTime - (*lastMatching).eventTime; + if(gap > 300){ + theEvents.push_back((*lastMatching)); + + // also log new slider evt + theEvents.push_back(newEvent); + eventCounter = 0; + + }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event + theEvents.push_back(newEvent); + eventCounter = 0; + // DELETE THAT PREVIOUS EVENT + unloggedEventsCache.erase(lastMatching); + + }else{ + // ignore for now but put in unlogged + unloggedEventsCache.push_back(newEvent); + } + + }else{ + // this event type wasnt in the cache + if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event + theEvents.push_back(newEvent); + eventCounter = 0; + }else{ + unloggedEventsCache.push_back(newEvent); + } + + } + // always count the new one + eventCounter++; + + + +} + +//-------------------------------------------------------------------- +// called from newUser +void EventLogger::deleteLogs(){ + // the + theEvents.clear(); + string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME; + ofFile logFile(fname,ofFile::WriteOnly); + logFile << ""; + logFile.close(); +} +//--------------------------------------------------------------------------- + +void EventLogger::exitAndSave(){ + + if(!consentGiven){ + Json::Value jlogs = logsToJson(); + // try to upload TODO (no - might hang and prevent exit???) + + // TODO pilot doesn't upload + // uploadEventLog(true); + return; + } + + savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); + // save user details + string fname = ofxiPhoneGetDocumentsDirectory() + userName + '_' + EVENT_LOG_FILENAME; + + // try to upload + // do it sync because event list needs to be cleared to prevent saving on device + + // TODO for pilot store to ipad + // uploadEventLog(false); + + // write to file + // json without the logs that were uploaded! + Json::Value jlogs = logsToJson(); + ofFile logFile(fname,ofFile::WriteOnly); + logFile << jlogs; + cout << jlogs; + logFile.close(); + +} +//--------------------------------------------------------------------------- + +Json::Value EventLogger::logsToJson(){ + // put all logged events into Json formatted string + Json::Value root; + + vector::iterator eventIter; + + root["programVersion"] = PROGRAM_VERSION; + root["userName"] = userName; + root["deviceID"] = deviceID; + root["uploadNumber"] = nextUploadNumber; + root["savedInteractionTime"] = savedInteractionTime; + root["questionnaireCompleted"] = questionnaireCompleted; + root["questionnaireUploaded"] = questionnaireUploaded; + + // this can mess up matlab script if it doesn't find this field + root["questionnaire"] = questionnaireToJson(); + + + int i = 0; + for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){ + root["events"][i] = (*eventIter).eventToJson(); + i++; + } + root["numEventsHere"] = i; + return root; +} + +//--------------------------------------------------------------------------- + +Json::Value EventLogger::questionnaireToJson(){ + // put all answers into Json formatted string + Json::Value root; + + vector::iterator aIter; + + Json::Value questionnaire; + + int i = 0; + for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){ + questionnaire[i] = (*aIter); + i++; + } + + root["qAnswers"] = questionnaire; + root["comments"] = questionnaireComments; + root["userName"] = userName; + root["deviceID"] = deviceID; + root["programVersion"] = PROGRAM_VERSION; + + return root; +} + +//--------------------------------------------------------------------------- +void EventLogger::printAll(){ + cout << "-----------------ALL LOGGED EVENTS----------------- \n"; + vector::iterator evIter; + cout << logsToJson() << "\n"; + cout << "---------------------QUESTIONNAIRE---------------- \n"; + cout << questionnaireToJson() << "\n"; +}; +//--------------------------------------------------------------------------- + +void EventLogger::saveSessionToFile(){ + stringstream fn; + fn << ofxiPhoneGetDocumentsDirectory() << userName << '_' << sessionStartTime << "_BACKUP.json"; + + string fname = fn.str(); //ofxiPhoneGetDocumentsDirectory() + userName + '_' + "TESTSAVE.json"; + + // write to file + // json without the logs that were uploaded! + Json::Value jlogs = logsToJson(); + ofFile logFile(fname,ofFile::WriteOnly); + logFile << jlogs; + logFile.close(); + +} +//---------------------------------------------------------------------------- + +// this builds up a file incrementally, which can be recovered on crash +//void EventLogger::appendToFile(){ +// +// +//} diff -r 000000000000 -r a223551fdc1f globalVariables.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/globalVariables.cpp Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,3 @@ +#include "globalVariables.h" + + diff -r 000000000000 -r a223551fdc1f globalVariables.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/globalVariables.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,39 @@ +// +// globalVariables.h +// emptyExample +// +// Created by Robert Tubb on 22/05/2013. +// +// + +#pragma once +#include "ofMain.h" + +// magic numbers for event ids +#define TRIGGER_TARGET_ID 99236082 +#define TRIGGER_CANDIDATE_ID 99233256 +#define RANDOMISE_TARGET_ID 99764448 +#define SUBMIT_CANDIDATE 99371538 +#define START_ALTERNATE_ID 99956352 +#define SHOW_HIDE_PANEL 99857329 +#define SHOW_HIDE_HINT 99724563 +#define NEW_TEST_ID 99163527 +#define CRAP_TEST_ID 99817364 +#define GOOD_TEST_ID 99090378 +#define RESTART_EXPERIMENT_ID 99658290 +#define SPEED_CHANGE_ID 99573012 +#define VOLUME_CHANGE_ID 99263748 +#define ALTERNATION_SPEED 180 // ms that target / candidate sounds play +// globles + +#define TOTAL_NUM_PARAMS 6 +#define TARGET_SCORE_CC_BAND 6 // number of cc vals per target band in dartboard +typedef enum {TOUCH_DOWN, TOUCH_MOVED, TOUCH_UP} touchType; +typedef enum {INTRO,QUESTIONNAIRE, HELP, TEST_IN_PROGRESS, SCORE_AND_HINT, COUNT_DOWN, READY_FOR_NEXT} interfaceType; + +typedef enum {SLIDER, XYPAD, BUTTON, LEAP3D} controllerType; +typedef enum {SEQUENTIAL, REVISITABLE, SIMULTANEOUS, MULTI_SIMPLE, MULTI_COMPLEX} controlPanelType; + +typedef enum {FILL,LINE, BLOB} SliderType; + +typedef enum {SMALLFONT, MEDIUMFONT, LARGEFONT} FontSize; \ No newline at end of file diff -r 000000000000 -r a223551fdc1f json/autolink.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/autolink.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,19 @@ +#ifndef JSON_AUTOLINK_H_INCLUDED +# define JSON_AUTOLINK_H_INCLUDED + +# include "config.h" + +# ifdef JSON_IN_CPPTL +# include +# endif + +# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) +# define CPPTL_AUTOLINK_NAME "json" +# undef CPPTL_AUTOLINK_DLL +# ifdef JSON_DLL +# define CPPTL_AUTOLINK_DLL +# endif +# include "autolink.h" +# endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/config.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,43 @@ +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +#endif // JSON_CONFIG_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/features.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/features.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,42 @@ +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +# define CPPTL_JSON_FEATURES_H_INCLUDED + +# include "forwards.h" + +namespace Json { + + /** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ + class JSON_API Features + { + public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; + }; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/json-forwards.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/json-forwards.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,249 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intented to be used with #include +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED +# define JSON_FORWARD_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGATED + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +# define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { + typedef int Int; + typedef unsigned int UInt; +# if defined(JSON_NO_INT64) + typedef int LargestInt; + typedef unsigned int LargestUInt; +# undef JSON_HAS_INT64 +# else // if defined(JSON_NO_INT64) + // For Microsoft Visual use specific types as long long is not supported +# if defined(_MSC_VER) // Microsoft Visual Studio + typedef __int64 Int64; + typedef unsigned __int64 UInt64; +# else // if defined(_MSC_VER) // Other platforms, use long long + typedef long long int Int64; + typedef unsigned long long int UInt64; +# endif // if defined(_MSC_VER) + typedef Int64 LargestInt; + typedef UInt64 LargestUInt; +# define JSON_HAS_INT64 +# endif // if defined(JSON_NO_INT64) +} // end namespace Json + + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + + // writer.h + class FastWriter; + class StyledWriter; + + // reader.h + class Reader; + + // features.h + class Features; + + // value.h + typedef unsigned int ArrayIndex; + class StaticString; + class Path; + class PathArgument; + class Value; + class ValueIteratorBase; + class ValueIterator; + class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + class ValueMapAllocator; + class ValueInternalLink; + class ValueInternalArray; + class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/json.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/json.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,1855 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intented to be used with #include + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGATED_H_INCLUDED +# define JSON_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332 +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + + +# ifdef JSON_IN_CPPTL +# include +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +# define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { + typedef int Int; + typedef unsigned int UInt; +# if defined(JSON_NO_INT64) + typedef int LargestInt; + typedef unsigned int LargestUInt; +# undef JSON_HAS_INT64 +# else // if defined(JSON_NO_INT64) + // For Microsoft Visual use specific types as long long is not supported +# if defined(_MSC_VER) // Microsoft Visual Studio + typedef __int64 Int64; + typedef unsigned __int64 UInt64; +# else // if defined(_MSC_VER) // Other platforms, use long long + typedef long long int Int64; + typedef unsigned long long int UInt64; +# endif // if defined(_MSC_VER) + typedef Int64 LargestInt; + typedef UInt64 LargestUInt; +# define JSON_HAS_INT64 +# endif // if defined(JSON_NO_INT64) +} // end namespace Json + + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + + // writer.h + class FastWriter; + class StyledWriter; + + // reader.h + class Reader; + + // features.h + class Features; + + // value.h + typedef unsigned int ArrayIndex; + class StaticString; + class Path; + class PathArgument; + class Value; + class ValueIteratorBase; + class ValueIterator; + class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + class ValueMapAllocator; + class ValueInternalLink; + class ValueInternalArray; + class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +# define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + + /** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ + class JSON_API Features + { + public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; + }; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include +# else +# include +# endif +# ifdef JSON_USE_CPPTL +# include +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + + /** \brief Type of the value held by a Value object. + */ + enum ValueType + { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). + }; + + enum CommentPlacement + { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement + }; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + + /** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + class JSON_API StaticString + { + public: + explicit StaticString( const char *czstring ) + : str_( czstring ) + { + } + + operator const char *() const + { + return str_; + } + + const char *c_str() const + { + return str_; + } + + private: + const char *str_; + }; + + /** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ + class JSON_API Value + { + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif + public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +# if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value null; + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; + + private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( ArrayIndex index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + ArrayIndex index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + ArrayIndex index_; + }; + + public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +# else + typedef CppTL::SmallMap ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); +#if defined(JSON_HAS_INT64) + Value( Int64 value ); + Value( UInt64 value ); +#endif // if defined(JSON_HAS_INT64) + Value( double value ); + Value( const char *value ); + Value( const char *beginValue, const char *endValue ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ) const; + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; + Int64 asInt64() const; + UInt64 asUInt64() const; + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( ArrayIndex size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( ArrayIndex index ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( int index ); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( ArrayIndex index ) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( int index ) const; + + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( ArrayIndex index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( ArrayIndex index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const + { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) + { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const + { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) + { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + + private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; + }; + + + /** \brief Experimental and untested: represents an element of the "path" to access a node. + */ + class PathArgument + { + public: + friend class Path; + + PathArgument(); + PathArgument( ArrayIndex index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + + private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + ArrayIndex index_; + Kind kind_; + }; + + /** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ + class Path + { + public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + + private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; + }; + + + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + /** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ + class JSON_API ValueMapAllocator + { + public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; + }; + + /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ + class JSON_API ValueInternalLink + { + public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; + }; + + + /** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ + class JSON_API ValueInternalMap + { + friend class ValueIteratorBase; + friend class Value; + public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) + { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + + private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + + private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; + }; + + /** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ + class JSON_API ValueInternalArray + { + friend class Value; + friend class ValueIteratorBase; + public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) + { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + + private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; + }; + + /** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destruct( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + \endcode + */ + class JSON_API ValueArrayAllocator + { + public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; + }; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + + /** \brief base class for Value iterators. + * + */ + class ValueIteratorBase + { + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const + { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const + { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const + { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + + protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + + private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif + }; + + /** \brief const iterator for object and array value. + * + */ + class ValueConstIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + + /** \brief Iterator for object and array value. + */ + class ValueIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "features.h" +# include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include +# include + +namespace Json { + + /** \brief Unserialize a JSON document into a Value. + * + */ + class JSON_API Reader + { + public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a JSON document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. + \ Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") + std::string getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormattedErrorMessages() const; + + private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; + }; + + /** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() + */ + std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +# include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include + +namespace Json { + + class Value; + + /** \brief Abstract class for writers. + */ + class JSON_API Writer + { + public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; + }; + + /** \brief Outputs a Value in JSON format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ + class JSON_API FastWriter : public Writer + { + public: + FastWriter(); + virtual ~FastWriter(){} + + void enableYAMLCompatibility(); + + public: // overridden from Writer + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledWriter: public Writer + { + public: + StyledWriter(); + virtual ~StyledWriter(){} + + public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledStreamWriter + { + public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter(){} + + public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; + }; + +# if defined(JSON_HAS_INT64) + std::string JSON_API valueToString( Int value ); + std::string JSON_API valueToString( UInt value ); +# endif // if defined(JSON_HAS_INT64) + std::string JSON_API valueToString( LargestInt value ); + std::string JSON_API valueToString( LargestUInt value ); + std::string JSON_API valueToString( double value ); + std::string JSON_API valueToString( bool value ); + std::string JSON_API valueToQuotedString( const char *value ); + + /// \brief Output using the StyledStreamWriter. + /// \see Json::operator>>() + std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/reader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/reader.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,196 @@ +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +# include "features.h" +# include "value.h" +# include +# include +# include +# include + +namespace Json { + + /** \brief Unserialize a JSON document into a Value. + * + */ + class JSON_API Reader + { + public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a JSON document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormatedErrorMessages() const; + + private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; + }; + + /** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() + */ + std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/value.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/value.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,1069 @@ +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +# include "forwards.h" +# include +# include + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include +# else +# include +# endif +# ifdef JSON_USE_CPPTL +# include +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + + /** \brief Type of the value held by a Value object. + */ + enum ValueType + { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). + }; + + enum CommentPlacement + { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement + }; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + + /** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + class JSON_API StaticString + { + public: + explicit StaticString( const char *czstring ) + : str_( czstring ) + { + } + + operator const char *() const + { + return str_; + } + + const char *c_str() const + { + return str_; + } + + private: + const char *str_; + }; + + /** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ + class JSON_API Value + { + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif + public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; + typedef UInt ArrayIndex; + + static const Value null; + static const Int minInt; + static const Int maxInt; + static const UInt maxUInt; + + private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( int index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + int index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + int index_; + }; + + public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +# else + typedef CppTL::SmallMap ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); + Value( double value ); + Value( const char *value ); + Value( const char *beginValue, const char *endValue ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ); + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + UInt size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( UInt size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( UInt index ); + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( UInt index ) const; + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( UInt index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( UInt index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const + { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) + { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const + { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) + { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + + private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + Int int_; + UInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; + }; + + + /** \brief Experimental and untested: represents an element of the "path" to access a node. + */ + class PathArgument + { + public: + friend class Path; + + PathArgument(); + PathArgument( UInt index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + + private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + UInt index_; + Kind kind_; + }; + + /** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ + class Path + { + public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + + private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; + }; + + /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. + * + * - makeMemberName() and releaseMemberName() are called to respectively duplicate and + * free an Json::objectValue member name. + * - duplicateStringValue() and releaseStringValue() are called similarly to + * duplicate and free a Json::stringValue value. + */ + class ValueAllocator + { + public: + enum { unknown = (unsigned)-1 }; + + virtual ~ValueAllocator(); + + virtual char *makeMemberName( const char *memberName ) = 0; + virtual void releaseMemberName( char *memberName ) = 0; + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) = 0; + virtual void releaseStringValue( char *value ) = 0; + }; + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + /** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ + class JSON_API ValueMapAllocator + { + public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; + }; + + /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ + class JSON_API ValueInternalLink + { + public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; + }; + + + /** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ + class JSON_API ValueInternalMap + { + friend class ValueIteratorBase; + friend class Value; + public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) + { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + + private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + + private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; + }; + + /** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ + class JSON_API ValueInternalArray + { + friend class Value; + friend class ValueIteratorBase; + public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) + { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + + private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; + }; + + /** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destruct( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + \endcode + */ + class JSON_API ValueArrayAllocator + { + public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; + }; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + + /** \brief base class for Value iterators. + * + */ + class ValueIteratorBase + { + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const + { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const + { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const + { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + + protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + + private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif + }; + + /** \brief const iterator for object and array value. + * + */ + class ValueConstIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + + /** \brief Iterator for object and array value. + */ + class ValueIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED diff -r 000000000000 -r a223551fdc1f json/writer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/json/writer.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,174 @@ +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +# include "value.h" +# include +# include +# include + +namespace Json { + + class Value; + + /** \brief Abstract class for writers. + */ + class JSON_API Writer + { + public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; + }; + + /** \brief Outputs a Value in JSON format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ + class JSON_API FastWriter : public Writer + { + public: + FastWriter(); + virtual ~FastWriter(){} + + void enableYAMLCompatibility(); + + public: // overridden from Writer + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledWriter: public Writer + { + public: + StyledWriter(); + virtual ~StyledWriter(){} + + public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; + }; + + /** \brief Writes a Value in JSON format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledStreamWriter + { + public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter(){} + + public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; + }; + + std::string JSON_API valueToString( Int value ); + std::string JSON_API valueToString( UInt value ); + std::string JSON_API valueToString( double value ); + std::string JSON_API valueToString( bool value ); + std::string JSON_API valueToQuotedString( const char *value ); + + /// \brief Output using the StyledStreamWriter. + /// \see Json::operator>>() + std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED diff -r 000000000000 -r a223551fdc1f jsoncpp.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jsoncpp.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,4230 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intented to be used with #include + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + +#define JSON_IS_AMALGAMATION + + +#include + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { + +/// Converts a unicode code-point to UTF-8. +static inline std::string +codePointToUTF8(unsigned int cp) +{ + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) + { + result.resize(1); + result[0] = static_cast(cp); + } + else if (cp <= 0x7FF) + { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) + { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); + } + else if (cp <= 0x10FFFF) + { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + + +/// Returns true if ch is a control character (in range [0,32[). +static inline bool +isControlCharacter(char ch) +{ + return ch > 0 && ch <= 0x1F; +} + + +enum { + /// Constant that specify the size of the buffer that must be passed to uintToString. + uintToStringBufferSize = 3*sizeof(LargestUInt)+1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + + +/** Converts an unsigned integer to string. + * @param value Unsigned interger to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void +uintToString( LargestUInt value, + char *¤t ) +{ + *--current = 0; + do + { + *--current = char(value % 10) + '0'; + value /= 10; + } + while ( value != 0 ); +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +# include +# include +# include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_( true ) + , strictRoot_( false ) +{ +} + + +Features +Features::all() +{ + return Features(); +} + + +Features +Features::strictMode() +{ + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4; +} + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; +} + + +static bool +containsNewLine( Reader::Location begin, + Reader::Location end ) +{ + for ( ;begin < end; ++begin ) + if ( *begin == '\n' || *begin == '\r' ) + return true; + return false; +} + + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : features_( Features::all() ) +{ +} + + +Reader::Reader( const Features &features ) + : features_( features ) +{ +} + + +bool +Reader::parse( const std::string &document, + Value &root, + bool collectComments ) +{ + document_ = document; + const char *begin = document_.c_str(); + const char *end = begin + document_.length(); + return parse( begin, end, root, collectComments ); +} + + +bool +Reader::parse( std::istream& sin, + Value &root, + bool collectComments ) +{ + //std::istream_iterator begin(sin); + //std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse( doc, root, collectComments ); +} + +bool +Reader::parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments ) +{ + if ( !features_.allowComments_ ) + { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while ( !nodes_.empty() ) + nodes_.pop(); + nodes_.push( &root ); + + bool successful = readValue(); + Token token; + skipCommentTokens( token ); + if ( collectComments_ && !commentsBefore_.empty() ) + root.setComment( commentsBefore_, commentAfter ); + if ( features_.strictRoot_ ) + { + if ( !root.isArray() && !root.isObject() ) + { + // Set error location to start of doc, ideally should be first token found in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( "A valid JSON document must be either an array or an object value.", + token ); + return false; + } + } + return successful; +} + + +bool +Reader::readValue() +{ + Token token; + skipCommentTokens( token ); + bool successful = true; + + if ( collectComments_ && !commentsBefore_.empty() ) + { + currentValue().setComment( commentsBefore_, commentBefore ); + commentsBefore_ = ""; + } + + + switch ( token.type_ ) + { + case tokenObjectBegin: + successful = readObject( token ); + break; + case tokenArrayBegin: + successful = readArray( token ); + break; + case tokenNumber: + successful = decodeNumber( token ); + break; + case tokenString: + successful = decodeString( token ); + break; + case tokenTrue: + currentValue() = true; + break; + case tokenFalse: + currentValue() = false; + break; + case tokenNull: + currentValue() = Value(); + break; + default: + return addError( "Syntax error: value, object or array expected.", token ); + } + + if ( collectComments_ ) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + + +void +Reader::skipCommentTokens( Token &token ) +{ + if ( features_.allowComments_ ) + { + do + { + readToken( token ); + } + while ( token.type_ == tokenComment ); + } + else + { + readToken( token ); + } +} + + +bool +Reader::expectToken( TokenType type, Token &token, const char *message ) +{ + readToken( token ); + if ( token.type_ != type ) + return addError( message, token ); + return true; +} + + +bool +Reader::readToken( Token &token ) +{ + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch ( c ) + { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match( "rue", 3 ); + break; + case 'f': + token.type_ = tokenFalse; + ok = match( "alse", 4 ); + break; + case 'n': + token.type_ = tokenNull; + ok = match( "ull", 3 ); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if ( !ok ) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + + +void +Reader::skipSpaces() +{ + while ( current_ != end_ ) + { + Char c = *current_; + if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) + ++current_; + else + break; + } +} + + +bool +Reader::match( Location pattern, + int patternLength ) +{ + if ( end_ - current_ < patternLength ) + return false; + int index = patternLength; + while ( index-- ) + if ( current_[index] != pattern[index] ) + return false; + current_ += patternLength; + return true; +} + + +bool +Reader::readComment() +{ + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if ( c == '*' ) + successful = readCStyleComment(); + else if ( c == '/' ) + successful = readCppStyleComment(); + if ( !successful ) + return false; + + if ( collectComments_ ) + { + CommentPlacement placement = commentBefore; + if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) + { + if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) + placement = commentAfterOnSameLine; + } + + addComment( commentBegin, current_, placement ); + } + return true; +} + + +void +Reader::addComment( Location begin, + Location end, + CommentPlacement placement ) +{ + assert( collectComments_ ); + if ( placement == commentAfterOnSameLine ) + { + assert( lastValue_ != 0 ); + lastValue_->setComment( std::string( begin, end ), placement ); + } + else + { + if ( !commentsBefore_.empty() ) + commentsBefore_ += "\n"; + commentsBefore_ += std::string( begin, end ); + } +} + + +bool +Reader::readCStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '*' && *current_ == '/' ) + break; + } + return getNextChar() == '/'; +} + + +bool +Reader::readCppStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '\r' || c == '\n' ) + break; + } + return true; +} + + +void +Reader::readNumber() +{ + while ( current_ != end_ ) + { + if ( !(*current_ >= '0' && *current_ <= '9') && + !in( *current_, '.', 'e', 'E', '+', '-' ) ) + break; + ++current_; + } +} + +bool +Reader::readString() +{ + Char c = 0; + while ( current_ != end_ ) + { + c = getNextChar(); + if ( c == '\\' ) + getNextChar(); + else if ( c == '"' ) + break; + } + return c == '"'; +} + + +bool +Reader::readObject( Token &/*tokenStart*/ ) +{ + Token tokenName; + std::string name; + currentValue() = Value( objectValue ); + while ( readToken( tokenName ) ) + { + bool initialTokenOk = true; + while ( tokenName.type_ == tokenComment && initialTokenOk ) + initialTokenOk = readToken( tokenName ); + if ( !initialTokenOk ) + break; + if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object + return true; + if ( tokenName.type_ != tokenString ) + break; + + name = ""; + if ( !decodeString( tokenName, name ) ) + return recoverFromError( tokenObjectEnd ); + + Token colon; + if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) + { + return addErrorAndRecover( "Missing ':' after object member name", + colon, + tokenObjectEnd ); + } + Value &value = currentValue()[ name ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenObjectEnd ); + + Token comma; + if ( !readToken( comma ) + || ( comma.type_ != tokenObjectEnd && + comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment ) ) + { + return addErrorAndRecover( "Missing ',' or '}' in object declaration", + comma, + tokenObjectEnd ); + } + bool finalizeTokenOk = true; + while ( comma.type_ == tokenComment && + finalizeTokenOk ) + finalizeTokenOk = readToken( comma ); + if ( comma.type_ == tokenObjectEnd ) + return true; + } + return addErrorAndRecover( "Missing '}' or object member name", + tokenName, + tokenObjectEnd ); +} + + +bool +Reader::readArray( Token &/*tokenStart*/ ) +{ + currentValue() = Value( arrayValue ); + skipSpaces(); + if ( *current_ == ']' ) // empty array + { + Token endArray; + readToken( endArray ); + return true; + } + int index = 0; + for (;;) + { + Value &value = currentValue()[ index++ ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenArrayEnd ); + + Token token; + // Accept Comment after last item in the array. + ok = readToken( token ); + while ( token.type_ == tokenComment && ok ) + { + ok = readToken( token ); + } + bool badTokenType = ( token.type_ != tokenArraySeparator && + token.type_ != tokenArrayEnd ); + if ( !ok || badTokenType ) + { + return addErrorAndRecover( "Missing ',' or ']' in array declaration", + token, + tokenArrayEnd ); + } + if ( token.type_ == tokenArrayEnd ) + break; + } + return true; +} + + +bool +Reader::decodeNumber( Token &token ) +{ + bool isDouble = false; + for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) + { + isDouble = isDouble + || in( *inspect, '.', 'e', 'E', '+' ) + || ( *inspect == '-' && inspect != token.start_ ); + } + if ( isDouble ) + return decodeDouble( token ); + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if ( isNegative ) + ++current; + Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 ); + assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 ); + Value::LargestUInt value = 0; + while ( current < token.end_ ) + { + Char c = *current++; + if ( c < '0' || c > '9' ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + Value::UInt digit(c - '0'); + if ( value >= threshold ) + { + // If the current digit is not the last one, or if it is + // greater than the last digit of the maximum integer value, + // the parse the number as a double. + if ( current != token.end_ || digit > lastDigitThreshold ) + { + return decodeDouble( token ); + } + } + value = value * 10 + digit; + } + if ( isNegative ) + currentValue() = -Value::LargestInt( value ); + else if ( value <= Value::LargestUInt(Value::maxInt) ) + currentValue() = Value::LargestInt( value ); + else + currentValue() = value; + return true; +} + + +bool +Reader::decodeDouble( Token &token ) +{ + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + if ( length <= bufferSize ) + { + Char buffer[bufferSize+1]; + memcpy( buffer, token.start_, length ); + buffer[length] = 0; + count = sscanf( buffer, "%lf", &value ); + } + else + { + std::string buffer( token.start_, token.end_ ); + count = sscanf( buffer.c_str(), "%lf", &value ); + } + + if ( count != 1 ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + currentValue() = value; + return true; +} + + +bool +Reader::decodeString( Token &token ) +{ + std::string decoded; + if ( !decodeString( token, decoded ) ) + return false; + currentValue() = decoded; + return true; +} + + +bool +Reader::decodeString( Token &token, std::string &decoded ) +{ + decoded.reserve( token.end_ - token.start_ - 2 ); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while ( current != end ) + { + Char c = *current++; + if ( c == '"' ) + break; + else if ( c == '\\' ) + { + if ( current == end ) + return addError( "Empty escape sequence in string", token, current ); + Char escape = *current++; + switch ( escape ) + { + case '"': decoded += '"'; break; + case '/': decoded += '/'; break; + case '\\': decoded += '\\'; break; + case 'b': decoded += '\b'; break; + case 'f': decoded += '\f'; break; + case 'n': decoded += '\n'; break; + case 'r': decoded += '\r'; break; + case 't': decoded += '\t'; break; + case 'u': + { + unsigned int unicode; + if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) + return false; + decoded += codePointToUTF8(unicode); + } + break; + default: + return addError( "Bad escape sequence in string", token, current ); + } + } + else + { + decoded += c; + } + } + return true; +} + +bool +Reader::decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + + if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) + { + // surrogate pairs + if (end - current < 6) + return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++)== 'u') + { + if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) + { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } + else + return false; + } + else + return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); + } + return true; +} + +bool +Reader::decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + if ( end - current < 4 ) + return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); + unicode = 0; + for ( int index =0; index < 4; ++index ) + { + Char c = *current++; + unicode *= 16; + if ( c >= '0' && c <= '9' ) + unicode += c - '0'; + else if ( c >= 'a' && c <= 'f' ) + unicode += c - 'a' + 10; + else if ( c >= 'A' && c <= 'F' ) + unicode += c - 'A' + 10; + else + return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); + } + return true; +} + + +bool +Reader::addError( const std::string &message, + Token &token, + Location extra ) +{ + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back( info ); + return false; +} + + +bool +Reader::recoverFromError( TokenType skipUntilToken ) +{ + int errorCount = int(errors_.size()); + Token skip; + for (;;) + { + if ( !readToken(skip) ) + errors_.resize( errorCount ); // discard errors caused by recovery + if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) + break; + } + errors_.resize( errorCount ); + return false; +} + + +bool +Reader::addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ) +{ + addError( message, token ); + return recoverFromError( skipUntilToken ); +} + + +Value & +Reader::currentValue() +{ + return *(nodes_.top()); +} + + +Reader::Char +Reader::getNextChar() +{ + if ( current_ == end_ ) + return 0; + return *current_++; +} + + +void +Reader::getLocationLineAndColumn( Location location, + int &line, + int &column ) const +{ + Location current = begin_; + Location lastLineStart = current; + line = 0; + while ( current < location && current != end_ ) + { + Char c = *current++; + if ( c == '\r' ) + { + if ( *current == '\n' ) + ++current; + lastLineStart = current; + ++line; + } + else if ( c == '\n' ) + { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + + +std::string +Reader::getLocationLineAndColumn( Location location ) const +{ + int line, column; + getLocationLineAndColumn( location, line, column ); + char buffer[18+16+16+1]; + sprintf( buffer, "Line %d, Column %d", line, column ); + return buffer; +} + + +// Deprecated. Preserved for backward compatibility +std::string +Reader::getFormatedErrorMessages() const +{ + return getFormattedErrorMessages(); +} + + +std::string +Reader::getFormattedErrorMessages() const +{ + std::string formattedMessage; + for ( Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError ) + { + const ErrorInfo &error = *itError; + formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if ( error.extra_ ) + formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; + } + return formattedMessage; +} + + +std::istream& operator>>( std::istream &sin, Value &root ) +{ + Json::Reader reader; + bool ok = reader.parse(sin, root, true); + //JSON_ASSERT( ok ); + if (!ok) throw std::runtime_error(reader.getFormattedErrorMessages()); + return sin; +} + + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_batchallocator.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED +# define JSONCPP_BATCHALLOCATOR_H_INCLUDED + +# include +# include + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +namespace Json { + +/* Fast memory allocator. + * + * This memory allocator allocates memory for a batch of object (specified by + * the page size, the number of object in each page). + * + * It does not allow the destruction of a single object. All the allocated objects + * can be destroyed at once. The memory can be either released or reused for future + * allocation. + * + * The in-place new operator must be used to construct the object using the pointer + * returned by allocate. + */ +template +class BatchAllocator +{ +public: + typedef AllocatedType Type; + + BatchAllocator( unsigned int objectsPerPage = 255 ) + : freeHead_( 0 ) + , objectsPerPage_( objectsPerPage ) + { +// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); + assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. + assert( objectsPerPage >= 16 ); + batches_ = allocateBatch( 0 ); // allocated a dummy page + currentBatch_ = batches_; + } + + ~BatchAllocator() + { + for ( BatchInfo *batch = batches_; batch; ) + { + BatchInfo *nextBatch = batch->next_; + free( batch ); + batch = nextBatch; + } + } + + /// allocate space for an array of objectPerAllocation object. + /// @warning it is the responsability of the caller to call objects constructors. + AllocatedType *allocate() + { + if ( freeHead_ ) // returns node from free list. + { + AllocatedType *object = freeHead_; + freeHead_ = *(AllocatedType **)object; + return object; + } + if ( currentBatch_->used_ == currentBatch_->end_ ) + { + currentBatch_ = currentBatch_->next_; + while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) + currentBatch_ = currentBatch_->next_; + + if ( !currentBatch_ ) // no free batch found, allocate a new one + { + currentBatch_ = allocateBatch( objectsPerPage_ ); + currentBatch_->next_ = batches_; // insert at the head of the list + batches_ = currentBatch_; + } + } + AllocatedType *allocated = currentBatch_->used_; + currentBatch_->used_ += objectPerAllocation; + return allocated; + } + + /// Release the object. + /// @warning it is the responsability of the caller to actually destruct the object. + void release( AllocatedType *object ) + { + assert( object != 0 ); + *(AllocatedType **)object = freeHead_; + freeHead_ = object; + } + +private: + struct BatchInfo + { + BatchInfo *next_; + AllocatedType *used_; + AllocatedType *end_; + AllocatedType buffer_[objectPerAllocation]; + }; + + // disabled copy constructor and assignement operator. + BatchAllocator( const BatchAllocator & ); + void operator =( const BatchAllocator &); + + static BatchInfo *allocateBatch( unsigned int objectsPerPage ) + { + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; + BatchInfo *batch = static_cast( malloc( mallocSize ) ); + batch->next_ = 0; + batch->used_ = batch->buffer_; + batch->end_ = batch->buffer_ + objectsPerPage; + return batch; + } + + BatchInfo *batches_; + BatchInfo *currentBatch_; + /// Head of a single linked list within the allocated space of freeed object + AllocatedType *freeHead_; + unsigned int objectsPerPage_; +}; + + +} // namespace Json + +# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION + +#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED + + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_batchallocator.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() +#ifndef JSON_VALUE_USE_INTERNAL_MAP + : current_() + , isNull_( true ) +{ +} +#else + : isArray_( true ) + , isNull_( true ) +{ + iterator_.array_ = ValueInternalArray::IteratorState(); +} +#endif + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) + : current_( current ) + , isNull_( false ) +{ +} +#else +ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) + : isArray_( true ) +{ + iterator_.array_ = state; +} + + +ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) + : isArray_( false ) +{ + iterator_.map_ = state; +} +#endif + +Value & +ValueIteratorBase::deref() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + return current_->second; +#else + if ( isArray_ ) + return ValueInternalArray::dereference( iterator_.array_ ); + return ValueInternalMap::value( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::increment() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ++current_; +#else + if ( isArray_ ) + ValueInternalArray::increment( iterator_.array_ ); + ValueInternalMap::increment( iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::decrement() +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + --current_; +#else + if ( isArray_ ) + ValueInternalArray::decrement( iterator_.array_ ); + ValueInternalMap::decrement( iterator_.map_ ); +#endif +} + + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP +# ifdef JSON_USE_CPPTL_SMALLMAP + return current_ - other.current_; +# else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if ( isNull_ && other.isNull_ ) + { + return 0; + } + + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) + { + ++myDistance; + } + return myDistance; +# endif +#else + if ( isArray_ ) + return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); + return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +bool +ValueIteratorBase::isEqual( const SelfType &other ) const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + if ( isNull_ ) + { + return other.isNull_; + } + return current_ == other.current_; +#else + if ( isArray_ ) + return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); + return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); +#endif +} + + +void +ValueIteratorBase::copy( const SelfType &other ) +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + current_ = other.current_; +#else + if ( isArray_ ) + iterator_.array_ = other.iterator_.array_; + iterator_.map_ = other.iterator_.map_; +#endif +} + + +Value +ValueIteratorBase::key() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( czstring.c_str() ) + { + if ( czstring.isStaticString() ) + return Value( StaticString( czstring.c_str() ) ); + return Value( czstring.c_str() ); + } + return Value( czstring.index() ); +#else + if ( isArray_ ) + return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); + bool isStatic; + const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); + if ( isStatic ) + return Value( StaticString( memberName ) ); + return Value( memberName ); +#endif +} + + +UInt +ValueIteratorBase::index() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const Value::CZString czstring = (*current_).first; + if ( !czstring.c_str() ) + return czstring.index(); + return Value::UInt( -1 ); +#else + if ( isArray_ ) + return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); + return Value::UInt( -1 ); +#endif +} + + +const char * +ValueIteratorBase::memberName() const +{ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + const char *name = (*current_).first.c_str(); + return name ? name : ""; +#else + if ( !isArray_ ) + return ValueInternalMap::key( iterator_.map_ ); + return ""; +#endif +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueConstIterator & +ValueConstIterator::operator =( const ValueIteratorBase &other ) +{ + copy( other ); + return *this; +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() +{ +} + + +#ifndef JSON_VALUE_USE_INTERNAL_MAP +ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) + : ValueIteratorBase( current ) +{ +} +#else +ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} + +ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) + : ValueIteratorBase( state ) +{ +} +#endif + +ValueIterator::ValueIterator( const ValueConstIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator::ValueIterator( const ValueIterator &other ) + : ValueIteratorBase( other ) +{ +} + +ValueIterator & +ValueIterator::operator =( const SelfType &other ) +{ + copy( other ); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +# include +# include +# ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +# include "json_batchallocator.h" +# endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +# include +#endif +#include // size_t + +#define JSON_ASSERT_UNREACHABLE assert( false ) +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw +#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message ); +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) JSON_FAIL_MESSAGE( message ) + +namespace Json { + +const Value Value::null; +const Int Value::minInt = Int( ~(UInt(-1)/2) ); +const Int Value::maxInt = Int( UInt(-1)/2 ); +const UInt Value::maxUInt = UInt(-1); +const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) ); +const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 ); +const UInt64 Value::maxUInt64 = UInt64(-1); +const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) ); +const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 ); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + + +/// Unknown size marker +static const unsigned int unknown = (unsigned)-1; + + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char * +duplicateStringValue( const char *value, + unsigned int length = unknown ) +{ + if ( length == unknown ) + length = (unsigned int)strlen(value); + char *newString = static_cast( malloc( length + 1 ) ); + JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" ); + memcpy( newString, value, length ); + newString[length] = 0; + return newString; +} + + +/** Free the string duplicated by duplicateStringValue(). + */ +static inline void +releaseStringValue( char *value ) +{ + if ( value ) + free( value ); +} + +} // namespace Json + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) +# ifdef JSON_VALUE_USE_INTERNAL_MAP +# include "json_internalarray.inl" +# include "json_internalmap.inl" +# endif // JSON_VALUE_USE_INTERNAL_MAP + +# include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + + +Value::CommentInfo::CommentInfo() + : comment_( 0 ) +{ +} + +Value::CommentInfo::~CommentInfo() +{ + if ( comment_ ) + releaseStringValue( comment_ ); +} + + +void +Value::CommentInfo::setComment( const char *text ) +{ + if ( comment_ ) + releaseStringValue( comment_ ); + JSON_ASSERT( text != 0 ); + JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue( text ); +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +# ifndef JSON_VALUE_USE_INTERNAL_MAP + +// Notes: index_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString( ArrayIndex index ) + : cstr_( 0 ) + , index_( index ) +{ +} + +Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) + : cstr_( allocate == duplicate ? duplicateStringValue(cstr) + : cstr ) + , index_( allocate ) +{ +} + +Value::CZString::CZString( const CZString &other ) +: cstr_( other.index_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue( other.cstr_ ) + : other.cstr_ ) + , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) + : other.index_ ) +{ +} + +Value::CZString::~CZString() +{ + if ( cstr_ && index_ == duplicate ) + releaseStringValue( const_cast( cstr_ ) ); +} + +void +Value::CZString::swap( CZString &other ) +{ + std::swap( cstr_, other.cstr_ ); + std::swap( index_, other.index_ ); +} + +Value::CZString & +Value::CZString::operator =( const CZString &other ) +{ + CZString temp( other ); + swap( temp ); + return *this; +} + +bool +Value::CZString::operator<( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) < 0; + return index_ < other.index_; +} + +bool +Value::CZString::operator==( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) == 0; + return index_ == other.index_; +} + + +ArrayIndex +Value::CZString::index() const +{ + return index_; +} + + +const char * +Value::CZString::c_str() const +{ + return cstr_; +} + +bool +Value::CZString::isStaticString() const +{ + return index_ == noDuplication; +} + +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value( ValueType type ) + : type_( type ) + , allocated_( 0 ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type ) + { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArray(); + break; + case objectValue: + value_.map_ = mapAllocator()->newMap(); + break; +#endif + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + + +#if defined(JSON_HAS_INT64) +Value::Value( UInt value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( Int value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + +#endif // if defined(JSON_HAS_INT64) + + +Value::Value( Int64 value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + + +Value::Value( UInt64 value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( double value ) + : type_( realValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.real_ = value; +} + +Value::Value( const char *value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( value ); +} + + +Value::Value( const char *beginValue, + const char *endValue ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( beginValue, + (unsigned int)(endValue - beginValue) ); +} + + +Value::Value( const std::string &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( value.c_str(), + (unsigned int)value.length() ); + +} + +Value::Value( const StaticString &value ) + : type_( stringValue ) + , allocated_( false ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = const_cast( value.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +Value::Value( const CppTL::ConstString &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = duplicateStringValue( value, value.length() ); +} +# endif + +Value::Value( bool value ) + : type_( booleanValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.bool_ = value; +} + + +Value::Value( const Value &other ) + : type_( other.type_ ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if ( other.value_.string_ ) + { + value_.string_ = duplicateStringValue( other.value_.string_ ); + allocated_ = true; + } + else + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues( *other.value_.map_ ); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); + break; + case objectValue: + value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + if ( other.comments_ ) + { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) + { + const CommentInfo &otherComment = other.comments_[comment]; + if ( otherComment.comment_ ) + comments_[comment].setComment( otherComment.comment_ ); + } + } +} + + +Value::~Value() +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if ( allocated_ ) + releaseStringValue( value_.string_ ); + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + delete value_.map_; + break; +#else + case arrayValue: + arrayAllocator()->destructArray( value_.array_ ); + break; + case objectValue: + mapAllocator()->destructMap( value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + + if ( comments_ ) + delete[] comments_; +} + +Value & +Value::operator=( const Value &other ) +{ + Value temp( other ); + swap( temp ); + return *this; +} + +void +Value::swap( Value &other ) +{ + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap( value_, other.value_ ); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2; +} + +ValueType +Value::type() const +{ + return type_; +} + + +int +Value::compare( const Value &other ) const +{ + if ( *this < other ) + return -1; + if ( *this > other ) + return 1; + return 0; +} + + +bool +Value::operator <( const Value &other ) const +{ + int typeDelta = type_ - other.type_; + if ( typeDelta ) + return typeDelta < 0 ? true : false; + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + return ( value_.string_ == 0 && other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) < 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + { + int delta = int( value_.map_->size() - other.value_.map_->size() ); + if ( delta ) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) < 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) < 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool +Value::operator <=( const Value &other ) const +{ + return !(other < *this); +} + +bool +Value::operator >=( const Value &other ) const +{ + return !(*this < other); +} + +bool +Value::operator >( const Value &other ) const +{ + return other < *this; +} + +bool +Value::operator ==( const Value &other ) const +{ + //if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if ( type_ != temp ) + return false; + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + return ( value_.string_ == other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) == 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() + && (*value_.map_) == (*other.value_.map_); +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) == 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) == 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool +Value::operator !=( const Value &other ) const +{ + return !( *this == other ); +} + +const char * +Value::asCString() const +{ + JSON_ASSERT( type_ == stringValue ); + return value_.string_; +} + + +std::string +Value::asString() const +{ + switch ( type_ ) + { + case nullValue: + return ""; + case stringValue: + return value_.string_ ? value_.string_ : ""; + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + case uintValue: + case realValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to string" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return ""; // unreachable +} + +# ifdef JSON_USE_CPPTL +CppTL::ConstString +Value::asConstString() const +{ + return CppTL::ConstString( asString().c_str() ); +} +# endif + + +Value::Int +Value::asInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" ); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" ); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to int" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +Value::UInt +Value::asUInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); + JSON_ASSERT_MESSAGE( value_.int_ <= maxUInt, "signed integer out of UInt range" ); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" ); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to uint" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +# if defined(JSON_HAS_INT64) + +Value::Int64 +Value::asInt64() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + return value_.int_; + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" ); + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to Int64" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +Value::UInt64 +Value::asUInt64() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" ); + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} +# endif // if defined(JSON_HAS_INT64) + + +LargestInt +Value::asLargestInt() const +{ +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + + +LargestUInt +Value::asLargestUInt() const +{ +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + + +double +Value::asDouble() const +{ + switch ( type_ ) + { + case nullValue: + return 0.0; + case intValue: + return static_cast( value_.int_ ); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( value_.uint_ ); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to double" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +float +Value::asFloat() const +{ + switch ( type_ ) + { + case nullValue: + return 0.0f; + case intValue: + return static_cast( value_.int_ ); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( value_.uint_ ); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + case stringValue: + case arrayValue: + case objectValue: + JSON_FAIL_MESSAGE( "Type is not convertible to float" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0.0f; // unreachable; +} + +bool +Value::asBool() const +{ + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + case uintValue: + return value_.int_ != 0; + case realValue: + return value_.real_ != 0.0; + case booleanValue: + return value_.bool_; + case stringValue: + return value_.string_ && value_.string_[0] != 0; + case arrayValue: + case objectValue: + return value_.map_->size() != 0; + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +bool +Value::isConvertibleTo( ValueType other ) const +{ + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return ( other == nullValue && value_.int_ == 0 ) + || other == intValue + || ( other == uintValue && value_.int_ >= 0 ) + || other == realValue + || other == stringValue + || other == booleanValue; + case uintValue: + return ( other == nullValue && value_.uint_ == 0 ) + || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case realValue: + return ( other == nullValue && value_.real_ == 0.0 ) + || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) + || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) + || other == realValue + || other == stringValue + || other == booleanValue; + case booleanValue: + return ( other == nullValue && value_.bool_ == false ) + || other == intValue + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case stringValue: + return other == stringValue + || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); + case arrayValue: + return other == arrayValue + || ( other == nullValue && value_.map_->size() == 0 ); + case objectValue: + return other == objectValue + || ( other == nullValue && value_.map_->size() == 0 ); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +/// Number of values in array or object +ArrayIndex +Value::size() const +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: // size of the array is highest index + 1 + if ( !value_.map_->empty() ) + { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index()+1; + } + return 0; + case objectValue: + return ArrayIndex( value_.map_->size() ); +#else + case arrayValue: + return Int( value_.array_->size() ); + case objectValue: + return Int( value_.map_->size() ); +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +bool +Value::empty() const +{ + if ( isNull() || isArray() || isObject() ) + return size() == 0u; + else + return false; +} + + +bool +Value::operator!() const +{ + return isNull(); +} + + +void +Value::clear() +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); + + switch ( type_ ) + { +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_->clear(); + break; +#else + case arrayValue: + value_.array_->clear(); + break; + case objectValue: + value_.map_->clear(); + break; +#endif + default: + break; + } +} + +void +Value::resize( ArrayIndex newSize ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ArrayIndex oldSize = size(); + if ( newSize == 0 ) + clear(); + else if ( newSize > oldSize ) + (*this)[ newSize - 1 ]; + else + { + for ( ArrayIndex index = newSize; index < oldSize; ++index ) + { + value_.map_->erase( index ); + } + assert( size() == newSize ); + } +#else + value_.array_->resize( newSize ); +#endif +} + + +Value & +Value::operator[]( ArrayIndex index ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::iterator it = value_.map_->lower_bound( key ); + if ( it != value_.map_->end() && (*it).first == key ) + return (*it).second; + + ObjectValues::value_type defaultValue( key, null ); + it = value_.map_->insert( it, defaultValue ); + return (*it).second; +#else + return value_.array_->resolveReference( index ); +#endif +} + + +Value & +Value::operator[]( int index ) +{ + JSON_ASSERT( index >= 0 ); + return (*this)[ ArrayIndex(index) ]; +} + + +const Value & +Value::operator[]( ArrayIndex index ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::const_iterator it = value_.map_->find( key ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + Value *value = value_.array_->find( index ); + return value ? *value : null; +#endif +} + + +const Value & +Value::operator[]( int index ) const +{ + JSON_ASSERT( index >= 0 ); + return (*this)[ ArrayIndex(index) ]; +} + + +Value & +Value::operator[]( const char *key ) +{ + return resolveReference( key, false ); +} + + +Value & +Value::resolveReference( const char *key, + bool isStatic ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + *this = Value( objectValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, isStatic ? CZString::noDuplication + : CZString::duplicateOnCopy ); + ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); + if ( it != value_.map_->end() && (*it).first == actualKey ) + return (*it).second; + + ObjectValues::value_type defaultValue( actualKey, null ); + it = value_.map_->insert( it, defaultValue ); + Value &value = (*it).second; + return value; +#else + return value_.map_->resolveReference( key, isStatic ); +#endif +} + + +Value +Value::get( ArrayIndex index, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[index]); + return value == &null ? defaultValue : *value; +} + + +bool +Value::isValidIndex( ArrayIndex index ) const +{ + return index < size(); +} + + + +const Value & +Value::operator[]( const char *key ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::const_iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + const Value *value = value_.map_->find( key ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const std::string &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const std::string &key ) const +{ + return (*this)[ key.c_str() ]; +} + +Value & +Value::operator[]( const StaticString &key ) +{ + return resolveReference( key, true ); +} + + +# ifdef JSON_USE_CPPTL +Value & +Value::operator[]( const CppTL::ConstString &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const CppTL::ConstString &key ) const +{ + return (*this)[ key.c_str() ]; +} +# endif + + +Value & +Value::append( const Value &value ) +{ + return (*this)[size()] = value; +} + + +Value +Value::get( const char *key, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[key]); + return value == &null ? defaultValue : *value; +} + + +Value +Value::get( const std::string &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} + +Value +Value::removeMember( const char* key ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + Value old(it->second); + value_.map_->erase(it); + return old; +#else + Value *value = value_.map_->find( key ); + if (value){ + Value old(*value); + value_.map_.remove( key ); + return old; + } else { + return null; + } +#endif +} + +Value +Value::removeMember( const std::string &key ) +{ + return removeMember( key.c_str() ); +} + +# ifdef JSON_USE_CPPTL +Value +Value::get( const CppTL::ConstString &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} +# endif + +bool +Value::isMember( const char *key ) const +{ + const Value *value = &((*this)[key]); + return value != &null; +} + + +bool +Value::isMember( const std::string &key ) const +{ + return isMember( key.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +bool +Value::isMember( const CppTL::ConstString &key ) const +{ + return isMember( key.c_str() ); +} +#endif + +Value::Members +Value::getMemberNames() const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return Value::Members(); + Members members; + members.reserve( value_.map_->size() ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for ( ; it != itEnd; ++it ) + members.push_back( std::string( (*it).first.c_str() ) ); +#else + ValueInternalMap::IteratorState it; + ValueInternalMap::IteratorState itEnd; + value_.map_->makeBeginIterator( it ); + value_.map_->makeEndIterator( itEnd ); + for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) + members.push_back( std::string( ValueInternalMap::key( it ) ) ); +#endif + return members; +} +// +//# ifdef JSON_USE_CPPTL +//EnumMemberNames +//Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +//EnumValues +//Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + + +bool +Value::isNull() const +{ + return type_ == nullValue; +} + + +bool +Value::isBool() const +{ + return type_ == booleanValue; +} + + +bool +Value::isInt() const +{ + return type_ == intValue; +} + + +bool +Value::isUInt() const +{ + return type_ == uintValue; +} + + +bool +Value::isIntegral() const +{ + return type_ == intValue + || type_ == uintValue + || type_ == booleanValue; +} + + +bool +Value::isDouble() const +{ + return type_ == realValue; +} + + +bool +Value::isNumeric() const +{ + return isIntegral() || isDouble(); +} + + +bool +Value::isString() const +{ + return type_ == stringValue; +} + + +bool +Value::isArray() const +{ + return type_ == nullValue || type_ == arrayValue; +} + + +bool +Value::isObject() const +{ + return type_ == nullValue || type_ == objectValue; +} + + +void +Value::setComment( const char *comment, + CommentPlacement placement ) +{ + if ( !comments_ ) + comments_ = new CommentInfo[numberOfCommentPlacement]; + comments_[placement].setComment( comment ); +} + + +void +Value::setComment( const std::string &comment, + CommentPlacement placement ) +{ + setComment( comment.c_str(), placement ); +} + + +bool +Value::hasComment( CommentPlacement placement ) const +{ + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string +Value::getComment( CommentPlacement placement ) const +{ + if ( hasComment(placement) ) + return comments_[placement].comment_; + return ""; +} + + +std::string +Value::toStyledString() const +{ + StyledWriter writer; + return writer.write( *this ); +} + + +Value::const_iterator +Value::begin() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + +Value::const_iterator +Value::end() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + + +Value::iterator +Value::begin() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return iterator(); +} + +Value::iterator +Value::end() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return iterator(); +} + + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() + : kind_( kindNone ) +{ +} + + +PathArgument::PathArgument( ArrayIndex index ) + : index_( index ) + , kind_( kindIndex ) +{ +} + + +PathArgument::PathArgument( const char *key ) + : key_( key ) + , kind_( kindKey ) +{ +} + + +PathArgument::PathArgument( const std::string &key ) + : key_( key.c_str() ) + , kind_( kindKey ) +{ +} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path( const std::string &path, + const PathArgument &a1, + const PathArgument &a2, + const PathArgument &a3, + const PathArgument &a4, + const PathArgument &a5 ) +{ + InArgs in; + in.push_back( &a1 ); + in.push_back( &a2 ); + in.push_back( &a3 ); + in.push_back( &a4 ); + in.push_back( &a5 ); + makePath( path, in ); +} + + +void +Path::makePath( const std::string &path, + const InArgs &in ) +{ + const char *current = path.c_str(); + const char *end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while ( current != end ) + { + if ( *current == '[' ) + { + ++current; + if ( *current == '%' ) + addPathInArg( path, in, itInArg, PathArgument::kindIndex ); + else + { + ArrayIndex index = 0; + for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back( index ); + } + if ( current == end || *current++ != ']' ) + invalidPath( path, int(current - path.c_str()) ); + } + else if ( *current == '%' ) + { + addPathInArg( path, in, itInArg, PathArgument::kindKey ); + ++current; + } + else if ( *current == '.' ) + { + ++current; + } + else + { + const char *beginName = current; + while ( current != end && !strchr( "[.", *current ) ) + ++current; + args_.push_back( std::string( beginName, current ) ); + } + } +} + + +void +Path::addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ) +{ + if ( itInArg == in.end() ) + { + // Error: missing argument %d + } + else if ( (*itInArg)->kind_ != kind ) + { + // Error: bad argument type + } + else + { + args_.push_back( **itInArg ); + } +} + + +void +Path::invalidPath( const std::string &path, + int location ) +{ + // Error: invalid path. +} + + +const Value & +Path::resolve( const Value &root ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + { + // Error: unable to resolve path (object has no member named '' at position...) + } + } + } + return *node; +} + + +Value +Path::resolve( const Value &root, + const Value &defaultValue ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + return defaultValue; + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + return defaultValue; + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + return defaultValue; + } + } + return *node; +} + + +Value & +Path::make( Value &root ) const +{ + Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() ) + { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +# include +# include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +static bool containsControlCharacter( const char* str ) +{ + while ( *str ) + { + if ( isControlCharacter( *(str++) ) ) + return true; + } + return false; +} + + +std::string valueToString( LargestInt value ) +{ + UIntToStringBuffer buffer; + char *current = buffer + sizeof(buffer); + bool isNegative = value < 0; + if ( isNegative ) + value = -value; + uintToString( LargestUInt(value), current ); + if ( isNegative ) + *--current = '-'; + assert( current >= buffer ); + return current; +} + + +std::string valueToString( LargestUInt value ) +{ + UIntToStringBuffer buffer; + char *current = buffer + sizeof(buffer); + uintToString( value, current ); + assert( current >= buffer ); + return current; +} + +#if defined(JSON_HAS_INT64) + +std::string valueToString( Int value ) +{ + return valueToString( LargestInt(value) ); +} + + +std::string valueToString( UInt value ) +{ + return valueToString( LargestUInt(value) ); +} + +#endif // # if defined(JSON_HAS_INT64) + + +std::string valueToString( double value ) +{ + char buffer[32]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. + sprintf_s(buffer, sizeof(buffer), "%#.16g", value); +#else + sprintf(buffer, "%#.16g", value); +#endif + char* ch = buffer + strlen(buffer) - 1; + if (*ch != '0') return buffer; // nothing to truncate, so save time + while(ch > buffer && *ch == '0'){ + --ch; + } + char* last_nonzero = ch; + while(ch >= buffer){ + switch(*ch){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --ch; + continue; + case '.': + // Truncate zeroes to save bytes in output, but keep one. + *(last_nonzero+2) = '\0'; + return buffer; + default: + return buffer; + } + } + return buffer; +} + + +std::string valueToString( bool value ) +{ + return value ? "true" : "false"; +} + +std::string valueToQuotedString( const char *value ) +{ + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c=value; *c != 0; ++c) + { + switch(*c) + { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + //case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } + else + { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() +{ +} + + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_( false ) +{ +} + + +void +FastWriter::enableYAMLCompatibility() +{ + yamlCompatiblityEnabled_ = true; +} + + +std::string +FastWriter::write( const Value &root ) +{ + document_ = ""; + writeValue( root ); + document_ += "\n"; + return document_; +} + + +void +FastWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString( value.asLargestInt() ); + break; + case uintValue: + document_ += valueToString( value.asLargestUInt() ); + break; + case realValue: + document_ += valueToString( value.asDouble() ); + break; + case stringValue: + document_ += valueToQuotedString( value.asCString() ); + break; + case booleanValue: + document_ += valueToString( value.asBool() ); + break; + case arrayValue: + { + document_ += "["; + int size = value.size(); + for ( int index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ","; + writeValue( value[index] ); + } + document_ += "]"; + } + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + document_ += "{"; + for ( Value::Members::iterator it = members.begin(); + it != members.end(); + ++it ) + { + const std::string &name = *it; + if ( it != members.begin() ) + document_ += ","; + document_ += valueToQuotedString( name.c_str() ); + document_ += yamlCompatiblityEnabled_ ? ": " + : ":"; + writeValue( value[name] ); + } + document_ += "}"; + } + break; + } +} + + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_( 74 ) + , indentSize_( 3 ) +{ +} + + +std::string +StyledWriter::write( const Value &root ) +{ + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + document_ += "\n"; + return document_; +} + + +void +StyledWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asLargestInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asLargestUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + document_ += " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + for (;;) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + document_ += "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + + +bool +StyledWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + document_ += value; +} + + +void +StyledWriter::writeIndent() +{ + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + + +void +StyledWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + document_ += value; +} + + +void +StyledWriter::indent() +{ + indentString_ += std::string( indentSize_, ' ' ); +} + + +void +StyledWriter::unindent() +{ + assert( int(indentString_.size()) >= indentSize_ ); + indentString_.resize( indentString_.size() - indentSize_ ); +} + + +void +StyledWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + document_ += normalizeEOL( root.getComment( commentBefore ) ); + document_ += "\n"; +} + + +void +StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + document_ += "\n"; + document_ += normalizeEOL( root.getComment( commentAfter ) ); + document_ += "\n"; + } +} + + +bool +StyledWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter( std::string indentation ) + : document_(NULL) + , rightMargin_( 74 ) + , indentation_( indentation ) +{ +} + + +void +StyledStreamWriter::write( std::ostream &out, const Value &root ) +{ + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + + +void +StyledStreamWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asLargestInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asLargestUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + *document_ << " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledStreamWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + for (;;) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + *document_ << "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + + +bool +StyledStreamWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledStreamWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + *document_ << value; +} + + +void +StyledStreamWriter::writeIndent() +{ + /* + Some comments in this method would have been nice. ;-) + + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + *document_ << '\n'; + } + */ + *document_ << '\n' << indentString_; +} + + +void +StyledStreamWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + *document_ << value; +} + + +void +StyledStreamWriter::indent() +{ + indentString_ += indentation_; +} + + +void +StyledStreamWriter::unindent() +{ + assert( indentString_.size() >= indentation_.size() ); + indentString_.resize( indentString_.size() - indentation_.size() ); +} + + +void +StyledStreamWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + *document_ << normalizeEOL( root.getComment( commentBefore ) ); + *document_ << "\n"; +} + + +void +StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + *document_ << "\n"; + *document_ << normalizeEOL( root.getComment( commentAfter ) ); + *document_ << "\n"; + } +} + + +bool +StyledStreamWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledStreamWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +std::ostream& operator<<( std::ostream &sout, const Value &root ) +{ + Json::StyledStreamWriter writer; + writer.write(sout, root); + return sout; +} + + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff -r 000000000000 -r a223551fdc1f main.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,19 @@ +#include "ofMain.h" + +#include "ofAppiOSWindow.h" +#include "testApp.h" + +int main(){ + ofAppiOSWindow * window = new ofAppiOSWindow(); + window->enableHardwareOrientation(); + window->enableOrientationAnimation(); + window->enableAntiAliasing(4); + window->enableRetina(); + + ofSeedRandom(); + + ofSetupOpenGL(window, 768, 1024,OF_FULLSCREEN); + ofRunApp(new testApp); +} + + diff -r 000000000000 -r a223551fdc1f pd patch/targetSynth7.pd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pd patch/targetSynth7.pd Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,2006 @@ +#N canvas 406 189 1013 774 10; +#X obj 109 189 dac~; +#X obj 100 162 +~; +#X obj 133 163 +~; +#X text 180 159 to do swap between with short fade to prevent reverb +mixing up; +#X text 278 110 to do: remove sine osc or make it FM and do something +clever; +#X obj 136 -68 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 313 -71 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 206 -267 r fromOF; +#X obj 200 -237 route list; +#X obj 153 -128 route candidateSynth; +#X obj 286 -128 route targetSynth; +#N canvas 0 22 450 300 alternator 0; +#X obj 126 64 inlet; +#X obj 65 234 outlet; +#X obj 245 232 outlet; +#X text 39 23 sends bangs to alternate outlets at certain interval +; +#X obj 126 119 metro 1000; +#X obj 181 64 inlet; +#X text 121 46 on off; +#X obj 181 91 * 2; +#X obj 244 188 delay 500; +#X connect 0 0 4 0; +#X connect 4 0 1 0; +#X connect 4 0 8 0; +#X connect 5 0 7 0; +#X connect 5 0 8 1; +#X connect 7 0 4 1; +#X connect 8 0 2 0; +#X restore 449 -111 pd alternator; +#X obj 448 -148 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 +1 1; +#X obj 523 -157 loadbang; +#X obj 523 -133 int 500; +#X obj 446 -182 route startAlternator; +#X obj 467 -232 loadbang; +#X obj 288 -99 route playSound; +#X obj 141 -93 route playSound; +#X obj 468 -207 int 0; +#N canvas 830 119 910 816 candidateSynth 0; +#X obj 83 467 outlet~; +#X obj 143 466 outlet~; +#X obj 659 -257 inlet; +#X obj 181 -294 inlet; +#X obj 96 296 *~; +#X obj 73 375 clip~ -1 1; +#X obj 664 -65 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 80 56 / 127; +#X obj 119 57 / 127; +#X text 81 -112 attack; +#X text 124 -112 decay; +#X text -53 -112 pitch; +#X text -7 -114 duration; +#X obj 258 49 / 127; +#X text 299 -115 ftype; +#X text 342 -115 ffreq; +#X text 464 -117 reson; +#X text 562 -111 reverb; +#X obj 92 335 *~ 0.1; +#X text 35 -102 wavef; +#X text 655 -95 trigger; +#X obj -38 -168 route pitch; +#X obj 44 -169 route waveform; +#X obj 138 -169 route attack; +#X obj 221 -171 route decay; +#X obj 301 -170 route fType; +#X obj 378 -167 route fFreq; +#X obj 459 -169 route reson; +#X obj 547 -172 route reverb; +#N canvas 42 77 1074 773 filterT 0; +#X obj 44 22 inlet~; +#X obj 165 84 route filtFreq; +#X obj 855 112 route reson; +#X obj 99 639 outlet~; +#X obj 169 306 mtof~; +#X obj 167 43 route list; +#X obj 165 11 r fromOF; +#X obj 316 19 inlet~; +#X text 362 19 envelope; +#X obj 171 189 sig~; +#X obj 174 250 +~; +#X obj 662 265 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 565 230 filetr freq; +#X text 645 226 resonance; +#X floatatom 822 416 5 0 0 0 - - -; +#X msg 363 391 \$1 100; +#X obj 363 415 line~; +#X obj 407 303 hsl 128 15 0 1 0 1 empty empty empty -2 -8 0 10 -262144 +-1 -1 5600 1; +#X text 284 273 Mode: 0 = lowpass \, 0.5 = resonant bandpass \, 1 = +highpass; +#X floatatom 403 356 5 0 0 0 - - -; +#X obj 820 472 + 100; +#X obj 820 496 dbtorms; +#X floatatom 820 525 5 0 0 0 - - -; +#X obj 820 443 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -8 0 10 +-262144 -1 -1 3 256; +#X obj 364 149 route fType; +#X obj 820 356 / 5; +#X obj 98 558 multimode_libpd.mmb~; +#X obj 99 598 biquad_libpd.mmb~; +#X floatatom 659 420 5 0 0 0 - - -; +#X obj 167 280 clip~ 20 128; +#X obj 169 220 lop~ 50; +#X obj 169 122 * 0.6; +#X obj 172 158 + 30; +#X obj 238 221 *~ 110; +#X obj 882 28 r fromOF; +#X obj 815 553 lop~ 50; +#X obj 881 57 route list; +#X obj 891 81 route smoothing; +#X text 38 2 audio in; +#X text 478 17 ftype; +#X text 590 17 ffreq; +#X obj 544 17 inlet; +#X obj 432 17 inlet; +#X obj 646 17 inlet; +#X text 692 17 reson; +#X floatatom 195 386 5 0 0 0 - - -; +#X obj 820 389 + 3; +#X connect 0 0 27 0; +#X connect 1 0 31 0; +#X connect 2 0 25 0; +#X connect 4 0 26 0; +#X connect 5 0 1 0; +#X connect 5 0 2 0; +#X connect 5 0 24 0; +#X connect 6 0 5 0; +#X connect 7 0 33 0; +#X connect 9 0 30 0; +#X connect 10 0 29 0; +#X connect 11 0 25 0; +#X connect 11 0 28 0; +#X connect 14 0 23 0; +#X connect 15 0 16 0; +#X connect 16 0 26 2; +#X connect 17 0 19 0; +#X connect 17 0 15 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 35 0; +#X connect 23 0 20 0; +#X connect 24 0 15 0; +#X connect 25 0 46 0; +#X connect 26 0 27 1; +#X connect 26 1 27 2; +#X connect 26 2 27 3; +#X connect 26 3 27 4; +#X connect 26 4 27 5; +#X connect 27 0 3 0; +#X connect 29 0 4 0; +#X connect 30 0 10 0; +#X connect 31 0 32 0; +#X connect 32 0 9 0; +#X connect 33 0 10 1; +#X connect 34 0 36 0; +#X connect 35 0 26 1; +#X connect 36 0 37 0; +#X connect 37 0 35 1; +#X connect 37 0 30 1; +#X connect 41 0 31 0; +#X connect 42 0 15 0; +#X connect 43 0 25 0; +#X connect 46 0 14 0; +#X restore 77 250 pd filterT; +#X obj 92 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 120 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 1400 1; +#X obj 268 -93 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 346 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 7600 1; +#X obj 457 -94 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 565 -75 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#N canvas 76 137 871 723 oscillatorC 0; +#X obj 83 269 phasor~; +#X obj 430 -51 inlet; +#X text 73 522 audio out; +#X obj 79 501 outlet~; +#X obj 402 171 mtof; +#X text 292 -112 "pWidth" \, "sqVol" \, "sawVol" \, "sineVol" \, "FMAmt" +; +#X obj 321 233 +~; +#X obj 402 193 sig~; +#X floatatom 564 131 5 0 0 0 - - -; +#X text 627 93 fm rfeq; +#X obj 353 113 loadbang; +#X obj 262 398 osc~ 220; +#X text 29 390 subtract out of phase one; +#X obj 84 377 -~; +#X obj 151 327 wrap~; +#X obj 150 302 +~ 0.5; +#X obj 83 437 -~ 0.5; +#X obj 568 186 *~ 0; +#X obj 562 156 osc~; +#X obj 561 105 mtof; +#X obj 731 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 723 64 / 127; +#X obj 548 29 * 100; +#X obj 765 -85 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 764 62 / 127; +#X obj 152 354 *~ 0; +#X obj 263 429 *~ 1; +#X obj 616 129 * 3500; +#X obj 559 81 +; +#X obj 560 54 - 40; +#X text 408 -73 pitch freq; +#X obj 552 1 route FMFreq FMAmt; +#X obj 564 218 lop~ 20; +#X obj 680 172 r fromOF; +#X obj 679 201 route list; +#X obj 677 226 route smoothing; +#X obj 84 346 *~ 1; +#X obj 66 124 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#X obj 16 122 inlet; +#X text 52 93 waveform; +#X floatatom 42 198 5 0 0 0 - - -; +#X floatatom 93 201 5 0 0 0 - - -; +#X floatatom 141 205 5 0 0 0 - - -; +#X floatatom 190 203 5 0 0 0 - - -; +#X obj 29 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 101 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 170 -14 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 31 19 float 10; +#X obj 103 19 float 64; +#X obj 173 21 float 120; +#X text 192 219 sineVol; +#X text 30 218 saw vol; +#X text 92 221 sq vol; +#N canvas 71 22 1849 1017 interpolatorWave 0; +#X obj 80 -91 inlet; +#X text 75 -113 slider control; +#X obj 217 74 < 32; +#X obj 202 100 &&; +#X floatatom 211 122 5 0 0 0 - - -; +#X obj 186 74 >= 0; +#X obj 279 99 &&; +#X obj 359 98 &&; +#X obj 444 97 &&; +#X obj 263 73 >= 32; +#X obj 300 73 < 64; +#X obj 339 73 >= 64; +#X obj 380 72 < 96; +#X obj 428 71 >= 96; +#X obj 465 71 < 128; +#X floatatom 273 121 5 0 0 0 - - -; +#X floatatom 354 119 5 0 0 0 - - -; +#X floatatom 438 118 5 0 0 0 - - -; +#X obj 273 148 * 2; +#X obj 355 147 * 3; +#X obj 436 147 * 4; +#X obj 246 205 +; +#X obj 398 200 +; +#X obj 315 246 +; +#X floatatom 105 352 5 0 0 0 - - -; +#X floatatom 181 356 5 0 0 0 - - -; +#X floatatom 246 356 5 0 0 0 - - -; +#X floatatom 316 352 5 0 0 0 - - -; +#X obj -125 824 outlet; +#X obj 116 408 / 32; +#X obj 181 408 / 32; +#X obj 243 410 / 32; +#X obj 316 408 / 32; +#X obj 177 381 - 32; +#X obj 245 382 - 64; +#X obj 317 378 - 96; +#X text 544 477 calc frac; +#X obj 35 498 -; +#X obj 35 479 float 1; +#X obj 159 626 loadbang; +#X obj -134 764 + 0; +#X floatatom 85 526 5 0 0 0 - - -; +#X floatatom 36 527 5 0 0 0 - - -; +#X obj -150 736 * 0.1; +#X obj -113 736 * 0.15; +#X obj -42 760 + 0; +#X obj -58 732 * 0.1; +#X obj -21 732 * 0.15; +#X obj 45 761 + 0; +#X obj 138 762 + 0; +#X obj 153 506 -; +#X obj 153 487 float 1; +#X floatatom 200 526 5 0 0 0 - - -; +#X floatatom 154 528 5 0 0 0 - - -; +#X obj 286 502 -; +#X obj 286 483 float 1; +#X floatatom 335 526 5 0 0 0 - - -; +#X floatatom 287 524 5 0 0 0 - - -; +#X text 6 678 insert values at points here; +#X obj 416 505 -; +#X obj 416 486 float 1; +#X floatatom 467 526 5 0 0 0 - - -; +#X floatatom 417 527 5 0 0 0 - - -; +#X obj 29 733 * 30; +#X obj 66 733 * 60; +#X obj 119 733 * 60; +#X obj 159 734 * 90; +#X obj -543 849 outlet; +#X obj -557 676 loadbang; +#X obj -552 789 + 0; +#X obj -568 761 * 0.1; +#X obj -531 761 * 0.15; +#X obj -460 785 + 0; +#X obj -476 757 * 0.1; +#X obj -439 757 * 0.15; +#X obj -373 786 + 0; +#X obj -280 787 + 0; +#X text -630 702 insert values at points here; +#X obj -389 758 * 30; +#X obj -352 758 * 60; +#X obj -299 758 * 60; +#X obj -259 759 * 90; +#X text -541 827 comment; +#X obj -543 728 float 0; +#X obj -262 725 float 1; +#X text -595 848 saw vol; +#X text -207 825 pulse volume; +#X obj -470 726 float 0; +#X obj -402 728 float 1; +#X obj -330 726 float 1; +#X obj -125 703 float 0; +#X obj -52 701 float 0; +#X obj 16 703 float 0; +#X obj 88 701 float 1; +#X obj 157 701 float 1; +#X obj 264 818 outlet; +#X obj 548 620 loadbang; +#X obj 255 758 + 0; +#X obj 239 730 * 0.1; +#X obj 276 730 * 0.15; +#X obj 347 754 + 0; +#X obj 331 726 * 0.1; +#X obj 368 726 * 0.15; +#X obj 434 755 + 0; +#X obj 527 756 + 0; +#X text 373 667 insert values at points here; +#X obj 418 727 * 30; +#X obj 455 727 * 60; +#X obj 508 727 * 60; +#X obj 548 728 * 90; +#X text 182 819 pulse width; +#X obj 677 819 outlet; +#X obj 961 621 loadbang; +#X obj 668 759 + 0; +#X obj 652 731 * 0.1; +#X obj 689 731 * 0.15; +#X obj 760 755 + 0; +#X obj 744 727 * 0.1; +#X obj 781 727 * 0.15; +#X obj 847 756 + 0; +#X obj 940 757 + 0; +#X text 682 664 insert values at points here; +#X obj 831 728 * 30; +#X obj 868 728 * 60; +#X obj 921 728 * 60; +#X obj 961 729 * 90; +#X obj 397 174 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 315 224 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 246 175 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 255 28 t f f f f f f f f; +#X obj 117 -57 t f f; +#X obj 415 462 t b f f; +#X obj 283 458 t b f f; +#X obj 155 463 t b f f; +#X obj 36 452 t b f f; +#X text 266 796 comment; +#X text -124 801 comment; +#X obj 959 696 float 0; +#X text 595 820 sine volume; +#X obj 677 698 float 1; +#X obj 750 696 float 1; +#X obj 818 698 float 0; +#X obj 891 696 float 0; +#X obj 477 695 float 0.5; +#X obj 405 697 float 0.5; +#X obj 337 695 float 0.5; +#X obj 264 697 float 0.5; +#X obj 166 308 route 1 2 3 4; +#X obj 164 281 pack; +#X obj 546 695 float 0.01; +#X obj 1061 811 outlet; +#X obj 1345 613 loadbang; +#X obj 1052 751 + 0; +#X obj 1036 723 * 0.1; +#X obj 1073 723 * 0.15; +#X obj 1144 747 + 0; +#X obj 1124 720 * 0.1; +#X obj 1165 719 * 0.15; +#X obj 1231 748 + 0; +#X obj 1324 749 + 0; +#X text 1066 656 insert values at points here; +#X obj 1215 720 * 30; +#X obj 1252 720 * 60; +#X obj 1305 720 * 60; +#X obj 1345 721 * 90; +#X obj 1343 688 float 0; +#X obj 1275 688 float 0; +#X text 979 812 FM Freq; +#X obj 1492 672 outlet; +#X obj 1776 474 loadbang; +#X obj 1483 612 + 0; +#X obj 1467 584 * 0.1; +#X obj 1504 584 * 0.15; +#X obj 1575 608 + 0; +#X obj 1555 581 * 0.1; +#X obj 1596 580 * 0.15; +#X obj 1662 609 + 0; +#X obj 1755 610 + 0; +#X text 1497 517 insert values at points here; +#X obj 1646 581 * 30; +#X obj 1683 581 * 60; +#X obj 1736 581 * 60; +#X obj 1776 582 * 90; +#X obj 1774 549 float 0; +#X obj 1492 551 float 1; +#X obj 1633 551 float 0; +#X obj 1706 549 float 0; +#X text 1436 674 FM Amt; +#X obj 1565 549 float 0.01; +#X obj 1134 688 float 0.7; +#X obj 1202 690 float 0.6; +#X obj 1061 690 float 1; +#X connect 0 0 130 0; +#X connect 2 0 3 1; +#X connect 3 0 4 0; +#X connect 4 0 21 0; +#X connect 5 0 3 0; +#X connect 6 0 15 0; +#X connect 7 0 16 0; +#X connect 8 0 17 0; +#X connect 9 0 6 0; +#X connect 10 0 6 1; +#X connect 11 0 7 0; +#X connect 12 0 7 1; +#X connect 13 0 8 0; +#X connect 14 0 8 1; +#X connect 15 0 18 0; +#X connect 16 0 19 0; +#X connect 17 0 20 0; +#X connect 18 0 21 1; +#X connect 18 0 128 0; +#X connect 19 0 22 0; +#X connect 20 0 22 1; +#X connect 20 0 126 0; +#X connect 21 0 23 0; +#X connect 22 0 23 1; +#X connect 22 0 127 0; +#X connect 23 0 148 0; +#X connect 24 0 29 0; +#X connect 25 0 33 0; +#X connect 26 0 34 0; +#X connect 27 0 35 0; +#X connect 29 0 134 0; +#X connect 30 0 133 0; +#X connect 31 0 132 0; +#X connect 32 0 131 0; +#X connect 33 0 30 0; +#X connect 34 0 31 0; +#X connect 35 0 32 0; +#X connect 37 0 42 0; +#X connect 38 0 37 0; +#X connect 39 0 90 0; +#X connect 39 0 91 0; +#X connect 39 0 92 0; +#X connect 39 0 93 0; +#X connect 39 0 94 0; +#X connect 40 0 28 0; +#X connect 41 0 44 0; +#X connect 41 0 71 0; +#X connect 41 0 99 0; +#X connect 41 0 115 0; +#X connect 41 0 154 0; +#X connect 41 0 172 0; +#X connect 42 0 43 0; +#X connect 42 0 70 0; +#X connect 42 0 98 0; +#X connect 42 0 114 0; +#X connect 42 0 153 0; +#X connect 42 0 171 0; +#X connect 43 0 40 0; +#X connect 44 0 40 1; +#X connect 45 0 28 0; +#X connect 46 0 45 0; +#X connect 47 0 45 1; +#X connect 48 0 28 0; +#X connect 49 0 28 0; +#X connect 50 0 53 0; +#X connect 51 0 50 0; +#X connect 52 0 47 0; +#X connect 52 0 74 0; +#X connect 52 0 102 0; +#X connect 52 0 118 0; +#X connect 52 0 157 0; +#X connect 52 0 175 0; +#X connect 53 0 46 0; +#X connect 53 0 73 0; +#X connect 53 0 101 0; +#X connect 53 0 117 0; +#X connect 53 0 156 0; +#X connect 53 0 174 0; +#X connect 54 0 57 0; +#X connect 55 0 54 0; +#X connect 56 0 64 0; +#X connect 56 0 79 0; +#X connect 56 0 107 0; +#X connect 56 0 123 0; +#X connect 56 0 162 0; +#X connect 56 0 180 0; +#X connect 57 0 63 0; +#X connect 57 0 78 0; +#X connect 57 0 106 0; +#X connect 57 0 122 0; +#X connect 57 0 161 0; +#X connect 57 0 179 0; +#X connect 59 0 62 0; +#X connect 60 0 59 0; +#X connect 61 0 66 0; +#X connect 61 0 81 0; +#X connect 61 0 109 0; +#X connect 61 0 125 0; +#X connect 61 0 164 0; +#X connect 61 0 182 0; +#X connect 62 0 65 0; +#X connect 62 0 80 0; +#X connect 62 0 108 0; +#X connect 62 0 124 0; +#X connect 62 0 163 0; +#X connect 62 0 181 0; +#X connect 63 0 48 0; +#X connect 64 0 48 1; +#X connect 65 0 49 0; +#X connect 66 0 49 1; +#X connect 68 0 83 0; +#X connect 68 0 84 0; +#X connect 68 0 87 0; +#X connect 68 0 88 0; +#X connect 68 0 89 0; +#X connect 69 0 67 0; +#X connect 70 0 69 0; +#X connect 71 0 69 1; +#X connect 72 0 67 0; +#X connect 73 0 72 0; +#X connect 74 0 72 1; +#X connect 75 0 67 0; +#X connect 76 0 67 0; +#X connect 78 0 75 0; +#X connect 79 0 75 1; +#X connect 80 0 76 0; +#X connect 81 0 76 1; +#X connect 83 0 70 1; +#X connect 84 0 81 1; +#X connect 87 0 71 1; +#X connect 87 0 73 1; +#X connect 88 0 74 1; +#X connect 88 0 78 1; +#X connect 89 0 79 1; +#X connect 89 0 80 1; +#X connect 90 0 43 1; +#X connect 91 0 44 1; +#X connect 91 0 46 1; +#X connect 92 0 47 1; +#X connect 92 0 63 1; +#X connect 93 0 64 1; +#X connect 93 0 65 1; +#X connect 94 0 66 1; +#X connect 96 0 143 0; +#X connect 96 0 144 0; +#X connect 96 0 145 0; +#X connect 96 0 146 0; +#X connect 96 0 149 0; +#X connect 97 0 95 0; +#X connect 98 0 97 0; +#X connect 99 0 97 1; +#X connect 100 0 95 0; +#X connect 101 0 100 0; +#X connect 102 0 100 1; +#X connect 103 0 95 0; +#X connect 104 0 95 0; +#X connect 106 0 103 0; +#X connect 107 0 103 1; +#X connect 108 0 104 0; +#X connect 109 0 104 1; +#X connect 112 0 137 0; +#X connect 112 0 139 0; +#X connect 112 0 140 0; +#X connect 112 0 141 0; +#X connect 112 0 142 0; +#X connect 113 0 111 0; +#X connect 114 0 113 0; +#X connect 115 0 113 1; +#X connect 116 0 111 0; +#X connect 117 0 116 0; +#X connect 118 0 116 1; +#X connect 119 0 111 0; +#X connect 120 0 111 0; +#X connect 122 0 119 0; +#X connect 123 0 119 1; +#X connect 124 0 120 0; +#X connect 125 0 120 1; +#X connect 126 0 22 0; +#X connect 127 0 23 0; +#X connect 128 0 21 0; +#X connect 129 0 5 0; +#X connect 129 1 2 0; +#X connect 129 2 9 0; +#X connect 129 3 10 0; +#X connect 129 4 11 0; +#X connect 129 5 12 0; +#X connect 129 6 13 0; +#X connect 129 7 14 0; +#X connect 130 0 129 0; +#X connect 130 1 148 1; +#X connect 131 0 60 0; +#X connect 131 1 59 1; +#X connect 131 2 61 0; +#X connect 132 0 55 0; +#X connect 132 1 54 1; +#X connect 132 2 56 0; +#X connect 133 0 51 0; +#X connect 133 1 50 1; +#X connect 133 2 52 0; +#X connect 134 0 38 0; +#X connect 134 1 37 1; +#X connect 134 2 41 0; +#X connect 137 0 125 1; +#X connect 139 0 114 1; +#X connect 140 0 115 1; +#X connect 140 0 117 1; +#X connect 141 0 118 1; +#X connect 141 0 122 1; +#X connect 142 0 123 1; +#X connect 142 0 124 1; +#X connect 143 0 107 1; +#X connect 143 0 108 1; +#X connect 144 0 102 1; +#X connect 144 0 106 1; +#X connect 145 0 99 1; +#X connect 145 0 101 1; +#X connect 146 0 98 1; +#X connect 147 0 24 0; +#X connect 147 1 25 0; +#X connect 147 2 26 0; +#X connect 147 3 27 0; +#X connect 148 0 147 0; +#X connect 149 0 109 1; +#X connect 151 0 165 0; +#X connect 151 0 166 0; +#X connect 151 0 189 0; +#X connect 151 0 190 0; +#X connect 151 0 191 0; +#X connect 152 0 150 0; +#X connect 153 0 152 0; +#X connect 154 0 152 1; +#X connect 155 0 150 0; +#X connect 156 0 155 0; +#X connect 157 0 155 1; +#X connect 158 0 150 0; +#X connect 159 0 150 0; +#X connect 161 0 158 0; +#X connect 162 0 158 1; +#X connect 163 0 159 0; +#X connect 164 0 159 1; +#X connect 165 0 164 1; +#X connect 166 0 162 1; +#X connect 166 0 163 1; +#X connect 169 0 183 0; +#X connect 169 0 184 0; +#X connect 169 0 185 0; +#X connect 169 0 186 0; +#X connect 169 0 188 0; +#X connect 170 0 168 0; +#X connect 171 0 170 0; +#X connect 172 0 170 1; +#X connect 173 0 168 0; +#X connect 174 0 173 0; +#X connect 175 0 173 1; +#X connect 176 0 168 0; +#X connect 177 0 168 0; +#X connect 179 0 176 0; +#X connect 180 0 176 1; +#X connect 181 0 177 0; +#X connect 182 0 177 1; +#X connect 183 0 182 1; +#X connect 184 0 171 1; +#X connect 185 0 175 1; +#X connect 185 0 179 1; +#X connect 186 0 180 1; +#X connect 186 0 181 1; +#X connect 188 0 172 1; +#X connect 188 0 174 1; +#X connect 189 0 154 1; +#X connect 189 0 156 1; +#X connect 190 0 157 1; +#X connect 190 0 161 1; +#X connect 191 0 153 1; +#X restore 44 163 pd interpolatorWave; +#X floatatom 246 201 5 0 0 0 - - -; +#X text 248 217 FMFreq; +#X floatatom 289 199 5 0 0 0 - - -; +#X text 291 215 FMAmt; +#X obj 354 136 int 40; +#X connect 0 0 15 0; +#X connect 0 0 36 0; +#X connect 1 0 4 0; +#X connect 1 0 28 1; +#X connect 4 0 7 0; +#X connect 6 0 11 0; +#X connect 6 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 18 0; +#X connect 10 0 58 0; +#X connect 11 0 26 0; +#X connect 13 0 16 0; +#X connect 14 0 25 0; +#X connect 15 0 14 0; +#X connect 16 0 3 0; +#X connect 17 0 32 0; +#X connect 18 0 17 0; +#X connect 19 0 8 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 29 0; +#X connect 23 0 24 0; +#X connect 24 0 27 0; +#X connect 25 0 13 1; +#X connect 26 0 3 0; +#X connect 27 0 17 1; +#X connect 28 0 19 0; +#X connect 29 0 28 0; +#X connect 31 0 22 0; +#X connect 31 1 27 0; +#X connect 32 0 6 1; +#X connect 33 0 34 0; +#X connect 34 0 35 0; +#X connect 35 0 32 1; +#X connect 36 0 13 0; +#X connect 37 0 53 0; +#X connect 38 0 53 0; +#X connect 40 0 36 1; +#X connect 41 0 25 1; +#X connect 42 0 15 1; +#X connect 43 0 26 1; +#X connect 44 0 47 0; +#X connect 45 0 48 0; +#X connect 46 0 49 0; +#X connect 47 0 37 0; +#X connect 48 0 37 0; +#X connect 49 0 37 0; +#X connect 53 0 40 0; +#X connect 53 1 41 0; +#X connect 53 2 42 0; +#X connect 53 3 43 0; +#X connect 53 4 54 0; +#X connect 53 5 56 0; +#X connect 54 0 22 0; +#X connect 56 0 27 0; +#X connect 58 0 4 0; +#X restore 76 221 pd oscillatorC; +#N canvas 525 162 1052 736 fenvelopeC 0; +#X obj 113 33 inlet; +#X text 162 27 tribber; +#X obj 347 0 inlet; +#X obj 216 137 * 123; +#X obj 306 163 * 123; +#X text 474 63 proportion of level that is allways on; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 308 134 * 6; +#X obj 123 176 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 262 301 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 260 395 pack 0 1; +#X obj 469 289 f 1; +#X obj 239 225 + 1; +#X obj 142 341 f 1; +#X obj 253 368 f 0; +#X obj 309 271 + 3; +#X obj 134 680 outlet~; +#X text 82 678 filter; +#X obj 316 461 *~ 1; +#X obj 303 368 f 125; +#X obj 182 339 f 1; +#X obj 330 559 *~ 1; +#X obj 306 191 + 10; +#X obj 404 0 inlet; +#X text 345 -20 attack; +#X text 406 -23 decay; +#X obj 494 5 inlet; +#X text 488 -16 duration; +#X obj 262 330 t b b; +#X obj 121 203 t b b b; +#X connect 0 0 10 0; +#X connect 2 0 3 0; +#X connect 3 0 16 0; +#X connect 4 0 26 0; +#X connect 6 0 22 1; +#X connect 7 0 15 0; +#X connect 7 1 6 1; +#X connect 8 0 7 0; +#X connect 9 0 4 0; +#X connect 10 0 33 0; +#X connect 11 0 32 0; +#X connect 12 0 22 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 6 0; +#X connect 16 0 19 0; +#X connect 16 0 24 1; +#X connect 17 0 13 0; +#X connect 18 0 14 0; +#X connect 19 0 11 1; +#X connect 22 0 25 0; +#X connect 23 0 14 1; +#X connect 24 0 13 1; +#X connect 25 0 20 0; +#X connect 26 0 23 1; +#X connect 27 0 9 0; +#X connect 30 0 3 1; +#X connect 30 0 4 1; +#X connect 32 0 18 0; +#X connect 32 1 23 0; +#X connect 33 0 17 0; +#X connect 33 1 24 0; +#X connect 33 2 11 0; +#X restore 167 221 pd fenvelopeC; +#N canvas 867 125 1052 736 aenvelope 0; +#X obj 113 33 inlet; +#X obj 539 46 inlet; +#X obj 216 137 * 123; +#X obj 341 162 * 123; +#X obj 468 202 route sustain; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 343 133 * 6; +#X obj 341 190 + 50; +#X obj 113 186 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 270 303 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 271 381 pack 0 1; +#X obj 257 645 clip~ -1 1; +#X obj 312 580 dbtorms~; +#X obj 254 682 outlet~; +#X obj 469 289 f 1; +#X obj 316 520 *~ 60; +#X obj 316 547 +~ 40; +#X obj 218 161 + 1; +#X obj 142 341 f 1; +#X obj 269 349 f 0; +#X obj 309 271 + 3; +#X text 318 681 amplitude; +#X obj 316 461 *~ 1; +#X obj 318 490 +~ 0; +#X obj 319 348 f 125; +#X obj 182 339 f 1; +#X obj 296 608 lop~ 50; +#X obj 484 511 r fromOF; +#X obj 481 565 route smoothing; +#X obj 483 538 route list; +#X obj 224 49 inlet; +#X obj 322 49 inlet; +#X text 232 28 attack; +#X text 330 28 decay; +#X text 162 28 trigger; +#X text 532 18 total time; +#X obj 237 225 t f f; +#X obj 102 243 t b b b; +#X obj 280 325 t b b; +#X connect 0 0 10 0; +#X connect 1 0 2 1; +#X connect 1 0 3 1; +#X connect 2 0 21 0; +#X connect 3 0 9 0; +#X connect 4 0 7 0; +#X connect 5 0 26 1; +#X connect 6 0 18 0; +#X connect 6 1 5 1; +#X connect 7 0 6 0; +#X connect 7 0 27 1; +#X connect 8 0 3 0; +#X connect 9 0 28 1; +#X connect 10 0 41 0; +#X connect 11 0 23 0; +#X connect 11 0 42 0; +#X connect 12 0 26 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 17 0; +#X connect 16 0 30 0; +#X connect 18 0 5 0; +#X connect 19 0 20 0; +#X connect 20 0 16 0; +#X connect 21 0 40 0; +#X connect 22 0 13 0; +#X connect 23 0 14 0; +#X connect 24 0 11 1; +#X connect 26 0 27 0; +#X connect 27 0 19 0; +#X connect 28 0 14 1; +#X connect 29 0 13 1; +#X connect 30 0 15 0; +#X connect 31 0 33 0; +#X connect 32 0 30 1; +#X connect 33 0 32 0; +#X connect 34 0 2 0; +#X connect 35 0 8 0; +#X connect 40 0 29 1; +#X connect 40 1 24 0; +#X connect 41 0 22 0; +#X connect 41 1 29 0; +#X connect 41 2 11 0; +#X connect 42 0 23 0; +#X connect 42 1 28 0; +#X restore 259 222 pd aenvelope; +#X text 182 -40 CANDIDATE; +#X obj -40 33 / 127; +#X obj -38 63 * 12; +#X obj -42 102 + 40; +#N canvas 0 22 450 300 ftypeResInterp 0; +#X obj 140 50 inlet; +#X obj 141 223 outlet; +#X text 70 13 resonance peaks in middle for band pass \, and goes down +at ends for lp and hp; +#X obj 254 107 > 0.5; +#X obj 232 151 spigot; +#X obj 53 136 spigot; +#X obj 97 96 <= 0.5; +#X obj 53 96 * 255; +#X obj 192 86 * -255; +#X obj 200 117 + 255; +#X connect 0 0 3 0; +#X connect 0 0 7 0; +#X connect 0 0 6 0; +#X connect 0 0 8 0; +#X connect 3 0 4 1; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 5 1; +#X connect 7 0 5 0; +#X connect 8 0 9 0; +#X connect 9 0 4 0; +#X restore 210 75 pd ftypeResInterp; +#X obj 344 82 * 0.8; +#X obj 331 105 - 150; +#X connect 2 0 6 0; +#X connect 3 0 21 0; +#X connect 3 0 22 0; +#X connect 3 0 23 0; +#X connect 3 0 24 0; +#X connect 3 0 25 0; +#X connect 3 0 26 0; +#X connect 3 0 27 0; +#X connect 3 0 28 0; +#X connect 4 0 18 0; +#X connect 5 0 0 0; +#X connect 5 0 1 0; +#X connect 6 0 37 0; +#X connect 6 0 38 0; +#X connect 7 0 37 1; +#X connect 7 0 38 1; +#X connect 8 0 37 2; +#X connect 8 0 38 2; +#X connect 13 0 29 2; +#X connect 13 0 43 0; +#X connect 18 0 5 0; +#X connect 21 0 40 0; +#X connect 22 0 36 0; +#X connect 23 0 30 0; +#X connect 24 0 31 0; +#X connect 25 0 32 0; +#X connect 26 0 33 0; +#X connect 27 0 34 0; +#X connect 28 0 35 0; +#X connect 29 0 4 0; +#X connect 30 0 7 0; +#X connect 31 0 8 0; +#X connect 32 0 13 0; +#X connect 33 0 44 0; +#X connect 36 0 29 0; +#X connect 37 0 29 1; +#X connect 38 0 4 1; +#X connect 40 0 41 0; +#X connect 41 0 42 0; +#X connect 42 0 36 1; +#X connect 43 0 29 4; +#X connect 44 0 45 0; +#X connect 45 0 29 3; +#X restore 47 -40 pd candidateSynth; +#N canvas 830 119 910 816 targetSynth 0; +#X obj 83 467 outlet~; +#X obj 143 466 outlet~; +#X obj 659 -257 inlet; +#X obj 181 -294 inlet; +#X obj 96 296 *~; +#X obj 73 375 clip~ -1 1; +#X obj 664 -65 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 80 56 / 127; +#X obj 119 57 / 127; +#X text 81 -112 attack; +#X text 124 -112 decay; +#X text -53 -112 pitch; +#X text -7 -114 duration; +#X obj 258 49 / 127; +#X text 299 -115 ftype; +#X text 342 -115 ffreq; +#X text 464 -117 reson; +#X text 562 -111 reverb; +#X obj 92 335 *~ 0.1; +#X text 35 -102 wavef; +#X text 655 -95 trigger; +#X obj -38 -168 route pitch; +#X obj 44 -169 route waveform; +#X obj 138 -169 route attack; +#X obj 221 -171 route decay; +#X obj 301 -170 route fType; +#X obj 378 -167 route fFreq; +#X obj 459 -169 route reson; +#X obj 547 -172 route reverb; +#N canvas 42 77 1074 773 filterT 0; +#X obj 44 22 inlet~; +#X obj 165 84 route filtFreq; +#X obj 855 112 route reson; +#X obj 99 639 outlet~; +#X obj 169 306 mtof~; +#X obj 167 43 route list; +#X obj 165 11 r fromOF; +#X obj 316 19 inlet~; +#X text 362 19 envelope; +#X obj 171 189 sig~; +#X obj 174 250 +~; +#X obj 662 265 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 565 230 filetr freq; +#X text 645 226 resonance; +#X floatatom 822 416 5 0 0 0 - - -; +#X msg 363 391 \$1 100; +#X obj 363 415 line~; +#X obj 407 303 hsl 128 15 0 1 0 1 empty empty empty -2 -8 0 10 -262144 +-1 -1 5600 1; +#X text 284 273 Mode: 0 = lowpass \, 0.5 = resonant bandpass \, 1 = +highpass; +#X floatatom 403 356 5 0 0 0 - - -; +#X obj 820 472 + 100; +#X obj 820 496 dbtorms; +#X floatatom 820 525 5 0 0 0 - - -; +#X obj 820 443 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -8 0 10 +-262144 -1 -1 3 256; +#X obj 364 149 route fType; +#X obj 820 356 / 5; +#X obj 98 558 multimode_libpd.mmb~; +#X obj 99 598 biquad_libpd.mmb~; +#X floatatom 659 420 5 0 0 0 - - -; +#X obj 167 280 clip~ 20 128; +#X obj 169 220 lop~ 50; +#X obj 169 122 * 0.6; +#X obj 172 158 + 30; +#X obj 238 221 *~ 110; +#X obj 882 28 r fromOF; +#X obj 815 553 lop~ 50; +#X obj 881 57 route list; +#X obj 891 81 route smoothing; +#X text 38 2 audio in; +#X text 478 17 ftype; +#X text 590 17 ffreq; +#X obj 544 17 inlet; +#X obj 432 17 inlet; +#X obj 646 17 inlet; +#X text 692 17 reson; +#X floatatom 195 386 5 0 0 0 - - -; +#X obj 820 389 + 3; +#X connect 0 0 27 0; +#X connect 1 0 31 0; +#X connect 2 0 25 0; +#X connect 4 0 26 0; +#X connect 5 0 1 0; +#X connect 5 0 2 0; +#X connect 5 0 24 0; +#X connect 6 0 5 0; +#X connect 7 0 33 0; +#X connect 9 0 30 0; +#X connect 10 0 29 0; +#X connect 11 0 25 0; +#X connect 11 0 28 0; +#X connect 14 0 23 0; +#X connect 15 0 16 0; +#X connect 16 0 26 2; +#X connect 17 0 19 0; +#X connect 17 0 15 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 35 0; +#X connect 23 0 20 0; +#X connect 24 0 15 0; +#X connect 25 0 46 0; +#X connect 26 0 27 1; +#X connect 26 1 27 2; +#X connect 26 2 27 3; +#X connect 26 3 27 4; +#X connect 26 4 27 5; +#X connect 27 0 3 0; +#X connect 29 0 4 0; +#X connect 30 0 10 0; +#X connect 31 0 32 0; +#X connect 32 0 9 0; +#X connect 33 0 10 1; +#X connect 34 0 36 0; +#X connect 35 0 26 1; +#X connect 36 0 37 0; +#X connect 37 0 35 1; +#X connect 37 0 30 1; +#X connect 41 0 31 0; +#X connect 42 0 15 0; +#X connect 43 0 25 0; +#X connect 46 0 14 0; +#X restore 77 250 pd filterT; +#X obj 92 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 120 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 268 -93 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 346 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 457 -94 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 565 -75 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#N canvas 76 137 871 723 oscillatorC 0; +#X obj 83 269 phasor~; +#X obj 430 -51 inlet; +#X text 73 522 audio out; +#X obj 79 501 outlet~; +#X obj 402 171 mtof; +#X text 292 -112 "pWidth" \, "sqVol" \, "sawVol" \, "sineVol" \, "FMAmt" +; +#X obj 321 233 +~; +#X obj 402 193 sig~; +#X floatatom 564 131 5 0 0 0 - - -; +#X text 627 93 fm rfeq; +#X obj 353 113 loadbang; +#X obj 262 398 osc~ 220; +#X text 29 390 subtract out of phase one; +#X obj 84 377 -~; +#X obj 151 327 wrap~; +#X obj 150 302 +~ 0.5; +#X obj 83 437 -~ 0.5; +#X obj 568 186 *~ 0; +#X obj 562 156 osc~; +#X obj 561 105 mtof; +#X obj 731 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 723 64 / 127; +#X obj 548 29 * 100; +#X obj 765 -85 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 764 62 / 127; +#X obj 152 354 *~ 0; +#X obj 263 429 *~ 1; +#X obj 616 129 * 3500; +#X obj 559 81 +; +#X obj 560 54 - 40; +#X text 408 -73 pitch freq; +#X obj 552 1 route FMFreq FMAmt; +#X obj 564 218 lop~ 20; +#X obj 680 172 r fromOF; +#X obj 679 201 route list; +#X obj 677 226 route smoothing; +#X obj 84 346 *~ 1; +#X obj 66 124 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#X obj 16 122 inlet; +#X text 52 93 waveform; +#X floatatom 42 198 5 0 0 0 - - -; +#X floatatom 93 201 5 0 0 0 - - -; +#X floatatom 141 205 5 0 0 0 - - -; +#X floatatom 190 203 5 0 0 0 - - -; +#X obj 29 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 101 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 170 -14 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 31 19 float 10; +#X obj 103 19 float 64; +#X obj 173 21 float 120; +#X text 192 219 sineVol; +#X text 30 218 saw vol; +#X text 92 221 sq vol; +#N canvas 71 22 1849 1017 interpolatorWave 0; +#X obj 80 -91 inlet; +#X text 75 -113 slider control; +#X obj 217 74 < 32; +#X obj 202 100 &&; +#X floatatom 211 122 5 0 0 0 - - -; +#X obj 186 74 >= 0; +#X obj 279 99 &&; +#X obj 359 98 &&; +#X obj 444 97 &&; +#X obj 263 73 >= 32; +#X obj 300 73 < 64; +#X obj 339 73 >= 64; +#X obj 380 72 < 96; +#X obj 428 71 >= 96; +#X obj 465 71 < 128; +#X floatatom 273 121 5 0 0 0 - - -; +#X floatatom 354 119 5 0 0 0 - - -; +#X floatatom 438 118 5 0 0 0 - - -; +#X obj 273 148 * 2; +#X obj 355 147 * 3; +#X obj 436 147 * 4; +#X obj 246 205 +; +#X obj 398 200 +; +#X obj 315 246 +; +#X floatatom 105 352 5 0 0 0 - - -; +#X floatatom 181 356 5 0 0 0 - - -; +#X floatatom 246 356 5 0 0 0 - - -; +#X floatatom 316 352 5 0 0 0 - - -; +#X obj -125 824 outlet; +#X obj 116 408 / 32; +#X obj 181 408 / 32; +#X obj 243 410 / 32; +#X obj 316 408 / 32; +#X obj 177 381 - 32; +#X obj 245 382 - 64; +#X obj 317 378 - 96; +#X text 544 477 calc frac; +#X obj 35 498 -; +#X obj 35 479 float 1; +#X obj 159 626 loadbang; +#X obj -134 764 + 0; +#X floatatom 85 526 5 0 0 0 - - -; +#X floatatom 36 527 5 0 0 0 - - -; +#X obj -150 736 * 0.1; +#X obj -113 736 * 0.15; +#X obj -42 760 + 0; +#X obj -58 732 * 0.1; +#X obj -21 732 * 0.15; +#X obj 45 761 + 0; +#X obj 138 762 + 0; +#X obj 153 506 -; +#X obj 153 487 float 1; +#X floatatom 200 526 5 0 0 0 - - -; +#X floatatom 154 528 5 0 0 0 - - -; +#X obj 286 502 -; +#X obj 286 483 float 1; +#X floatatom 335 526 5 0 0 0 - - -; +#X floatatom 287 524 5 0 0 0 - - -; +#X text 6 678 insert values at points here; +#X obj 416 505 -; +#X obj 416 486 float 1; +#X floatatom 467 526 5 0 0 0 - - -; +#X floatatom 417 527 5 0 0 0 - - -; +#X obj 29 733 * 30; +#X obj 66 733 * 60; +#X obj 119 733 * 60; +#X obj 159 734 * 90; +#X obj -543 849 outlet; +#X obj -557 676 loadbang; +#X obj -552 789 + 0; +#X obj -568 761 * 0.1; +#X obj -531 761 * 0.15; +#X obj -460 785 + 0; +#X obj -476 757 * 0.1; +#X obj -439 757 * 0.15; +#X obj -373 786 + 0; +#X obj -280 787 + 0; +#X text -630 702 insert values at points here; +#X obj -389 758 * 30; +#X obj -352 758 * 60; +#X obj -299 758 * 60; +#X obj -259 759 * 90; +#X text -541 827 comment; +#X obj -543 728 float 0; +#X obj -262 725 float 1; +#X text -595 848 saw vol; +#X text -207 825 pulse volume; +#X obj -470 726 float 0; +#X obj -402 728 float 1; +#X obj -330 726 float 1; +#X obj -125 703 float 0; +#X obj -52 701 float 0; +#X obj 16 703 float 0; +#X obj 88 701 float 1; +#X obj 157 701 float 1; +#X obj 264 818 outlet; +#X obj 548 620 loadbang; +#X obj 255 758 + 0; +#X obj 239 730 * 0.1; +#X obj 276 730 * 0.15; +#X obj 347 754 + 0; +#X obj 331 726 * 0.1; +#X obj 368 726 * 0.15; +#X obj 434 755 + 0; +#X obj 527 756 + 0; +#X text 373 667 insert values at points here; +#X obj 418 727 * 30; +#X obj 455 727 * 60; +#X obj 508 727 * 60; +#X obj 548 728 * 90; +#X text 182 819 pulse width; +#X obj 677 819 outlet; +#X obj 961 621 loadbang; +#X obj 668 759 + 0; +#X obj 652 731 * 0.1; +#X obj 689 731 * 0.15; +#X obj 760 755 + 0; +#X obj 744 727 * 0.1; +#X obj 781 727 * 0.15; +#X obj 847 756 + 0; +#X obj 940 757 + 0; +#X text 682 664 insert values at points here; +#X obj 831 728 * 30; +#X obj 868 728 * 60; +#X obj 921 728 * 60; +#X obj 961 729 * 90; +#X obj 397 174 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 315 224 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 246 175 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 255 28 t f f f f f f f f; +#X obj 117 -57 t f f; +#X obj 415 462 t b f f; +#X obj 283 458 t b f f; +#X obj 155 463 t b f f; +#X obj 36 452 t b f f; +#X text 266 796 comment; +#X text -124 801 comment; +#X obj 959 696 float 0; +#X text 595 820 sine volume; +#X obj 677 698 float 1; +#X obj 750 696 float 1; +#X obj 818 698 float 0; +#X obj 891 696 float 0; +#X obj 477 695 float 0.5; +#X obj 405 697 float 0.5; +#X obj 337 695 float 0.5; +#X obj 264 697 float 0.5; +#X obj 166 308 route 1 2 3 4; +#X obj 164 281 pack; +#X obj 546 695 float 0.01; +#X obj 1061 811 outlet; +#X obj 1345 613 loadbang; +#X obj 1052 751 + 0; +#X obj 1036 723 * 0.1; +#X obj 1073 723 * 0.15; +#X obj 1144 747 + 0; +#X obj 1124 720 * 0.1; +#X obj 1165 719 * 0.15; +#X obj 1231 748 + 0; +#X obj 1324 749 + 0; +#X text 1066 656 insert values at points here; +#X obj 1215 720 * 30; +#X obj 1252 720 * 60; +#X obj 1305 720 * 60; +#X obj 1345 721 * 90; +#X obj 1343 688 float 0; +#X obj 1275 688 float 0; +#X text 979 812 FM Freq; +#X obj 1492 672 outlet; +#X obj 1776 474 loadbang; +#X obj 1483 612 + 0; +#X obj 1467 584 * 0.1; +#X obj 1504 584 * 0.15; +#X obj 1575 608 + 0; +#X obj 1555 581 * 0.1; +#X obj 1596 580 * 0.15; +#X obj 1662 609 + 0; +#X obj 1755 610 + 0; +#X text 1497 517 insert values at points here; +#X obj 1646 581 * 30; +#X obj 1683 581 * 60; +#X obj 1736 581 * 60; +#X obj 1776 582 * 90; +#X obj 1774 549 float 0; +#X obj 1492 551 float 1; +#X obj 1633 551 float 0; +#X obj 1706 549 float 0; +#X text 1436 674 FM Amt; +#X obj 1565 549 float 0.01; +#X obj 1134 688 float 0.7; +#X obj 1202 690 float 0.6; +#X obj 1061 690 float 1; +#X connect 0 0 130 0; +#X connect 2 0 3 1; +#X connect 3 0 4 0; +#X connect 4 0 21 0; +#X connect 5 0 3 0; +#X connect 6 0 15 0; +#X connect 7 0 16 0; +#X connect 8 0 17 0; +#X connect 9 0 6 0; +#X connect 10 0 6 1; +#X connect 11 0 7 0; +#X connect 12 0 7 1; +#X connect 13 0 8 0; +#X connect 14 0 8 1; +#X connect 15 0 18 0; +#X connect 16 0 19 0; +#X connect 17 0 20 0; +#X connect 18 0 21 1; +#X connect 18 0 128 0; +#X connect 19 0 22 0; +#X connect 20 0 22 1; +#X connect 20 0 126 0; +#X connect 21 0 23 0; +#X connect 22 0 23 1; +#X connect 22 0 127 0; +#X connect 23 0 148 0; +#X connect 24 0 29 0; +#X connect 25 0 33 0; +#X connect 26 0 34 0; +#X connect 27 0 35 0; +#X connect 29 0 134 0; +#X connect 30 0 133 0; +#X connect 31 0 132 0; +#X connect 32 0 131 0; +#X connect 33 0 30 0; +#X connect 34 0 31 0; +#X connect 35 0 32 0; +#X connect 37 0 42 0; +#X connect 38 0 37 0; +#X connect 39 0 90 0; +#X connect 39 0 91 0; +#X connect 39 0 92 0; +#X connect 39 0 93 0; +#X connect 39 0 94 0; +#X connect 40 0 28 0; +#X connect 41 0 44 0; +#X connect 41 0 71 0; +#X connect 41 0 99 0; +#X connect 41 0 115 0; +#X connect 41 0 154 0; +#X connect 41 0 172 0; +#X connect 42 0 43 0; +#X connect 42 0 70 0; +#X connect 42 0 98 0; +#X connect 42 0 114 0; +#X connect 42 0 153 0; +#X connect 42 0 171 0; +#X connect 43 0 40 0; +#X connect 44 0 40 1; +#X connect 45 0 28 0; +#X connect 46 0 45 0; +#X connect 47 0 45 1; +#X connect 48 0 28 0; +#X connect 49 0 28 0; +#X connect 50 0 53 0; +#X connect 51 0 50 0; +#X connect 52 0 47 0; +#X connect 52 0 74 0; +#X connect 52 0 102 0; +#X connect 52 0 118 0; +#X connect 52 0 157 0; +#X connect 52 0 175 0; +#X connect 53 0 46 0; +#X connect 53 0 73 0; +#X connect 53 0 101 0; +#X connect 53 0 117 0; +#X connect 53 0 156 0; +#X connect 53 0 174 0; +#X connect 54 0 57 0; +#X connect 55 0 54 0; +#X connect 56 0 64 0; +#X connect 56 0 79 0; +#X connect 56 0 107 0; +#X connect 56 0 123 0; +#X connect 56 0 162 0; +#X connect 56 0 180 0; +#X connect 57 0 63 0; +#X connect 57 0 78 0; +#X connect 57 0 106 0; +#X connect 57 0 122 0; +#X connect 57 0 161 0; +#X connect 57 0 179 0; +#X connect 59 0 62 0; +#X connect 60 0 59 0; +#X connect 61 0 66 0; +#X connect 61 0 81 0; +#X connect 61 0 109 0; +#X connect 61 0 125 0; +#X connect 61 0 164 0; +#X connect 61 0 182 0; +#X connect 62 0 65 0; +#X connect 62 0 80 0; +#X connect 62 0 108 0; +#X connect 62 0 124 0; +#X connect 62 0 163 0; +#X connect 62 0 181 0; +#X connect 63 0 48 0; +#X connect 64 0 48 1; +#X connect 65 0 49 0; +#X connect 66 0 49 1; +#X connect 68 0 83 0; +#X connect 68 0 84 0; +#X connect 68 0 87 0; +#X connect 68 0 88 0; +#X connect 68 0 89 0; +#X connect 69 0 67 0; +#X connect 70 0 69 0; +#X connect 71 0 69 1; +#X connect 72 0 67 0; +#X connect 73 0 72 0; +#X connect 74 0 72 1; +#X connect 75 0 67 0; +#X connect 76 0 67 0; +#X connect 78 0 75 0; +#X connect 79 0 75 1; +#X connect 80 0 76 0; +#X connect 81 0 76 1; +#X connect 83 0 70 1; +#X connect 84 0 81 1; +#X connect 87 0 71 1; +#X connect 87 0 73 1; +#X connect 88 0 74 1; +#X connect 88 0 78 1; +#X connect 89 0 79 1; +#X connect 89 0 80 1; +#X connect 90 0 43 1; +#X connect 91 0 44 1; +#X connect 91 0 46 1; +#X connect 92 0 47 1; +#X connect 92 0 63 1; +#X connect 93 0 64 1; +#X connect 93 0 65 1; +#X connect 94 0 66 1; +#X connect 96 0 143 0; +#X connect 96 0 144 0; +#X connect 96 0 145 0; +#X connect 96 0 146 0; +#X connect 96 0 149 0; +#X connect 97 0 95 0; +#X connect 98 0 97 0; +#X connect 99 0 97 1; +#X connect 100 0 95 0; +#X connect 101 0 100 0; +#X connect 102 0 100 1; +#X connect 103 0 95 0; +#X connect 104 0 95 0; +#X connect 106 0 103 0; +#X connect 107 0 103 1; +#X connect 108 0 104 0; +#X connect 109 0 104 1; +#X connect 112 0 137 0; +#X connect 112 0 139 0; +#X connect 112 0 140 0; +#X connect 112 0 141 0; +#X connect 112 0 142 0; +#X connect 113 0 111 0; +#X connect 114 0 113 0; +#X connect 115 0 113 1; +#X connect 116 0 111 0; +#X connect 117 0 116 0; +#X connect 118 0 116 1; +#X connect 119 0 111 0; +#X connect 120 0 111 0; +#X connect 122 0 119 0; +#X connect 123 0 119 1; +#X connect 124 0 120 0; +#X connect 125 0 120 1; +#X connect 126 0 22 0; +#X connect 127 0 23 0; +#X connect 128 0 21 0; +#X connect 129 0 5 0; +#X connect 129 1 2 0; +#X connect 129 2 9 0; +#X connect 129 3 10 0; +#X connect 129 4 11 0; +#X connect 129 5 12 0; +#X connect 129 6 13 0; +#X connect 129 7 14 0; +#X connect 130 0 129 0; +#X connect 130 1 148 1; +#X connect 131 0 60 0; +#X connect 131 1 59 1; +#X connect 131 2 61 0; +#X connect 132 0 55 0; +#X connect 132 1 54 1; +#X connect 132 2 56 0; +#X connect 133 0 51 0; +#X connect 133 1 50 1; +#X connect 133 2 52 0; +#X connect 134 0 38 0; +#X connect 134 1 37 1; +#X connect 134 2 41 0; +#X connect 137 0 125 1; +#X connect 139 0 114 1; +#X connect 140 0 115 1; +#X connect 140 0 117 1; +#X connect 141 0 118 1; +#X connect 141 0 122 1; +#X connect 142 0 123 1; +#X connect 142 0 124 1; +#X connect 143 0 107 1; +#X connect 143 0 108 1; +#X connect 144 0 102 1; +#X connect 144 0 106 1; +#X connect 145 0 99 1; +#X connect 145 0 101 1; +#X connect 146 0 98 1; +#X connect 147 0 24 0; +#X connect 147 1 25 0; +#X connect 147 2 26 0; +#X connect 147 3 27 0; +#X connect 148 0 147 0; +#X connect 149 0 109 1; +#X connect 151 0 165 0; +#X connect 151 0 166 0; +#X connect 151 0 189 0; +#X connect 151 0 190 0; +#X connect 151 0 191 0; +#X connect 152 0 150 0; +#X connect 153 0 152 0; +#X connect 154 0 152 1; +#X connect 155 0 150 0; +#X connect 156 0 155 0; +#X connect 157 0 155 1; +#X connect 158 0 150 0; +#X connect 159 0 150 0; +#X connect 161 0 158 0; +#X connect 162 0 158 1; +#X connect 163 0 159 0; +#X connect 164 0 159 1; +#X connect 165 0 164 1; +#X connect 166 0 162 1; +#X connect 166 0 163 1; +#X connect 169 0 183 0; +#X connect 169 0 184 0; +#X connect 169 0 185 0; +#X connect 169 0 186 0; +#X connect 169 0 188 0; +#X connect 170 0 168 0; +#X connect 171 0 170 0; +#X connect 172 0 170 1; +#X connect 173 0 168 0; +#X connect 174 0 173 0; +#X connect 175 0 173 1; +#X connect 176 0 168 0; +#X connect 177 0 168 0; +#X connect 179 0 176 0; +#X connect 180 0 176 1; +#X connect 181 0 177 0; +#X connect 182 0 177 1; +#X connect 183 0 182 1; +#X connect 184 0 171 1; +#X connect 185 0 175 1; +#X connect 185 0 179 1; +#X connect 186 0 180 1; +#X connect 186 0 181 1; +#X connect 188 0 172 1; +#X connect 188 0 174 1; +#X connect 189 0 154 1; +#X connect 189 0 156 1; +#X connect 190 0 157 1; +#X connect 190 0 161 1; +#X connect 191 0 153 1; +#X restore 44 163 pd interpolatorWave; +#X floatatom 246 201 5 0 0 0 - - -; +#X text 248 217 FMFreq; +#X floatatom 289 199 5 0 0 0 - - -; +#X text 291 215 FMAmt; +#X obj 354 136 int 40; +#X connect 0 0 15 0; +#X connect 0 0 36 0; +#X connect 1 0 4 0; +#X connect 1 0 28 1; +#X connect 4 0 7 0; +#X connect 6 0 11 0; +#X connect 6 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 18 0; +#X connect 10 0 58 0; +#X connect 11 0 26 0; +#X connect 13 0 16 0; +#X connect 14 0 25 0; +#X connect 15 0 14 0; +#X connect 16 0 3 0; +#X connect 17 0 32 0; +#X connect 18 0 17 0; +#X connect 19 0 8 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 29 0; +#X connect 23 0 24 0; +#X connect 24 0 27 0; +#X connect 25 0 13 1; +#X connect 26 0 3 0; +#X connect 27 0 17 1; +#X connect 28 0 19 0; +#X connect 29 0 28 0; +#X connect 31 0 22 0; +#X connect 31 1 27 0; +#X connect 32 0 6 1; +#X connect 33 0 34 0; +#X connect 34 0 35 0; +#X connect 35 0 32 1; +#X connect 36 0 13 0; +#X connect 37 0 53 0; +#X connect 38 0 53 0; +#X connect 40 0 36 1; +#X connect 41 0 25 1; +#X connect 42 0 15 1; +#X connect 43 0 26 1; +#X connect 44 0 47 0; +#X connect 45 0 48 0; +#X connect 46 0 49 0; +#X connect 47 0 37 0; +#X connect 48 0 37 0; +#X connect 49 0 37 0; +#X connect 53 0 40 0; +#X connect 53 1 41 0; +#X connect 53 2 42 0; +#X connect 53 3 43 0; +#X connect 53 4 54 0; +#X connect 53 5 56 0; +#X connect 54 0 22 0; +#X connect 56 0 27 0; +#X connect 58 0 4 0; +#X restore 76 221 pd oscillatorC; +#N canvas 525 162 1052 736 fenvelopeC 0; +#X obj 113 33 inlet; +#X text 162 27 tribber; +#X obj 347 0 inlet; +#X obj 216 137 * 123; +#X obj 306 163 * 123; +#X text 474 63 proportion of level that is allways on; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 308 134 * 6; +#X obj 123 176 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 262 301 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 260 395 pack 0 1; +#X obj 469 289 f 1; +#X obj 239 225 + 1; +#X obj 142 341 f 1; +#X obj 253 368 f 0; +#X obj 309 271 + 3; +#X obj 134 680 outlet~; +#X text 82 678 filter; +#X obj 316 461 *~ 1; +#X obj 303 368 f 125; +#X obj 182 339 f 1; +#X obj 330 559 *~ 1; +#X obj 306 191 + 10; +#X obj 404 0 inlet; +#X text 345 -20 attack; +#X text 406 -23 decay; +#X obj 494 5 inlet; +#X text 488 -16 duration; +#X obj 262 330 t b b; +#X obj 121 203 t b b b; +#X connect 0 0 10 0; +#X connect 2 0 3 0; +#X connect 3 0 16 0; +#X connect 4 0 26 0; +#X connect 6 0 22 1; +#X connect 7 0 15 0; +#X connect 7 1 6 1; +#X connect 8 0 7 0; +#X connect 9 0 4 0; +#X connect 10 0 33 0; +#X connect 11 0 32 0; +#X connect 12 0 22 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 6 0; +#X connect 16 0 19 0; +#X connect 16 0 24 1; +#X connect 17 0 13 0; +#X connect 18 0 14 0; +#X connect 19 0 11 1; +#X connect 22 0 25 0; +#X connect 23 0 14 1; +#X connect 24 0 13 1; +#X connect 25 0 20 0; +#X connect 26 0 23 1; +#X connect 27 0 9 0; +#X connect 30 0 3 1; +#X connect 30 0 4 1; +#X connect 32 0 18 0; +#X connect 32 1 23 0; +#X connect 33 0 17 0; +#X connect 33 1 24 0; +#X connect 33 2 11 0; +#X restore 167 221 pd fenvelopeC; +#N canvas 867 125 1052 736 aenvelope 0; +#X obj 113 33 inlet; +#X obj 539 46 inlet; +#X obj 216 137 * 123; +#X obj 341 162 * 123; +#X obj 468 202 route sustain; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 343 133 * 6; +#X obj 341 190 + 50; +#X obj 113 186 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 270 303 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 271 381 pack 0 1; +#X obj 257 645 clip~ -1 1; +#X obj 312 580 dbtorms~; +#X obj 254 682 outlet~; +#X obj 469 289 f 1; +#X obj 316 520 *~ 60; +#X obj 316 547 +~ 40; +#X obj 218 161 + 1; +#X obj 142 341 f 1; +#X obj 269 349 f 0; +#X obj 309 271 + 3; +#X text 318 681 amplitude; +#X obj 316 461 *~ 1; +#X obj 318 490 +~ 0; +#X obj 319 348 f 125; +#X obj 182 339 f 1; +#X obj 296 608 lop~ 50; +#X obj 484 511 r fromOF; +#X obj 481 565 route smoothing; +#X obj 483 538 route list; +#X obj 224 49 inlet; +#X obj 322 49 inlet; +#X text 232 28 attack; +#X text 330 28 decay; +#X text 162 28 trigger; +#X text 532 18 total time; +#X obj 237 225 t f f; +#X obj 102 243 t b b b; +#X obj 280 325 t b b; +#X connect 0 0 10 0; +#X connect 1 0 2 1; +#X connect 1 0 3 1; +#X connect 2 0 21 0; +#X connect 3 0 9 0; +#X connect 4 0 7 0; +#X connect 5 0 26 1; +#X connect 6 0 18 0; +#X connect 6 1 5 1; +#X connect 7 0 6 0; +#X connect 7 0 27 1; +#X connect 8 0 3 0; +#X connect 9 0 28 1; +#X connect 10 0 41 0; +#X connect 11 0 23 0; +#X connect 11 0 42 0; +#X connect 12 0 26 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 17 0; +#X connect 16 0 30 0; +#X connect 18 0 5 0; +#X connect 19 0 20 0; +#X connect 20 0 16 0; +#X connect 21 0 40 0; +#X connect 22 0 13 0; +#X connect 23 0 14 0; +#X connect 24 0 11 1; +#X connect 26 0 27 0; +#X connect 27 0 19 0; +#X connect 28 0 14 1; +#X connect 29 0 13 1; +#X connect 30 0 15 0; +#X connect 31 0 33 0; +#X connect 32 0 30 1; +#X connect 33 0 32 0; +#X connect 34 0 2 0; +#X connect 35 0 8 0; +#X connect 40 0 29 1; +#X connect 40 1 24 0; +#X connect 41 0 22 0; +#X connect 41 1 29 0; +#X connect 41 2 11 0; +#X connect 42 0 23 0; +#X connect 42 1 28 0; +#X restore 259 222 pd aenvelope; +#X obj -40 33 / 127; +#X obj -38 63 * 12; +#X obj -42 102 + 40; +#N canvas 0 22 450 300 ftypeResInterp 0; +#X obj 140 50 inlet; +#X obj 141 223 outlet; +#X text 70 13 resonance peaks in middle for band pass \, and goes down +at ends for lp and hp; +#X obj 254 107 > 0.5; +#X obj 232 151 spigot; +#X obj 53 136 spigot; +#X obj 97 96 <= 0.5; +#X obj 53 96 * 255; +#X obj 192 86 * -255; +#X obj 200 117 + 255; +#X connect 0 0 3 0; +#X connect 0 0 7 0; +#X connect 0 0 6 0; +#X connect 0 0 8 0; +#X connect 3 0 4 1; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 5 1; +#X connect 7 0 5 0; +#X connect 8 0 9 0; +#X connect 9 0 4 0; +#X restore 210 75 pd ftypeResInterp; +#X obj 344 82 * 0.8; +#X obj 331 105 - 150; +#X text 184 -41 TARGET; +#X connect 2 0 6 0; +#X connect 3 0 21 0; +#X connect 3 0 22 0; +#X connect 3 0 23 0; +#X connect 3 0 24 0; +#X connect 3 0 25 0; +#X connect 3 0 26 0; +#X connect 3 0 27 0; +#X connect 3 0 28 0; +#X connect 4 0 18 0; +#X connect 5 0 0 0; +#X connect 5 0 1 0; +#X connect 6 0 37 0; +#X connect 6 0 38 0; +#X connect 7 0 37 1; +#X connect 7 0 38 1; +#X connect 8 0 37 2; +#X connect 8 0 38 2; +#X connect 13 0 29 2; +#X connect 13 0 42 0; +#X connect 18 0 5 0; +#X connect 21 0 39 0; +#X connect 22 0 36 0; +#X connect 23 0 30 0; +#X connect 24 0 31 0; +#X connect 25 0 32 0; +#X connect 26 0 33 0; +#X connect 27 0 34 0; +#X connect 28 0 35 0; +#X connect 29 0 4 0; +#X connect 30 0 7 0; +#X connect 31 0 8 0; +#X connect 32 0 13 0; +#X connect 33 0 43 0; +#X connect 36 0 29 0; +#X connect 37 0 29 1; +#X connect 38 0 4 1; +#X connect 39 0 40 0; +#X connect 40 0 41 0; +#X connect 41 0 36 1; +#X connect 42 0 29 4; +#X connect 43 0 44 0; +#X connect 44 0 29 3; +#X restore 215 -31 pd targetSynth; +#X connect 1 0 0 0; +#X connect 2 0 0 1; +#X connect 5 0 20 1; +#X connect 6 0 21 1; +#X connect 7 0 8 0; +#X connect 8 0 9 0; +#X connect 8 0 10 0; +#X connect 8 0 15 0; +#X connect 9 0 18 0; +#X connect 9 0 20 0; +#X connect 10 0 17 0; +#X connect 10 0 21 0; +#X connect 11 0 5 0; +#X connect 11 1 6 0; +#X connect 12 0 11 0; +#X connect 13 0 14 0; +#X connect 14 0 11 1; +#X connect 15 0 12 0; +#X connect 16 0 19 0; +#X connect 17 0 6 0; +#X connect 18 0 5 0; +#X connect 19 0 12 0; +#X connect 20 0 1 0; +#X connect 20 1 2 0; +#X connect 21 0 1 1; +#X connect 21 1 2 1; diff -r 000000000000 -r a223551fdc1f targetSynth6.pd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targetSynth6.pd Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,2350 @@ +#N canvas 898 149 1013 774 10; +#X obj 109 189 dac~; +#X obj 70 -182 metro 500; +#X obj 44 -258 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#N canvas 903 68 910 816 targetSynth 0; +#N canvas 76 137 871 723 oscillator 0; +#X obj 83 269 phasor~; +#X obj 430 -51 inlet; +#X text 73 522 audio out; +#X obj 79 501 outlet~; +#X obj 402 171 mtof; +#X text 292 -112 "pWidth" \, "sqVol" \, "sawVol" \, "sineVol" \, "FMAmt" +; +#X obj 321 233 +~; +#X obj 402 193 sig~; +#X floatatom 564 131 5 0 0 0 - - -; +#X text 627 93 fm rfeq; +#X obj 354 136 int 64; +#X obj 353 113 loadbang; +#X obj 262 398 osc~ 220; +#X text 29 390 subtract out of phase one; +#X obj 84 377 -~; +#X obj 151 327 wrap~; +#X obj 150 302 +~ 0.5; +#X obj 83 437 -~ 0.5; +#X obj 568 186 *~ 0; +#X obj 562 156 osc~; +#X obj 561 105 mtof; +#X obj 731 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 723 64 / 127; +#X obj 548 29 * 100; +#X obj 765 -85 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 764 62 / 127; +#X obj 152 354 *~ 0; +#X obj 263 429 *~ 1; +#X obj 616 129 * 3500; +#X obj 559 81 +; +#X obj 560 54 - 40; +#X text 408 -73 pitch freq; +#X obj 552 1 route FMFreq FMAmt; +#X obj 564 218 lop~ 20; +#X obj 680 172 r fromOF; +#X obj 679 201 route list; +#X obj 677 226 route smoothing; +#X obj 84 346 *~ 1; +#X obj 62 124 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 12700 1; +#X obj 16 122 inlet; +#X text 52 93 waveform; +#X floatatom 42 198 5 0 0 0 - - -; +#X floatatom 93 201 5 0 0 0 - - -; +#X floatatom 141 205 5 0 0 0 - - -; +#X floatatom 190 203 5 0 0 0 - - -; +#X obj 29 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 101 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 170 -14 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 31 19 float 10; +#X obj 103 19 float 64; +#X obj 173 21 float 120; +#X text 192 219 sineVol; +#X text 30 218 saw vol; +#X text 92 221 sq vol; +#N canvas 584 22 1336 1017 interpolatorWave 0; +#X obj 80 -91 inlet; +#X text 75 -113 slider control; +#X obj 217 74 < 32; +#X obj 202 100 &&; +#X floatatom 211 122 5 0 0 0 - - -; +#X obj 186 74 >= 0; +#X obj 279 99 &&; +#X obj 359 98 &&; +#X obj 444 97 &&; +#X obj 263 73 >= 32; +#X obj 300 73 < 64; +#X obj 339 73 >= 64; +#X obj 380 72 < 96; +#X obj 428 71 >= 96; +#X obj 465 71 < 128; +#X floatatom 273 121 5 0 0 0 - - -; +#X floatatom 354 119 5 0 0 0 - - -; +#X floatatom 438 118 5 0 0 0 - - -; +#X obj 273 148 * 2; +#X obj 355 147 * 3; +#X obj 436 147 * 4; +#X obj 246 205 +; +#X obj 398 200 +; +#X obj 315 246 +; +#X floatatom 105 352 5 0 0 0 - - -; +#X floatatom 181 356 5 0 0 0 - - -; +#X floatatom 246 356 5 0 0 0 - - -; +#X floatatom 316 352 5 0 0 0 - - -; +#X obj -125 824 outlet; +#X obj 116 408 / 32; +#X obj 181 408 / 32; +#X obj 243 410 / 32; +#X obj 316 408 / 32; +#X obj 177 381 - 32; +#X obj 245 382 - 64; +#X obj 317 378 - 96; +#X text 544 477 calc frac; +#X obj 35 498 -; +#X obj 35 479 float 1; +#X obj 159 626 loadbang; +#X obj -134 764 + 0; +#X floatatom 85 526 5 0 0 0 - - -; +#X floatatom 36 527 5 0 0 0 - - -; +#X obj -150 736 * 0.1; +#X obj -113 736 * 0.15; +#X obj -42 760 + 0; +#X obj -58 732 * 0.1; +#X obj -21 732 * 0.15; +#X obj 45 761 + 0; +#X obj 138 762 + 0; +#X obj 153 506 -; +#X obj 153 487 float 1; +#X floatatom 200 526 5 0 0 0 - - -; +#X floatatom 154 528 5 0 0 0 - - -; +#X obj 286 502 -; +#X obj 286 483 float 1; +#X floatatom 335 526 5 0 0 0 - - -; +#X floatatom 287 524 5 0 0 0 - - -; +#X text 6 678 insert values at points here; +#X obj 416 505 -; +#X obj 416 486 float 1; +#X floatatom 467 526 5 0 0 0 - - -; +#X floatatom 417 527 5 0 0 0 - - -; +#X obj 29 733 * 30; +#X obj 66 733 * 60; +#X obj 119 733 * 60; +#X obj 159 734 * 90; +#X obj -543 849 outlet; +#X obj -557 676 loadbang; +#X obj -552 789 + 0; +#X obj -568 761 * 0.1; +#X obj -531 761 * 0.15; +#X obj -460 785 + 0; +#X obj -476 757 * 0.1; +#X obj -439 757 * 0.15; +#X obj -373 786 + 0; +#X obj -280 787 + 0; +#X text -630 702 insert values at points here; +#X obj -389 758 * 30; +#X obj -352 758 * 60; +#X obj -299 758 * 60; +#X obj -259 759 * 90; +#X text -541 827 comment; +#X obj -543 728 float 0; +#X obj -262 725 float 1; +#X text -595 848 saw vol; +#X text -207 825 pulse volume; +#X obj -470 726 float 0; +#X obj -402 728 float 1; +#X obj -330 726 float 1; +#X obj -125 703 float 0; +#X obj -52 701 float 0; +#X obj 16 703 float 0; +#X obj 88 701 float 1; +#X obj 157 701 float 1; +#X obj 264 818 outlet; +#X obj 548 620 loadbang; +#X obj 255 758 + 0; +#X obj 239 730 * 0.1; +#X obj 276 730 * 0.15; +#X obj 347 754 + 0; +#X obj 331 726 * 0.1; +#X obj 368 726 * 0.15; +#X obj 434 755 + 0; +#X obj 527 756 + 0; +#X text 373 667 insert values at points here; +#X obj 418 727 * 30; +#X obj 455 727 * 60; +#X obj 508 727 * 60; +#X obj 548 728 * 90; +#X text 182 819 pulse width; +#X obj 677 819 outlet; +#X obj 961 621 loadbang; +#X obj 668 759 + 0; +#X obj 652 731 * 0.1; +#X obj 689 731 * 0.15; +#X obj 760 755 + 0; +#X obj 744 727 * 0.1; +#X obj 781 727 * 0.15; +#X obj 847 756 + 0; +#X obj 940 757 + 0; +#X text 682 664 insert values at points here; +#X obj 831 728 * 30; +#X obj 868 728 * 60; +#X obj 921 728 * 60; +#X obj 961 729 * 90; +#X obj 397 174 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 315 224 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 246 175 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 255 28 t f f f f f f f f; +#X obj 117 -57 t f f; +#X obj 415 462 t b f f; +#X obj 283 458 t b f f; +#X obj 155 463 t b f f; +#X obj 36 452 t b f f; +#X text 266 796 comment; +#X text -124 801 comment; +#X obj 959 696 float 0; +#X text 595 820 sine volume; +#X obj 677 698 float 1; +#X obj 750 696 float 1; +#X obj 818 698 float 0; +#X obj 891 696 float 0; +#X obj 477 695 float 0.5; +#X obj 405 697 float 0.5; +#X obj 337 695 float 0.5; +#X obj 264 697 float 0.5; +#X obj 166 308 route 1 2 3 4; +#X obj 164 281 pack; +#X obj 546 695 float 0.01; +#X connect 0 0 130 0; +#X connect 2 0 3 1; +#X connect 3 0 4 0; +#X connect 4 0 21 0; +#X connect 5 0 3 0; +#X connect 6 0 15 0; +#X connect 7 0 16 0; +#X connect 8 0 17 0; +#X connect 9 0 6 0; +#X connect 10 0 6 1; +#X connect 11 0 7 0; +#X connect 12 0 7 1; +#X connect 13 0 8 0; +#X connect 14 0 8 1; +#X connect 15 0 18 0; +#X connect 16 0 19 0; +#X connect 17 0 20 0; +#X connect 18 0 21 1; +#X connect 18 0 128 0; +#X connect 19 0 22 0; +#X connect 20 0 22 1; +#X connect 20 0 126 0; +#X connect 21 0 23 0; +#X connect 22 0 23 1; +#X connect 22 0 127 0; +#X connect 23 0 148 0; +#X connect 24 0 29 0; +#X connect 25 0 33 0; +#X connect 26 0 34 0; +#X connect 27 0 35 0; +#X connect 29 0 134 0; +#X connect 30 0 133 0; +#X connect 31 0 132 0; +#X connect 32 0 131 0; +#X connect 33 0 30 0; +#X connect 34 0 31 0; +#X connect 35 0 32 0; +#X connect 37 0 42 0; +#X connect 38 0 37 0; +#X connect 39 0 90 0; +#X connect 39 0 91 0; +#X connect 39 0 92 0; +#X connect 39 0 93 0; +#X connect 39 0 94 0; +#X connect 40 0 28 0; +#X connect 41 0 44 0; +#X connect 41 0 71 0; +#X connect 41 0 99 0; +#X connect 41 0 115 0; +#X connect 42 0 43 0; +#X connect 42 0 70 0; +#X connect 42 0 98 0; +#X connect 42 0 114 0; +#X connect 43 0 40 0; +#X connect 44 0 40 1; +#X connect 45 0 28 0; +#X connect 46 0 45 0; +#X connect 47 0 45 1; +#X connect 48 0 28 0; +#X connect 49 0 28 0; +#X connect 50 0 53 0; +#X connect 51 0 50 0; +#X connect 52 0 47 0; +#X connect 52 0 74 0; +#X connect 52 0 102 0; +#X connect 52 0 118 0; +#X connect 53 0 46 0; +#X connect 53 0 73 0; +#X connect 53 0 101 0; +#X connect 53 0 117 0; +#X connect 54 0 57 0; +#X connect 55 0 54 0; +#X connect 56 0 64 0; +#X connect 56 0 79 0; +#X connect 56 0 107 0; +#X connect 56 0 123 0; +#X connect 57 0 63 0; +#X connect 57 0 78 0; +#X connect 57 0 106 0; +#X connect 57 0 122 0; +#X connect 59 0 62 0; +#X connect 60 0 59 0; +#X connect 61 0 66 0; +#X connect 61 0 81 0; +#X connect 61 0 109 0; +#X connect 61 0 125 0; +#X connect 62 0 65 0; +#X connect 62 0 80 0; +#X connect 62 0 108 0; +#X connect 62 0 124 0; +#X connect 63 0 48 0; +#X connect 64 0 48 1; +#X connect 65 0 49 0; +#X connect 66 0 49 1; +#X connect 68 0 83 0; +#X connect 68 0 84 0; +#X connect 68 0 87 0; +#X connect 68 0 88 0; +#X connect 68 0 89 0; +#X connect 69 0 67 0; +#X connect 70 0 69 0; +#X connect 71 0 69 1; +#X connect 72 0 67 0; +#X connect 73 0 72 0; +#X connect 74 0 72 1; +#X connect 75 0 67 0; +#X connect 76 0 67 0; +#X connect 78 0 75 0; +#X connect 79 0 75 1; +#X connect 80 0 76 0; +#X connect 81 0 76 1; +#X connect 83 0 70 1; +#X connect 84 0 81 1; +#X connect 87 0 71 1; +#X connect 87 0 73 1; +#X connect 88 0 74 1; +#X connect 88 0 78 1; +#X connect 89 0 79 1; +#X connect 89 0 80 1; +#X connect 90 0 43 1; +#X connect 91 0 44 1; +#X connect 91 0 46 1; +#X connect 92 0 47 1; +#X connect 92 0 63 1; +#X connect 93 0 64 1; +#X connect 93 0 65 1; +#X connect 94 0 66 1; +#X connect 96 0 143 0; +#X connect 96 0 144 0; +#X connect 96 0 145 0; +#X connect 96 0 146 0; +#X connect 96 0 149 0; +#X connect 97 0 95 0; +#X connect 98 0 97 0; +#X connect 99 0 97 1; +#X connect 100 0 95 0; +#X connect 101 0 100 0; +#X connect 102 0 100 1; +#X connect 103 0 95 0; +#X connect 104 0 95 0; +#X connect 106 0 103 0; +#X connect 107 0 103 1; +#X connect 108 0 104 0; +#X connect 109 0 104 1; +#X connect 112 0 137 0; +#X connect 112 0 139 0; +#X connect 112 0 140 0; +#X connect 112 0 141 0; +#X connect 112 0 142 0; +#X connect 113 0 111 0; +#X connect 114 0 113 0; +#X connect 115 0 113 1; +#X connect 116 0 111 0; +#X connect 117 0 116 0; +#X connect 118 0 116 1; +#X connect 119 0 111 0; +#X connect 120 0 111 0; +#X connect 122 0 119 0; +#X connect 123 0 119 1; +#X connect 124 0 120 0; +#X connect 125 0 120 1; +#X connect 126 0 22 0; +#X connect 127 0 23 0; +#X connect 128 0 21 0; +#X connect 129 0 5 0; +#X connect 129 1 2 0; +#X connect 129 2 9 0; +#X connect 129 3 10 0; +#X connect 129 4 11 0; +#X connect 129 5 12 0; +#X connect 129 6 13 0; +#X connect 129 7 14 0; +#X connect 130 0 129 0; +#X connect 130 1 148 1; +#X connect 131 0 60 0; +#X connect 131 1 59 1; +#X connect 131 2 61 0; +#X connect 132 0 55 0; +#X connect 132 1 54 1; +#X connect 132 2 56 0; +#X connect 133 0 51 0; +#X connect 133 1 50 1; +#X connect 133 2 52 0; +#X connect 134 0 38 0; +#X connect 134 1 37 1; +#X connect 134 2 41 0; +#X connect 137 0 125 1; +#X connect 139 0 114 1; +#X connect 140 0 115 1; +#X connect 140 0 117 1; +#X connect 141 0 118 1; +#X connect 141 0 122 1; +#X connect 142 0 123 1; +#X connect 142 0 124 1; +#X connect 143 0 107 1; +#X connect 143 0 108 1; +#X connect 144 0 102 1; +#X connect 144 0 106 1; +#X connect 145 0 99 1; +#X connect 145 0 101 1; +#X connect 146 0 98 1; +#X connect 147 0 24 0; +#X connect 147 1 25 0; +#X connect 147 2 26 0; +#X connect 147 3 27 0; +#X connect 148 0 147 0; +#X connect 149 0 109 1; +#X restore 44 163 pd interpolatorWave; +#X connect 0 0 16 0; +#X connect 0 0 37 0; +#X connect 1 0 4 0; +#X connect 1 0 29 1; +#X connect 4 0 7 0; +#X connect 6 0 12 0; +#X connect 6 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 19 0; +#X connect 10 0 4 0; +#X connect 11 0 10 0; +#X connect 12 0 27 0; +#X connect 14 0 17 0; +#X connect 15 0 26 0; +#X connect 16 0 15 0; +#X connect 17 0 3 0; +#X connect 18 0 33 0; +#X connect 19 0 18 0; +#X connect 20 0 8 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 30 0; +#X connect 24 0 25 0; +#X connect 25 0 28 0; +#X connect 26 0 14 1; +#X connect 27 0 3 0; +#X connect 28 0 18 1; +#X connect 29 0 20 0; +#X connect 30 0 29 0; +#X connect 32 0 23 0; +#X connect 32 1 28 0; +#X connect 33 0 6 1; +#X connect 34 0 35 0; +#X connect 35 0 36 0; +#X connect 36 0 33 1; +#X connect 37 0 14 0; +#X connect 38 0 54 0; +#X connect 39 0 54 0; +#X connect 41 0 37 1; +#X connect 42 0 26 1; +#X connect 43 0 16 1; +#X connect 44 0 27 1; +#X connect 45 0 48 0; +#X connect 46 0 49 0; +#X connect 47 0 50 0; +#X connect 48 0 38 0; +#X connect 49 0 38 0; +#X connect 50 0 38 0; +#X connect 54 0 41 0; +#X connect 54 1 42 0; +#X connect 54 2 43 0; +#X connect 54 3 44 0; +#X restore 76 221 pd oscillator; +#N canvas 42 77 1074 773 filter 0; +#X obj 44 22 inlet~; +#X obj 165 84 route filtFreq; +#X obj 855 112 route reson; +#X obj 99 639 outlet~; +#X obj 169 306 mtof~; +#X obj 167 43 route list; +#X obj 165 11 r fromOF; +#X obj 316 19 inlet~; +#X text 362 19 envelope; +#X obj 171 189 sig~; +#X obj 174 250 +~; +#X obj 662 265 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 565 230 filetr freq; +#X text 645 226 resonance; +#X floatatom 822 416 5 0 0 0 - - -; +#X msg 363 391 \$1 100; +#X obj 363 415 line~; +#X obj 407 303 hsl 128 15 0 1 0 1 empty empty empty -2 -8 0 10 -262144 +-1 -1 5600 1; +#X text 284 273 Mode: 0 = lowpass \, 0.5 = resonant bandpass \, 1 = +highpass; +#X floatatom 403 356 5 0 0 0 - - -; +#X obj 820 389 - 3; +#X obj 820 472 + 100; +#X obj 820 496 dbtorms; +#X floatatom 820 525 5 0 0 0 - - -; +#X obj 820 443 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -8 0 10 +-262144 -1 -1 -0.8 256; +#X obj 364 149 route fType; +#X obj 820 356 / 5; +#X obj 98 558 multimode_libpd.mmb~; +#X obj 99 598 biquad_libpd.mmb~; +#X floatatom 659 420 5 0 0 0 - - -; +#X obj 167 280 clip~ 20 128; +#X obj 169 220 lop~ 50; +#X obj 169 122 * 0.6; +#X obj 172 158 + 30; +#X obj 238 221 *~ 110; +#X obj 882 28 r fromOF; +#X obj 815 553 lop~ 50; +#X obj 881 57 route list; +#X obj 891 81 route smoothing; +#X text 38 2 audio in; +#X text 478 17 ftype; +#X text 590 17 ffreq; +#X obj 544 17 inlet; +#X obj 432 17 inlet; +#X obj 646 17 inlet; +#X text 692 17 reson; +#X floatatom 195 386 5 0 0 0 - - -; +#X connect 0 0 28 0; +#X connect 1 0 32 0; +#X connect 2 0 26 0; +#X connect 4 0 27 0; +#X connect 5 0 1 0; +#X connect 5 0 2 0; +#X connect 5 0 25 0; +#X connect 6 0 5 0; +#X connect 7 0 34 0; +#X connect 9 0 31 0; +#X connect 10 0 30 0; +#X connect 11 0 26 0; +#X connect 11 0 29 0; +#X connect 14 0 24 0; +#X connect 15 0 16 0; +#X connect 16 0 27 2; +#X connect 17 0 19 0; +#X connect 17 0 15 0; +#X connect 20 0 14 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 36 0; +#X connect 24 0 21 0; +#X connect 25 0 15 0; +#X connect 26 0 20 0; +#X connect 27 0 28 1; +#X connect 27 1 28 2; +#X connect 27 2 28 3; +#X connect 27 3 28 4; +#X connect 27 4 28 5; +#X connect 28 0 3 0; +#X connect 30 0 4 0; +#X connect 31 0 10 0; +#X connect 32 0 33 0; +#X connect 33 0 9 0; +#X connect 34 0 10 1; +#X connect 35 0 37 0; +#X connect 36 0 27 1; +#X connect 37 0 38 0; +#X connect 38 0 36 1; +#X connect 38 0 31 1; +#X connect 42 0 32 0; +#X connect 43 0 15 0; +#X connect 44 0 26 0; +#X restore 77 250 pd filter; +#X obj 96 296 *~; +#X obj 73 375 clip~ -1 1; +#N canvas 525 162 1052 736 fenvelope 0; +#X obj 113 33 inlet; +#X text 162 27 tribber; +#X obj 347 0 inlet; +#X obj 216 137 * 123; +#X obj 306 163 * 123; +#X text 474 63 proportion of level that is allways on; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 308 134 * 6; +#X obj 123 176 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 262 301 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 260 395 pack 0 1; +#X obj 469 289 f 1; +#X obj 239 225 + 1; +#X obj 142 341 f 1; +#X obj 253 368 f 0; +#X obj 309 271 + 3; +#X obj 134 680 outlet~; +#X text 82 678 filter; +#X obj 316 461 *~ 1; +#X obj 303 368 f 125; +#X obj 182 339 f 1; +#X obj 330 559 *~ 1; +#X obj 306 191 + 10; +#X obj 404 0 inlet; +#X text 345 -20 attack; +#X text 406 -23 decay; +#X obj 494 5 inlet; +#X text 488 -16 duration; +#X obj 262 330 t b b; +#X obj 121 203 t b b b; +#X connect 0 0 10 0; +#X connect 2 0 3 0; +#X connect 3 0 16 0; +#X connect 4 0 26 0; +#X connect 6 0 22 1; +#X connect 7 0 15 0; +#X connect 7 1 6 1; +#X connect 8 0 7 0; +#X connect 9 0 4 0; +#X connect 10 0 33 0; +#X connect 11 0 32 0; +#X connect 12 0 22 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 6 0; +#X connect 16 0 19 0; +#X connect 16 0 24 1; +#X connect 17 0 13 0; +#X connect 18 0 14 0; +#X connect 19 0 11 1; +#X connect 22 0 25 0; +#X connect 23 0 14 1; +#X connect 24 0 13 1; +#X connect 25 0 20 0; +#X connect 26 0 23 1; +#X connect 27 0 9 0; +#X connect 30 0 3 1; +#X connect 30 0 4 1; +#X connect 32 0 18 0; +#X connect 32 1 23 0; +#X connect 33 0 17 0; +#X connect 33 1 24 0; +#X connect 33 2 11 0; +#X restore 167 221 pd fenvelope; +#N canvas 867 125 1052 736 aenvelope 0; +#X obj 113 33 inlet; +#X obj 539 46 inlet; +#X obj 216 137 * 123; +#X obj 341 162 * 123; +#X obj 468 202 route sustain; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 343 133 * 6; +#X obj 341 190 + 50; +#X obj 113 186 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 270 303 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 271 381 pack 0 1; +#X obj 257 645 clip~ -1 1; +#X obj 312 580 dbtorms~; +#X obj 254 682 outlet~; +#X obj 469 289 f 1; +#X obj 316 520 *~ 60; +#X obj 316 547 +~ 40; +#X obj 218 161 + 1; +#X obj 142 341 f 1; +#X obj 269 349 f 0; +#X obj 309 271 + 3; +#X text 318 681 amplitude; +#X obj 316 461 *~ 1; +#X obj 318 490 +~ 0; +#X obj 319 348 f 125; +#X obj 182 339 f 1; +#X obj 296 608 lop~ 50; +#X obj 484 511 r fromOF; +#X obj 481 565 route smoothing; +#X obj 483 538 route list; +#X obj 224 49 inlet; +#X obj 322 49 inlet; +#X text 232 28 attack; +#X text 330 28 decay; +#X text 162 28 trigger; +#X text 532 18 total time; +#X obj 237 225 t f f; +#X obj 102 243 t b b b; +#X obj 280 325 t b b; +#X connect 0 0 10 0; +#X connect 1 0 2 1; +#X connect 1 0 3 1; +#X connect 2 0 21 0; +#X connect 3 0 9 0; +#X connect 4 0 7 0; +#X connect 5 0 26 1; +#X connect 6 0 18 0; +#X connect 6 1 5 1; +#X connect 7 0 6 0; +#X connect 7 0 27 1; +#X connect 8 0 3 0; +#X connect 9 0 28 1; +#X connect 10 0 41 0; +#X connect 11 0 23 0; +#X connect 11 0 42 0; +#X connect 12 0 26 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 17 0; +#X connect 16 0 30 0; +#X connect 18 0 5 0; +#X connect 19 0 20 0; +#X connect 20 0 16 0; +#X connect 21 0 40 0; +#X connect 22 0 13 0; +#X connect 23 0 14 0; +#X connect 24 0 11 1; +#X connect 26 0 27 0; +#X connect 27 0 19 0; +#X connect 28 0 14 1; +#X connect 29 0 13 1; +#X connect 30 0 15 0; +#X connect 31 0 33 0; +#X connect 32 0 30 1; +#X connect 33 0 32 0; +#X connect 34 0 2 0; +#X connect 35 0 8 0; +#X connect 40 0 29 1; +#X connect 40 1 24 0; +#X connect 41 0 22 0; +#X connect 41 1 29 0; +#X connect 41 2 11 0; +#X connect 42 0 23 0; +#X connect 42 1 28 0; +#X restore 259 222 pd aenvelope; +#N canvas 22 194 893 724 reverb 0; +#X obj 44 173 *~; +#X obj 351 160 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#X floatatom 344 184 5 0 0 0 - - -; +#X obj 342 206 * -1; +#X obj 343 232 + 1; +#X obj 149 167 *~; +#X floatatom 490 281 5 0 0 0 - - -; +#X obj 96 206 rev1~ 70; +#X obj 158 208 rev1~ 68; +#X obj 557 173 vsl 15 128 0 100 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 490 307 + 3; +#X obj 408 70 r fromOF; +#X obj 408 94 route list; +#X obj 408 118 route revDryWet revLength; +#X obj 76 370 outlet~; +#X obj 141 369 outlet~; +#X obj 73 80 inlet~; +#X obj 262 41 inlet; +#X obj 390 27 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#N canvas 861 22 993 1015 interpolatorReverb 0; +#X obj 71 34 inlet; +#X text 66 12 slider control; +#X floatatom 105 352 5 0 0 0 - - -; +#X floatatom 181 356 5 0 0 0 - - -; +#X floatatom 246 356 5 0 0 0 - - -; +#X floatatom 316 352 5 0 0 0 - - -; +#X obj 530 652 float 0.1; +#X text 60 827 rev mix; +#X obj 530 773 outlet; +#X text 532 751 rev dec time; +#X obj 116 408 / 32; +#X obj 181 408 / 32; +#X obj 243 410 / 32; +#X obj 316 408 / 32; +#X obj 177 381 - 32; +#X obj 245 382 - 64; +#X obj 317 378 - 96; +#X text 544 477 calc frac; +#X obj 70 500 -; +#X obj 70 481 float 1; +#X obj 814 575 loadbang; +#X obj 603 650 float 0.15; +#X obj 521 713 + 0; +#X floatatom 126 524 5 0 0 0 - - -; +#X floatatom 71 529 5 0 0 0 - - -; +#X obj 505 685 * 0.1; +#X obj 542 685 * 0.15; +#X obj 613 709 + 0; +#X obj 597 681 * 0.1; +#X obj 634 681 * 0.15; +#X obj 700 710 + 0; +#X obj 793 711 + 0; +#X obj 181 502 -; +#X obj 178 483 float 1; +#X floatatom 241 523 5 0 0 0 - - -; +#X floatatom 182 524 5 0 0 0 - - -; +#X obj 289 504 -; +#X obj 289 485 float 1; +#X floatatom 345 524 5 0 0 0 - - -; +#X floatatom 290 526 5 0 0 0 - - -; +#X text 772 621 insert values at points here; +#X obj 396 504 -; +#X obj 396 485 float 1; +#X floatatom 503 518 5 0 0 0 - - -; +#X floatatom 397 526 5 0 0 0 - - -; +#X obj 684 682 * 30; +#X obj 721 682 * 60; +#X obj 774 682 * 60; +#X obj 814 683 * 90; +#X obj 114 825 outlet; +#X obj 251 643 loadbang; +#X obj 106 754 + 0; +#X obj 87 710 * 0.1; +#X obj 124 710 * 0.15; +#X obj 195 734 + 0; +#X obj 179 706 * 0.1; +#X obj 216 706 * 0.15; +#X obj 282 735 + 0; +#X obj 375 736 + 0; +#X text 25 651 insert values at points here; +#X obj 266 707 * 30; +#X obj 303 707 * 60; +#X obj 356 707 * 60; +#X obj 396 708 * 90; +#X text 114 776 comment; +#X obj 112 677 float 0; +#X obj 253 677 float 0.3; +#X obj 325 675 float 0.6; +#X obj 393 674 float 1; +#X obj 185 675 float 0.02; +#X obj 671 652 float 20; +#X obj 812 650 float 65; +#X obj 743 650 float 40; +#X obj 174 93 < 32; +#X obj 159 119 &&; +#X floatatom 168 141 5 0 0 0 - - -; +#X obj 143 93 >= 0; +#X obj 236 118 &&; +#X obj 316 117 &&; +#X obj 401 116 &&; +#X obj 220 92 >= 32; +#X obj 257 92 < 64; +#X obj 296 92 >= 64; +#X obj 337 91 < 96; +#X obj 385 90 >= 96; +#X obj 422 90 < 128; +#X floatatom 230 140 5 0 0 0 - - -; +#X floatatom 311 138 5 0 0 0 - - -; +#X floatatom 395 137 5 0 0 0 - - -; +#X obj 230 167 * 2; +#X obj 312 166 * 3; +#X obj 393 166 * 4; +#X obj 203 224 +; +#X obj 355 219 +; +#X obj 272 265 +; +#X obj 354 193 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 272 243 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 203 194 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 212 47 t f f f f f f f f; +#X obj 103 57 t f f; +#X obj 394 457 t b f f; +#X obj 288 457 t b f f; +#X obj 178 454 t b f f; +#X obj 74 450 t b f f; +#X obj 166 311 route 1 2 3 4; +#X obj 166 288 pack f f; +#X connect 0 0 99 0; +#X connect 2 0 10 0; +#X connect 3 0 14 0; +#X connect 4 0 15 0; +#X connect 5 0 16 0; +#X connect 6 0 25 1; +#X connect 10 0 103 0; +#X connect 11 0 102 0; +#X connect 12 0 101 0; +#X connect 13 0 100 0; +#X connect 14 0 11 0; +#X connect 15 0 12 0; +#X connect 16 0 13 0; +#X connect 18 0 24 0; +#X connect 19 0 18 0; +#X connect 20 0 6 0; +#X connect 20 0 21 0; +#X connect 20 0 70 0; +#X connect 20 0 71 0; +#X connect 20 0 72 0; +#X connect 21 0 26 1; +#X connect 21 0 28 1; +#X connect 22 0 8 0; +#X connect 23 0 26 0; +#X connect 23 0 53 0; +#X connect 24 0 25 0; +#X connect 24 0 52 0; +#X connect 25 0 22 0; +#X connect 26 0 22 1; +#X connect 27 0 8 0; +#X connect 28 0 27 0; +#X connect 29 0 27 1; +#X connect 30 0 8 0; +#X connect 31 0 8 0; +#X connect 32 0 35 0; +#X connect 33 0 32 0; +#X connect 34 0 29 0; +#X connect 34 0 56 0; +#X connect 35 0 28 0; +#X connect 35 0 55 0; +#X connect 36 0 39 0; +#X connect 37 0 36 0; +#X connect 38 0 46 0; +#X connect 38 0 61 0; +#X connect 39 0 45 0; +#X connect 39 0 60 0; +#X connect 41 0 44 0; +#X connect 42 0 41 0; +#X connect 43 0 48 0; +#X connect 43 0 63 0; +#X connect 44 0 47 0; +#X connect 44 0 62 0; +#X connect 45 0 30 0; +#X connect 46 0 30 1; +#X connect 47 0 31 0; +#X connect 48 0 31 1; +#X connect 50 0 65 0; +#X connect 50 0 66 0; +#X connect 50 0 67 0; +#X connect 50 0 68 0; +#X connect 50 0 69 0; +#X connect 51 0 49 0; +#X connect 52 0 51 0; +#X connect 53 0 51 1; +#X connect 54 0 49 0; +#X connect 55 0 54 0; +#X connect 56 0 54 1; +#X connect 57 0 49 0; +#X connect 58 0 49 0; +#X connect 60 0 57 0; +#X connect 61 0 57 1; +#X connect 62 0 58 0; +#X connect 63 0 58 1; +#X connect 65 0 52 1; +#X connect 66 0 56 1; +#X connect 66 0 60 1; +#X connect 67 0 61 1; +#X connect 67 0 62 1; +#X connect 68 0 63 1; +#X connect 69 0 53 1; +#X connect 69 0 55 1; +#X connect 70 0 29 1; +#X connect 70 0 45 1; +#X connect 71 0 48 1; +#X connect 72 0 46 1; +#X connect 72 0 47 1; +#X connect 73 0 74 1; +#X connect 74 0 75 0; +#X connect 75 0 92 0; +#X connect 76 0 74 0; +#X connect 77 0 86 0; +#X connect 78 0 87 0; +#X connect 79 0 88 0; +#X connect 80 0 77 0; +#X connect 81 0 77 1; +#X connect 82 0 78 0; +#X connect 83 0 78 1; +#X connect 84 0 79 0; +#X connect 85 0 79 1; +#X connect 86 0 89 0; +#X connect 87 0 90 0; +#X connect 88 0 91 0; +#X connect 89 0 92 1; +#X connect 89 0 97 0; +#X connect 90 0 93 0; +#X connect 91 0 93 1; +#X connect 91 0 95 0; +#X connect 92 0 94 0; +#X connect 93 0 94 1; +#X connect 93 0 96 0; +#X connect 94 0 105 0; +#X connect 95 0 93 0; +#X connect 96 0 94 0; +#X connect 97 0 92 0; +#X connect 98 0 76 0; +#X connect 98 1 73 0; +#X connect 98 2 80 0; +#X connect 98 3 81 0; +#X connect 98 4 82 0; +#X connect 98 5 83 0; +#X connect 98 6 84 0; +#X connect 98 7 85 0; +#X connect 99 0 98 0; +#X connect 99 1 105 1; +#X connect 100 0 42 0; +#X connect 100 1 41 1; +#X connect 100 2 43 0; +#X connect 101 0 37 0; +#X connect 101 1 36 1; +#X connect 101 2 38 0; +#X connect 102 0 33 0; +#X connect 102 1 32 1; +#X connect 102 2 34 0; +#X connect 103 0 19 0; +#X connect 103 1 18 1; +#X connect 103 2 23 0; +#X connect 104 0 2 0; +#X connect 104 1 3 0; +#X connect 104 2 4 0; +#X connect 104 3 5 0; +#X connect 105 0 104 0; +#X restore 249 115 pd interpolatorReverb; +#X connect 0 0 14 0; +#X connect 0 0 15 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 2 0 5 1; +#X connect 3 0 4 0; +#X connect 4 0 0 1; +#X connect 5 0 7 0; +#X connect 5 0 8 0; +#X connect 6 0 7 1; +#X connect 6 0 10 0; +#X connect 7 0 14 0; +#X connect 8 0 15 0; +#X connect 9 0 6 0; +#X connect 10 0 8 1; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 13 0 2 0; +#X connect 13 1 6 0; +#X connect 16 0 0 0; +#X connect 16 0 5 0; +#X connect 17 0 19 0; +#X connect 18 0 19 0; +#X connect 19 0 2 0; +#X connect 19 1 6 0; +#X restore 73 407 pd reverb; +#X obj 664 -65 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 92 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 120 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 80 56 / 127; +#X obj 119 57 / 127; +#X text 81 -112 attack; +#X text 124 -112 decay; +#X obj -42 -77 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text -53 -112 pitch; +#X text -7 -114 duration; +#X obj 314 -85 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 346 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 301 53 / 127; +#X text 299 -115 ftype; +#X text 342 -115 ffreq; +#X obj 380 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 381 -116 reson; +#X obj 569 -88 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 562 -111 reverb; +#X obj 344 82 +; +#X floatatom 339 135 5 0 0 0 - - -; +#X obj 92 335 *~ 0.1; +#X obj 47 -81 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 35 -102 wavef; +#X text 655 -95 trigger; +#X obj -38 -168 route pitch; +#X obj 44 -169 route waveform; +#X obj 138 -169 route attack; +#X obj 221 -171 route decay; +#X obj 301 -170 route fType; +#X obj 378 -167 route fFreq; +#X obj 459 -169 route reson; +#X obj 547 -172 route reverb; +#X obj 636 -172 route trigger; +#X obj 337 110 - 185; +#X obj -42 102 + 30; +#X obj -41 72 / 3; +#X obj 83 467 outlet~; +#X obj 143 466 outlet~; +#X obj 659 -257 inlet; +#X obj 181 -294 inlet; +#X text 182 -83 TARGET SYNTH; +#X text 182 -61 TARGET SYNTH; +#X text 180 -34 TARGET SYNTH; +#X text 178 -5 TARGET SYNTH; +#X obj 255 465 random 127; +#X obj 513 430 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 329 464 random 127; +#X obj 401 463 random 127; +#X obj 476 462 random 127; +#X obj 551 462 random 127; +#X obj 631 460 random 127; +#X obj 708 460 random 127; +#X obj 800 457 random 127; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 28 0; +#X connect 3 0 6 0; +#X connect 4 0 1 1; +#X connect 5 0 2 1; +#X connect 6 0 44 0; +#X connect 6 1 45 0; +#X connect 7 0 4 0; +#X connect 7 0 5 0; +#X connect 8 0 10 0; +#X connect 9 0 11 0; +#X connect 10 0 4 1; +#X connect 10 0 5 1; +#X connect 11 0 4 2; +#X connect 11 0 5 2; +#X connect 14 0 43 0; +#X connect 17 0 19 0; +#X connect 18 0 26 0; +#X connect 19 0 1 2; +#X connect 22 0 1 4; +#X connect 24 0 6 1; +#X connect 26 0 41 0; +#X connect 28 0 3 0; +#X connect 29 0 0 0; +#X connect 32 0 14 0; +#X connect 33 0 29 0; +#X connect 34 0 8 0; +#X connect 35 0 9 0; +#X connect 36 0 17 0; +#X connect 37 0 18 0; +#X connect 38 0 22 0; +#X connect 39 0 24 0; +#X connect 40 0 7 0; +#X connect 41 0 1 3; +#X connect 41 0 27 0; +#X connect 42 0 26 1; +#X connect 42 0 0 1; +#X connect 43 0 42 0; +#X connect 46 0 7 0; +#X connect 47 0 32 0; +#X connect 47 0 33 0; +#X connect 47 0 34 0; +#X connect 47 0 35 0; +#X connect 47 0 36 0; +#X connect 47 0 37 0; +#X connect 47 0 38 0; +#X connect 47 0 39 0; +#X connect 47 0 40 0; +#X connect 53 0 52 0; +#X connect 53 0 54 0; +#X connect 53 0 55 0; +#X connect 53 0 56 0; +#X connect 53 0 57 0; +#X connect 53 0 58 0; +#X connect 53 0 59 0; +#X connect 53 0 60 0; +#X restore 237 -44 pd targetSynth; +#N canvas 99 28 824 911 candidateSynth 0; +#N canvas 76 137 871 723 oscillator 0; +#X obj 83 269 phasor~; +#X obj 430 -51 inlet; +#X text 73 522 audio out; +#X obj 79 501 outlet~; +#X obj 402 171 mtof; +#X text 292 -112 "pWidth" \, "sqVol" \, "sawVol" \, "sineVol" \, "FMAmt" +; +#X obj 321 233 +~; +#X obj 402 193 sig~; +#X floatatom 564 131 5 0 0 0 - - -; +#X text 627 93 fm rfeq; +#X obj 354 136 int 64; +#X obj 353 113 loadbang; +#X obj 262 398 osc~ 220; +#X text 29 390 subtract out of phase one; +#X obj 84 377 -~; +#X obj 151 327 wrap~; +#X obj 150 302 +~ 0.5; +#X obj 83 437 -~ 0.5; +#X obj 568 186 *~ 0; +#X obj 562 156 osc~; +#X obj 561 105 mtof; +#X obj 731 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 723 64 / 127; +#X obj 548 29 * 100; +#X obj 765 -85 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 764 62 / 127; +#X obj 152 354 *~ 0; +#X obj 263 429 *~ 1; +#X obj 616 129 * 3500; +#X obj 559 81 +; +#X obj 560 54 - 40; +#X text 408 -73 pitch freq; +#X obj 552 1 route FMFreq FMAmt; +#X obj 564 218 lop~ 20; +#X obj 680 172 r fromOF; +#X obj 679 201 route list; +#X obj 677 226 route smoothing; +#X obj 84 346 *~ 1; +#N canvas 584 22 1336 1017 interpolatorWave 0; +#X obj 80 -91 inlet; +#X text 75 -113 slider control; +#X obj 217 74 < 32; +#X obj 202 100 &&; +#X floatatom 211 122 5 0 0 0 - - -; +#X obj 186 74 >= 0; +#X obj 279 99 &&; +#X obj 359 98 &&; +#X obj 444 97 &&; +#X obj 263 73 >= 32; +#X obj 300 73 < 64; +#X obj 339 73 >= 64; +#X obj 380 72 < 96; +#X obj 428 71 >= 96; +#X obj 465 71 < 128; +#X floatatom 273 121 5 0 0 0 - - -; +#X floatatom 354 119 5 0 0 0 - - -; +#X floatatom 438 118 5 0 0 0 - - -; +#X obj 273 148 * 2; +#X obj 355 147 * 3; +#X obj 436 147 * 4; +#X obj 246 205 +; +#X obj 398 200 +; +#X obj 315 246 +; +#X floatatom 105 352 5 0 0 0 - - -; +#X floatatom 181 356 5 0 0 0 - - -; +#X floatatom 246 356 5 0 0 0 - - -; +#X floatatom 316 352 5 0 0 0 - - -; +#X obj -125 824 outlet; +#X obj 116 408 / 32; +#X obj 181 408 / 32; +#X obj 243 410 / 32; +#X obj 316 408 / 32; +#X obj 177 381 - 32; +#X obj 245 382 - 64; +#X obj 317 378 - 96; +#X text 544 477 calc frac; +#X obj 35 498 -; +#X obj 35 479 float 1; +#X obj 159 626 loadbang; +#X obj -134 764 + 0; +#X floatatom 85 526 5 0 0 0 - - -; +#X floatatom 36 527 5 0 0 0 - - -; +#X obj -150 736 * 0.1; +#X obj -113 736 * 0.15; +#X obj -42 760 + 0; +#X obj -58 732 * 0.1; +#X obj -21 732 * 0.15; +#X obj 45 761 + 0; +#X obj 138 762 + 0; +#X obj 153 506 -; +#X obj 153 487 float 1; +#X floatatom 200 526 5 0 0 0 - - -; +#X floatatom 154 528 5 0 0 0 - - -; +#X obj 286 502 -; +#X obj 286 483 float 1; +#X floatatom 335 526 5 0 0 0 - - -; +#X floatatom 287 524 5 0 0 0 - - -; +#X text 6 678 insert values at points here; +#X obj 416 505 -; +#X obj 416 486 float 1; +#X floatatom 467 526 5 0 0 0 - - -; +#X floatatom 417 527 5 0 0 0 - - -; +#X obj 29 733 * 30; +#X obj 66 733 * 60; +#X obj 119 733 * 60; +#X obj 159 734 * 90; +#X obj -543 849 outlet; +#X obj -557 676 loadbang; +#X obj -552 789 + 0; +#X obj -568 761 * 0.1; +#X obj -531 761 * 0.15; +#X obj -460 785 + 0; +#X obj -476 757 * 0.1; +#X obj -439 757 * 0.15; +#X obj -373 786 + 0; +#X obj -280 787 + 0; +#X text -630 702 insert values at points here; +#X obj -389 758 * 30; +#X obj -352 758 * 60; +#X obj -299 758 * 60; +#X obj -259 759 * 90; +#X text -541 827 comment; +#X obj -543 728 float 0; +#X obj -262 725 float 1; +#X text -595 848 saw vol; +#X text -207 825 pulse volume; +#X obj -470 726 float 0; +#X obj -402 728 float 1; +#X obj -330 726 float 1; +#X obj -125 703 float 0; +#X obj -52 701 float 0; +#X obj 16 703 float 0; +#X obj 88 701 float 1; +#X obj 157 701 float 1; +#X obj 264 818 outlet; +#X obj 548 620 loadbang; +#X obj 255 758 + 0; +#X obj 239 730 * 0.1; +#X obj 276 730 * 0.15; +#X obj 347 754 + 0; +#X obj 331 726 * 0.1; +#X obj 368 726 * 0.15; +#X obj 434 755 + 0; +#X obj 527 756 + 0; +#X text 373 667 insert values at points here; +#X obj 418 727 * 30; +#X obj 455 727 * 60; +#X obj 508 727 * 60; +#X obj 548 728 * 90; +#X text 182 819 pulse width; +#X obj 546 695 float 0.1; +#X obj 677 819 outlet; +#X obj 961 621 loadbang; +#X obj 668 759 + 0; +#X obj 652 731 * 0.1; +#X obj 689 731 * 0.15; +#X obj 760 755 + 0; +#X obj 744 727 * 0.1; +#X obj 781 727 * 0.15; +#X obj 847 756 + 0; +#X obj 940 757 + 0; +#X text 682 664 insert values at points here; +#X obj 831 728 * 30; +#X obj 868 728 * 60; +#X obj 921 728 * 60; +#X obj 961 729 * 90; +#X obj 397 174 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 315 224 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 246 175 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 255 28 t f f f f f f f f; +#X obj 117 -57 t f f; +#X obj 415 462 t b f f; +#X obj 283 458 t b f f; +#X obj 155 463 t b f f; +#X obj 36 452 t b f f; +#X text 266 796 comment; +#X text -124 801 comment; +#X obj 959 696 float 0; +#X text 595 820 sine volume; +#X obj 677 698 float 1; +#X obj 750 696 float 1; +#X obj 818 698 float 0; +#X obj 891 696 float 0; +#X obj 477 695 float 0.5; +#X obj 405 697 float 0.5; +#X obj 337 695 float 0.5; +#X obj 264 697 float 0.5; +#X obj 166 308 route 1 2 3 4; +#X obj 164 281 pack; +#X connect 0 0 131 0; +#X connect 2 0 3 1; +#X connect 3 0 4 0; +#X connect 4 0 21 0; +#X connect 5 0 3 0; +#X connect 6 0 15 0; +#X connect 7 0 16 0; +#X connect 8 0 17 0; +#X connect 9 0 6 0; +#X connect 10 0 6 1; +#X connect 11 0 7 0; +#X connect 12 0 7 1; +#X connect 13 0 8 0; +#X connect 14 0 8 1; +#X connect 15 0 18 0; +#X connect 16 0 19 0; +#X connect 17 0 20 0; +#X connect 18 0 21 1; +#X connect 18 0 129 0; +#X connect 19 0 22 0; +#X connect 20 0 22 1; +#X connect 20 0 127 0; +#X connect 21 0 23 0; +#X connect 22 0 23 1; +#X connect 22 0 128 0; +#X connect 23 0 149 0; +#X connect 24 0 29 0; +#X connect 25 0 33 0; +#X connect 26 0 34 0; +#X connect 27 0 35 0; +#X connect 29 0 135 0; +#X connect 30 0 134 0; +#X connect 31 0 133 0; +#X connect 32 0 132 0; +#X connect 33 0 30 0; +#X connect 34 0 31 0; +#X connect 35 0 32 0; +#X connect 37 0 42 0; +#X connect 38 0 37 0; +#X connect 39 0 90 0; +#X connect 39 0 91 0; +#X connect 39 0 92 0; +#X connect 39 0 93 0; +#X connect 39 0 94 0; +#X connect 40 0 28 0; +#X connect 41 0 44 0; +#X connect 41 0 71 0; +#X connect 41 0 99 0; +#X connect 41 0 116 0; +#X connect 42 0 43 0; +#X connect 42 0 70 0; +#X connect 42 0 98 0; +#X connect 42 0 115 0; +#X connect 43 0 40 0; +#X connect 44 0 40 1; +#X connect 45 0 28 0; +#X connect 46 0 45 0; +#X connect 47 0 45 1; +#X connect 48 0 28 0; +#X connect 49 0 28 0; +#X connect 50 0 53 0; +#X connect 51 0 50 0; +#X connect 52 0 47 0; +#X connect 52 0 74 0; +#X connect 52 0 102 0; +#X connect 52 0 119 0; +#X connect 53 0 46 0; +#X connect 53 0 73 0; +#X connect 53 0 101 0; +#X connect 53 0 118 0; +#X connect 54 0 57 0; +#X connect 55 0 54 0; +#X connect 56 0 64 0; +#X connect 56 0 79 0; +#X connect 56 0 107 0; +#X connect 56 0 124 0; +#X connect 57 0 63 0; +#X connect 57 0 78 0; +#X connect 57 0 106 0; +#X connect 57 0 123 0; +#X connect 59 0 62 0; +#X connect 60 0 59 0; +#X connect 61 0 66 0; +#X connect 61 0 81 0; +#X connect 61 0 109 0; +#X connect 61 0 126 0; +#X connect 62 0 65 0; +#X connect 62 0 80 0; +#X connect 62 0 108 0; +#X connect 62 0 125 0; +#X connect 63 0 48 0; +#X connect 64 0 48 1; +#X connect 65 0 49 0; +#X connect 66 0 49 1; +#X connect 68 0 83 0; +#X connect 68 0 84 0; +#X connect 68 0 87 0; +#X connect 68 0 88 0; +#X connect 68 0 89 0; +#X connect 69 0 67 0; +#X connect 70 0 69 0; +#X connect 71 0 69 1; +#X connect 72 0 67 0; +#X connect 73 0 72 0; +#X connect 74 0 72 1; +#X connect 75 0 67 0; +#X connect 76 0 67 0; +#X connect 78 0 75 0; +#X connect 79 0 75 1; +#X connect 80 0 76 0; +#X connect 81 0 76 1; +#X connect 83 0 70 1; +#X connect 84 0 81 1; +#X connect 87 0 71 1; +#X connect 87 0 73 1; +#X connect 88 0 74 1; +#X connect 88 0 78 1; +#X connect 89 0 79 1; +#X connect 89 0 80 1; +#X connect 90 0 43 1; +#X connect 91 0 44 1; +#X connect 91 0 46 1; +#X connect 92 0 47 1; +#X connect 92 0 63 1; +#X connect 93 0 64 1; +#X connect 93 0 65 1; +#X connect 94 0 66 1; +#X connect 96 0 111 0; +#X connect 96 0 144 0; +#X connect 96 0 145 0; +#X connect 96 0 146 0; +#X connect 96 0 147 0; +#X connect 97 0 95 0; +#X connect 98 0 97 0; +#X connect 99 0 97 1; +#X connect 100 0 95 0; +#X connect 101 0 100 0; +#X connect 102 0 100 1; +#X connect 103 0 95 0; +#X connect 104 0 95 0; +#X connect 106 0 103 0; +#X connect 107 0 103 1; +#X connect 108 0 104 0; +#X connect 109 0 104 1; +#X connect 111 0 109 1; +#X connect 113 0 138 0; +#X connect 113 0 140 0; +#X connect 113 0 141 0; +#X connect 113 0 142 0; +#X connect 113 0 143 0; +#X connect 114 0 112 0; +#X connect 115 0 114 0; +#X connect 116 0 114 1; +#X connect 117 0 112 0; +#X connect 118 0 117 0; +#X connect 119 0 117 1; +#X connect 120 0 112 0; +#X connect 121 0 112 0; +#X connect 123 0 120 0; +#X connect 124 0 120 1; +#X connect 125 0 121 0; +#X connect 126 0 121 1; +#X connect 127 0 22 0; +#X connect 128 0 23 0; +#X connect 129 0 21 0; +#X connect 130 0 5 0; +#X connect 130 1 2 0; +#X connect 130 2 9 0; +#X connect 130 3 10 0; +#X connect 130 4 11 0; +#X connect 130 5 12 0; +#X connect 130 6 13 0; +#X connect 130 7 14 0; +#X connect 131 0 130 0; +#X connect 131 1 149 1; +#X connect 132 0 60 0; +#X connect 132 1 59 1; +#X connect 132 2 61 0; +#X connect 133 0 55 0; +#X connect 133 1 54 1; +#X connect 133 2 56 0; +#X connect 134 0 51 0; +#X connect 134 1 50 1; +#X connect 134 2 52 0; +#X connect 135 0 38 0; +#X connect 135 1 37 1; +#X connect 135 2 41 0; +#X connect 138 0 126 1; +#X connect 140 0 115 1; +#X connect 141 0 116 1; +#X connect 141 0 118 1; +#X connect 142 0 119 1; +#X connect 142 0 123 1; +#X connect 143 0 124 1; +#X connect 143 0 125 1; +#X connect 144 0 107 1; +#X connect 144 0 108 1; +#X connect 145 0 102 1; +#X connect 145 0 106 1; +#X connect 146 0 99 1; +#X connect 146 0 101 1; +#X connect 147 0 98 1; +#X connect 148 0 24 0; +#X connect 148 1 25 0; +#X connect 148 2 26 0; +#X connect 148 3 27 0; +#X connect 149 0 148 0; +#X restore 51 166 pd interpolatorWave; +#X obj 62 124 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#X obj 16 122 inlet; +#X text 52 93 waveform; +#X floatatom 42 198 5 0 0 0 - - -; +#X floatatom 93 201 5 0 0 0 - - -; +#X floatatom 141 205 5 0 0 0 - - -; +#X floatatom 190 203 5 0 0 0 - - -; +#X obj 29 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1 +-1; +#X obj 101 -16 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 170 -14 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 31 19 float 10; +#X obj 103 19 float 64; +#X obj 173 21 float 120; +#X text 192 219 sineVol; +#X text 30 218 saw vol; +#X text 92 221 sq vol; +#X connect 0 0 16 0; +#X connect 0 0 37 0; +#X connect 1 0 4 0; +#X connect 1 0 29 1; +#X connect 4 0 7 0; +#X connect 6 0 12 0; +#X connect 6 0 0 0; +#X connect 7 0 6 0; +#X connect 8 0 19 0; +#X connect 10 0 4 0; +#X connect 11 0 10 0; +#X connect 12 0 27 0; +#X connect 14 0 17 0; +#X connect 15 0 26 0; +#X connect 16 0 15 0; +#X connect 17 0 3 0; +#X connect 18 0 33 0; +#X connect 19 0 18 0; +#X connect 20 0 8 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 30 0; +#X connect 24 0 25 0; +#X connect 25 0 28 0; +#X connect 26 0 14 1; +#X connect 27 0 3 0; +#X connect 28 0 18 1; +#X connect 29 0 20 0; +#X connect 30 0 29 0; +#X connect 32 0 23 0; +#X connect 32 1 28 0; +#X connect 33 0 6 1; +#X connect 34 0 35 0; +#X connect 35 0 36 0; +#X connect 36 0 33 1; +#X connect 37 0 14 0; +#X connect 38 0 42 0; +#X connect 38 1 43 0; +#X connect 38 2 44 0; +#X connect 38 3 45 0; +#X connect 39 0 38 0; +#X connect 40 0 38 0; +#X connect 42 0 37 1; +#X connect 43 0 26 1; +#X connect 44 0 16 1; +#X connect 45 0 27 1; +#X connect 46 0 49 0; +#X connect 47 0 50 0; +#X connect 48 0 51 0; +#X connect 49 0 39 0; +#X connect 50 0 39 0; +#X connect 51 0 39 0; +#X restore 76 221 pd oscillator; +#N canvas 42 77 1074 773 filter 0; +#X obj 44 22 inlet~; +#X obj 165 84 route filtFreq; +#X obj 855 112 route reson; +#X obj 99 639 outlet~; +#X obj 169 306 mtof~; +#X obj 167 43 route list; +#X obj 165 11 r fromOF; +#X obj 316 19 inlet~; +#X text 362 19 envelope; +#X obj 171 189 sig~; +#X obj 174 250 +~; +#X obj 662 265 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 565 230 filetr freq; +#X text 645 226 resonance; +#X floatatom 822 416 5 0 0 0 - - -; +#X msg 363 391 \$1 100; +#X obj 363 415 line~; +#X obj 407 303 hsl 128 15 0 1 0 1 empty empty empty -2 -8 0 10 -262144 +-1 -1 5600 1; +#X text 284 273 Mode: 0 = lowpass \, 0.5 = resonant bandpass \, 1 = +highpass; +#X floatatom 403 356 5 0 0 0 - - -; +#X obj 820 389 - 3; +#X obj 820 472 + 100; +#X obj 820 496 dbtorms; +#X floatatom 820 525 5 0 0 0 - - -; +#X obj 820 443 nbx 5 14 -1e+37 1e+37 0 1 empty empty empty 0 -8 0 10 +-262144 -1 -1 2 256; +#X obj 364 149 route fType; +#X obj 820 356 / 5; +#X obj 98 558 multimode_libpd.mmb~; +#X obj 99 598 biquad_libpd.mmb~; +#X floatatom 659 420 5 0 0 0 - - -; +#X obj 167 280 clip~ 20 128; +#X obj 169 220 lop~ 50; +#X obj 169 122 * 0.6; +#X obj 172 158 + 30; +#X obj 238 221 *~ 110; +#X obj 882 28 r fromOF; +#X obj 815 553 lop~ 50; +#X obj 881 57 route list; +#X obj 891 81 route smoothing; +#X text 38 2 audio in; +#X text 478 17 ftype; +#X text 590 17 ffreq; +#X obj 544 17 inlet; +#X obj 432 17 inlet; +#X obj 646 17 inlet; +#X text 692 17 reson; +#X floatatom 195 386 5 0 0 0 - - -; +#X connect 0 0 28 0; +#X connect 1 0 32 0; +#X connect 2 0 26 0; +#X connect 4 0 27 0; +#X connect 5 0 1 0; +#X connect 5 0 2 0; +#X connect 5 0 25 0; +#X connect 6 0 5 0; +#X connect 7 0 34 0; +#X connect 9 0 31 0; +#X connect 10 0 30 0; +#X connect 11 0 26 0; +#X connect 11 0 29 0; +#X connect 14 0 24 0; +#X connect 15 0 16 0; +#X connect 16 0 27 2; +#X connect 17 0 19 0; +#X connect 17 0 15 0; +#X connect 20 0 14 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 36 0; +#X connect 24 0 21 0; +#X connect 25 0 15 0; +#X connect 26 0 20 0; +#X connect 27 0 28 1; +#X connect 27 1 28 2; +#X connect 27 2 28 3; +#X connect 27 3 28 4; +#X connect 27 4 28 5; +#X connect 28 0 3 0; +#X connect 30 0 4 0; +#X connect 31 0 10 0; +#X connect 32 0 33 0; +#X connect 33 0 9 0; +#X connect 34 0 10 1; +#X connect 35 0 37 0; +#X connect 36 0 27 1; +#X connect 37 0 38 0; +#X connect 38 0 36 1; +#X connect 38 0 31 1; +#X connect 42 0 32 0; +#X connect 43 0 15 0; +#X connect 44 0 26 0; +#X restore 77 250 pd filter; +#X obj 96 296 *~; +#X obj 73 375 clip~ -1 1; +#N canvas 525 162 1052 736 fenvelope 0; +#X obj 113 33 inlet; +#X text 162 27 tribber; +#X obj 347 0 inlet; +#X obj 216 137 * 123; +#X obj 306 163 * 123; +#X text 474 63 proportion of level that is allways on; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 308 134 * 6; +#X obj 123 176 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 262 301 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 260 395 pack 0 1; +#X obj 469 289 f 1; +#X obj 239 225 + 1; +#X obj 142 341 f 1; +#X obj 253 368 f 0; +#X obj 309 271 + 3; +#X obj 134 680 outlet~; +#X text 82 678 filter; +#X obj 316 461 *~ 1; +#X obj 303 368 f 125; +#X obj 182 339 f 1; +#X obj 330 559 *~ 1; +#X obj 306 191 + 10; +#X obj 404 0 inlet; +#X text 345 -20 attack; +#X text 406 -23 decay; +#X obj 494 5 inlet; +#X text 488 -16 duration; +#X obj 262 330 t b b; +#X obj 121 203 t b b b; +#X connect 0 0 10 0; +#X connect 2 0 3 0; +#X connect 3 0 16 0; +#X connect 4 0 26 0; +#X connect 6 0 22 1; +#X connect 7 0 15 0; +#X connect 7 1 6 1; +#X connect 8 0 7 0; +#X connect 9 0 4 0; +#X connect 10 0 33 0; +#X connect 11 0 32 0; +#X connect 12 0 22 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 6 0; +#X connect 16 0 19 0; +#X connect 16 0 24 1; +#X connect 17 0 13 0; +#X connect 18 0 14 0; +#X connect 19 0 11 1; +#X connect 22 0 25 0; +#X connect 23 0 14 1; +#X connect 24 0 13 1; +#X connect 25 0 20 0; +#X connect 26 0 23 1; +#X connect 27 0 9 0; +#X connect 30 0 3 1; +#X connect 30 0 4 1; +#X connect 32 0 18 0; +#X connect 32 1 23 0; +#X connect 33 0 17 0; +#X connect 33 1 24 0; +#X connect 33 2 11 0; +#X restore 167 221 pd fenvelope; +#N canvas 867 125 1052 736 aenvelope 0; +#X obj 113 33 inlet; +#X obj 539 46 inlet; +#X obj 216 137 * 123; +#X obj 341 162 * 123; +#X obj 468 202 route sustain; +#X obj 471 317 -; +#X obj 465 262 t b f; +#X floatatom 465 235 5 0 0 0 - - -; +#X obj 343 133 * 6; +#X obj 341 190 + 50; +#X obj 113 186 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 270 303 delay 100; +#X obj 253 431 line~ 10 10; +#X obj 146 369 pack 1 1; +#X obj 271 381 pack 0 1; +#X obj 257 645 clip~ -1 1; +#X obj 312 580 dbtorms~; +#X obj 254 682 outlet~; +#X obj 469 289 f 1; +#X obj 316 520 *~ 60; +#X obj 316 547 +~ 40; +#X obj 218 161 + 1; +#X obj 142 341 f 1; +#X obj 269 349 f 0; +#X obj 309 271 + 3; +#X text 318 681 amplitude; +#X obj 316 461 *~ 1; +#X obj 318 490 +~ 0; +#X obj 319 348 f 125; +#X obj 182 339 f 1; +#X obj 296 608 lop~ 50; +#X obj 484 511 r fromOF; +#X obj 481 565 route smoothing; +#X obj 483 538 route list; +#X obj 224 49 inlet; +#X obj 322 49 inlet; +#X text 232 28 attack; +#X text 330 28 decay; +#X text 162 28 trigger; +#X text 532 18 total time; +#X obj 237 225 t f f; +#X obj 102 243 t b b b; +#X obj 280 325 t b b; +#X connect 0 0 10 0; +#X connect 1 0 2 1; +#X connect 1 0 3 1; +#X connect 2 0 21 0; +#X connect 3 0 9 0; +#X connect 4 0 7 0; +#X connect 5 0 26 1; +#X connect 6 0 18 0; +#X connect 6 1 5 1; +#X connect 7 0 6 0; +#X connect 7 0 27 1; +#X connect 8 0 3 0; +#X connect 9 0 28 1; +#X connect 10 0 41 0; +#X connect 11 0 23 0; +#X connect 11 0 42 0; +#X connect 12 0 26 0; +#X connect 13 0 12 0; +#X connect 14 0 12 0; +#X connect 15 0 17 0; +#X connect 16 0 30 0; +#X connect 18 0 5 0; +#X connect 19 0 20 0; +#X connect 20 0 16 0; +#X connect 21 0 40 0; +#X connect 22 0 13 0; +#X connect 23 0 14 0; +#X connect 24 0 11 1; +#X connect 26 0 27 0; +#X connect 27 0 19 0; +#X connect 28 0 14 1; +#X connect 29 0 13 1; +#X connect 30 0 15 0; +#X connect 31 0 33 0; +#X connect 32 0 30 1; +#X connect 33 0 32 0; +#X connect 34 0 2 0; +#X connect 35 0 8 0; +#X connect 40 0 29 1; +#X connect 40 1 24 0; +#X connect 41 0 22 0; +#X connect 41 1 29 0; +#X connect 41 2 11 0; +#X connect 42 0 23 0; +#X connect 42 1 28 0; +#X restore 259 222 pd aenvelope; +#N canvas 22 194 893 724 reverb 0; +#X obj 44 173 *~; +#X obj 354 161 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#X floatatom 344 184 5 0 0 0 - - -; +#X obj 342 206 * -1; +#X obj 343 232 + 1; +#X obj 149 167 *~; +#X floatatom 490 281 5 0 0 0 - - -; +#X obj 96 206 rev1~ 70; +#X obj 158 208 rev1~ 68; +#X obj 538 113 vsl 15 128 0 100 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 490 307 + 3; +#X obj 76 370 outlet~; +#X obj 141 369 outlet~; +#X obj 73 80 inlet~; +#X obj 433 41 inlet; +#X obj 507 53 hsl 128 15 0 127 0 0 empty empty empty -2 -8 0 10 -262144 +-1 -1 0 1; +#N canvas 861 22 993 1015 interpolatorReverb 0; +#X obj 71 34 inlet; +#X text 66 12 slider control; +#X floatatom 105 352 5 0 0 0 - - -; +#X floatatom 181 356 5 0 0 0 - - -; +#X floatatom 246 356 5 0 0 0 - - -; +#X floatatom 316 352 5 0 0 0 - - -; +#X obj 530 652 float 0.1; +#X text 60 827 rev mix; +#X obj 530 773 outlet; +#X text 532 751 rev dec time; +#X obj 116 408 / 32; +#X obj 181 408 / 32; +#X obj 243 410 / 32; +#X obj 316 408 / 32; +#X obj 177 381 - 32; +#X obj 245 382 - 64; +#X obj 317 378 - 96; +#X text 544 477 calc frac; +#X obj 70 500 -; +#X obj 70 481 float 1; +#X obj 814 575 loadbang; +#X obj 603 650 float 0.15; +#X obj 521 713 + 0; +#X floatatom 126 524 5 0 0 0 - - -; +#X floatatom 71 529 5 0 0 0 - - -; +#X obj 505 685 * 0.1; +#X obj 542 685 * 0.15; +#X obj 613 709 + 0; +#X obj 597 681 * 0.1; +#X obj 634 681 * 0.15; +#X obj 700 710 + 0; +#X obj 793 711 + 0; +#X obj 181 502 -; +#X obj 178 483 float 1; +#X floatatom 241 523 5 0 0 0 - - -; +#X floatatom 182 524 5 0 0 0 - - -; +#X obj 289 504 -; +#X obj 289 485 float 1; +#X floatatom 345 524 5 0 0 0 - - -; +#X floatatom 290 526 5 0 0 0 - - -; +#X text 772 621 insert values at points here; +#X obj 396 504 -; +#X obj 396 485 float 1; +#X floatatom 503 518 5 0 0 0 - - -; +#X floatatom 397 526 5 0 0 0 - - -; +#X obj 684 682 * 30; +#X obj 721 682 * 60; +#X obj 774 682 * 60; +#X obj 814 683 * 90; +#X obj 114 825 outlet; +#X obj 251 643 loadbang; +#X obj 106 754 + 0; +#X obj 87 710 * 0.1; +#X obj 124 710 * 0.15; +#X obj 195 734 + 0; +#X obj 179 706 * 0.1; +#X obj 216 706 * 0.15; +#X obj 282 735 + 0; +#X obj 375 736 + 0; +#X text 25 651 insert values at points here; +#X obj 266 707 * 30; +#X obj 303 707 * 60; +#X obj 356 707 * 60; +#X obj 396 708 * 90; +#X text 114 776 comment; +#X obj 112 677 float 0; +#X obj 253 677 float 0.3; +#X obj 325 675 float 0.6; +#X obj 393 674 float 1; +#X obj 185 675 float 0.02; +#X obj 671 652 float 20; +#X obj 812 650 float 65; +#X obj 743 650 float 40; +#X obj 174 93 < 32; +#X obj 159 119 &&; +#X floatatom 168 141 5 0 0 0 - - -; +#X obj 143 93 >= 0; +#X obj 236 118 &&; +#X obj 316 117 &&; +#X obj 401 116 &&; +#X obj 220 92 >= 32; +#X obj 257 92 < 64; +#X obj 296 92 >= 64; +#X obj 337 91 < 96; +#X obj 385 90 >= 96; +#X obj 422 90 < 128; +#X floatatom 230 140 5 0 0 0 - - -; +#X floatatom 311 138 5 0 0 0 - - -; +#X floatatom 395 137 5 0 0 0 - - -; +#X obj 230 167 * 2; +#X obj 312 166 * 3; +#X obj 393 166 * 4; +#X obj 203 224 +; +#X obj 355 219 +; +#X obj 272 265 +; +#X obj 354 193 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 272 243 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 203 194 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 212 47 t f f f f f f f f; +#X obj 103 57 t f f; +#X obj 394 457 t b f f; +#X obj 288 457 t b f f; +#X obj 178 454 t b f f; +#X obj 74 450 t b f f; +#X obj 166 311 route 1 2 3 4; +#X obj 166 288 pack f f; +#X connect 0 0 99 0; +#X connect 2 0 10 0; +#X connect 3 0 14 0; +#X connect 4 0 15 0; +#X connect 5 0 16 0; +#X connect 6 0 25 1; +#X connect 10 0 103 0; +#X connect 11 0 102 0; +#X connect 12 0 101 0; +#X connect 13 0 100 0; +#X connect 14 0 11 0; +#X connect 15 0 12 0; +#X connect 16 0 13 0; +#X connect 18 0 24 0; +#X connect 19 0 18 0; +#X connect 20 0 6 0; +#X connect 20 0 21 0; +#X connect 20 0 70 0; +#X connect 20 0 71 0; +#X connect 20 0 72 0; +#X connect 21 0 26 1; +#X connect 21 0 28 1; +#X connect 22 0 8 0; +#X connect 23 0 26 0; +#X connect 23 0 53 0; +#X connect 24 0 25 0; +#X connect 24 0 52 0; +#X connect 25 0 22 0; +#X connect 26 0 22 1; +#X connect 27 0 8 0; +#X connect 28 0 27 0; +#X connect 29 0 27 1; +#X connect 30 0 8 0; +#X connect 31 0 8 0; +#X connect 32 0 35 0; +#X connect 33 0 32 0; +#X connect 34 0 29 0; +#X connect 34 0 56 0; +#X connect 35 0 28 0; +#X connect 35 0 55 0; +#X connect 36 0 39 0; +#X connect 37 0 36 0; +#X connect 38 0 46 0; +#X connect 38 0 61 0; +#X connect 39 0 45 0; +#X connect 39 0 60 0; +#X connect 41 0 44 0; +#X connect 42 0 41 0; +#X connect 43 0 48 0; +#X connect 43 0 63 0; +#X connect 44 0 47 0; +#X connect 44 0 62 0; +#X connect 45 0 30 0; +#X connect 46 0 30 1; +#X connect 47 0 31 0; +#X connect 48 0 31 1; +#X connect 50 0 65 0; +#X connect 50 0 66 0; +#X connect 50 0 67 0; +#X connect 50 0 68 0; +#X connect 50 0 69 0; +#X connect 51 0 49 0; +#X connect 52 0 51 0; +#X connect 53 0 51 1; +#X connect 54 0 49 0; +#X connect 55 0 54 0; +#X connect 56 0 54 1; +#X connect 57 0 49 0; +#X connect 58 0 49 0; +#X connect 60 0 57 0; +#X connect 61 0 57 1; +#X connect 62 0 58 0; +#X connect 63 0 58 1; +#X connect 65 0 52 1; +#X connect 66 0 56 1; +#X connect 66 0 60 1; +#X connect 67 0 61 1; +#X connect 67 0 62 1; +#X connect 68 0 63 1; +#X connect 69 0 53 1; +#X connect 69 0 55 1; +#X connect 70 0 29 1; +#X connect 70 0 45 1; +#X connect 71 0 48 1; +#X connect 72 0 46 1; +#X connect 72 0 47 1; +#X connect 73 0 74 1; +#X connect 74 0 75 0; +#X connect 75 0 92 0; +#X connect 76 0 74 0; +#X connect 77 0 86 0; +#X connect 78 0 87 0; +#X connect 79 0 88 0; +#X connect 80 0 77 0; +#X connect 81 0 77 1; +#X connect 82 0 78 0; +#X connect 83 0 78 1; +#X connect 84 0 79 0; +#X connect 85 0 79 1; +#X connect 86 0 89 0; +#X connect 87 0 90 0; +#X connect 88 0 91 0; +#X connect 89 0 92 1; +#X connect 89 0 97 0; +#X connect 90 0 93 0; +#X connect 91 0 93 1; +#X connect 91 0 95 0; +#X connect 92 0 94 0; +#X connect 93 0 94 1; +#X connect 93 0 96 0; +#X connect 94 0 105 0; +#X connect 95 0 93 0; +#X connect 96 0 94 0; +#X connect 97 0 92 0; +#X connect 98 0 76 0; +#X connect 98 1 73 0; +#X connect 98 2 80 0; +#X connect 98 3 81 0; +#X connect 98 4 82 0; +#X connect 98 5 83 0; +#X connect 98 6 84 0; +#X connect 98 7 85 0; +#X connect 99 0 98 0; +#X connect 99 1 105 1; +#X connect 100 0 42 0; +#X connect 100 1 41 1; +#X connect 100 2 43 0; +#X connect 101 0 37 0; +#X connect 101 1 36 1; +#X connect 101 2 38 0; +#X connect 102 0 33 0; +#X connect 102 1 32 1; +#X connect 102 2 34 0; +#X connect 103 0 19 0; +#X connect 103 1 18 1; +#X connect 103 2 23 0; +#X connect 104 0 2 0; +#X connect 104 1 3 0; +#X connect 104 2 4 0; +#X connect 104 3 5 0; +#X connect 105 0 104 0; +#X restore 379 97 pd interpolatorReverb; +#X connect 0 0 11 0; +#X connect 0 0 12 0; +#X connect 1 0 2 0; +#X connect 2 0 3 0; +#X connect 2 0 5 1; +#X connect 3 0 4 0; +#X connect 4 0 0 1; +#X connect 5 0 7 0; +#X connect 5 0 8 0; +#X connect 6 0 7 1; +#X connect 6 0 10 0; +#X connect 7 0 11 0; +#X connect 8 0 12 0; +#X connect 9 0 6 0; +#X connect 10 0 8 1; +#X connect 13 0 0 0; +#X connect 13 0 5 0; +#X connect 14 0 16 0; +#X connect 15 0 16 0; +#X connect 16 0 2 0; +#X connect 16 1 6 0; +#X restore 73 407 pd reverb; +#X obj 664 -65 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 92 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 120 -86 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 80 56 / 127; +#X obj 119 57 / 127; +#X text 81 -112 attack; +#X text 124 -112 decay; +#X obj -42 -77 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text -53 -112 pitch; +#X text -7 -114 duration; +#X obj 314 -85 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 346 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X obj 301 53 / 127; +#X text 299 -115 ftype; +#X text 342 -115 ffreq; +#X obj 380 -83 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 381 -116 reson; +#X obj 569 -90 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 562 -111 reverb; +#X obj 344 82 +; +#X floatatom 339 135 5 0 0 0 - - -; +#X obj 92 335 *~ 0.1; +#X obj 46 -84 vsl 15 128 0 127 0 0 empty empty empty 0 -9 0 10 -262144 +-1 -1 0 1; +#X text 35 -102 wavef; +#X text 655 -95 trigger; +#X obj -38 -168 route pitch; +#X obj 44 -169 route waveform; +#X obj 138 -169 route attack; +#X obj 221 -171 route decay; +#X obj 301 -170 route fType; +#X obj 378 -167 route fFreq; +#X obj 459 -169 route reson; +#X obj 547 -172 route reverb; +#X obj 636 -172 route trigger; +#X obj 337 110 - 185; +#X obj -42 102 + 30; +#X obj -41 72 / 3; +#X obj 93 477 outlet~; +#X obj 153 476 outlet~; +#X obj 647 -232 inlet; +#X text 181 -80 candidate synth; +#X text 177 -51 candidate synth; +#X text 176 -24 candidate synth; +#X text 174 4 candidate synth; +#X obj 134 -233 inlet; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 28 0; +#X connect 3 0 6 0; +#X connect 4 0 1 1; +#X connect 5 0 2 1; +#X connect 6 0 44 0; +#X connect 6 1 45 0; +#X connect 7 0 4 0; +#X connect 7 0 5 0; +#X connect 8 0 10 0; +#X connect 9 0 11 0; +#X connect 10 0 4 1; +#X connect 10 0 5 1; +#X connect 11 0 4 2; +#X connect 11 0 5 2; +#X connect 14 0 43 0; +#X connect 17 0 19 0; +#X connect 18 0 26 0; +#X connect 19 0 1 2; +#X connect 22 0 1 4; +#X connect 24 0 6 1; +#X connect 26 0 41 0; +#X connect 28 0 3 0; +#X connect 29 0 0 0; +#X connect 32 0 14 0; +#X connect 33 0 29 0; +#X connect 34 0 8 0; +#X connect 35 0 9 0; +#X connect 36 0 17 0; +#X connect 37 0 18 0; +#X connect 38 0 22 0; +#X connect 39 0 24 0; +#X connect 40 0 7 0; +#X connect 41 0 1 3; +#X connect 41 0 27 0; +#X connect 42 0 26 1; +#X connect 42 0 0 1; +#X connect 43 0 42 0; +#X connect 46 0 7 0; +#X connect 51 0 32 0; +#X connect 51 0 33 0; +#X connect 51 0 34 0; +#X connect 51 0 35 0; +#X connect 51 0 36 0; +#X connect 51 0 37 0; +#X connect 51 0 38 0; +#X connect 51 0 39 0; +#X connect 51 0 40 0; +#X restore 41 -45 pd candidateSynth; +#X obj 100 162 +~; +#X obj 133 163 +~; +#X obj -14 -179 int 1; +#X obj 28 -180 int 2; +#X obj 23 -136 gate 2; +#X obj 136 -68 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 313 -71 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj -14 -200 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 +-1 -1; +#X obj 277 -128 route toTarget; +#X obj 224 -191 r fromOF; +#X obj 153 -128 route toCandidate; +#X obj 43 -289 route startTrigger; +#X text 180 159 to do swap between with short fade to prevent reverb +mixing up; +#X text 278 110 to do: remove sine osc or make it FM and do something +clever; +#X obj 141 -93 route trigger; +#X obj 288 -99 route trigger; +#X connect 1 0 9 1; +#X connect 2 0 1 0; +#X connect 2 0 12 0; +#X connect 3 0 5 1; +#X connect 3 1 6 1; +#X connect 4 0 5 0; +#X connect 4 1 6 0; +#X connect 5 0 0 0; +#X connect 6 0 0 1; +#X connect 7 0 9 0; +#X connect 8 0 9 0; +#X connect 9 0 8 0; +#X connect 9 0 10 0; +#X connect 9 1 7 0; +#X connect 9 1 11 0; +#X connect 10 0 4 1; +#X connect 11 0 3 1; +#X connect 12 0 7 0; +#X connect 13 0 3 0; +#X connect 13 0 20 0; +#X connect 14 0 13 0; +#X connect 14 0 15 0; +#X connect 15 0 4 0; +#X connect 15 0 19 0; +#X connect 16 0 2 0; +#X connect 19 0 10 0; +#X connect 20 0 11 0; diff -r 000000000000 -r a223551fdc1f testApp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testApp.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,168 @@ +#pragma once + +#include "ofMain.h" + +//#include "ofxiPhone.h" +//#include "ofxiPhoneExtras.h" +// #include "ofxiPhoneExternalDisplay.h" + +#include "ofxiOS.h" +#include "ofxiOSExtras.h" + +#include "ofxOsc.h" +#include "ofxMidi.h" +#include "2dvector.h" +#include "AppCore.h" +#include "eventLogger.h" +#include "ofxPd.h" +#include "json.h" +#import "QuestionnaireViewController.h" +#import "HelpViewController.h" +#import "UsernameAlertViewController.h" +#import "IntroViewController.h" +#include "sliderPanel.h" +#include "UIElement.h" +#include "UIElementContainer.h" +#include "buttron.h" +#include "ButtronSlider.h" +#include "buttronXY.h" +#include "UIGrid.h" +#include "MessageOrganiser.h" +#include "TestController.h" +#include "timeController.h" +#include +#include "targetSymbol.h" +#include "3Dbox.h" +#include "TextPanel.h" +//#define OSC_HOST "169.254.1.1" +//#define OSC_PORT 12345 + +#define SLIDER_GUI_WIDTH 256 +#define SLIDER_HEIGHT 256 +#define NUM_PARAMS 10 + + + +class testApp : public ofxiOSApp , public ofxMidiListener, public ofxMidiConnectionListener { + + +public: + ofTrueTypeFont verdBig; + bool sendMIDIAndOSC; + bool paused; + + int midiChannel; + int midiOffset; + double tx,ty; + ofColor generalBackground; + // + void initialiseGUIs(); + void initialiseVariables(); + void initialiseMIDI(); + void setupUIElements(); + + void setup(); + void update(); + void draw(); + void drawUIElements(); + void exit(); + + HelpViewController *helpViewController; + QuestionnaireViewController *questionnaireViewController; + UsernameAlertViewController *usernameAlertViewController; + IntroViewController * introViewController; + + MessageOrganiser messageOrganiser; + TestController* testController; + //TimeController timeController; + interfaceType whichInterfaceShowing, previousInterface; + + // pannels buttrons and slidertrons + vector UIElements; + + void touchToUIElements(int x, int y, touchType ttype, int tid); + void touchDown(ofTouchEventArgs &touch); + void touchMoved(ofTouchEventArgs &touch); + void touchUp(ofTouchEventArgs &touch); + void touchDoubleTap(ofTouchEventArgs &touch); + void touchCancelled(ofTouchEventArgs &touch); + double ofFixGetWidth(); + double ofFixGetHeight(); + ofTouchEventArgs transformTouchCoords(ofTouchEventArgs &point); + ofLight light; + + void lostFocus(); + void gotFocus(); + void gotMemoryWarning(); + void deviceOrientationChanged(int newOrientation); + +// ofxOscSender sender; +// void sendOSCParams(); + + void showQuestionnaire(); + void questionnaireHidden(vector answers, const char* userComments); + + void showIntro(); + void introHidden(); + void startTheTests(); + void showHelp(); + void helpHidden(); + void setupNewUser(); + void appModeChange(interfaceType mode); + + void sendParametersToPD(); + + void sendMidiParams(); + void sendMidiParam(int which); + + // audio callbacks + float * wavetableNew; + int bufSize; + void drawWaveform(); + void drawScore(); + void audioReceived(float * input, int bufferSize, int nChannels); + void audioRequested(float * output, int bufferSize, int nChannels); + + AppCore core; + + // message + void addMessage(string msg); + + // midi message callback + void newMidiMessage(ofxMidiMessage& msg); + + // midi device (dis)connection event callbacks + void midiInputAdded(string name, bool isNetwork); + void midiInputRemoved(string name, bool isNetwork); + + void midiOutputAdded(string nam, bool isNetwork); + void midiOutputRemoved(string name, bool isNetwork); + + vector inputs; + vector outputs; + + deque messages; + int maxMessages; + + int note, ctl; + vector bytes; + + // in the h file: + ofTrueTypeFont myfont; + + void windowResized(int w, int h){}; + + void rotateToPortrait(){}; + void rotateToPortraitUpSideDown(){}; + void rotateToLandscapeLeft(){}; + void rotateToLandscapeRight(){}; + void toggleAutoRotation(){}; + +}; + +// should be off split into +// GUI controller +// parameter converter +// MIDI stuff(?) + + diff -r 000000000000 -r a223551fdc1f testApp.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testApp.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,734 @@ +#include "testApp.h" +#include "ofAppiOSWindow.h" + +extern EventLogger eventLogger; + +// 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]; + // initilaise + + + initialiseVariables(); + + + testController = new TestController; + + messageOrganiser.init(&core, testController); + timeController.init(); + initialiseGUIs(); + initialiseMIDI(); + setupUIElements(); + + + + light.setSpotlight(45. , 1.); + light.enable(); + ofEnableSeparateSpecularLight(); + ofEnableDepthTest(); + ofEnableAlphaBlending(); + // in setup: + myfont.loadFont("NewMedia Fett.ttf", 32); + + verdBig.loadFont("verdana.ttf", 18, true, true); + verdBig.setLineHeight(18.0f); + verdBig.setLetterSpacing(1.037); + + //-------------------------------------- + + eventLogger.startLoadAll(); + //-------------------------------------- + + // now do things that will affect the start up state of the app + + // initialise PD + + 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(true){ // force start + startTheTests(); + }else{ + + if(eventLogger.questionnaireCompleted){ // then show play again dialog, and log the test number + + }else{ + // then we're in timed session mode + showIntro(); + } + } + 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); + + +} +//--------------------------------------------------------- +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]; + +} + +//-------------------------------------------------------------- +void testApp::setupUIElements(){ + + // eventually: sliderpanel, topbuttonpanel, submitbuttonpanel, countdown panel, + + // --------------------- BUTTONS + UIProps p; + ofBackground(p.generalBackground); + + ButtonPanel* bottomButtonPanel = new ButtonPanel(1,160+p.sliderPanelHeight,ofGetWidth(),250,p); + + Buttron* playTargetButton = new Buttron(p.buttonWidth*0.2,680, p); + playTargetButton->setLabel("Target"); + messageOrganiser.mapButtonToAction(playTargetButton, TRIGGER_TARGET_ID); + bottomButtonPanel->addButton(playTargetButton); + messageOrganiser.setTargetButton(playTargetButton); + + Buttron * playCandidateButton = new Buttron(p.buttonWidth*1.4,680, p); + playCandidateButton->setLabel("Current"); + messageOrganiser.mapButtonToAction(playCandidateButton, TRIGGER_CANDIDATE_ID); + bottomButtonPanel->addButton(playCandidateButton); + + + // submit button - only one for now + Buttron * submitButton = new Buttron(ofGetWidth()*0.5 - p.buttonWidth*0.5,680, p); + submitButton->setLabel("Submit"); + messageOrganiser.mapButtonToAction(submitButton, SUBMIT_CANDIDATE); + bottomButtonPanel->addButton(submitButton); + + // button - just for spacing pruposes + Buttron * spacerButton = new Buttron(ofGetWidth()*0.5 - p.buttonWidth*0.5,680, p); + spacerButton->setLabel("-"); + messageOrganiser.mapButtonToAction(spacerButton, TRIGGER_CANDIDATE_ID); + bottomButtonPanel->addButton(spacerButton); + spacerButton->hide(); + + Buttron * spacerButton2 = new Buttron(ofGetWidth()*0.5 - p.buttonWidth*0.5,680, p); + spacerButton2->setLabel("-"); + messageOrganiser.mapButtonToAction(spacerButton2, TRIGGER_CANDIDATE_ID); + bottomButtonPanel->addButton(spacerButton2); + spacerButton2->hide(); + + messageOrganiser.setBottomPanel(bottomButtonPanel); + UIElements.push_back(bottomButtonPanel); + bottomButtonPanel->showBorder(false); + + + + // ------------------------------------ SLIDERS + + vector sl2; + sl2.push_back(SLIDER); + + SliderPanel * controlPanel = new SliderPanel(1, + 160, + ofGetWidth(), + p.sliderPanelHeight, + p, + sl2); + + UIElements.push_back(controlPanel); + messageOrganiser.setControlPanel(controlPanel); + controlPanel->showBorder(true); + + // - - - - - -- - - OTHER BITS + + CountdownText * countDownBox = new CountdownText("5" , 500, 380, 455, 455, p); + UIElements.push_back(countDownBox); + messageOrganiser.setCountdownPanel(countDownBox); + countDownBox->hide(); + + TextPanel * scoreFeedback = new TextPanel("Feedback panel", ofGetWidth()*0.5 - p.buttonWidth*0.5, 666, 400,100,p); + scoreFeedback->setFontSize(SMALLFONT); + UIElements.push_back(scoreFeedback); + messageOrganiser.setScorePanel(scoreFeedback); + scoreFeedback->hide(); + + TextPanel * finishPanel = new TextPanel("Finish txt panel", 250, 250, 1000,400,p); + finishPanel->setFontSize(LARGEFONT); + finishPanel->setText("Experiment completed"); + messageOrganiser.setFinishPanel(finishPanel); + + UIElements.push_back(finishPanel); + finishPanel->hide(); + + + Buttron * newTestButton = new Buttron(ofGetWidth()-300,690, p); + newTestButton->setLabel("Next Test"); + UIElements.push_back(newTestButton); + messageOrganiser.mapButtonToAction(newTestButton, NEW_TEST_ID); + newTestButton->hide(); + messageOrganiser.setNewTestButton(newTestButton); + + TargetSymbol* targetSymbol = new TargetSymbol(ofGetWidth()*0.5,160,30,p); + messageOrganiser.setTargetSymbol(targetSymbol); + UIElements.push_back(targetSymbol); + + // alternation speed + + +// ButtronSlider * speedSlider = new ButtronSlider(ofGetWidth()-60, 210, 50, p.sliderHeight/2,FILL, p); +// UIElements.push_back(speedSlider); +// messageOrganiser.mapButtonToAction(speedSlider, SPEED_CHANGE_ID); +// +// Buttron * altButton = new Buttron(ofGetWidth()-60, 500, 50, 50,p); +// UIElements.push_back(altButton); +// altButton->setLabel("Alt"); +// messageOrganiser.mapButtonToAction(altButton, START_ALTERNATE_ID); + +// TextPanel * speedLabel = new TextPanel("Speed", ofGetWidth()-55, 195, 50,20,p); +// speedLabel->setText("Speed"); +// speedLabel->setFontSize(SMALLFONT); +// speedLabel->show(); +// UIElements.push_back(speedLabel); + + // volume +// ButtronSlider * volumeSlider = new ButtronSlider(50, 210, 30, p.sliderHeight,FILL, p); +// UIElements.push_back(volumeSlider); +// messageOrganiser.mapButtonToAction(volumeSlider, VOLUME_CHANGE_ID); +} +//-------------------------------------------------------------------------- +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 +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?? + + + delete testController; + + 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 answers, const char* userComments){ + // send answers to server as json + eventLogger.questionnaireAnswersObtained(answers, userComments); + +} + +//-------------------------------------------------------------- +void testApp::showIntro(){ + + 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 startTheTests() +} + +//-------------------------------------------------------------- +void testApp::startTheTests(){ + eventLogger.logEvent(START_THE_TESTS); + whichInterfaceShowing = COUNT_DOWN; + // do countdown etc + messageOrganiser.countdownToNewTest(); + // TODO how is testApp going to kknow whichInterfaceShowing ??? + +} +//-------------------------------------------------------------- +//-------------------------------------------------------------- +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::sendOSCParams(){ +// +// ofxOscMessage m; +// m.setAddress( "Template" ); +// +// m.addFloatArg(9.9999); +// +// sender.sendMessage( m ); +//} +//-------------------------------------------------------------- + +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(); + + // test mutex crash thing + //eventLogger.logEvent(CANDIDATE_PLAYED); +} +//-------------------------------------------------------------- + +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(); + drawScore(); + + + +} +//------------------------------------------------------------------------ +void testApp::drawUIElements(){ + + vector::iterator UIitr; + for(UIitr = UIElements.begin(); UIitr < UIElements.end(); UIitr++){ + (*UIitr)->draw(); + } +} +//------------------------------------------------------------------------ +void testApp::drawScore(){ + ofColor txtCol = ofColor(150,235,200,255); + + int score = messageOrganiser.getScore(); + stringstream msg; + + msg << "Test: " << testController->getCurrentTestLetter(); + ofSetColor(txtCol); + verdBig.drawString(msg.str(), 40, 140); + msg.str(std::string()); + + msg << "Score: " << score; + verdBig.drawString(msg.str(), 240, 140); + msg.str(std::string()); + + pair time; + time = messageOrganiser.getTime(); + msg << "Time taken: " << time.first << ":" << time.second << endl; + verdBig.drawString(msg.str(), 600, 140); + +} +//------------------------------------------------------------------------ + +//-------------------------------------------------------------- +// passes touch to UI elements +//-------------------------------------------------------------- + +void testApp::touchToUIElements(int x, int y, touchType ttype, int tid){ + vector::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 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; + messageOrganiser.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::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::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; + } + } +} diff -r 000000000000 -r a223551fdc1f timeController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/timeController.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,80 @@ + // +// timeController.h +// tweakathlon +// +// Created by Robert Tubb on 10/02/2014. +// +// + +#ifndef __tweakathlon__timeController__ +#define __tweakathlon__timeController__ +#include "ofMain.h" +#include +#include "boost/function.hpp" +#include +#import "TimedCallController.h" + +typedef boost::function TimerCallbackFunction; +typedef map TimesAndCallsMap; +typedef std::pair TimeAndCallPair; + +typedef unsigned long long TimerID; // the id is just the time it's set to fire, microsecs(?) +typedef unsigned long long TimerMicrosec; //microsecs(?) +typedef unsigned long long TimerMillisec; + +class TimeController{ + +public: + + + //---------------- + //---------------- + void init(){ + iosTimer = [[TimedCallController alloc] init]; + [iosTimer setAppRef:(id)this]; + }; + + //---------------- + // called from testApp.update() + void tick(){ + TimerID timeNow = getMicrosecTimeNow(); + callAndEraseAllExpired(timeNow); + + }; + + //---------------- + void cancelEvent(TimerID which); + //---------------- + TimerID scheduleEvent(TimerCallbackFunction cbfunc, int howLongMillisec); + //---------------- + void startStopwatch(); + TimerMicrosec stopStopwatch(); + TimerMicrosec getStopwatchElapsedTime(); + + void startCountDown(){ + + }; + void countdownFinished(){ + + }; + //---------------- + +private: + TimesAndCallsMap timesAndCalls; + TimerMillisec stopWatchStartTime; // millisec + bool stopWatchRunning; + //---------------- + void callAndEraseAllExpired(TimerMicrosec timeNow); + + TimedCallController* iosTimer; + + TimerMicrosec getMicrosecTimeNow(){ + double time_sec = [NSDate timeIntervalSinceReferenceDate]; + return TimerMicrosec(time_sec*1000000); + } + +}; + + + +#endif /* defined(__tweakathlon__timeController__) */ diff -r 000000000000 -r a223551fdc1f timeController.mm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/timeController.mm Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,72 @@ +// +// timeController.cpp +// tweakathlon +// +// Created by Robert Tubb on 10/02/2014. +// +// + +#include "timeController.h" + +TimeController timeController; + + +//---------------- +void TimeController::callAndEraseAllExpired(TimerMicrosec timeNow){ + + for(auto iter = timesAndCalls.begin(); iter != timesAndCalls.end(); ) { + if ( (*iter).first < timeNow) { + (*iter).second(); + timesAndCalls.erase(iter++); + } else { + ++iter; + } + } +}; + +//---------------- +void TimeController::cancelEvent(TimerID which){ + // + for(auto it = timesAndCalls.begin(); it != timesAndCalls.end();){ + if ((*it).first == which) { + timesAndCalls.erase(it++); + } else { + ++it; + } + } + +}; +//---------------- +TimerID TimeController::scheduleEvent(TimerCallbackFunction cbfunc, int howLongMillisec){ + + TimerID fireTime = TimerID(getMicrosecTimeNow()+ 1000.0*howLongMillisec); + timesAndCalls.insert( TimeAndCallPair(fireTime, cbfunc)); + + + return fireTime; +}; + +//---------------- +void TimeController::startStopwatch(){ + if (stopWatchRunning){ + cout << "ERROR stop watch already running" << endl; + } + + stopWatchStartTime = TimerMillisec(getMicrosecTimeNow()/1000); + stopWatchRunning = true; +} +//---------------- +TimerMillisec TimeController::stopStopwatch(){ + if (!stopWatchRunning) return 0; + stopWatchRunning = false; + TimerMillisec elapsedTime = getMicrosecTimeNow()/1000 - stopWatchStartTime; + stopWatchStartTime = 0; + return elapsedTime; +} +//---------------- +TimerMillisec TimeController::getStopwatchElapsedTime(){ + if (!stopWatchRunning) return 0; + TimerMillisec elapsedTime = getMicrosecTimeNow()/1000 - stopWatchStartTime; + return elapsedTime; +} +//---------------- \ No newline at end of file diff -r 000000000000 -r a223551fdc1f xyView.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xyView.cpp Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,39 @@ +// +// xyView.cpp +// soundspeed +// +// Created by Robert Tubb on 20/05/2013. +// +// + +#include "xyView.h" + +void XYView::draw(){ + + ofFill(); + ofNoFill(); + ofSetColor(0,0,155); + + ofRect(screenX, screenY, width, height); + ofCircle(screenX+ctrlX, screenY+ctrlY, 60); + // cross hairs + + ofLine(screenX+ctrlX - 30, screenY+ctrlY, screenX+ctrlX + 30, screenY+ctrlY); + ofLine(screenX+ctrlX,screenY+ctrlY - 30,screenX+ctrlX,screenY+ctrlY+30); + +} + +bool XYView::handleTouch(double x, double y){ + if(isInMyArea(x,y)){ + ctrlX = x; + ctrlY = y; + + return true; + }else{ + return false; + } + +} +bool XYView::isInMyArea(int x, int y){ + return (x > screenX && x < screenX + width && y > screenY && y < screenY + height); +} \ No newline at end of file diff -r 000000000000 -r a223551fdc1f xyView.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xyView.h Fri Oct 10 11:46:42 2014 +0100 @@ -0,0 +1,39 @@ +// +// xyView.h +// soundspeed +// +// Created by Robert Tubb on 20/05/2013. +// +// + +#ifndef __soundspeed__xyView__ +#define __soundspeed__xyView__ + +#include +#include "ofMain.h" + +// very sketchy XY + +class XYView{ +private: + float screenX, screenY, height, width; + float ctrlX, ctrlY; + + bool isInMyArea(int x, int y); + +public: + + XYView(double x, double y, double w, double h){ + screenX = x; + screenY = y; + width = w; + height = h; + ctrlX = w*0.5; + ctrlY = h*0.5; + } + void draw(); + bool handleTouch(double x, double y); // return false if ouside my area + +}; + +#endif /* defined(__soundspeed__xyView__) */